Pārlūkot izejas kodu

地铁代码上传了

miaofuhao 3 gadi atpakaļ
vecāks
revīzija
252134baf1
45 mainītis faili ar 15658 papildinājumiem un 0 dzēšanām
  1. 21 0
      dtkf_web-master/.babelrc
  2. 9 0
      dtkf_web-master/.editorconfig
  3. 14 0
      dtkf_web-master/.gitignore
  4. 10 0
      dtkf_web-master/.postcssrc.js
  5. BIN
      dtkf_web-master/202108271003dist.zip
  6. 21 0
      dtkf_web-master/README.md
  7. 41 0
      dtkf_web-master/build/build.js
  8. 54 0
      dtkf_web-master/build/check-versions.js
  9. BIN
      dtkf_web-master/build/logo.png
  10. 102 0
      dtkf_web-master/build/utils.js
  11. 22 0
      dtkf_web-master/build/vue-loader.conf.js
  12. 81 0
      dtkf_web-master/build/webpack.base.conf.js
  13. 95 0
      dtkf_web-master/build/webpack.dev.conf.js
  14. 145 0
      dtkf_web-master/build/webpack.prod.conf.js
  15. 7 0
      dtkf_web-master/config/dev.env.js
  16. 77 0
      dtkf_web-master/config/index.js
  17. 4 0
      dtkf_web-master/config/prod.env.js
  18. BIN
      dtkf_web-master/dtkf_web-master.zip
  19. 22 0
      dtkf_web-master/index.blade.php
  20. 30 0
      dtkf_web-master/index.html
  21. 9830 0
      dtkf_web-master/package-lock.json
  22. 69 0
      dtkf_web-master/package.json
  23. 202 0
      dtkf_web-master/src/App.vue
  24. BIN
      dtkf_web-master/src/assets/logo.png
  25. 515 0
      dtkf_web-master/src/components/dialogue.vue
  26. 158 0
      dtkf_web-master/src/components/face.vue
  27. 290 0
      dtkf_web-master/src/components/manage.vue
  28. 244 0
      dtkf_web-master/src/components/quick.vue
  29. 153 0
      dtkf_web-master/src/components/record.vue
  30. 78 0
      dtkf_web-master/src/components/screenshot.vue
  31. 96 0
      dtkf_web-master/src/components/talking.vue
  32. 65 0
      dtkf_web-master/src/components/upload.vue
  33. 51 0
      dtkf_web-master/src/components/voice.vue
  34. 69 0
      dtkf_web-master/src/components/waiting.vue
  35. 39 0
      dtkf_web-master/src/main.js
  36. 15 0
      dtkf_web-master/src/router/index.js
  37. 0 0
      dtkf_web-master/static/.gitkeep
  38. BIN
      dtkf_web-master/static/icon/MaterialIcons-Regular.eot
  39. 2373 0
      dtkf_web-master/static/icon/MaterialIcons-Regular.svg
  40. BIN
      dtkf_web-master/static/icon/MaterialIcons-Regular.ttf
  41. BIN
      dtkf_web-master/static/icon/MaterialIcons-Regular.woff
  42. BIN
      dtkf_web-master/static/icon/MaterialIcons-Regular.woff2
  43. 1 0
      dtkf_web-master/static/icon/material-icons.css
  44. BIN
      dtkf_web-master/static/images/face.png
  45. 655 0
      dtkf_web-master/static/js/niuniucapture.js

+ 21 - 0
dtkf_web-master/.babelrc

@@ -0,0 +1,21 @@
1
+{
2
+	"presets": [
3
+		[
4
+			"env",
5
+			{
6
+				"useBuiltIns": true,
7
+				"modules": false,
8
+				"targets": {
9
+					"browsers": [
10
+						"ie 11"
11
+					]
12
+				}
13
+			}
14
+		],
15
+		"stage-2"
16
+	],
17
+	"plugins": [
18
+		"transform-vue-jsx",
19
+		"transform-runtime"
20
+	]
21
+}

+ 9 - 0
dtkf_web-master/.editorconfig

@@ -0,0 +1,9 @@
1
+root = true
2
+
3
+[*]
4
+charset = utf-8
5
+indent_style = tab
6
+indent_size = 4
7
+end_of_line = lf
8
+insert_final_newline = true
9
+trim_trailing_whitespace = true

+ 14 - 0
dtkf_web-master/.gitignore

@@ -0,0 +1,14 @@
1
+.DS_Store
2
+node_modules/
3
+/dist/
4
+npm-debug.log*
5
+yarn-debug.log*
6
+yarn-error.log*
7
+
8
+# Editor directories and files
9
+.idea
10
+.vscode
11
+*.suo
12
+*.ntvs*
13
+*.njsproj
14
+*.sln

+ 10 - 0
dtkf_web-master/.postcssrc.js

@@ -0,0 +1,10 @@
1
+// https://github.com/michael-ciniawsky/postcss-load-config
2
+
3
+module.exports = {
4
+  "plugins": {
5
+    "postcss-import": {},
6
+    "postcss-url": {},
7
+    // to edit target browsers: use "browserslist" field in package.json
8
+    "autoprefixer": {}
9
+  }
10
+}

BIN
dtkf_web-master/202108271003dist.zip


+ 21 - 0
dtkf_web-master/README.md

@@ -0,0 +1,21 @@
1
+# newmsg
2
+
3
+> 地铁客服
4
+
5
+## Build Setup
6
+
7
+``` bash
8
+# install dependencies
9
+npm install
10
+
11
+# serve with hot reload at localhost:8080
12
+npm run dev
13
+
14
+# build for production with minification
15
+npm run build
16
+
17
+# build for production and view the bundle analyzer report
18
+npm run build --report
19
+```
20
+
21
+For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).

+ 41 - 0
dtkf_web-master/build/build.js

@@ -0,0 +1,41 @@
1
+'use strict'
2
+require('./check-versions')()
3
+
4
+process.env.NODE_ENV = 'production'
5
+
6
+const ora = require('ora')
7
+const rm = require('rimraf')
8
+const path = require('path')
9
+const chalk = require('chalk')
10
+const webpack = require('webpack')
11
+const config = require('../config')
12
+const webpackConfig = require('./webpack.prod.conf')
13
+
14
+const spinner = ora('building for production...')
15
+spinner.start()
16
+
17
+rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18
+  if (err) throw err
19
+  webpack(webpackConfig, (err, stats) => {
20
+    spinner.stop()
21
+    if (err) throw err
22
+    process.stdout.write(stats.toString({
23
+      colors: true,
24
+      modules: false,
25
+      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
26
+      chunks: false,
27
+      chunkModules: false
28
+    }) + '\n\n')
29
+
30
+    if (stats.hasErrors()) {
31
+      console.log(chalk.red('  Build failed with errors.\n'))
32
+      process.exit(1)
33
+    }
34
+
35
+    console.log(chalk.cyan('  Build complete.\n'))
36
+    console.log(chalk.yellow(
37
+      '  Tip: built files are meant to be served over an HTTP server.\n' +
38
+      '  Opening index.html over file:// won\'t work.\n'
39
+    ))
40
+  })
41
+})

+ 54 - 0
dtkf_web-master/build/check-versions.js

@@ -0,0 +1,54 @@
1
+'use strict'
2
+const chalk = require('chalk')
3
+const semver = require('semver')
4
+const packageConfig = require('../package.json')
5
+const shell = require('shelljs')
6
+
7
+function exec (cmd) {
8
+  return require('child_process').execSync(cmd).toString().trim()
9
+}
10
+
11
+const versionRequirements = [
12
+  {
13
+    name: 'node',
14
+    currentVersion: semver.clean(process.version),
15
+    versionRequirement: packageConfig.engines.node
16
+  }
17
+]
18
+
19
+if (shell.which('npm')) {
20
+  versionRequirements.push({
21
+    name: 'npm',
22
+    currentVersion: exec('npm --version'),
23
+    versionRequirement: packageConfig.engines.npm
24
+  })
25
+}
26
+
27
+module.exports = function () {
28
+  const warnings = []
29
+
30
+  for (let i = 0; i < versionRequirements.length; i++) {
31
+    const mod = versionRequirements[i]
32
+
33
+    if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
34
+      warnings.push(mod.name + ': ' +
35
+        chalk.red(mod.currentVersion) + ' should be ' +
36
+        chalk.green(mod.versionRequirement)
37
+      )
38
+    }
39
+  }
40
+
41
+  if (warnings.length) {
42
+    console.log('')
43
+    console.log(chalk.yellow('To use this template, you must update following to modules:'))
44
+    console.log()
45
+
46
+    for (let i = 0; i < warnings.length; i++) {
47
+      const warning = warnings[i]
48
+      console.log('  ' + warning)
49
+    }
50
+
51
+    console.log()
52
+    process.exit(1)
53
+  }
54
+}

BIN
dtkf_web-master/build/logo.png


+ 102 - 0
dtkf_web-master/build/utils.js

@@ -0,0 +1,102 @@
1
+'use strict'
2
+const path = require('path')
3
+const config = require('../config')
4
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
5
+const packageConfig = require('../package.json')
6
+
7
+exports.assetsPath = function (_path) {
8
+  const assetsSubDirectory = process.env.NODE_ENV === 'production'
9
+    ? config.build.assetsSubDirectory
10
+    : config.dev.assetsSubDirectory
11
+
12
+  return path.posix.join(assetsSubDirectory, _path)
13
+}
14
+
15
+exports.cssLoaders = function (options) {
16
+  options = options || {}
17
+
18
+  const cssLoader = {
19
+    loader: 'css-loader',
20
+    options: {
21
+      sourceMap: options.sourceMap
22
+    }
23
+  }
24
+
25
+  const postcssLoader = {
26
+    loader: 'postcss-loader',
27
+    options: {
28
+      sourceMap: options.sourceMap
29
+    }
30
+  }
31
+
32
+  // generate loader string to be used with extract text plugin
33
+  function generateLoaders (loader, loaderOptions) {
34
+    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
35
+
36
+    if (loader) {
37
+      loaders.push({
38
+        loader: loader + '-loader',
39
+        options: Object.assign({}, loaderOptions, {
40
+          sourceMap: options.sourceMap
41
+        })
42
+      })
43
+    }
44
+
45
+    // Extract CSS when that option is specified
46
+    // (which is the case during production build)
47
+    if (options.extract) {
48
+      return ExtractTextPlugin.extract({
49
+        use: loaders,
50
+        fallback: 'vue-style-loader',
51
+		publicPath:'../../'
52
+      })
53
+    } else {
54
+      return ['vue-style-loader'].concat(loaders)
55
+    }
56
+  }
57
+
58
+  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
59
+  return {
60
+    css: generateLoaders(),
61
+    postcss: generateLoaders(),
62
+    less: generateLoaders('less'),
63
+    sass: generateLoaders('sass', { indentedSyntax: true }),
64
+    scss: generateLoaders('sass'),
65
+    stylus: generateLoaders('stylus'),
66
+    styl: generateLoaders('stylus')
67
+  }
68
+}
69
+
70
+// Generate loaders for standalone style files (outside of .vue)
71
+exports.styleLoaders = function (options) {
72
+  const output = []
73
+  const loaders = exports.cssLoaders(options)
74
+
75
+  for (const extension in loaders) {
76
+    const loader = loaders[extension]
77
+    output.push({
78
+      test: new RegExp('\\.' + extension + '$'),
79
+      use: loader
80
+    })
81
+  }
82
+
83
+  return output
84
+}
85
+
86
+exports.createNotifierCallback = () => {
87
+  const notifier = require('node-notifier')
88
+
89
+  return (severity, errors) => {
90
+    if (severity !== 'error') return
91
+
92
+    const error = errors[0]
93
+    const filename = error.file && error.file.split('!').pop()
94
+
95
+    notifier.notify({
96
+      title: packageConfig.name,
97
+      message: severity + ': ' + error.name,
98
+      subtitle: filename || '',
99
+      icon: path.join(__dirname, 'logo.png')
100
+    })
101
+  }
102
+}

+ 22 - 0
dtkf_web-master/build/vue-loader.conf.js

@@ -0,0 +1,22 @@
1
+'use strict'
2
+const utils = require('./utils')
3
+const config = require('../config')
4
+const isProduction = process.env.NODE_ENV === 'production'
5
+const sourceMapEnabled = isProduction
6
+  ? config.build.productionSourceMap
7
+  : config.dev.cssSourceMap
8
+
9
+module.exports = {
10
+  loaders: utils.cssLoaders({
11
+    sourceMap: sourceMapEnabled,
12
+    extract: isProduction
13
+  }),
14
+  cssSourceMap: sourceMapEnabled,
15
+  cacheBusting: config.dev.cacheBusting,
16
+  transformToRequire: {
17
+    video: ['src', 'poster'],
18
+    source: 'src',
19
+    img: 'src',
20
+    image: 'xlink:href'
21
+  }
22
+}

+ 81 - 0
dtkf_web-master/build/webpack.base.conf.js

@@ -0,0 +1,81 @@
1
+'use strict'
2
+const path = require('path')
3
+const utils = require('./utils')
4
+const config = require('../config')
5
+const vueLoaderConfig = require('./vue-loader.conf')
6
+
7
+function resolve(dir) {
8
+	return path.join(__dirname, '..', dir)
9
+}
10
+
11
+
12
+
13
+module.exports = {
14
+	context: path.resolve(__dirname, '../'),
15
+	entry: {
16
+		app: ["babel-polyfill", "./src/main.js"]
17
+	},
18
+	output: {
19
+		path: config.build.assetsRoot,
20
+		filename: '[name].js',
21
+		publicPath: process.env.NODE_ENV === 'production'
22
+			? config.build.assetsPublicPath
23
+			: config.dev.assetsPublicPath
24
+	},
25
+	resolve: {
26
+		extensions: ['.js', '.vue', '.json'],
27
+		alias: {
28
+			'@': resolve('src'),
29
+		}
30
+	},
31
+	module: {
32
+		rules: [
33
+			{
34
+				test: /\.vue$/,
35
+				loader: 'vue-loader',
36
+				options: vueLoaderConfig
37
+			},
38
+			{
39
+				test: /\.js$/,
40
+				loader: 'babel-loader',
41
+				include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client'), resolve('node_modules/muse-ui')]
42
+			},
43
+			{
44
+				test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
45
+				loader: 'url-loader',
46
+				options: {
47
+					limit: 1000,
48
+					name: utils.assetsPath('img/[name].[hash:7].[ext]')
49
+				}
50
+			},
51
+			{
52
+				test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
53
+				loader: 'url-loader',
54
+				options: {
55
+					limit: 1000,
56
+					name: utils.assetsPath('media/[name].[hash:7].[ext]')
57
+				}
58
+			},
59
+			{
60
+				test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
61
+				loader: 'url-loader',
62
+				options: {
63
+					limit: 1000,
64
+					name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
65
+				}
66
+			}
67
+		]
68
+	},
69
+	node: {
70
+		// prevent webpack from injecting useless setImmediate polyfill because Vue
71
+		// source contains it (although only uses it if it's native).
72
+		setImmediate: false,
73
+		// prevent webpack from injecting mocks to Node native modules
74
+		// that does not make sense for the client
75
+		dgram: 'empty',
76
+		fs: 'empty',
77
+		net: 'empty',
78
+		tls: 'empty',
79
+		child_process: 'empty'
80
+	}
81
+}

+ 95 - 0
dtkf_web-master/build/webpack.dev.conf.js

@@ -0,0 +1,95 @@
1
+'use strict'
2
+const utils = require('./utils')
3
+const webpack = require('webpack')
4
+const config = require('../config')
5
+const merge = require('webpack-merge')
6
+const path = require('path')
7
+const baseWebpackConfig = require('./webpack.base.conf')
8
+const CopyWebpackPlugin = require('copy-webpack-plugin')
9
+const HtmlWebpackPlugin = require('html-webpack-plugin')
10
+const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
11
+const portfinder = require('portfinder')
12
+
13
+const HOST = process.env.HOST
14
+const PORT = process.env.PORT && Number(process.env.PORT)
15
+
16
+const devWebpackConfig = merge(baseWebpackConfig, {
17
+  module: {
18
+    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
19
+  },
20
+  // cheap-module-eval-source-map is faster for development
21
+  devtool: config.dev.devtool,
22
+
23
+  // these devServer options should be customized in /config/index.js
24
+  devServer: { 
25
+    clientLogLevel: 'warning',
26
+    historyApiFallback: {
27
+      rewrites: [
28
+        { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
29
+      ],
30
+    },
31
+    hot: true,
32
+    contentBase: false, // since we use CopyWebpackPlugin.
33
+    compress: true,
34
+    host: HOST || config.dev.host,
35
+    port: PORT || config.dev.port,
36
+    open: config.dev.autoOpenBrowser,
37
+    overlay: config.dev.errorOverlay
38
+      ? { warnings: false, errors: true }
39
+      : false,
40
+    publicPath: config.dev.assetsPublicPath,
41
+    proxy: config.dev.proxyTable,
42
+    quiet: true, // necessary for FriendlyErrorsPlugin
43
+    watchOptions: {
44
+      poll: config.dev.poll,
45
+    }
46
+  },
47
+  plugins: [
48
+    new webpack.DefinePlugin({
49
+      'process.env': require('../config/dev.env')
50
+    }),
51
+    new webpack.HotModuleReplacementPlugin(),
52
+    new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
53
+    new webpack.NoEmitOnErrorsPlugin(),
54
+    // https://github.com/ampedandwired/html-webpack-plugin
55
+    new HtmlWebpackPlugin({
56
+      filename: 'index.html',
57
+      template: 'index.html',
58
+      inject: true
59
+    }),
60
+    // copy custom static assets
61
+    new CopyWebpackPlugin([
62
+      {
63
+        from: path.resolve(__dirname, '../static'),
64
+        to: config.dev.assetsSubDirectory,
65
+        ignore: ['.*']
66
+      }
67
+    ])
68
+  ]
69
+})
70
+
71
+module.exports = new Promise((resolve, reject) => {
72
+  portfinder.basePort = process.env.PORT || config.dev.port
73
+  portfinder.getPort((err, port) => {
74
+    if (err) {
75
+      reject(err)
76
+    } else {
77
+      // publish the new Port, necessary for e2e tests
78
+      process.env.PORT = port
79
+      // add port to devServer config
80
+      devWebpackConfig.devServer.port = port
81
+
82
+      // Add FriendlyErrorsPlugin
83
+      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
84
+        compilationSuccessInfo: {
85
+          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
86
+        },
87
+        onErrors: config.dev.notifyOnErrors
88
+        ? utils.createNotifierCallback()
89
+        : undefined
90
+      }))
91
+
92
+      resolve(devWebpackConfig)
93
+    }
94
+  })
95
+})

+ 145 - 0
dtkf_web-master/build/webpack.prod.conf.js

@@ -0,0 +1,145 @@
1
+'use strict'
2
+const path = require('path')
3
+const utils = require('./utils')
4
+const webpack = require('webpack')
5
+const config = require('../config')
6
+const merge = require('webpack-merge')
7
+const baseWebpackConfig = require('./webpack.base.conf')
8
+const CopyWebpackPlugin = require('copy-webpack-plugin')
9
+const HtmlWebpackPlugin = require('html-webpack-plugin')
10
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
11
+const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12
+const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
13
+
14
+const env = require('../config/prod.env')
15
+
16
+const webpackConfig = merge(baseWebpackConfig, {
17
+  module: {
18
+    rules: utils.styleLoaders({
19
+      sourceMap: config.build.productionSourceMap,
20
+      extract: true,
21
+      usePostCSS: true
22
+    })
23
+  },
24
+  devtool: config.build.productionSourceMap ? config.build.devtool : false,
25
+  output: {
26
+    path: config.build.assetsRoot,
27
+    filename: utils.assetsPath('js/[name].[chunkhash].js'),
28
+    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
29
+  },
30
+  plugins: [
31
+    // http://vuejs.github.io/vue-loader/en/workflow/production.html
32
+    new webpack.DefinePlugin({
33
+      'process.env': env
34
+    }),
35
+    new UglifyJsPlugin({
36
+      uglifyOptions: {
37
+        compress: {
38
+          warnings: false
39
+        }
40
+      },
41
+      sourceMap: config.build.productionSourceMap,
42
+      parallel: true
43
+    }),
44
+    // extract css into its own file
45
+    new ExtractTextPlugin({
46
+      filename: utils.assetsPath('css/[name].[contenthash].css'),
47
+      // Setting the following option to `false` will not extract CSS from codesplit chunks.
48
+      // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
49
+      // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
50
+      // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
51
+      allChunks: true,
52
+    }),
53
+    // Compress extracted CSS. We are using this plugin so that possible
54
+    // duplicated CSS from different components can be deduped.
55
+    new OptimizeCSSPlugin({
56
+      cssProcessorOptions: config.build.productionSourceMap
57
+        ? { safe: true, map: { inline: false } }
58
+        : { safe: true }
59
+    }),
60
+    // generate dist index.html with correct asset hash for caching.
61
+    // you can customize output by editing /index.html
62
+    // see https://github.com/ampedandwired/html-webpack-plugin
63
+    new HtmlWebpackPlugin({
64
+      filename: config.build.index,
65
+      template: 'index.blade.php',
66
+      inject: true,
67
+      minify: {
68
+        removeComments: true,
69
+        collapseWhitespace: true,
70
+        removeAttributeQuotes: true
71
+        // more options:
72
+        // https://github.com/kangax/html-minifier#options-quick-reference
73
+      },
74
+      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
75
+      chunksSortMode: 'dependency'
76
+    }),
77
+    // keep module.id stable when vendor modules does not change
78
+    new webpack.HashedModuleIdsPlugin(),
79
+    // enable scope hoisting
80
+    new webpack.optimize.ModuleConcatenationPlugin(),
81
+    // split vendor js into its own file
82
+    new webpack.optimize.CommonsChunkPlugin({
83
+      name: 'vendor',
84
+      minChunks (module) {
85
+        // any required modules inside node_modules are extracted to vendor
86
+        return (
87
+          module.resource &&
88
+          /\.js$/.test(module.resource) &&
89
+          module.resource.indexOf(
90
+            path.join(__dirname, '../node_modules')
91
+          ) === 0
92
+        )
93
+      }
94
+    }),
95
+    // extract webpack runtime and module manifest to its own file in order to
96
+    // prevent vendor hash from being updated whenever app bundle is updated
97
+    new webpack.optimize.CommonsChunkPlugin({
98
+      name: 'manifest',
99
+      minChunks: Infinity
100
+    }),
101
+    // This instance extracts shared chunks from code splitted chunks and bundles them
102
+    // in a separate chunk, similar to the vendor chunk
103
+    // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
104
+    new webpack.optimize.CommonsChunkPlugin({
105
+      name: 'app',
106
+      async: 'vendor-async',
107
+      children: true,
108
+      minChunks: 3
109
+    }),
110
+
111
+    // copy custom static assets
112
+    new CopyWebpackPlugin([
113
+      {
114
+        from: path.resolve(__dirname, '../static'),
115
+        to: config.build.assetsSubDirectory,
116
+        ignore: ['.*']
117
+      }
118
+    ])
119
+  ]
120
+})
121
+
122
+if (config.build.productionGzip) {
123
+  const CompressionWebpackPlugin = require('compression-webpack-plugin')
124
+
125
+  webpackConfig.plugins.push(
126
+    new CompressionWebpackPlugin({
127
+      asset: '[path].gz[query]',
128
+      algorithm: 'gzip',
129
+      test: new RegExp(
130
+        '\\.(' +
131
+        config.build.productionGzipExtensions.join('|') +
132
+        ')$'
133
+      ),
134
+      threshold: 10240,
135
+      minRatio: 0.8
136
+    })
137
+  )
138
+}
139
+
140
+if (config.build.bundleAnalyzerReport) {
141
+  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
142
+  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
143
+}
144
+
145
+module.exports = webpackConfig

+ 7 - 0
dtkf_web-master/config/dev.env.js

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

+ 77 - 0
dtkf_web-master/config/index.js

@@ -0,0 +1,77 @@
1
+'use strict'
2
+// Template version: 1.3.1
3
+// see http://vuejs-templates.github.io/webpack for documentation.
4
+
5
+const path = require('path')
6
+
7
+module.exports = {
8
+  dev: {
9
+
10
+    // Paths
11
+    assetsSubDirectory: 'static', 
12
+    assetsPublicPath: '/',
13
+    //proxyTable: {},
14
+    proxyTable: {
15
+      "/api": {
16
+         target: "http://dtkf.hyrjdz.cn/api", //设置调用的接口域名和端口
17
+         changeOrigin: true,    //是否跨域
18
+         pathRewrite: {
19
+           "^/api": "" //用'/api' 代替 'http://www.liulongbin.top:3005/api'
20
+         }
21
+       }
22
+    },
23
+    // Various Dev Server settings
24
+    host: 'localhost', // can be overwritten by process.env.HOST
25
+    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
26
+    autoOpenBrowser: false,
27
+    errorOverlay: true,
28
+    notifyOnErrors: true,
29
+    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
30
+
31
+
32
+    /**
33
+     * Source Maps
34
+     */
35
+
36
+    // https://webpack.js.org/configuration/devtool/#development
37
+    devtool: 'cheap-module-eval-source-map',
38
+
39
+    // If you have problems debugging vue-files in devtools,
40
+    // set this to false - it *may* help
41
+    // https://vue-loader.vuejs.org/en/options.html#cachebusting
42
+    cacheBusting: true,
43
+
44
+    cssSourceMap: true
45
+  },
46
+
47
+  build: {
48
+    // Template for index.html
49
+    index: path.resolve(__dirname, '../dist/index.blade.php'),
50
+
51
+    // Paths
52
+    assetsRoot: path.resolve(__dirname, '../dist'),
53
+    assetsSubDirectory: 'static',
54
+    assetsPublicPath: './',
55
+
56
+    /**
57
+     * Source Maps
58
+     */
59
+
60
+    productionSourceMap: false,
61
+    // https://webpack.js.org/configuration/devtool/#production
62
+    devtool: '#source-map',
63
+
64
+    // Gzip off by default as many popular static hosts such as
65
+    // Surge or Netlify already gzip all static assets for you.
66
+    // Before setting to `true`, make sure to:
67
+    // npm install --save-dev compression-webpack-plugin
68
+    productionGzip: false,
69
+    productionGzipExtensions: ['js', 'css'],
70
+
71
+    // Run the build command with an extra argument to
72
+    // View the bundle analyzer report after build finishes:
73
+    // `npm run build --report`
74
+    // Set to `true` or `false` to always turn it on or off
75
+    bundleAnalyzerReport: process.env.npm_config_report
76
+  }
77
+}

+ 4 - 0
dtkf_web-master/config/prod.env.js

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

BIN
dtkf_web-master/dtkf_web-master.zip


+ 22 - 0
dtkf_web-master/index.blade.php

@@ -0,0 +1,22 @@
1
+<!DOCTYPE html>
2
+<html>
3
+
4
+<head>
5
+	<meta charset="utf-8">
6
+	<base href="{!! asset('web/wxkf') !!}/">
7
+	<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
8
+	<meta name="viewport" content="width=device-width,initial-scale=1.0">
9
+	<title>微信在线客服</title>
10
+	<link rel="stylesheet" href="./static/icon/material-icons.css">
11
+	<script>
12
+		var config = {!! json_encode($config,256) !!};
13
+	</script>
14
+</head>
15
+
16
+<body>
17
+	<div id="app"></div>
18
+	<script src="./static/js/niuniucapture.js"></script>
19
+	<!-- built files will be auto injected -->
20
+</body>
21
+
22
+</html>

+ 30 - 0
dtkf_web-master/index.html

@@ -0,0 +1,30 @@
1
+<!DOCTYPE html>
2
+<html>
3
+
4
+<head>
5
+  <meta charset="utf-8">
6
+  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
7
+  <meta name="viewport" content="width=device-width,initial-scale=1.0">
8
+  <title>微信客服</title>
9
+  <link rel="stylesheet" href="./static/icon/material-icons.css">
10
+  <script>
11
+    var config = {
12
+      img_path: 'http://127.0.0.1/dtkf/public/storage/',
13
+      base: 'http://dtkf.hyrjdz.cn/api/dtkf',
14
+      service_id: 1,
15
+      service: [
16
+        { id: 1, name: '客服1' },
17
+        { id: 2, name: '客服2' },
18
+        { id: 3, name: '客服3' }
19
+      ]
20
+    }
21
+  </script>
22
+</head>
23
+
24
+<body>
25
+  <div id="app"></div>
26
+  <script src="./static/js/niuniucapture.js"></script>
27
+  <!-- built files will be auto injected -->
28
+</body>
29
+
30
+</html>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 9830 - 0
dtkf_web-master/package-lock.json


+ 69 - 0
dtkf_web-master/package.json

@@ -0,0 +1,69 @@
1
+{
2
+  "name": "newmsg",
3
+  "version": "1.0.0",
4
+  "description": "地铁客服",
5
+  "author": "赵雪林 <409774878@qq.com>",
6
+  "private": true,
7
+  "scripts": {
8
+    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9
+    "start": "npm run dev",
10
+    "build": "node build/build.js" 
11
+  },
12
+  "dependencies": {
13
+    "axios": "^0.18.0",
14
+    "copy-to-clipboard": "^3.2.0",
15
+    "muse-ui": "^3.0.1",
16
+    "muse-ui-message": "^0.2.1",
17
+    "muse-ui-toast": "^0.3.0",
18
+    "qq-wechat-emotion-parser": "^1.0.4",
19
+    "vue": "^2.5.2"
20
+  },
21
+  "devDependencies": {
22
+    "autoprefixer": "^7.1.2",
23
+    "babel-core": "^6.22.1",
24
+    "babel-helper-vue-jsx-merge-props": "^2.0.3",
25
+    "babel-loader": "^7.1.1",
26
+    "babel-plugin-import": "^1.10.0",
27
+    "babel-plugin-syntax-jsx": "^6.18.0",
28
+    "babel-plugin-transform-runtime": "^6.22.0",
29
+    "babel-plugin-transform-vue-jsx": "^3.5.0",
30
+    "babel-polyfill": "^6.26.0",
31
+    "babel-preset-env": "^1.3.2",
32
+    "babel-preset-stage-2": "^6.22.0",
33
+    "chalk": "^2.0.1",
34
+    "copy-webpack-plugin": "^4.0.1",
35
+    "css-loader": "^3.1.0",
36
+    "extract-text-webpack-plugin": "^3.0.0",
37
+    "file-loader": "^1.1.4",
38
+    "friendly-errors-webpack-plugin": "^1.6.1",
39
+    "html-webpack-plugin": "^2.30.1",
40
+    "koa2-cors": "^2.0.6",
41
+    "node-notifier": "^5.1.2",
42
+    "optimize-css-assets-webpack-plugin": "^3.2.0",
43
+    "ora": "^1.2.0",
44
+    "portfinder": "^1.0.13",
45
+    "postcss-import": "^11.0.0",
46
+    "postcss-loader": "^2.0.8",
47
+    "postcss-url": "^7.2.1",
48
+    "promise.prototype.finally": "^3.1.0",
49
+    "rimraf": "^2.6.0",
50
+    "semver": "^5.3.0",
51
+    "shelljs": "^0.7.6",
52
+    "uglifyjs-webpack-plugin": "^1.1.1",
53
+    "url-loader": "^2.1.0",
54
+    "vue-loader": "^13.3.0",
55
+    "vue-style-loader": "^3.0.1",
56
+    "vue-template-compiler": "^2.5.2",
57
+    "webpack": "^3.6.0",
58
+    "webpack-bundle-analyzer": "^3.3.2",
59
+    "webpack-dev-server": "^2.9.1",
60
+    "webpack-merge": "^4.1.0"
61
+  },
62
+  "engines": {
63
+    "node": ">= 6.0.0",
64
+    "npm": ">= 3.0.0"
65
+  },
66
+  "browserslist": [
67
+    "ie 11"
68
+  ]
69
+}

+ 202 - 0
dtkf_web-master/src/App.vue

@@ -0,0 +1,202 @@
1
+<template>
2
+	<div class="main">
3
+		<div class="left">
4
+			<mu-tabs :value.sync="active" inverse indicator-color="blue" center class="top-tabs">
5
+				<mu-tab>对话中</mu-tab>
6
+				<mu-tab>
7
+					<span>待接入
8
+						<mu-badge :content="waiting_count.toString()" color="red" v-show="waiting_count>0"></mu-badge>
9
+					</span>
10
+				</mu-tab>
11
+			</mu-tabs>
12
+			<div class="tab-items">
13
+				<Talking v-show="active==0" :last_time="last_time" @change="(id)=>{talk_with=id}"></Talking>
14
+				<Waiting v-show="active!=0"></Waiting>
15
+				<mu-menu class="main-menu">
16
+					<mu-button fab small color="teal500">
17
+						<mu-icon value="menu"></mu-icon>
18
+					</mu-button>
19
+					<ul class="mu-list static-list" slot="content">
20
+						<li @click="view='Manage'">
21
+							<div class="mu-item">
22
+								<i class="mu-icon material-icons">find_in_page</i>
23
+								<div class="mu-item-title">消息管理器</div>
24
+							</div>
25
+						</li>
26
+					</ul>
27
+				</mu-menu>
28
+			</div>
29
+		</div>
30
+		<div class="middle">
31
+			<Dialogue v-show="view=='Dialogue'"/>
32
+			<Manage v-if="view=='Manage'" @close="view='Dialogue'"/>
33
+		</div>
34
+		<div class="right">
35
+			<Quick></Quick>
36
+		</div>
37
+		<Upload></Upload>
38
+		<Record></Record>
39
+		<Voice></Voice>
40
+		<mu-dialog class="loading" width="400" max-width="80%" :esc-press-close="false" :overlay-close="false" :open="loading">
41
+			<mu-icon value="loop" class="rotate"></mu-icon>
42
+			<h2>正在处理……</h2>
43
+		</mu-dialog>
44
+	</div>
45
+</template>
46
+
47
+<script>
48
+import Talking from './components/talking';
49
+import Waiting from './components/waiting';
50
+import Dialogue from './components/dialogue';
51
+import Record from './components/record';
52
+import Upload from './components/upload';
53
+import Quick from './components/quick';
54
+import Manage from './components/manage';
55
+import Voice from './components/voice';
56
+
57
+let wait_step = 0;
58
+
59
+export default {
60
+	name: "App",
61
+	components: {
62
+		Talking, Waiting, Record, Dialogue, Upload, Quick, Manage, Voice
63
+	},
64
+	data() {
65
+		return {
66
+			loading: false,
67
+			active: 0,
68
+			talk_with: 0,
69
+			last_time: 0,
70
+			waiting_count: 0,
71
+			service: config.service,
72
+			view: 'Dialogue'
73
+		}
74
+	},
75
+	methods: {
76
+		openRecord() {
77
+			this.$refs.record.open();
78
+		},
79
+		polling() {
80
+			let query = {
81
+				service_id: config.service_id,
82
+				talking_list: this.last_time
83
+			};
84
+			if (this.talk_with) query.talk_with = this.talk_with;
85
+			this.$ajax.get('polling', { params: query }).then((res) => {
86
+				if (res.code === 0) {
87
+					if (res.data.talking_list.length > 0) {
88
+						this.$bus.$emit('update_talking_list', res.data.talking_list);
89
+						wait_step = 0;
90
+					} else if (++wait_step > 30) {
91
+						this.$bus.$emit('update_talking_list', []);
92
+						wait_step = 0;
93
+					}
94
+					if (res.data.waiting_count != this.waiting_count) {
95
+						this.$bus.$emit('update_waiting_list');
96
+					}
97
+					this.waiting_count = res.data.waiting_count;
98
+					this.last_time = res.data.last_time;
99
+				} else {
100
+
101
+				}
102
+			}).finally(() => {
103
+				setTimeout(() => {
104
+					this.polling();
105
+				}, 5000);
106
+			})
107
+		}
108
+	},
109
+	created() {
110
+		this.$bus.loading = (l) => {
111
+			this.active = 0;
112
+			this.loading = l;
113
+		};
114
+		this.$bus.$on('access_user', (item) => {
115
+			this.waiting_count--;
116
+		});
117
+		this.polling();
118
+	}
119
+};
120
+</script>
121
+
122
+<style>
123
+.main {
124
+	position: relative;
125
+	height: 100vh;
126
+	width: 100vw;
127
+	background: #fff;
128
+	min-width: 1280px;
129
+	min-height: 480px;
130
+}
131
+.left,
132
+.middle,
133
+.right {
134
+	height: 100%;
135
+}
136
+.left,
137
+.right {
138
+	width: 350px;
139
+	position: absolute;
140
+	top: 0;
141
+}
142
+.middle {
143
+	width: 100%;
144
+	padding: 0 350px;
145
+	box-sizing: border-box;
146
+}
147
+.left {
148
+	border-right: 1px #ddd solid;
149
+}
150
+.right {
151
+	border-left: 1px #ddd solid;
152
+	right: 0;
153
+}
154
+
155
+.top-tabs {
156
+	position: absolute;
157
+	width: 100%;
158
+}
159
+.tab-items {
160
+	width: 100%;
161
+	height: 100%;
162
+	padding-top: 50px;
163
+	overflow-y: auto;
164
+}
165
+.loading h2 {
166
+	font-size: 22px;
167
+	margin: 0;
168
+	padding-left: 50px;
169
+}
170
+@keyframes icon-rotate {
171
+	0% {
172
+		transform: rotate(0);
173
+	}
174
+	100% {
175
+		transform: rotate(-360deg);
176
+	}
177
+}
178
+.loading .mu-icon {
179
+	font-size: 35px;
180
+	position: absolute;
181
+}
182
+.mu-icon.rotate {
183
+	animation: icon-rotate 1s linear infinite;
184
+}
185
+.mu-avatar {
186
+	line-height: 38px;
187
+}
188
+.mu-list {
189
+	padding: 0;
190
+}
191
+.main-menu {
192
+	position: absolute;
193
+	right: 10px;
194
+	bottom: 10px;
195
+}
196
+.mu-button {
197
+	vertical-align: middle;
198
+}
199
+.mu-card-header{
200
+	padding: 5px 10px;
201
+}
202
+</style>

BIN
dtkf_web-master/src/assets/logo.png


+ 515 - 0
dtkf_web-master/src/components/dialogue.vue

@@ -0,0 +1,515 @@
1
+<template>
2
+	<div class="talking" v-if="user">
3
+		<mu-card-header :title="user.nickname" sub-title="微信用户" class="mu-elevation-2">
4
+			<mu-avatar slot="avatar" v-html="user.headimg"></mu-avatar>
5
+			<div style="float:right;line-height: 36px">
6
+				<mu-menu>
7
+					<mu-button round color="error">
8
+						<mu-icon value="close"></mu-icon>结束
9
+					</mu-button>
10
+					<ul class="mu-list static-list" slot="content">
11
+						<li @click="closeOrder">
12
+							<div class="mu-item">
13
+								<i class="mu-icon material-icons">launch</i>
14
+								<div class="mu-item-title">生成工单</div>
15
+							</div>
16
+						</li>
17
+						<li @click="closeMsg">
18
+							<div class="mu-item">
19
+								<i class="mu-icon material-icons">remove_circle_outline</i>
20
+								<div class="mu-item-title">结束会话</div>
21
+							</div>
22
+						</li>
23
+					</ul>
24
+				</mu-menu>
25
+				<mu-menu>
26
+					<mu-button round color="success">
27
+						<mu-icon value="refresh"></mu-icon>转接
28
+					</mu-button>
29
+					<ul class="mu-list static-list" slot="content">
30
+						<li v-for="item in service" :key="item.id" @click="transfer(item.id)">
31
+							<div class="mu-item">
32
+								<i class="mu-icon material-icons">account_box</i>
33
+								<div class="mu-item-title">{{item.name}}</div>
34
+							</div>
35
+						</li>
36
+					</ul>
37
+				</mu-menu>
38
+			</div>
39
+		</mu-card-header>
40
+		<div class="chat-list" ref="list">
41
+			<template v-for="item in user.msg">
42
+				<div class="chat-msg chat-tip" v-if="item.type==2" :key="item.id" style="text-align:center">{{item.msg}} {{item.created_at}}</div>
43
+				<div class="chat-msg" v-else :key="item.id" :class="{self:item.source>=1,error:item.load==2}">
44
+					<div class="chat-info">
45
+						<span class="chat-name">{{item.source>0?'客服':user.nickname}}</span>
46
+						<span class="chat-timestamp">{{item.created_at}}</span>
47
+					</div>
48
+					<mu-avatar v-html="item.source>0?'客':user.headimg"></mu-avatar>
49
+					<div class="chat-text">
50
+						<span>
51
+							<mu-icon class="tip" :class="{rotate:item.load==1}" :value="item.load==1?'loop':'error'" v-if="item.load"></mu-icon>
52
+							<p v-html="item.msg"></p>
53
+						</span>
54
+					</div>
55
+				</div>
56
+			</template>
57
+		</div>
58
+		<div class="editer">
59
+			<textarea ref="input" @keyup="keyUp" @keydown="keyDown"></textarea>
60
+			<div class="action top">
61
+				<Face @change="insertText"></Face>
62
+				<Screenshot></Screenshot>
63
+				<mu-button flat style="float:right" @click="$bus.$emit('open_record', user)">聊天记录
64
+					<mu-icon right value="more_horiz"></mu-icon>
65
+				</mu-button>
66
+			</div>
67
+			<div class="action bottom">
68
+				<span style="margin-right: 20px">Enter发送,Ctrl+Enter换行</span>
69
+				<mu-button round color="primary" @click="send">发送
70
+					<mu-icon value="send" right></mu-icon>
71
+				</mu-button>
72
+			</div>
73
+		</div>
74
+	</div>
75
+	<div class="talking" v-else>
76
+		<mu-icon value="sms" class="none"></mu-icon>
77
+	</div>
78
+</template>
79
+
80
+<script>
81
+import Face from './face';
82
+import Screenshot from './screenshot';
83
+import emotion from "qq-wechat-emotion-parser";
84
+
85
+function transform(text) {
86
+	text = text.replace(/\n/g, "<br>");
87
+	return emotion(text);
88
+}
89
+
90
+function imgTag(path) {
91
+	return '<img src="' + config.img_path + path + '">';
92
+}
93
+
94
+function insertText(obj, str) {
95
+	if (document.selection) {
96
+		var sel = document.selection.createRange();
97
+		sel.text = str;
98
+	} else if (typeof obj.selectionStart === "number" && typeof obj.selectionEnd === "number") {
99
+		var startPos = obj.selectionStart,
100
+			endPos = obj.selectionEnd,
101
+			cursorPos = startPos,
102
+			tmpStr = obj.value;
103
+		obj.value = tmpStr.substring(0, startPos) + str + tmpStr.substring(endPos, tmpStr.length);
104
+		cursorPos += str.length;
105
+		obj.selectionStart = obj.selectionEnd = cursorPos;
106
+	} else {
107
+		obj.value += str;
108
+	}
109
+}
110
+
111
+let last_timer = 0;
112
+
113
+export default {
114
+	name: "dialogue",
115
+	components: {
116
+		Face, Screenshot
117
+	},
118
+	data() {
119
+		return {
120
+			user_id: 0,
121
+			record: {},
122
+			service: config.service
123
+		}
124
+	},
125
+	computed: {
126
+		user() {
127
+			return this.record[this.user_id];
128
+		}
129
+	},
130
+	methods: {
131
+		closeOrder() {
132
+			this.$confirm('点击确认将会打开生成工单界面,填写提交后将会生成工单并在稍后结束当前会话。', '确定要生成工单吗?').then(({ result }) => {
133
+				if (result) {
134
+					window.open(config.base + 'close/' + this.user_id);
135
+					this.$alert("请在打开的工单窗口填写工单信息,提交工单后聊天将在稍后自动结束。");
136
+				}
137
+			});
138
+		},
139
+		closeMsg() {
140
+			this.$confirm('点击确认将会结束当前会话并从会话列表移除对话,但不会生成工单。', '确定要结束会话吗?').then(({ result }) => {
141
+				if (result) {
142
+					this.$bus.loading(true);
143
+					this.$ajax.get('close_msg', {
144
+						params: {
145
+							service_id: config.service_id,
146
+							customer_id: this.user_id
147
+						}
148
+					}).finally(() => {
149
+						this.$bus.loading(false);
150
+					}).then((res) => {
151
+						this.$alert("已结束会话。");
152
+						this.$bus.$emit('update_msg', {
153
+							id: this.user_id,
154
+							close: 1
155
+						});
156
+						this.user_id = 0;
157
+					});
158
+				}
159
+			});
160
+		},
161
+		scrollBottom() {
162
+			this.$nextTick(() => {
163
+				this.$refs.list.scrollTop = this.$refs.list.scrollHeight;
164
+			});
165
+		},
166
+		insertText(str) {
167
+			insertText(this.$refs.input, str);
168
+		},
169
+		keyDown(e) {
170
+			switch (e.keyCode) {
171
+				case 13:
172
+					if (this.ctrl) {
173
+						this.insertText('\n');
174
+					} else {
175
+						this.send();
176
+					}
177
+					e.preventDefault();
178
+					return false;
179
+				case 17:
180
+					this.ctrl = 1;
181
+					break;
182
+			}
183
+		},
184
+		keyUp(e) {
185
+			if (e.keyCode === 17)
186
+				this.ctrl = 0;
187
+		},
188
+		transfer(id) {
189
+			this.$prompt('请输入转接原因', '提示').then(({ result, value }) => {
190
+				if (result) {
191
+					this.$bus.loading(true);
192
+					this.$ajax.get('transfer', {
193
+						params: {
194
+							service_id: id,
195
+							customer_id: this.user_id,
196
+							msg: value
197
+						}
198
+					}).finally(() => {
199
+						this.$bus.loading(false);
200
+					}).then((res) => {
201
+						if (res.code === 0) {
202
+							this.$alert('转接完毕');
203
+							this.$bus.$emit('update_msg', {
204
+								id: this.user_id,
205
+								close: 1
206
+							});
207
+							this.user_id = 0;
208
+						}
209
+					});
210
+				}
211
+			});
212
+		},
213
+		postMsg(msg, text) {
214
+			let user = this.user;
215
+			this.user.msg.push(msg);
216
+			this.scrollBottom();
217
+			this.$ajax.post('send_msg', {
218
+				service_id: config.service_id,
219
+				customer_id: user.id,
220
+				type: msg.type,
221
+				msg: text
222
+			}).then((res) => {
223
+				if (res.code === 0) {
224
+					msg.load = 0;
225
+					this.$bus.$emit('update_msg', {
226
+						id: user.id,
227
+						msg: msg.type ? '[图片]' : text,
228
+						clean: 1
229
+					});
230
+				} else {
231
+					msg.load = 2;
232
+				}
233
+			}).catch(() => {
234
+				msg.load = 2;
235
+			});
236
+		},
237
+		send() {
238
+			let text = this.$refs.input.value;
239
+			if (!text.length) {
240
+				this.$alert('发送消息不能为空');
241
+				return;
242
+			}
243
+			let now = new Date;
244
+			let msg = {
245
+				id: now.getTime(),
246
+				source: 1,
247
+				type: 0,
248
+				created_at: now.toLocaleString(),
249
+				msg: transform(text),
250
+				load: 1
251
+			}
252
+			this.postMsg(msg, text);
253
+			this.$refs.input.value = '';
254
+		},
255
+		loadMsg(user_id) {
256
+			if (user_id != this.user_id) return;
257
+			let timer = ++last_timer;
258
+			let user = this.record[user_id];
259
+			this.$ajax.get('msg_list', {
260
+				params: {
261
+					service_id: config.service_id,
262
+					customer_id: user.id,
263
+					last_id: user.last_id
264
+				}
265
+			}).then((res) => {
266
+				if (res.code === 0 && timer == last_timer) {
267
+					if (res.data.length > 0) {
268
+						let msg;
269
+						for (let index = 0; index < res.data.length; index++) {
270
+							msg = res.data[index];
271
+							msg.created_at = (new Date(msg.created_at * 1000)).toLocaleString();
272
+							switch (msg.type) {
273
+								case 0:
274
+									msg.msg = transform(msg.msg);
275
+									break;
276
+								case 1:
277
+									msg.msg = imgTag(msg.msg)
278
+									break;
279
+								case 3:
280
+									msg.msg = '<span onclick="voice(\''+msg.msg+'\','+msg.id+')" class="mu-chip mu-success-color mu-inverse"><i class="mu-icon material-icons">keyboard_voice</i> 点击播放语音</span>'
281
+									break;
282
+							}
283
+							user.msg.push(msg);
284
+						}
285
+						this.$bus.$emit('update_msg', {
286
+							id: user.id,
287
+							msg: (msg.type == 1||msg.type == 3) ? ('['+(msg.type == 1?'图片':'语音')+']') : msg.msg,
288
+							close: user.last_id && msg.type == 2 ? 1 : 0
289
+						});
290
+						user.last_id = msg.id;
291
+						if (user.msg.length > 50) {
292
+							user.msg = user.msg.slice(-20);
293
+						}
294
+						this.scrollBottom();
295
+					}
296
+				}
297
+				setTimeout(() => {
298
+					if (timer == last_timer) this.loadMsg(user_id, timer);
299
+				}, 3000);
300
+			}).catch(() => {
301
+				setTimeout(() => {
302
+					if (timer == last_timer) this.loadMsg(user_id, timer);
303
+				}, 5000);
304
+			});
305
+		}
306
+	},
307
+	created() {
308
+		this.$bus.$on('talk_with', (item) => {
309
+			if (!this.record[item.id]) {
310
+				this.$set(this.record, item.id, {
311
+					id: item.id,
312
+					nickname: item.nickname,
313
+					headimg: item.headimg,
314
+					last_id: 0,
315
+					msg: []
316
+				});
317
+			} else {
318
+				this.scrollBottom();
319
+			}
320
+			this.user_id = item.id;
321
+			this.loadMsg(item.id);
322
+		});
323
+		this.$bus.$on('img_path', (text) => {
324
+			let now = new Date;
325
+			let msg = {
326
+				id: now.getTime(),
327
+				source: 1,
328
+				type: 1,
329
+				created_at: now.toLocaleString(),
330
+				msg: imgTag(text),
331
+				load: 1
332
+			}
333
+			this.postMsg(msg, text);
334
+		});
335
+		this.$bus.$on('delete_talk', (id) => {
336
+			if (this.user_id == id) this.user_id = 0;
337
+			delete (this.record[id]);
338
+		});
339
+		this.$bus.$on('quick_msg', ({msg, send}) => {
340
+			if(this.user_id){
341
+				this.$refs.input.value = msg;
342
+				if(send) this.send();
343
+			}
344
+		});
345
+	},
346
+	beforeDestroy() {
347
+		last_timer = 0;
348
+	}
349
+};
350
+</script>
351
+
352
+<style>
353
+.talking {
354
+	position: relative;
355
+	width: 100%;
356
+	height: 100%;
357
+	overflow: hidden;
358
+	box-sizing: border-box;
359
+}
360
+.talking .none {
361
+	font-size: 200px;
362
+	color: #ccc;
363
+	display: block;
364
+	margin-top: 30vh;
365
+	text-align: center;
366
+}
367
+.talking .chat-list {
368
+	position: absolute;
369
+	left: 0;
370
+	top: 57px;
371
+	bottom: 30%;
372
+	right: 0;
373
+	overflow-y: scroll;
374
+	padding: 10px 20px 0;
375
+}
376
+.editer {
377
+	left: 0;
378
+	right: 0;
379
+	bottom: 0;
380
+	height: 30%;
381
+	position: absolute;
382
+	border-top: 1px #ccc solid;
383
+	overflow: hidden;
384
+	padding: 50px 10px;
385
+}
386
+.editer textarea {
387
+	width: 100%;
388
+	height: 100%;
389
+	border: none;
390
+	outline: none;
391
+	resize: none;
392
+}
393
+.editer .action {
394
+	position: absolute;
395
+	width: 100%;
396
+	left: 0;
397
+	padding: 5px 10px;
398
+}
399
+.editer .top {
400
+	top: 0;
401
+}
402
+.editer .bottom {
403
+	bottom: 0;
404
+	text-align: right;
405
+}
406
+button {
407
+	vertical-align: middle;
408
+}
409
+.editer .top .mu-fab-button.mu-button-small .mu-icon {
410
+	font-size: 24px;
411
+}
412
+
413
+.chat-info {
414
+	margin-bottom: 2px;
415
+	font-size: 12px;
416
+	height: 20px;
417
+}
418
+.chat-msg {
419
+	margin-bottom: 20px;
420
+	position: relative;
421
+}
422
+.chat-msg .tip {
423
+	color: #333;
424
+	position: absolute;
425
+	margin-left: -40px;
426
+}
427
+.chat-msg .chat-info > * {
428
+	float: left;
429
+}
430
+.chat-msg.self .chat-info > * {
431
+	float: right;
432
+}
433
+.chat-info .chat-name {
434
+	font-weight: 600;
435
+}
436
+.chat-info .chat-timestamp {
437
+	margin: 0 10px;
438
+	color: #888;
439
+}
440
+.chat-msg .mu-avatar {
441
+	float: left;
442
+}
443
+.chat-msg.self .mu-avatar {
444
+	float: right;
445
+	background: #2196f3;
446
+}
447
+.chat-text {
448
+	position: relative;
449
+	margin: 5px 30px 0 50px;
450
+	word-break: break-all;
451
+}
452
+.chat-text > span {
453
+	display: inline-block;
454
+	border-radius: 5px;
455
+	position: relative;
456
+	padding: 5px 10px;
457
+	background: #ddd;
458
+	color: #333;
459
+	min-height: 32px;
460
+}
461
+.chat-text p {
462
+	margin: 0;
463
+}
464
+.chat-msg.self .chat-text {
465
+	text-align: right;
466
+	margin: 5px 50px 0 30px;
467
+}
468
+.chat-msg.self .chat-text > span {
469
+	text-align: left;
470
+	background: #03a9f4;
471
+	color: #fff;
472
+}
473
+.chat-msg.error .chat-text > span {
474
+	border: 1px #ff5722 solid;
475
+}
476
+.chat-msg.error .mu-icon {
477
+	color: #ff5722;
478
+}
479
+.chat-text:before {
480
+	margin-top: -6px;
481
+	position: absolute;
482
+	right: 100%;
483
+	top: 15px;
484
+	border: 6px solid transparent;
485
+	border-right-color: #ddd;
486
+	content: ' ';
487
+	height: 0;
488
+	width: 0;
489
+	pointer-events: none;
490
+	box-sizing: border-box;
491
+}
492
+.chat-msg.self .chat-text:before {
493
+	right: auto;
494
+	left: 100%;
495
+	border-color: transparent;
496
+	border-left-color: #03a9f4;
497
+}
498
+.chat-msg.chat-tip{
499
+	background: #aaa;
500
+	color:#fff;
501
+	padding: 5px 10px;
502
+}
503
+.chat-text img {
504
+	max-width: 400px;
505
+}
506
+.static-list li {
507
+	cursor: pointer;
508
+}
509
+.static-list li:hover {
510
+	background: #eee;
511
+}
512
+.static-list .mu-icon {
513
+	margin-right: 10px;
514
+}
515
+</style>

+ 158 - 0
dtkf_web-master/src/components/face.vue

@@ -0,0 +1,158 @@
1
+<template>
2
+	<mu-menu>
3
+		<mu-button fab small color="grey800">
4
+			<mu-icon value="face"></mu-icon>
5
+		</mu-button>
6
+		<mu-paper slot="content" :z-depth="4" class="face-card">
7
+			<a v-once href="javascript:;" v-for="(item,key) in icons" :key="key" :title="item[1]" @click="choose(item[0])"></a>
8
+			<img src="static/images/face.png">
9
+		</mu-paper>
10
+	</mu-menu>
11
+</template>
12
+
13
+<script>
14
+export default {
15
+	name: 'face',
16
+	data() {
17
+		return {
18
+			icons: [
19
+				["/::)", "微笑"],
20
+				["/::~", "撇嘴"],
21
+				["/::B", "色"],
22
+				["/::|", "发呆"],
23
+				["/:8-)", "得意"],
24
+				["/::<", "流泪"],
25
+				["/::$", "害羞"],
26
+				["/::X", "闭嘴"],
27
+				["/::Z", "睡"],
28
+				["/::'(", "大哭"],
29
+				["/::-|", "尴尬"],
30
+				["/::@", "发怒"],
31
+				["/::P", "调皮"],
32
+				["/::D", "呲牙"],
33
+				["/::O", "惊讶"],
34
+				["/::(", "难过"],
35
+				["/::+", "酷"],
36
+				["/:–b", "冷汗"],
37
+				["/::Q", "抓狂"],
38
+				["/::T", "吐"],
39
+				["/:,@P", "偷笑"],
40
+				["/:,@-D", "愉快"],
41
+				["/::d", "白眼"],
42
+				["/:,@o", "傲慢"],
43
+				["/::g", "饥饿"],
44
+				["/:|-)", "困"],
45
+				["/::!", "惊恐"],
46
+				["/::L", "流汗"],
47
+				["/::>", "憨笑"],
48
+				["/::,@", "悠闲"],
49
+				["/:,@f", "奋斗"],
50
+				["/::-S", "咒骂"],
51
+				["/:?", "疑问"],
52
+				["/:,@x", "嘘"],
53
+				["/:,@@", "晕"],
54
+				["/::8", "疯了"],
55
+				["/:,@!", "哀"],
56
+				["/:!!!", "骷髅"],
57
+				["/:xx", "敲打"],
58
+				["/:bye", "再见"],
59
+				["/:wipe", "擦汗"],
60
+				["/:dig", "抠鼻"],
61
+				["/:handclap", "鼓掌"],
62
+				["/:&-(", "糗大了"],
63
+				["/:B-)", "坏笑"],
64
+				["/:<@", "左哼哼"],
65
+				["/:@>", "右哼哼"],
66
+				["/::-O", "哈欠"],
67
+				["/:>-|", "鄙视"],
68
+				["/:P-(", "委屈"],
69
+				["/::'|", "快哭了"],
70
+				["/:X-)", "阴险"],
71
+				["/::*", "亲亲"],
72
+				["/:@x", "吓"],
73
+				["/:8*", "可怜"],
74
+				["/:pd", "菜刀"],
75
+				["/:<W>", "西瓜"],
76
+				["/:beer", "啤酒"],
77
+				["/:basketb", "篮球"],
78
+				["/:oo", "乒乓"],
79
+				["/:coffee", "咖啡"],
80
+				["/:eat", "饭"],
81
+				["/:pig", "猪头"],
82
+				["/:rose", "玫瑰"],
83
+				["/:fade", "凋谢"],
84
+				["/:showlove", "嘴唇"],
85
+				["/:heart", "爱心"],
86
+				["/:break", "心碎"],
87
+				["/:cake", "蛋糕"],
88
+				["/:li", "闪电"],
89
+				["/:bome", "炸弹"],
90
+				["/:kn", "刀"],
91
+				["/:footb", "足球"],
92
+				["/:ladybug", "瓢虫"],
93
+				["/:shit", "便便"],
94
+				["/:moon", "月亮"],
95
+				["/:sun", "太阳"],
96
+				["/:gift", "礼物"],
97
+				["/:hug", "拥抱"],
98
+				["/:strong", "强"],
99
+				["/:weak", "弱"],
100
+				["/:share", "握手"],
101
+				["/:v", "胜利"],
102
+				["/:@)", "抱拳"],
103
+				["/:jj", "勾引"],
104
+				["/:@@", "拳头"],
105
+				["/:bad", "差劲"],
106
+				["/:lvu", "爱你"],
107
+				["/:no", "NO"],
108
+				["/:ok", "OK"],
109
+				["/:love", "爱情"],
110
+				["/:<L>", "飞吻"],
111
+				["/:jump", "跳跳"],
112
+				["/:shake", "发抖"],
113
+				["/:<O>", "怄火"],
114
+				["/:circle", "转圈"],
115
+				["/:kotow", "磕头"],
116
+				["/:turn", "回头"],
117
+				["/:skip", "跳绳"],
118
+				["/:oY", "投降"],
119
+				["/:#-0", "激动"],
120
+				["/:hiphot", "乱舞"],
121
+				["/:kiss", "献吻"],
122
+				["/:<&", "左太极"],
123
+				["/:&>", "右太极"]
124
+			]
125
+		}
126
+	},
127
+	methods:{
128
+		choose(t){
129
+			this.$emit('change',t);
130
+		}
131
+	}
132
+}
133
+</script>
134
+
135
+<style>
136
+.face-card{
137
+	width: 435px;
138
+	height: 203px;
139
+	position: relative;
140
+}
141
+.face-card img{
142
+	position: absolute;
143
+	top: 0;
144
+	left: 0;
145
+	pointer-events:none;
146
+}
147
+.face-card a{
148
+	float: left;
149
+	width: 29px;
150
+	height: 29px;
151
+}
152
+.face-card a:hover{
153
+	background: #ccc;
154
+}
155
+.face-card * {
156
+	display: block;
157
+}
158
+</style>

+ 290 - 0
dtkf_web-master/src/components/manage.vue

@@ -0,0 +1,290 @@
1
+<template>
2
+  <div class="talking manage">
3
+    <mu-tabs
4
+      :value.sync="active"
5
+      inverse
6
+      indicator-color="blue"
7
+      center
8
+      class="top-tabs"
9
+      @change="reset()"
10
+    >
11
+    </mu-tabs>
12
+    
13
+    <mu-button
14
+        flat
15
+        style="position: absolute; left: 6px; top: 5px"
16
+        @click="$emit('close')"
17
+        ><mu-icon value="arrow_back" left></mu-icon>返回</mu-button
18
+      >
19
+
20
+    <div class="search">
21
+      <mu-form :model="filter">
22
+        <mu-form-item prop="search" label="关键词">
23
+          <mu-text-field v-model="filter.search"></mu-text-field>
24
+        </mu-form-item>
25
+        <mu-form-item prop="begin" label="起始日期">
26
+          <mu-date-input v-model="filter.begin" type="date" value-format="YYYY-MM-DD" ></mu-date-input>
27
+        </mu-form-item>
28
+        <mu-form-item prop="end" label="截止日期">
29
+          <mu-date-input v-model="filter.end" type="date" value-format="YYYY-MM-DD" ></mu-date-input>
30
+        </mu-form-item>
31
+        <mu-button color="primary" @click="search()">搜索</mu-button>
32
+        <mu-button @click="clear">清除</mu-button>
33
+      </mu-form>
34
+    </div>
35
+    <div class="resultCon">
36
+      <div class="resultTit"  v-show="pagination.data.length>0">用户</div>
37
+      <div class="resultPer"  v-show="pagination.data.length>0" style="text-align: center">
38
+        
39
+        <p v-show="loadingTion || !pagination.data.length" style="text-align: center">
40
+          {{ loadingTion ? "正在查询……" : "未找到数据" }}
41
+        </p>
42
+
43
+        <mu-list>
44
+          <mu-list-item
45
+            avatar
46
+            button
47
+            :ripple="false"
48
+            v-for="item in pagination.data"
49
+            :key="item.id"
50
+            @click="info(item)"
51
+          >
52
+            <mu-list-item-action>
53
+              <mu-avatar v-if="item.headimg == ''">{{
54
+                item.nickname.substr(0, 1)
55
+              }}</mu-avatar>
56
+              <mu-avatar v-else><img :src="item.headimg" /></mu-avatar>
57
+            </mu-list-item-action>
58
+            <mu-list-item-title
59
+              >{{ item.nickname }}
60
+              <span class="time">{{ item.last_time }}</span></mu-list-item-title
61
+            >
62
+          </mu-list-item>
63
+        </mu-list>
64
+        
65
+        <mu-pagination
66
+          v-show="!loadingTion && pagination.total > 10"
67
+          style="margin-top: 20px"
68
+          :total="pagination.total"
69
+          :current.sync="pagination.current"
70
+          @change="searchUser()"
71
+        ></mu-pagination>
72
+      </div>
73
+      <div class="resultTallTit" v-show="paginatall.data.length>0">聊天记录</div>
74
+      <p v-show=" loadingTall|| !paginatall.data.length" style="text-align: center">
75
+          {{ loadingTall ? "正在查询……" : "未找到数据" }}
76
+        </p>
77
+      <div class="resultTall" v-show="paginatall.data.length>0">
78
+        <mu-list textline="two-line">
79
+          <mu-list-item
80
+            button
81
+            :ripple="false"
82
+            v-for="item in paginatall.data"
83
+            :key="item.customer_id"
84
+            @click="info(item)"
85
+          >
86
+            <mu-list-item-content>
87
+              <mu-list-item-title>
88
+                <mu-badge v-if="item.source > 0" color="primary" content="客服" />
89
+                <mu-badge v-else content="用户" />
90
+                {{ item.name }}
91
+                <span class="time">{{ item.created_at }}</span>
92
+              </mu-list-item-title>
93
+              <mu-list-item-sub-title>{{ item.msg }}</mu-list-item-sub-title>
94
+            </mu-list-item-content>
95
+          </mu-list-item>
96
+        </mu-list>
97
+        <mu-pagination
98
+          v-show="!loadingTall && paginatall.total > 10"
99
+          style="margin-top: 20px"
100
+          :total="paginatall.total"
101
+          :current.sync="paginatall.current"
102
+          @change="searchTall()"
103
+        ></mu-pagination>
104
+      </div>
105
+    </div>
106
+
107
+  </div>
108
+</template>
109
+
110
+<script>
111
+export default {
112
+  name: 'manage',
113
+  data () {
114
+    return {
115
+      active: 0,
116
+      loading: 0,
117
+      loadingTion:0,
118
+      loadingTall:0,
119
+      filter: {
120
+        search: '',
121
+        begin: '',
122
+        end: ''
123
+      },
124
+      pagination: {
125
+        total: 0,
126
+        current: 1,
127
+        data: []
128
+      },
129
+      paginatall: {
130
+        total: 0,
131
+        current: 1,
132
+        data: []
133
+      }
134
+    }
135
+  },
136
+  methods: {
137
+    searchUser () {
138
+      this.loadingTion = 1;
139
+      this.pagination.data = [];
140
+      this.$ajax.get('manage/user?page=' + this.pagination.current, {
141
+      //this.$ajax.post('manage/search?page=' + this.pagination.current, {
142
+        params: this.filter
143
+      }).then((res) => {
144
+        this.loadingTion = 0;
145
+        this.pagination = res;
146
+        console.log(this.pagination)
147
+      });
148
+    },
149
+    searchTall () {
150
+      this.loadingTall = 1;
151
+      this.paginatall.data = [];
152
+      this.$ajax.get('manage/msg?page=' + this.paginatall.current, {
153
+      //this.$ajax.post('manage/search?page=' + this.pagination.current, {
154
+        params: this.filter
155
+      }).then((res) => {
156
+        this.loadingTall = 0;
157
+        this.paginatall = res;
158
+        console.log(this.paginatall)
159
+      });
160
+      
161
+      
162
+    },
163
+    search(){
164
+      this.loadingTion = 1;
165
+      this.pagination.data = [];
166
+      this.$ajax.get('manage/user?page=' + this.pagination.current, {
167
+      //this.$ajax.post('manage/search?page=' + this.pagination.current, {
168
+        params: this.filter
169
+      }).then((res) => {
170
+        this.loadingTion = 0;
171
+        this.pagination = res;
172
+        console.log(this.pagination)
173
+      });
174
+
175
+      this.loadingTall = 1;
176
+      this.paginatall.data = [];
177
+      this.$ajax.get('manage/msg?page=' + this.paginatall.current, {
178
+      //this.$ajax.post('manage/search?page=' + this.pagination.current, {
179
+        params: this.filter
180
+      }).then((res) => {
181
+        this.loadingTall = 0;
182
+        this.paginatall = res;
183
+        console.log(this.paginatall)
184
+      });
185
+    },
186
+    reset () {
187
+      this.pagination.total = 0;
188
+      this.pagination.current = 1;
189
+      this.searchTall();
190
+    },
191
+    clear () {
192
+      for (let k in this.filter) {
193
+        this.filter[k] = '';
194
+      }
195
+      this.reset();
196
+    },
197
+    info (item) {
198
+      this.$bus.$emit('open_record', {
199
+        id: item.customer_id,
200
+        nickname: item.nickname,
201
+        msg_id: item.id
202
+      });
203
+    }
204
+  },
205
+  created () {
206
+    this.searchUser();
207
+    this.searchTall();
208
+    
209
+  }
210
+}
211
+</script>
212
+
213
+<style>
214
+.talking {
215
+  position: relative;
216
+  width: 100%;
217
+  height: 100%;
218
+  overflow: hidden;
219
+  box-sizing: border-box;
220
+}
221
+.search {
222
+  width: 35%;
223
+  border-right: 1px #eee solid;
224
+}
225
+.resultCon{
226
+  padding: 10px;
227
+  position: absolute;
228
+  top: 50px;
229
+  right: 0px;
230
+  bottom: 0;
231
+  overflow-y: auto;
232
+  height: 900px;
233
+  width: 65%;
234
+}
235
+.result {
236
+  width: 100%;
237
+  right: 0;
238
+}
239
+.search,
240
+.result {
241
+  padding: 10px;
242
+  overflow-y: auto;
243
+  height: 400px;
244
+  position: absolute;
245
+  top: 50px;
246
+}
247
+.result .resultTit, .resultTall .resultTit{
248
+  line-height: 30px;
249
+  border-bottom: 1px solid #cccccc;
250
+  height: 30px;
251
+}
252
+.resultTit{
253
+  line-height: 30px;
254
+  background: #cccccc;
255
+  border-bottom: 1px solid #cccccc;
256
+  width: 100%;
257
+  height: 30px;
258
+  z-index: 11;
259
+}
260
+.resultTallTit{
261
+  background: #cccccc;
262
+  width: 100%;
263
+  right: 0;
264
+  line-height: 30px;
265
+  border-bottom: 1px solid #cccccc;
266
+  height: 30px;
267
+}
268
+.result .time {
269
+  float: right;
270
+  color: #aaa;
271
+}
272
+.resultTall {
273
+  width: 100%;
274
+  right: 0;
275
+}
276
+.resultPer {
277
+  padding: 10px;
278
+  overflow-y: auto;
279
+  height: 370px;
280
+}
281
+.resultTall {
282
+  padding: 10px;
283
+  overflow-y: auto;
284
+  height: 450px;
285
+}
286
+.resultTall .time {
287
+  float: right;
288
+  color: #aaa;
289
+}
290
+</style>

+ 244 - 0
dtkf_web-master/src/components/quick.vue

@@ -0,0 +1,244 @@
1
+<template>
2
+  <div class="quick-msg">
3
+    <div class="quick-head">
4
+      <span class="tag" :class="{ action: !action }" @click="action = 0"
5
+        >公共回复</span
6
+      >
7
+      <span class="tag" :class="{ action: action }" @click="action = 1"
8
+        >私有回复</span
9
+      >
10
+      <mu-icon value="add" @click="add"></mu-icon>
11
+    </div>
12
+    <div style="width:100%;">
13
+      <mu-text-field v-model="filter" style="width:60%"></mu-text-field>
14
+      <mu-button color="primary" @click="loadList">搜索</mu-button>
15
+    </div>
16
+    <div class="quick-list" v-if="action">
17
+      <div
18
+        class="quick-item"
19
+        v-for="(item, id) in private_msg"
20
+        :key="id"
21
+        @click="menu(id, $event)"
22
+      >
23
+        {{ item }}
24
+      </div>
25
+    </div>
26
+    <div class="quick-list" v-else>
27
+      <div
28
+        class="quick-item"
29
+        v-for="(item, id) in public_msg"
30
+        :key="id"
31
+        @click="menu(id, $event)"
32
+      >
33
+        {{ item }}
34
+      </div>
35
+    </div>
36
+    <mu-popover cover :open.sync="open" :trigger="trigger">
37
+      <mu-list class="static-list">
38
+        <mu-list-item button @click="send(true)">
39
+          <mu-icon value="send"></mu-icon>
40
+          <mu-list-item-title>直接发送</mu-list-item-title>
41
+        </mu-list-item>
42
+        <mu-list-item button @click="copy">
43
+          <mu-icon value="library_books"></mu-icon>
44
+          <mu-list-item-title>复制到剪切板</mu-list-item-title>
45
+        </mu-list-item>
46
+        <mu-list-item button @click="send(false)">
47
+          <mu-icon value="input"></mu-icon>
48
+          <mu-list-item-title>填入消息框</mu-list-item-title>
49
+        </mu-list-item>
50
+        <mu-list-item button @click="edit">
51
+          <mu-icon value="edit"></mu-icon>
52
+          <mu-list-item-title>编辑</mu-list-item-title>
53
+        </mu-list-item>
54
+        <mu-list-item button @click="del">
55
+          <mu-icon value="delete"></mu-icon>
56
+          <mu-list-item-title>删除</mu-list-item-title>
57
+        </mu-list-item>
58
+      </mu-list>
59
+    </mu-popover>
60
+  </div>
61
+</template>
62
+
63
+<script>
64
+import copy from 'copy-to-clipboard';
65
+export default {
66
+  name: 'quick',
67
+  data () {
68
+    return {
69
+      action: 1,
70
+      public_msg: {},
71
+      private_msg: {},
72
+      on_edit: 0,
73
+      choose: null,
74
+      trigger: null,
75
+      open: false,
76
+      filter:'',
77
+    }
78
+  },
79
+  methods: {
80
+    menu (id, e) {
81
+      this.trigger = e.target;
82
+      this.choose = id;
83
+      this.open = true;
84
+    },
85
+    copy () {
86
+      let res = copy(this[this.action > 0 ? 'private_msg' : 'public_msg'][this.choose]);
87
+      if (res) this.$toast.success('已复制');
88
+      this.open = false;
89
+    },
90
+    send (now) {
91
+      this.$bus.$emit('quick_msg', {
92
+        msg: this[this.action > 0 ? 'private_msg' : 'public_msg'][this.choose],
93
+        send: now
94
+      });
95
+      this.open = false;
96
+    },
97
+    loadList () {
98
+      this.$ajax.get('quick_list?service_id=' + config.service_id+'&msg='+this.filter+'' ).then(res => {
99
+        if (res.code === 0) {
100
+          this.public_msg = res.data.public_msg;
101
+          this.private_msg = res.data.private_msg;
102
+        }
103
+      });
104
+    },
105
+    add () {
106
+      this.$prompt('请输入快捷回复内容', '添加', {
107
+        validator (value) {
108
+          return {
109
+            valid: value && value.length > 0,
110
+            message: '快捷回复内容不能为空'
111
+          }
112
+        }
113
+      }).then(({ result, value }) => {
114
+        if (result) {
115
+          this.$bus.loading(true);
116
+          this.$ajax.post('quick_list', {
117
+            service_id: this.action > 0 ? config.service_id : 0,
118
+            msg: value
119
+          }).then((res) => {
120
+            this.$bus.loading(false);
121
+            if (res.code === 0) {
122
+              this.$alert('添加完毕');
123
+              this.$set(this[this.action > 0 ? 'private_msg' : 'public_msg'], res.data, value);
124
+            } else {
125
+              this.$alert(res.msg);
126
+            }
127
+          }).catch(() => {
128
+            this.$bus.loading(false);
129
+          })
130
+        }
131
+      });
132
+      this.open = false;
133
+    },
134
+    del () {
135
+      let type = this.action;
136
+      let id = this.choose;
137
+      this.$confirm('确定要删除?', '提示', {
138
+        type: 'warning'
139
+      }).then(({ result }) => {
140
+        if (result) {
141
+          this.$bus.loading(true);
142
+          this.$ajax.delete('quick_list/' + id).then((res) => {
143
+            this.$bus.loading(false);
144
+            if (res.code === 0) {
145
+              this.$alert('删除完毕');
146
+              this.$delete(this[type > 0 ? 'private_msg' : 'public_msg'], id);
147
+            }
148
+          }).catch(() => {
149
+            this.$bus.loading(false);
150
+          })
151
+        }
152
+      });
153
+      this.open = false;
154
+    },
155
+    edit () {
156
+      let type = this.action;
157
+      let id = this.choose;
158
+      this.$prompt('请输入快捷回复内容', '修改', {
159
+        validator (value) {
160
+          return {
161
+            valid: value && value.length > 0,
162
+            message: '快捷回复内容不能为空'
163
+          }
164
+        }
165
+      }).then(({ result, value }) => {
166
+        if (result) {
167
+          this.$bus.loading(true);
168
+          this.$ajax.put('quick_list', {
169
+            id: id,
170
+            service_id: type > 0 ? config.service_id : 0,
171
+            msg: value
172
+          }).then((res) => {
173
+            this.$bus.loading(false);
174
+            if (res.code === 0) {
175
+              this.$alert('修改完毕');
176
+              this.$set(this[type > 0 ? 'private_msg' : 'public_msg'], id, value);
177
+            } else {
178
+              this.$alert(res.msg);
179
+            }
180
+          }).catch(() => {
181
+            this.$bus.loading(false);
182
+          })
183
+        }
184
+      });
185
+      this.open = false;
186
+    }
187
+  },
188
+  created () {
189
+    this.loadList();
190
+  }
191
+}
192
+</script>
193
+
194
+<style>
195
+.quick-msg {
196
+  padding-top: 40px;
197
+  height: 100%;
198
+  width: 350px;
199
+  position: absolute;
200
+  right: 0;
201
+  top: 0;
202
+}
203
+.quick-msg .quick-list {
204
+  /* height: 100%; */
205
+  width: 100%;
206
+  overflow-y: scroll;
207
+}
208
+.quick-head {
209
+  position: absolute;
210
+  background-color: #fafafa;
211
+  height: 48px;
212
+  line-height: 48px;
213
+  top: 0;
214
+  left: 1px;
215
+  right: 0;
216
+}
217
+.quick-head .tag {
218
+  cursor: pointer;
219
+  padding: 0 20px;
220
+  height: 48px;
221
+  display: inline-block;
222
+  border-bottom: 3px solid transparent;
223
+}
224
+.quick-head .tag.action {
225
+  border-color: #2196f3;
226
+}
227
+.quick-item {
228
+  padding: 13px;
229
+  cursor: pointer;
230
+  border-bottom: 1px #ccc solid;
231
+  word-break: break-all;
232
+}
233
+.quick-item:hover {
234
+  background: #eee;
235
+}
236
+.quick-head .mu-icon {
237
+  float: right;
238
+  margin: 7px;
239
+  cursor: pointer;
240
+}
241
+.quick-head .mu-icon:hover {
242
+  background: #eee;
243
+}
244
+</style>

+ 153 - 0
dtkf_web-master/src/components/record.vue

@@ -0,0 +1,153 @@
1
+<template>
2
+	<mu-drawer :open.sync="show" :docked="false" right width="500">
3
+		<div class="record-head">与 {{user.nickname}} 的聊天记录</div>
4
+		<div class="msg-record">
5
+			<div class="record-list">
6
+				<div class="record-item" v-for="item in list" :key="item.id" :class="{on:item.id==user.msg_id}">
7
+					<h5>
8
+						<mu-badge v-if="item.source>0" color="primary" content="客服" />
9
+						<mu-badge v-else content="用户" />
10
+						{{item.source>0?item.name:user.nickname}}
11
+						<span class="time">{{item.created_at}}</span>
12
+					</h5>
13
+					<img v-if="item.type==1" :src="path+item.msg">
14
+					<span  v-else-if="item.type==3" @click="play(item)" class="mu-chip mu-success-color mu-inverse">
15
+						<i class="mu-icon material-icons">keyboard_voice</i> 点击播放语音
16
+					</span>
17
+					<p v-else v-html="emotion(item.msg)"></p>
18
+				</div>
19
+			</div>
20
+		</div>
21
+		<div class="record-btn">
22
+			<mu-button flat @click="loadList(has_prev,'prev')" :disabled="has_prev==0">
23
+				<mu-icon value="chevron_left" left></mu-icon>
24
+				上一页
25
+			</mu-button>
26
+			<mu-button flat @click="loadList(has_next,'next')" :disabled="has_next==0">
27
+				下一页
28
+				<mu-icon value="chevron_right" right></mu-icon>
29
+			</mu-button>
30
+		</div>
31
+	</mu-drawer>
32
+</template>
33
+
34
+<script>
35
+import emotion from "qq-wechat-emotion-parser";
36
+export default {
37
+	name: 'record',
38
+	data() {
39
+		return {
40
+			show: false,
41
+			user: { id: 0, nickname: '' },
42
+			list: [],
43
+			has_next: 0,
44
+			has_prev: 0,
45
+			loading: 0,
46
+			path: config.img_path
47
+		}
48
+	},
49
+	methods: {
50
+		emotion(text) {
51
+			text = text.replace(/\n/g, "<br>");
52
+			return emotion(text);
53
+		},
54
+		loadList(id, type) {
55
+			if (id == 0 || this.loading) return;
56
+			this.loading = 1;
57
+			this.$ajax.get('manage/info', {
58
+				params: {
59
+					id: id,
60
+					type: type,
61
+					customer_id: this.user.id
62
+				}
63
+			}).then(res => {
64
+				this.loading = 0;
65
+				if (res.code === 0) {
66
+					this.list = res.data.list;
67
+					this.has_next = res.data.has_next;
68
+					this.has_prev = res.data.has_prev;
69
+				}
70
+			}).catch(() => {
71
+				this.loading = 0;
72
+			});
73
+		},
74
+		reset(user) {
75
+			this.user = user;
76
+			this.list = [];
77
+			this.has_next = 0;
78
+			this.has_prev = 0;
79
+			this.loading = 0;
80
+		},
81
+		play(item) {
82
+			voice(item.msg, item.id);
83
+		}
84
+	},
85
+	created() {
86
+		this.$bus.$on('open_record', (user) => {
87
+			if (user.msg_id && this.user.msg_id != user.msg_id) {
88
+				this.reset(user);
89
+				this.loadList(user.msg_id, 'middle');
90
+			} else if (this.user.id != user.id) {
91
+				this.reset(user);
92
+				this.loadList(-1, '');
93
+			}
94
+			this.show = true;
95
+		});
96
+	}
97
+}
98
+</script>
99
+
100
+<style>
101
+.msg-record {
102
+	height: 100%;
103
+	width: 100%;
104
+	padding: 50px 0;
105
+	word-break: break-all;
106
+}
107
+.msg-record .record-list {
108
+	height: 100%;
109
+	width: 100%;
110
+	overflow-y: scroll;
111
+}
112
+.record-item {
113
+	padding: 13px;
114
+	border-bottom: 1px #ccc solid;
115
+}
116
+.record-item.on {
117
+	background: #bcf1be;
118
+}
119
+.record-item h5 {
120
+	margin: 0 0 8px 0;
121
+	font-size: 16px;
122
+}
123
+.record-item p {
124
+	margin: 0;
125
+}
126
+.record-item img {
127
+	display: inline-block;
128
+	max-width: 100%;
129
+}
130
+.record-item h5 > .time {
131
+	float: right;
132
+	font-weight: 300;
133
+}
134
+.record-btn,
135
+.record-head {
136
+	position: absolute;
137
+	width: 100%;
138
+	height: 50px;
139
+	z-index: 10;
140
+	text-align: center;
141
+	line-height: 50px;
142
+}
143
+.record-btn {
144
+	border-top: 1px #ccc solid;
145
+	bottom: 0;
146
+}
147
+.record-head {
148
+	border-bottom: 1px #ccc solid;
149
+	top: 0;
150
+	font-size: 18px;
151
+	font-weight: 500;
152
+}
153
+</style>

+ 78 - 0
dtkf_web-master/src/components/screenshot.vue

@@ -0,0 +1,78 @@
1
+<template>
2
+	<mu-menu>
3
+		<mu-button fab small color="grey800">
4
+			<mu-icon value="image"></mu-icon>
5
+		</mu-button>
6
+		<ul class="mu-list static-list" slot="content">
7
+			<li @click="screenshot">
8
+				<div class="mu-item">
9
+					<i class="mu-icon material-icons" style="user-select: none;">crop_free</i>
10
+					<div class="mu-item-title">屏幕截图</div>
11
+				</div>
12
+			</li>
13
+			<li>
14
+				<label class="mu-item">
15
+					<input type="file" accept="image/jpeg, image/jpg, image/png" style="display: none;" @change="choose">
16
+					<i class="mu-icon material-icons" style="user-select: none;">folder</i>
17
+					<div class="mu-item-title">选择本地图片</div>
18
+				</label>
19
+			</li>
20
+			<li @click="shearPlate">
21
+				<div class="mu-item">
22
+					<i class="mu-icon material-icons" style="user-select: none;">dashboard</i>
23
+					<div class="mu-item-title">从剪切板获取</div>
24
+				</div>
25
+			</li>
26
+		</ul>
27
+	</mu-menu>
28
+</template>
29
+
30
+<script>
31
+window.captureObj = new NiuniuCaptureObject();
32
+captureObj.NiuniuAuthKey = "niuniu";
33
+
34
+//初始化控件
35
+captureObj.InitNiuniuCapture();
36
+
37
+export default {
38
+	name: 'screenshot',
39
+	methods: {
40
+		shearPlate() {
41
+			captureObj.DoCapture('', 0, 4, 0, 0, 0, 0);
42
+		},
43
+		screenshot() {
44
+			captureObj.DoCapture('1.jpg', 0, 3, 0, 0, 0, 0);
45
+		},
46
+		choose(e) {
47
+			let file = e.target.files[0];
48
+			e.target.value = "";
49
+			let ex = file.name.split(".")[1];
50
+			if (ex !== "jpg" && ex !== "png" && ex !== "jpeg" && ex !== "gif") {
51
+				this.$alert("不支持该类型的图片。");
52
+				return;
53
+			}
54
+			if (file.size > 500 * 1024) {
55
+				this.$alert("图片不能大于500KB。");
56
+				return;
57
+			}
58
+			this.reader.readAsDataURL(file);
59
+		}
60
+	},
61
+	created() {
62
+		this.reader = new FileReader();
63
+		this.reader.onload = (e) => {
64
+			this.$bus.$emit('view_imge', this.reader.result);
65
+		}
66
+		captureObj.FinishedCallback = (type, x, y, width, height, info, content) => {
67
+			if (content === '') {
68
+				this.$alert("未能获取有效的图像。");
69
+			} else {
70
+				this.$bus.$emit('view_imge', 'data:image/jpeg;base64,' + content);
71
+			}
72
+		};
73
+	}
74
+}
75
+</script>
76
+
77
+<style>
78
+</style>

+ 96 - 0
dtkf_web-master/src/components/talking.vue

@@ -0,0 +1,96 @@
1
+<template>
2
+	<mu-list textline="two-line">
3
+		<mu-list-item avatar button :ripple="false" v-for="item in list" :key="item.id" @click="talk(item)" :class="{action:item.id==talk_with}" v-if="item.last_time>0">
4
+			<mu-list-item-action>
5
+				<mu-avatar v-html="item.headimg"></mu-avatar>
6
+			</mu-list-item-action>
7
+			<mu-list-item-content>
8
+				<mu-list-item-title>{{item.nickname}}</mu-list-item-title>
9
+				<mu-list-item-sub-title>{{item.msg}}</mu-list-item-sub-title>
10
+			</mu-list-item-content>
11
+			<mu-list-item-action>
12
+				<mu-badge :content="item.unread.toString()" color="red" v-show="item.unread>0&&item.id!=talk_with"></mu-badge>
13
+			</mu-list-item-action>
14
+		</mu-list-item>
15
+	</mu-list>
16
+</template>
17
+
18
+<script>
19
+export default {
20
+	name: 'talking',
21
+	props: ['last_time'],
22
+	data() {
23
+		return {
24
+			talk_with: 0,
25
+			list: [],
26
+			keyindex: {}
27
+		}
28
+	},
29
+	watch: {
30
+		talk_with(id) {
31
+			this.$emit('change', id);
32
+		}
33
+	},
34
+	methods: {
35
+		talk(item) {
36
+			this.talk_with = item.id;
37
+			this.$bus.$emit('talk_with', item);
38
+		},
39
+		refresh(list) {
40
+			let ids = {};
41
+			let deadline = this.last_time - 172800;
42
+			for (let index = 0; index < list.length; index++) {
43
+				let item = list[index];
44
+				ids[item.id] = 1;
45
+				item.headimg = (item.headimg == '') ? item.nickname.substr(0, 1) : ('<img src="' + item.headimg + '">');
46
+				this.keyindex[list[index].id] = index;
47
+			}
48
+			for (let index = 0; index < this.list.length; index++) {
49
+				let item = this.list[index];
50
+				if (!ids[item.id]) {
51
+					if (item.last_time > deadline) {
52
+						this.keyindex[item.id] = list.push(item) - 1;
53
+					} else {
54
+						if (this.talk_with == item.id) {
55
+							this.talk_with = 0;
56
+						}
57
+						delete (this.keyindex[item.id]);
58
+						this.$bus.$emit('delete_talk', item.id);
59
+					}
60
+				} else {
61
+
62
+				}
63
+			}
64
+			this.list = list;
65
+		}
66
+	},
67
+	created() {
68
+		this.$bus.$on('update_talking_list', (list) => {
69
+			this.refresh(list);
70
+		});
71
+		this.$bus.$on('access_user', (item) => {
72
+			this.refresh([item]);
73
+			this.talk(item);
74
+		});
75
+		this.$bus.$on('update_msg', (res) => {
76
+			let item = this.list[this.keyindex[res.id]];
77
+			if (res.close) {
78
+				item.last_time = 0;
79
+				if (this.talk_with == res.id) {
80
+					this.talk_with = 0;
81
+				}
82
+			} else {
83
+				item.msg = res.msg;
84
+				item.last_time = this.last_time;
85
+				if (res.clean) item.unread = 0;
86
+			}
87
+		});
88
+	}
89
+}
90
+</script>
91
+
92
+<style>
93
+.mu-list .action {
94
+	background: #eaeaea;
95
+}
96
+</style>

+ 65 - 0
dtkf_web-master/src/components/upload.vue

@@ -0,0 +1,65 @@
1
+<template>
2
+	<mu-dialog title="图片预览" width="400" :open.sync="open" scrollable>
3
+		<img :src="src" v-if="src" style="width:100%;border:1px #ccc solid">
4
+		<mu-button slot="actions" flat @click="close">取消</mu-button>
5
+		<mu-button slot="actions" flat color="primary" @click="send">发送</mu-button>
6
+	</mu-dialog>
7
+</template>
8
+
9
+<script>
10
+
11
+function dataURLtoBlob(dataurl) {
12
+	var arr = dataurl.split(','),
13
+		mime = arr[0].match(/:(.*?);/)[1],
14
+		bstr = atob(arr[1]),
15
+		n = bstr.length,
16
+		u8arr = new Uint8Array(n);
17
+	while (n--) {
18
+		u8arr[n] = bstr.charCodeAt(n);
19
+	}
20
+	return new Blob([u8arr], {
21
+		type: mime
22
+	});
23
+}
24
+
25
+export default {
26
+	name: 'upload',
27
+	data() {
28
+		return {
29
+			open: false,
30
+			src: null
31
+		}
32
+	},
33
+	methods: {
34
+		close() {
35
+			this.open = false;
36
+			this.src = null;
37
+		},
38
+		send() {
39
+			let form = new FormData();
40
+			form.append("img", dataURLtoBlob(this.src));
41
+			this.close();
42
+			this.$bus.loading(true);
43
+			this.$ajax.post("send_img", form).then((res) => {
44
+				this.$bus.loading(false);
45
+				if (res.code === 0) {
46
+					this.$bus.$emit('img_path', res.data);
47
+				} else {
48
+					this.$alert(res.msg);
49
+				}
50
+			}).catch(() => {
51
+				this.$bus.loading(false);
52
+			});
53
+		}
54
+	},
55
+	created() {
56
+		this.$bus.$on('view_imge', (res) => {
57
+			this.src = res;
58
+			this.open = true;
59
+		});
60
+	}
61
+}
62
+</script>
63
+
64
+<style>
65
+</style>

+ 51 - 0
dtkf_web-master/src/components/voice.vue

@@ -0,0 +1,51 @@
1
+<template>
2
+	<mu-dialog title="语音播放" width="360" :open.sync="open">
3
+		<audio controls autoplay ref="audio" :src="path+src" style="width:100%">您的浏览器不支持播放语音</audio>
4
+		<mu-button slot="actions" flat color="primary" @click="open=false">关闭</mu-button>
5
+	</mu-dialog>
6
+</template>
7
+
8
+<script>
9
+	let cache = {};
10
+	export default {
11
+		name: 'voice',
12
+		data() {
13
+			return {
14
+				open: false,
15
+				src: '',
16
+				path: config.img_path
17
+			};
18
+		},
19
+		methods: {
20
+			play(src, id) {
21
+				if (cache[id]) {
22
+					this.src = cache[id];
23
+					this.open = true;
24
+				} else {
25
+					let ext = src.slice(-3);
26
+					if (ext === 'mp3') {
27
+						this.src = src;
28
+						this.open = true;
29
+					} else {
30
+						this.$bus.loading(true);
31
+						this.$ajax
32
+							.get('voice/' + id)
33
+							.then(res => {
34
+								this.$bus.loading(false);
35
+								if (res.code === 0) {
36
+									cache[id] = res.data;
37
+									this.play(src, id);
38
+								}
39
+							})
40
+							.catch(() => {
41
+								this.$bus.loading(false);
42
+							});
43
+					}
44
+				}
45
+			}
46
+		},
47
+		created() {
48
+			window.voice = this.play;
49
+		}
50
+	};
51
+</script>

+ 69 - 0
dtkf_web-master/src/components/waiting.vue

@@ -0,0 +1,69 @@
1
+<template>
2
+	<mu-list textline="two-line" class="waiting-list">
3
+		<mu-list-item avatar :ripple="false" v-for="(item,index) in list" :key="item.id">
4
+			<mu-list-item-action>
5
+				<mu-avatar v-if="item.headimg == ''">{{item.nickname.substr(0, 1)}}</mu-avatar>
6
+				<mu-avatar v-else><img :src="item.headimg"></mu-avatar>
7
+			</mu-list-item-action>
8
+			<mu-list-item-content>
9
+				<mu-list-item-title>{{item.nickname}}</mu-list-item-title>
10
+				<mu-list-item-sub-title>{{item.msg}}</mu-list-item-sub-title>
11
+			</mu-list-item-content>
12
+			<mu-list-item-action>
13
+				<mu-button small flat color="primary" @click="access(index)">
14
+					<mu-icon value="add"></mu-icon>接入
15
+				</mu-button>
16
+			</mu-list-item-action>
17
+		</mu-list-item>
18
+	</mu-list>
19
+</template>
20
+
21
+<script>
22
+export default {
23
+	name: 'waiting',
24
+	data() {
25
+		return {
26
+			list: []
27
+		}
28
+	},
29
+	methods: {
30
+		access(index) {
31
+			this.$bus.loading(true);
32
+			let item = this.list[index];
33
+			this.$ajax.get('access', {
34
+				params: {
35
+					service_id: config.service_id,
36
+					customer_id: item.id
37
+				}
38
+			}).then((res) => {
39
+				this.$bus.loading(false);
40
+				if (res.code === 0) {
41
+					this.$bus.$emit('access_user', item);
42
+					this.list.splice(index, 1);
43
+				} else {
44
+
45
+				}
46
+			});
47
+		}
48
+	},
49
+	created() {
50
+		this.$bus.$on('update_waiting_list', () => {
51
+			this.$ajax.get('waiting_list').then((res) => {
52
+				if (res.code === 0) {
53
+					this.list = res.data;
54
+				} else {
55
+
56
+				}
57
+			});
58
+		});
59
+	}
60
+}
61
+</script>
62
+
63
+<style>
64
+.waiting-list .mu-button {
65
+	position: absolute;
66
+	right: 10px;
67
+	top: 23px;
68
+}
69
+</style>

+ 39 - 0
dtkf_web-master/src/main.js

@@ -0,0 +1,39 @@
1
+import 'muse-ui/dist/muse-ui.css';
2
+import 'muse-ui-message/dist/muse-ui-message.css';
3
+
4
+import promiseFinally from 'promise.prototype.finally';
5
+import Axios from "axios";
6
+import Vue from 'vue';
7
+import MuseUI from 'muse-ui';
8
+import Message from 'muse-ui-message';
9
+import Toast from 'muse-ui-toast';
10
+import App from './App';
11
+
12
+promiseFinally.shim();
13
+Vue.use(MuseUI);
14
+Vue.use(Message);
15
+Vue.use(Toast);
16
+
17
+Vue.config.productionTip = false;
18
+
19
+const ajax = Axios.create({
20
+	//baseURL: config.base
21
+});
22
+
23
+ajax.defaults.baseURL = '/api/dtkf'
24
+ajax.interceptors.response.use(
25
+	function(res) {
26
+		return res.data;
27
+	},
28
+	function(e) {
29
+		Toast.error("网络错误");
30
+		return Promise.reject(e);
31
+	}
32
+);
33
+Vue.prototype.$ajax = ajax;
34
+Vue.prototype.$bus = new Vue();
35
+
36
+new Vue({
37
+	el: '#app',
38
+	render: h => h(App)
39
+});

+ 15 - 0
dtkf_web-master/src/router/index.js

@@ -0,0 +1,15 @@
1
+import Vue from 'vue'
2
+import Router from 'vue-router'
3
+import HelloWorld from '@/components/HelloWorld'
4
+
5
+Vue.use(Router)
6
+
7
+export default new Router({
8
+  routes: [
9
+    {
10
+      path: '/',
11
+      name: 'HelloWorld',
12
+      component: HelloWorld
13
+    }
14
+  ]
15
+})

+ 0 - 0
dtkf_web-master/static/.gitkeep


BIN
dtkf_web-master/static/icon/MaterialIcons-Regular.eot


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 2373 - 0
dtkf_web-master/static/icon/MaterialIcons-Regular.svg


BIN
dtkf_web-master/static/icon/MaterialIcons-Regular.ttf


BIN
dtkf_web-master/static/icon/MaterialIcons-Regular.woff


BIN
dtkf_web-master/static/icon/MaterialIcons-Regular.woff2


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 0
dtkf_web-master/static/icon/material-icons.css


BIN
dtkf_web-master/static/images/face.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 655 - 0
dtkf_web-master/static/js/niuniucapture.js