Browse Source

Merge branch 'master' of http://124.70.43.205:3000/GYEE_R.D/exam

chenminghua 2 years ago
parent
commit
3184b19426
53 changed files with 3544 additions and 1596 deletions
  1. 49 19
      exam-06173-uni/App.vue
  2. 4 2
      exam-06173-uni/common/config.js
  3. 101 0
      exam-06173-uni/node_modules/js-md5/CHANGELOG.md
  4. 20 0
      exam-06173-uni/node_modules/js-md5/LICENSE.txt
  5. 76 0
      exam-06173-uni/node_modules/js-md5/README.md
  6. 10 0
      exam-06173-uni/node_modules/js-md5/build/md5.min.js
  7. 45 0
      exam-06173-uni/node_modules/js-md5/package.json
  8. 683 0
      exam-06173-uni/node_modules/js-md5/src/md5.js
  9. 2 1
      exam-06173-uni/package.json
  10. 39 8
      exam-06173-uni/pages/course/index.vue
  11. 39 30
      exam-06173-uni/pages/exam/detail.vue
  12. 65 43
      exam-06173-uni/pages/exam/index.vue
  13. 7 1
      exam-06173-uni/pages/index/index.vue
  14. 11 11
      exam-06173-uni/pages/login/login.vue
  15. 1 1
      exam-06173-vue/.env.demo
  16. 1 1
      exam-06173-vue/.env.development
  17. 1 1
      exam-06173-vue/.env.production
  18. BIN
      exam-06173-vue/dist.rar
  19. 4 0
      exam-06173-vue/public/config/config.js
  20. 20 14
      exam-06173-vue/public/index.html
  21. 26 0
      exam-06173-vue/src/App.vue
  22. 1 1
      exam-06173-vue/src/api/archives/index.js
  23. 7 10
      exam-06173-vue/src/api/dashboard/index.js
  24. 21 0
      exam-06173-vue/src/api/exam/form.js
  25. BIN
      exam-06173-vue/src/assets/web/images/login3.png
  26. BIN
      exam-06173-vue/src/assets/web/images/login4.png
  27. 74 37
      exam-06173-vue/src/components/DepartRefs/index.vue
  28. 23 29
      exam-06173-vue/src/components/DicListSelect/index.vue
  29. 4 1
      exam-06173-vue/src/components/Tinymce/index.vue
  30. 113 93
      exam-06173-vue/src/layout/components/WebHeader.vue
  31. 2 2
      exam-06173-vue/src/permission.js
  32. 8 0
      exam-06173-vue/src/router/index.js
  33. 1 0
      exam-06173-vue/src/store/modules/permission.js
  34. 1 1
      exam-06173-vue/src/views/admin/course/file/dir.vue
  35. 201 152
      exam-06173-vue/src/views/admin/course/file/index.vue
  36. 129 93
      exam-06173-vue/src/views/admin/course/form.vue
  37. 65 86
      exam-06173-vue/src/views/admin/course/index.vue
  38. 289 211
      exam-06173-vue/src/views/admin/exam/exam/form.vue
  39. 72 94
      exam-06173-vue/src/views/admin/exam/exam/index.vue
  40. 40 65
      exam-06173-vue/src/views/admin/exam/review/index.vue
  41. 323 226
      exam-06173-vue/src/views/admin/paper/paper/detail.vue
  42. 425 0
      exam-06173-vue/src/views/admin/paper/paper/view.vue
  43. 1 1
      exam-06173-vue/src/views/admin/repo/form.vue
  44. 52 30
      exam-06173-vue/src/views/admin/stat/total/archives.vue
  45. 7 3
      exam-06173-vue/src/views/admin/stat/total/detailBm.vue
  46. 5 2
      exam-06173-vue/src/views/admin/stat/total/detailZg.vue
  47. 28 0
      exam-06173-vue/src/views/checkPoint/index.vue
  48. 55 32
      exam-06173-vue/src/views/dashboard/index.vue
  49. 27 29
      exam-06173-vue/src/views/login/components/third-login.vue
  50. 124 78
      exam-06173-vue/src/views/login/index.vue
  51. 75 50
      exam-06173-vue/src/views/login/layout/LoginLayout.vue
  52. 86 68
      exam-06173-vue/src/views/web/course/list.vue
  53. 81 70
      exam-06173-vue/src/views/web/exam/list.vue

+ 49 - 19
exam-06173-uni/App.vue

@@ -1,39 +1,69 @@
 <script>
+	import {
+		login
+	} from '@/api/user.js'
+	import md5 from 'js-md5'
 	export default {
-		onLaunch: function() {
-			
+		onLoad: function(option) {
+			if(option && option.user){
+				this.getUserInfo({
+					smsCode: "",
+					captchaKey: "",
+					captchaValue: "",
+					username: option.user,
+					password: "",
+					mark: ""
+				}).then(res => {
+					if(this.loginCallBack){
+						this.loginCallBack()
+					}
+				})
+			}
 		},
 		onShow: function() {
-			
+
 		},
 		onHide: function() {
-			
+
+		},
+		methods: {
+			getUserInfo(params) {
+				return new Promise((resolve, reject) => {
+					login({
+						...params,
+						mark: md5(params.username + 'gdnxfdexam321')
+					}).then(res => {
+						// 保存本地token
+						uni.setStorageSync('token', res.token);
+						resolve(res)
+					}).catch(err => {
+						reject(err)
+					})
+				})
+			}
 		}
 	}
-	
 </script>
 
 <style lang="scss">
-
-	
 	/* uni.css - 通用组件、模板样式库,可以当作一套ui库应用 */
 	@import './style/uni.css';
-	
-	
+
+
 	/* 考试相关样式 */
-	@import './style/style.css';	
-	
-	
-	
+	@import './style/style.css';
+
+
+
 	/* 重写样式 */
-	.uni-load-more__text{
+	.uni-load-more__text {
 		font-size: 14px !important;
 	}
-	
-	
-	
-	
-	
+
+
+
+
+
 	.page-box {
 		padding: 20px;
 		font-size: 14px;

+ 4 - 2
exam-06173-uni/common/config.js

@@ -5,8 +5,10 @@ let urls = {
 
 if(process.env.NODE_ENV === 'development'){
     // 开发环境
-    urls.api = 'http://localhost:8617'
-    urls.socket = 'ws://localhost:8617'
+    // urls.api = 'http://localhost:8617'
+    // urls.socket = 'ws://localhost:8617'
+	urls.api = 'http://124.70.18.168:8617'
+	urls.socket = 'ws://124.70.18.168:8617'
 }else{
     // t2预发布环境
     // urls.api = 'https://t2-api.jeegen.com'

+ 101 - 0
exam-06173-uni/node_modules/js-md5/CHANGELOG.md

@@ -0,0 +1,101 @@
+# Change Log
+
+## v0.7.3 / 2017-12-18
+### Fixed
+- incorrect result when first bit is 1 of bytes. #18
+
+## v0.7.2 / 2017-10-31
+### Improved
+- performance of hBytes increment.
+
+## v0.7.1 / 2017-10-29
+### Fixed
+- incorrect result when file size >= 4G.
+
+## v0.7.0 / 2017-10-29
+### Fixed
+- incorrect result when file size >= 512M.
+
+## v0.6.1 / 2017-10-07
+### Fixed
+- ArrayBuffer.isView issue in IE10.
+
+### Improved
+- performance of input check.
+
+## v0.6.0 / 2017-07-28
+### Added
+- support base64 string output.
+
+## v0.5.0 / 2017-07-14
+### Added
+- support for web worker. #11
+
+### Changed
+- throw error if input type is incorrect.
+- prevent webpack to require dependencies.
+
+## v0.4.2 / 2017-01-18
+### Fixed
+- `root` is undefined in some special environment. #7
+
+## v0.4.1 / 2016-03-31
+### Removed
+- length detection in node.js.
+### Deprecated
+- `buffer` and replace by `arrayBuffer`.
+
+## v0.4.0 / 2015-12-28
+### Added
+- support for update hash.
+- support for bytes array output.
+- support for ArrayBuffer output.
+- support for AMD.
+
+## v0.3.0 / 2015-03-07
+### Added
+- support byte Array, Uint8Array and ArrayBuffer input.
+
+## v0.2.2 / 2015-02-01
+### Fixed
+- bug when special length.
+### Improve
+- performance for node.js.
+
+## v0.2.1 / 2015-01-13
+### Improve
+- performance.
+
+## v0.2.0 / 2015-01-12
+### Removed
+- ascii parameter.
+### Improve
+- performance.
+
+## v0.1.4 / 2015-01-11
+### Improve
+- performance.
+### Added
+- test cases.
+
+## v0.1.3 / 2015-01-05
+### Added
+- bower package.
+- travis.
+- coveralls.
+### Improved
+- performance.
+### Fixed
+- JSHint warnings.
+
+## v0.1.2 / 2014-07-27
+### Fixed
+- accents bug
+
+## v0.1.1 / 2014-01-05
+### Changed
+- license
+
+## v0.1.0 / 2014-01-04
+### Added
+- initial release

+ 20 - 0
exam-06173-uni/node_modules/js-md5/LICENSE.txt

@@ -0,0 +1,20 @@
+Copyright 2014-2017 Chen, Yi-Cyuan
+
+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.

+ 76 - 0
exam-06173-uni/node_modules/js-md5/README.md

@@ -0,0 +1,76 @@
+# js-md5
+[![Build Status](https://travis-ci.org/emn178/js-md5.svg?branch=master)](https://travis-ci.org/emn178/js-md5)
+[![Coverage Status](https://coveralls.io/repos/emn178/js-md5/badge.svg?branch=master)](https://coveralls.io/r/emn178/js-md5?branch=master)  
+[![NPM](https://nodei.co/npm/js-md5.png?stars&downloads)](https://nodei.co/npm/js-md5/)
+
+A simple MD5 hash function for JavaScript supports UTF-8 encoding.
+
+## Demo
+[MD5 Online](http://emn178.github.io/online-tools/md5.html)  
+[MD5 File Checksum Online](http://emn178.github.io/online-tools/md5_checksum.html)
+
+## Download
+[Compress](https://raw.github.com/emn178/js-md5/master/build/md5.min.js)  
+[Uncompress](https://raw.github.com/emn178/js-md5/master/src/md5.js)
+
+## Installation
+You can also install js-md5 by using Bower.
+
+    bower install md5
+
+For node.js, you can use this command to install:
+
+    npm install js-md5
+
+## Notice
+`buffer` method is deprecated. This maybe confuse with Buffer in node.js. Please use `arrayBuffer` instead.
+
+## Usage
+You could use like this:
+```JavaScript
+md5('Message to hash');
+var hash = md5.create();
+hash.update('Message to hash');
+hash.hex();
+```
+If you use node.js, you should require the module first:
+```JavaScript
+md5 = require('js-md5');
+```
+It supports AMD:
+```JavaScript
+require(['your/path/md5.js'], function(md5) {
+// ...
+});
+```
+[See document](https://emn178.github.com/js-md5/doc/)
+
+## Example
+```JavaScript
+md5(''); // d41d8cd98f00b204e9800998ecf8427e
+md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
+md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0
+
+// It also supports UTF-8 encoding
+md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07
+
+// It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
+md5([]); // d41d8cd98f00b204e9800998ecf8427e
+md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e
+
+// Different output
+md5(''); // d41d8cd98f00b204e9800998ecf8427e
+md5.hex(''); // d41d8cd98f00b204e9800998ecf8427e
+md5.array(''); // [212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126]
+md5.digest(''); // [212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126]
+md5.arrayBuffer(''); // ArrayBuffer
+md5.buffer(''); // ArrayBuffer, deprecated, This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
+md5.base64(''); // 1B2M2Y8AsgTpgAmY7PhCfg==
+```
+
+## License
+The project is released under the [MIT license](http://www.opensource.org/licenses/MIT).
+
+## Contact
+The project's website is located at https://github.com/emn178/js-md5  
+Author: Chen, Yi-Cyuan (emn178@gmail.com)

File diff suppressed because it is too large
+ 10 - 0
exam-06173-uni/node_modules/js-md5/build/md5.min.js


+ 45 - 0
exam-06173-uni/node_modules/js-md5/package.json

@@ -0,0 +1,45 @@
+{
+  "name": "js-md5",
+  "version": "0.7.3",
+  "description": "A simple MD5 hash function for JavaScript supports UTF-8 encoding.",
+  "main": "src/md5.js",
+  "devDependencies": {
+    "expect.js": "~0.3.1",
+    "jsdoc": "^3.4.0",
+    "mocha": "~2.3.4",
+    "nyc": "^11.3.0",
+    "requirejs": "^2.1.22",
+    "uglify-js": "^3.1.9",
+    "webworker-threads": "^0.7.11"
+  },
+  "scripts": {
+    "test": "nyc mocha tests/node-test.js",
+    "report": "nyc --reporter=html --reporter=text mocha tests/node-test.js",
+    "coveralls": "nyc report --reporter=text-lcov | coveralls",
+    "doc": "rm -rf doc;jsdoc src README.md -d doc",
+    "compress": "uglifyjs src/md5.js -c -m eval --comments --output build/md5.min.js",
+    "build": "npm run-script compress;npm run-script doc"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/emn178/js-md5.git"
+  },
+  "keywords": [
+    "md5",
+    "hash",
+    "encryption",
+    "cryptography",
+    "HMAC"
+  ],
+  "license": "MIT",
+  "author": "Chen, Yi-Cyuan <emn178@gmail.com>",
+  "homepage": "https://github.com/emn178/js-md5",
+  "bugs": {
+    "url": "https://github.com/emn178/js-md5/issues"
+  },
+  "nyc": {
+    "exclude": [
+      "tests"
+    ]
+  }
+}

+ 683 - 0
exam-06173-uni/node_modules/js-md5/src/md5.js

@@ -0,0 +1,683 @@
+/**
+ * [js-md5]{@link https://github.com/emn178/js-md5}
+ *
+ * @namespace md5
+ * @version 0.7.3
+ * @author Chen, Yi-Cyuan [emn178@gmail.com]
+ * @copyright Chen, Yi-Cyuan 2014-2017
+ * @license MIT
+ */
+(function () {
+  'use strict';
+
+  var ERROR = 'input is invalid type';
+  var WINDOW = typeof window === 'object';
+  var root = WINDOW ? window : {};
+  if (root.JS_MD5_NO_WINDOW) {
+    WINDOW = false;
+  }
+  var WEB_WORKER = !WINDOW && typeof self === 'object';
+  var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
+  if (NODE_JS) {
+    root = global;
+  } else if (WEB_WORKER) {
+    root = self;
+  }
+  var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports;
+  var AMD = typeof define === 'function' && define.amd;
+  var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
+  var HEX_CHARS = '0123456789abcdef'.split('');
+  var EXTRA = [128, 32768, 8388608, -2147483648];
+  var SHIFT = [0, 8, 16, 24];
+  var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64'];
+  var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
+
+  var blocks = [], buffer8;
+  if (ARRAY_BUFFER) {
+    var buffer = new ArrayBuffer(68);
+    buffer8 = new Uint8Array(buffer);
+    blocks = new Uint32Array(buffer);
+  }
+
+  if (root.JS_MD5_NO_NODE_JS || !Array.isArray) {
+    Array.isArray = function (obj) {
+      return Object.prototype.toString.call(obj) === '[object Array]';
+    };
+  }
+
+  if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
+    ArrayBuffer.isView = function (obj) {
+      return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
+    };
+  }
+
+  /**
+   * @method hex
+   * @memberof md5
+   * @description Output hash as hex string
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {String} Hex string
+   * @example
+   * md5.hex('The quick brown fox jumps over the lazy dog');
+   * // equal to
+   * md5('The quick brown fox jumps over the lazy dog');
+   */
+  /**
+   * @method digest
+   * @memberof md5
+   * @description Output hash as bytes array
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {Array} Bytes array
+   * @example
+   * md5.digest('The quick brown fox jumps over the lazy dog');
+   */
+  /**
+   * @method array
+   * @memberof md5
+   * @description Output hash as bytes array
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {Array} Bytes array
+   * @example
+   * md5.array('The quick brown fox jumps over the lazy dog');
+   */
+  /**
+   * @method arrayBuffer
+   * @memberof md5
+   * @description Output hash as ArrayBuffer
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {ArrayBuffer} ArrayBuffer
+   * @example
+   * md5.arrayBuffer('The quick brown fox jumps over the lazy dog');
+   */
+  /**
+   * @method buffer
+   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
+   * @memberof md5
+   * @description Output hash as ArrayBuffer
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {ArrayBuffer} ArrayBuffer
+   * @example
+   * md5.buffer('The quick brown fox jumps over the lazy dog');
+   */
+  /**
+   * @method base64
+   * @memberof md5
+   * @description Output hash as base64 string
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {String} base64 string
+   * @example
+   * md5.base64('The quick brown fox jumps over the lazy dog');
+   */
+  var createOutputMethod = function (outputType) {
+    return function (message) {
+      return new Md5(true).update(message)[outputType]();
+    };
+  };
+
+  /**
+   * @method create
+   * @memberof md5
+   * @description Create Md5 object
+   * @returns {Md5} Md5 object.
+   * @example
+   * var hash = md5.create();
+   */
+  /**
+   * @method update
+   * @memberof md5
+   * @description Create and update Md5 object
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {Md5} Md5 object.
+   * @example
+   * var hash = md5.update('The quick brown fox jumps over the lazy dog');
+   * // equal to
+   * var hash = md5.create();
+   * hash.update('The quick brown fox jumps over the lazy dog');
+   */
+  var createMethod = function () {
+    var method = createOutputMethod('hex');
+    if (NODE_JS) {
+      method = nodeWrap(method);
+    }
+    method.create = function () {
+      return new Md5();
+    };
+    method.update = function (message) {
+      return method.create().update(message);
+    };
+    for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
+      var type = OUTPUT_TYPES[i];
+      method[type] = createOutputMethod(type);
+    }
+    return method;
+  };
+
+  var nodeWrap = function (method) {
+    var crypto = eval("require('crypto')");
+    var Buffer = eval("require('buffer').Buffer");
+    var nodeMethod = function (message) {
+      if (typeof message === 'string') {
+        return crypto.createHash('md5').update(message, 'utf8').digest('hex');
+      } else {
+        if (message === null || message === undefined) {
+          throw ERROR;
+        } else if (message.constructor === ArrayBuffer) {
+          message = new Uint8Array(message);
+        }
+      }
+      if (Array.isArray(message) || ArrayBuffer.isView(message) ||
+        message.constructor === Buffer) {
+        return crypto.createHash('md5').update(new Buffer(message)).digest('hex');
+      } else {
+        return method(message);
+      }
+    };
+    return nodeMethod;
+  };
+
+  /**
+   * Md5 class
+   * @class Md5
+   * @description This is internal class.
+   * @see {@link md5.create}
+   */
+  function Md5(sharedMemory) {
+    if (sharedMemory) {
+      blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+      blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+      blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+      this.blocks = blocks;
+      this.buffer8 = buffer8;
+    } else {
+      if (ARRAY_BUFFER) {
+        var buffer = new ArrayBuffer(68);
+        this.buffer8 = new Uint8Array(buffer);
+        this.blocks = new Uint32Array(buffer);
+      } else {
+        this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+      }
+    }
+    this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0;
+    this.finalized = this.hashed = false;
+    this.first = true;
+  }
+
+  /**
+   * @method update
+   * @memberof Md5
+   * @instance
+   * @description Update hash
+   * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+   * @returns {Md5} Md5 object.
+   * @see {@link md5.update}
+   */
+  Md5.prototype.update = function (message) {
+    if (this.finalized) {
+      return;
+    }
+
+    var notString, type = typeof message;
+    if (type !== 'string') {
+      if (type === 'object') {
+        if (message === null) {
+          throw ERROR;
+        } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
+          message = new Uint8Array(message);
+        } else if (!Array.isArray(message)) {
+          if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
+            throw ERROR;
+          }
+        }
+      } else {
+        throw ERROR;
+      }
+      notString = true;
+    }
+    var code, index = 0, i, length = message.length, blocks = this.blocks;
+    var buffer8 = this.buffer8;
+
+    while (index < length) {
+      if (this.hashed) {
+        this.hashed = false;
+        blocks[0] = blocks[16];
+        blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+      }
+
+      if (notString) {
+        if (ARRAY_BUFFER) {
+          for (i = this.start; index < length && i < 64; ++index) {
+            buffer8[i++] = message[index];
+          }
+        } else {
+          for (i = this.start; index < length && i < 64; ++index) {
+            blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
+          }
+        }
+      } else {
+        if (ARRAY_BUFFER) {
+          for (i = this.start; index < length && i < 64; ++index) {
+            code = message.charCodeAt(index);
+            if (code < 0x80) {
+              buffer8[i++] = code;
+            } else if (code < 0x800) {
+              buffer8[i++] = 0xc0 | (code >> 6);
+              buffer8[i++] = 0x80 | (code & 0x3f);
+            } else if (code < 0xd800 || code >= 0xe000) {
+              buffer8[i++] = 0xe0 | (code >> 12);
+              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
+              buffer8[i++] = 0x80 | (code & 0x3f);
+            } else {
+              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+              buffer8[i++] = 0xf0 | (code >> 18);
+              buffer8[i++] = 0x80 | ((code >> 12) & 0x3f);
+              buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
+              buffer8[i++] = 0x80 | (code & 0x3f);
+            }
+          }
+        } else {
+          for (i = this.start; index < length && i < 64; ++index) {
+            code = message.charCodeAt(index);
+            if (code < 0x80) {
+              blocks[i >> 2] |= code << SHIFT[i++ & 3];
+            } else if (code < 0x800) {
+              blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            } else if (code < 0xd800 || code >= 0xe000) {
+              blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            } else {
+              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+              blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            }
+          }
+        }
+      }
+      this.lastByteIndex = i;
+      this.bytes += i - this.start;
+      if (i >= 64) {
+        this.start = i - 64;
+        this.hash();
+        this.hashed = true;
+      } else {
+        this.start = i;
+      }
+    }
+    if (this.bytes > 4294967295) {
+      this.hBytes += this.bytes / 4294967296 << 0;
+      this.bytes = this.bytes % 4294967296;
+    }
+    return this;
+  };
+
+  Md5.prototype.finalize = function () {
+    if (this.finalized) {
+      return;
+    }
+    this.finalized = true;
+    var blocks = this.blocks, i = this.lastByteIndex;
+    blocks[i >> 2] |= EXTRA[i & 3];
+    if (i >= 56) {
+      if (!this.hashed) {
+        this.hash();
+      }
+      blocks[0] = blocks[16];
+      blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+      blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+      blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+    }
+    blocks[14] = this.bytes << 3;
+    blocks[15] = this.hBytes << 3 | this.bytes >>> 29;
+    this.hash();
+  };
+
+  Md5.prototype.hash = function () {
+    var a, b, c, d, bc, da, blocks = this.blocks;
+
+    if (this.first) {
+      a = blocks[0] - 680876937;
+      a = (a << 7 | a >>> 25) - 271733879 << 0;
+      d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708;
+      d = (d << 12 | d >>> 20) + a << 0;
+      c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375;
+      c = (c << 17 | c >>> 15) + d << 0;
+      b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209;
+      b = (b << 22 | b >>> 10) + c << 0;
+    } else {
+      a = this.h0;
+      b = this.h1;
+      c = this.h2;
+      d = this.h3;
+      a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936;
+      a = (a << 7 | a >>> 25) + b << 0;
+      d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586;
+      d = (d << 12 | d >>> 20) + a << 0;
+      c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819;
+      c = (c << 17 | c >>> 15) + d << 0;
+      b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330;
+      b = (b << 22 | b >>> 10) + c << 0;
+    }
+
+    a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897;
+    a = (a << 7 | a >>> 25) + b << 0;
+    d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426;
+    d = (d << 12 | d >>> 20) + a << 0;
+    c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341;
+    c = (c << 17 | c >>> 15) + d << 0;
+    b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983;
+    b = (b << 22 | b >>> 10) + c << 0;
+    a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416;
+    a = (a << 7 | a >>> 25) + b << 0;
+    d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417;
+    d = (d << 12 | d >>> 20) + a << 0;
+    c += (b ^ (d & (a ^ b))) + blocks[10] - 42063;
+    c = (c << 17 | c >>> 15) + d << 0;
+    b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162;
+    b = (b << 22 | b >>> 10) + c << 0;
+    a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682;
+    a = (a << 7 | a >>> 25) + b << 0;
+    d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101;
+    d = (d << 12 | d >>> 20) + a << 0;
+    c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290;
+    c = (c << 17 | c >>> 15) + d << 0;
+    b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329;
+    b = (b << 22 | b >>> 10) + c << 0;
+    a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510;
+    a = (a << 5 | a >>> 27) + b << 0;
+    d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632;
+    d = (d << 9 | d >>> 23) + a << 0;
+    c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713;
+    c = (c << 14 | c >>> 18) + d << 0;
+    b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302;
+    b = (b << 20 | b >>> 12) + c << 0;
+    a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691;
+    a = (a << 5 | a >>> 27) + b << 0;
+    d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083;
+    d = (d << 9 | d >>> 23) + a << 0;
+    c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335;
+    c = (c << 14 | c >>> 18) + d << 0;
+    b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848;
+    b = (b << 20 | b >>> 12) + c << 0;
+    a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438;
+    a = (a << 5 | a >>> 27) + b << 0;
+    d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690;
+    d = (d << 9 | d >>> 23) + a << 0;
+    c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961;
+    c = (c << 14 | c >>> 18) + d << 0;
+    b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501;
+    b = (b << 20 | b >>> 12) + c << 0;
+    a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467;
+    a = (a << 5 | a >>> 27) + b << 0;
+    d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784;
+    d = (d << 9 | d >>> 23) + a << 0;
+    c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473;
+    c = (c << 14 | c >>> 18) + d << 0;
+    b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734;
+    b = (b << 20 | b >>> 12) + c << 0;
+    bc = b ^ c;
+    a += (bc ^ d) + blocks[5] - 378558;
+    a = (a << 4 | a >>> 28) + b << 0;
+    d += (bc ^ a) + blocks[8] - 2022574463;
+    d = (d << 11 | d >>> 21) + a << 0;
+    da = d ^ a;
+    c += (da ^ b) + blocks[11] + 1839030562;
+    c = (c << 16 | c >>> 16) + d << 0;
+    b += (da ^ c) + blocks[14] - 35309556;
+    b = (b << 23 | b >>> 9) + c << 0;
+    bc = b ^ c;
+    a += (bc ^ d) + blocks[1] - 1530992060;
+    a = (a << 4 | a >>> 28) + b << 0;
+    d += (bc ^ a) + blocks[4] + 1272893353;
+    d = (d << 11 | d >>> 21) + a << 0;
+    da = d ^ a;
+    c += (da ^ b) + blocks[7] - 155497632;
+    c = (c << 16 | c >>> 16) + d << 0;
+    b += (da ^ c) + blocks[10] - 1094730640;
+    b = (b << 23 | b >>> 9) + c << 0;
+    bc = b ^ c;
+    a += (bc ^ d) + blocks[13] + 681279174;
+    a = (a << 4 | a >>> 28) + b << 0;
+    d += (bc ^ a) + blocks[0] - 358537222;
+    d = (d << 11 | d >>> 21) + a << 0;
+    da = d ^ a;
+    c += (da ^ b) + blocks[3] - 722521979;
+    c = (c << 16 | c >>> 16) + d << 0;
+    b += (da ^ c) + blocks[6] + 76029189;
+    b = (b << 23 | b >>> 9) + c << 0;
+    bc = b ^ c;
+    a += (bc ^ d) + blocks[9] - 640364487;
+    a = (a << 4 | a >>> 28) + b << 0;
+    d += (bc ^ a) + blocks[12] - 421815835;
+    d = (d << 11 | d >>> 21) + a << 0;
+    da = d ^ a;
+    c += (da ^ b) + blocks[15] + 530742520;
+    c = (c << 16 | c >>> 16) + d << 0;
+    b += (da ^ c) + blocks[2] - 995338651;
+    b = (b << 23 | b >>> 9) + c << 0;
+    a += (c ^ (b | ~d)) + blocks[0] - 198630844;
+    a = (a << 6 | a >>> 26) + b << 0;
+    d += (b ^ (a | ~c)) + blocks[7] + 1126891415;
+    d = (d << 10 | d >>> 22) + a << 0;
+    c += (a ^ (d | ~b)) + blocks[14] - 1416354905;
+    c = (c << 15 | c >>> 17) + d << 0;
+    b += (d ^ (c | ~a)) + blocks[5] - 57434055;
+    b = (b << 21 | b >>> 11) + c << 0;
+    a += (c ^ (b | ~d)) + blocks[12] + 1700485571;
+    a = (a << 6 | a >>> 26) + b << 0;
+    d += (b ^ (a | ~c)) + blocks[3] - 1894986606;
+    d = (d << 10 | d >>> 22) + a << 0;
+    c += (a ^ (d | ~b)) + blocks[10] - 1051523;
+    c = (c << 15 | c >>> 17) + d << 0;
+    b += (d ^ (c | ~a)) + blocks[1] - 2054922799;
+    b = (b << 21 | b >>> 11) + c << 0;
+    a += (c ^ (b | ~d)) + blocks[8] + 1873313359;
+    a = (a << 6 | a >>> 26) + b << 0;
+    d += (b ^ (a | ~c)) + blocks[15] - 30611744;
+    d = (d << 10 | d >>> 22) + a << 0;
+    c += (a ^ (d | ~b)) + blocks[6] - 1560198380;
+    c = (c << 15 | c >>> 17) + d << 0;
+    b += (d ^ (c | ~a)) + blocks[13] + 1309151649;
+    b = (b << 21 | b >>> 11) + c << 0;
+    a += (c ^ (b | ~d)) + blocks[4] - 145523070;
+    a = (a << 6 | a >>> 26) + b << 0;
+    d += (b ^ (a | ~c)) + blocks[11] - 1120210379;
+    d = (d << 10 | d >>> 22) + a << 0;
+    c += (a ^ (d | ~b)) + blocks[2] + 718787259;
+    c = (c << 15 | c >>> 17) + d << 0;
+    b += (d ^ (c | ~a)) + blocks[9] - 343485551;
+    b = (b << 21 | b >>> 11) + c << 0;
+
+    if (this.first) {
+      this.h0 = a + 1732584193 << 0;
+      this.h1 = b - 271733879 << 0;
+      this.h2 = c - 1732584194 << 0;
+      this.h3 = d + 271733878 << 0;
+      this.first = false;
+    } else {
+      this.h0 = this.h0 + a << 0;
+      this.h1 = this.h1 + b << 0;
+      this.h2 = this.h2 + c << 0;
+      this.h3 = this.h3 + d << 0;
+    }
+  };
+
+  /**
+   * @method hex
+   * @memberof Md5
+   * @instance
+   * @description Output hash as hex string
+   * @returns {String} Hex string
+   * @see {@link md5.hex}
+   * @example
+   * hash.hex();
+   */
+  Md5.prototype.hex = function () {
+    this.finalize();
+
+    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
+
+    return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
+      HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
+      HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
+      HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
+      HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
+      HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
+      HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
+      HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
+      HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
+      HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
+      HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
+      HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
+      HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
+      HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
+      HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
+      HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F];
+  };
+
+  /**
+   * @method toString
+   * @memberof Md5
+   * @instance
+   * @description Output hash as hex string
+   * @returns {String} Hex string
+   * @see {@link md5.hex}
+   * @example
+   * hash.toString();
+   */
+  Md5.prototype.toString = Md5.prototype.hex;
+
+  /**
+   * @method digest
+   * @memberof Md5
+   * @instance
+   * @description Output hash as bytes array
+   * @returns {Array} Bytes array
+   * @see {@link md5.digest}
+   * @example
+   * hash.digest();
+   */
+  Md5.prototype.digest = function () {
+    this.finalize();
+
+    var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
+    return [
+      h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF,
+      h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF,
+      h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF,
+      h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF
+    ];
+  };
+
+  /**
+   * @method array
+   * @memberof Md5
+   * @instance
+   * @description Output hash as bytes array
+   * @returns {Array} Bytes array
+   * @see {@link md5.array}
+   * @example
+   * hash.array();
+   */
+  Md5.prototype.array = Md5.prototype.digest;
+
+  /**
+   * @method arrayBuffer
+   * @memberof Md5
+   * @instance
+   * @description Output hash as ArrayBuffer
+   * @returns {ArrayBuffer} ArrayBuffer
+   * @see {@link md5.arrayBuffer}
+   * @example
+   * hash.arrayBuffer();
+   */
+  Md5.prototype.arrayBuffer = function () {
+    this.finalize();
+
+    var buffer = new ArrayBuffer(16);
+    var blocks = new Uint32Array(buffer);
+    blocks[0] = this.h0;
+    blocks[1] = this.h1;
+    blocks[2] = this.h2;
+    blocks[3] = this.h3;
+    return buffer;
+  };
+
+  /**
+   * @method buffer
+   * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
+   * @memberof Md5
+   * @instance
+   * @description Output hash as ArrayBuffer
+   * @returns {ArrayBuffer} ArrayBuffer
+   * @see {@link md5.buffer}
+   * @example
+   * hash.buffer();
+   */
+  Md5.prototype.buffer = Md5.prototype.arrayBuffer;
+
+  /**
+   * @method base64
+   * @memberof Md5
+   * @instance
+   * @description Output hash as base64 string
+   * @returns {String} base64 string
+   * @see {@link md5.base64}
+   * @example
+   * hash.base64();
+   */
+  Md5.prototype.base64 = function () {
+    var v1, v2, v3, base64Str = '', bytes = this.array();
+    for (var i = 0; i < 15;) {
+      v1 = bytes[i++];
+      v2 = bytes[i++];
+      v3 = bytes[i++];
+      base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
+        BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] +
+        BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] +
+        BASE64_ENCODE_CHAR[v3 & 63];
+    }
+    v1 = bytes[i];
+    base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
+      BASE64_ENCODE_CHAR[(v1 << 4) & 63] +
+      '==';
+    return base64Str;
+  };
+
+  var exports = createMethod();
+
+  if (COMMON_JS) {
+    module.exports = exports;
+  } else {
+    /**
+     * @method md5
+     * @description Md5 hash function, export to global in browsers.
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {String} md5 hashes
+     * @example
+     * md5(''); // d41d8cd98f00b204e9800998ecf8427e
+     * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
+     * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0
+     *
+     * // It also supports UTF-8 encoding
+     * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07
+     *
+     * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
+     * md5([]); // d41d8cd98f00b204e9800998ecf8427e
+     * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e
+     */
+    root.md5 = exports;
+    if (AMD) {
+      define(function () {
+        return exports;
+      });
+    }
+  }
+})();

+ 2 - 1
exam-06173-uni/package.json

@@ -18,6 +18,7 @@
   "dependencies": {
     "cos-js-sdk-v5": "^1.3.7",
     "cos-wx-sdk-v5": "^1.1.7",
-    "image-tools": "^1.4.0"
+    "image-tools": "^1.4.0",
+		"js-md5": "0.7.3"
   }
 }

+ 39 - 8
exam-06173-uni/pages/course/index.vue

@@ -14,13 +14,28 @@
 		</view>
 
 		<yf-more-list url="/api/course/course/user-paging" :params="queryParams" ref="moreList">
-			<template v-slot:item="{ data }" >
+			<template v-slot:item="{ data }">
 				<uni-list-item :show-arrow="true" :title="data.title" :note="'类型:'+data.catId_dictText"
-				link="navigateTo" :to="'/pages/course/detail?id='+data.id">
+					link="navigateTo" :to="'/pages/course/detail?id='+data.id">
+					<template v-slot:body>
+						<view class="" style="width: 100%;">
+							{{data.title}}
+						</view>
+						<view class="" style="width: 100%;display: flex; flex-direction: column;">
+							<view class="" style="font-size: 14px;">
+								类型:{{data.catId_dictText}}
+							</view>
+							<view class="" style="display: flex;align-items: center;font-size: 14px;">
+								学习进度:<progress show-info style="width: 200px;"
+									:percent="Number(data.proportion * 100).toFixed(0)"
+									activeColor="#10AEFF" stroke-width="6" />
+							</view>
+						</view>
+					</template>
 				</uni-list-item>
 			</template>
 		</yf-more-list>
-		
+
 	</view>
 </template>
 
@@ -35,7 +50,7 @@
 
 				current: 0,
 				tabs: ['全部', '未学习', '学习中', '已学完'],
-				queryParams:{
+				queryParams: {
 					title: '',
 					learnState: "0",
 					onlyLearn: false
@@ -45,7 +60,7 @@
 			}
 		},
 		onPullDownRefresh() {
-			if(this.$refs.moreList){
+			if (this.$refs.moreList) {
 				this.$refs.moreList.initData()
 			}
 		},
@@ -55,18 +70,18 @@
 			this.$refs.moreList.loadData()
 		},
 		onShow() {
-			if(this.$refs.moreList){
+			if (this.$refs.moreList) {
 				this.$refs.moreList.initData()
 			}
 		},
 		mounted() {
-			if(this.onlyLearn!=null){
+			if (this.onlyLearn != null) {
 				this.queryParams.onlyLearn = this.onlyLearn
 			}
 		},
 
 		methods: {
-			
+
 			// 搜索课程
 			search(e) {
 				this.queryParams.title = e
@@ -132,3 +147,19 @@
 		margin-right: 5px;
 	}
 </style>
+<style scoped>
+	::v-deep .uni-list-item__container {
+		flex-direction: column;
+	}
+
+	::v-deep .uni-progress-inner-bar {
+		background-color: unset;
+		background-image: linear-gradient(to right, #3587d8, #6855ff);
+	}
+	::v-deep .uni-progress-info{
+		font-size: 14px;
+	}
+	::v-deep .uni-progress-bar,::v-deep .uni-progress-inner-bar{
+		border-radius: 6px;
+	}
+</style>

+ 39 - 30
exam-06173-uni/pages/exam/detail.vue

@@ -8,6 +8,10 @@
 				<view>考试时长:{{checkData.totalTime}}分钟</view>
 				<view>试卷总分:{{checkData.totalScore}}</view>
 				<view>及格分数:{{checkData.qualifyScore}}</view>
+				<view>关联培训:
+					<text v-if="checkData.associate === 1" style="color: rgb(24, 144, 255)" @click="funJumpCourse">是</text>
+					<text v-if="checkData.associate !== 1">否</text>
+				</view>
 			</view>
 		</uni-card>
 
@@ -24,32 +28,32 @@
 
 		<view v-else>
 
-				<view v-if="checkData.late" class="empty">
-					<view>您已经迟到超过{{checkData.lateMax}}分钟,不允许进入考试!</view>
-					<view>
-						<button type="primary" @tap="backList">返回</button>
-					</view>
-				</view>
-				<view v-else-if="checkData.overTime" class="empty">
-					<view>考试未开始或已结束!</view>
+			<view v-if="checkData.late" class="empty">
+				<view>您已经迟到超过{{checkData.lateMax}}分钟,不允许进入考试!</view>
+				<view>
 					<button type="primary" @tap="backList">返回</button>
 				</view>
-				<view v-else-if="checkData.chance>0 && checkData.examCount>=checkData.chance" class="empty">
-					<view>开始次数超限,总共有{{checkData.chance}}次考试机会!</view>
-					<button type="primary" @tap="backList">返回</button>
-				</view>
-				<view v-else>
-
-					<uni-card title="考试密码" v-if="checkData.openType ===9 ">
-						<uni-easyinput v-model="password" placeholder="请输入密码" type="password" />
-					</uni-card>
+			</view>
+			<view v-else-if="checkData.overTime" class="empty">
+				<view>考试未开始或已结束!</view>
+				<button type="primary" @tap="backList">返回</button>
+			</view>
+			<view v-else-if="checkData.chance>0 && checkData.examCount>=checkData.chance" class="empty">
+				<view>开始次数超限,总共有{{checkData.chance}}次考试机会!</view>
+				<button type="primary" @tap="backList">返回</button>
+			</view>
+			<view v-else>
 
-					<view style="padding: 20px;">
-						<button type="primary" @tap="startExam">开始考试</button>
-					</view>
+				<uni-card title="考试密码" v-if="checkData.openType ===9 ">
+					<uni-easyinput v-model="password" placeholder="请输入密码" type="password" />
+				</uni-card>
 
+				<view style="padding: 20px;">
+					<button type="primary" @tap="startExam">开始考试</button>
 				</view>
 
+			</view>
+
 
 		</view>
 
@@ -59,7 +63,6 @@
 </template>
 
 <script>
-
 	import {
 		checkInfo,
 		createPaper,
@@ -109,7 +112,7 @@
 				let that = this
 
 				// 如果要人脸识别
-				if(this.checkData.faceOn){
+				if (this.checkData.faceOn) {
 					//打印请求返回的数据
 					uni.navigateTo({
 						url: '/pages/exam/face?examId=' + this.examId + '&password=' + this.password
@@ -136,7 +139,7 @@
 						url: '/pages/exam/exam?id=' + data.id
 					});
 
-				}).catch(err=>{
+				}).catch(err => {
 
 
 					// 有正在进行的考试
@@ -144,7 +147,7 @@
 						uni.showModal({
 							title: '提示信息',
 							content: '您有其它正在进行的考试,是否继续进入该考试?',
-							success: function (res) {
+							success: function(res) {
 								if (res.confirm) {
 									that.backExam()
 								}
@@ -159,19 +162,25 @@
 				uni.navigateBack()
 			},
 
-			backExam(){
+			backExam() {
 				checkProcess().then(data => {
-				      if (data && data.id) {
+					if (data && data.id) {
 						this.continueExam(data.id)
-				      }
+					}
+				})
+			},
+			
+			funJumpCourse(){
+				uni.navigateTo({
+					url:'/pages/course/detail?id='+ this.checkData.courseId
 				})
 			},
 
 			// 继续考试
 			continueExam(id) {
-			  uni.redirectTo({
-			  	url: '/pages/exam/exam?id=' + id
-			  });
+				uni.redirectTo({
+					url: '/pages/exam/exam?id=' + id
+				});
 			},
 		},
 		onUnload() {

+ 65 - 43
exam-06173-uni/pages/exam/index.vue

@@ -1,78 +1,100 @@
 <template>
 	<view class="container">
-		
+
 		<!-- 设置圆角 -->
 		<view style="padding: 10px 30px 10px 30px;">
 			<uni-search-bar :radius="100" @input="search" placeholder="搜索考试"></uni-search-bar>
 		</view>
-		
-		
+
+
 		<view style="background: #f5f5f5">
 			<uni-segmented-control :current="current" :values="tabs" @clickItem="changeTab" styleType="text"
 				activeColor="#007aff">
 			</uni-segmented-control>
 		</view>
-		
-		
+
+
 		<yf-more-list url="/api/exam/exam/online-paging" :params="queryParams" ref="moreList">
-						
+
 			<template v-slot:item="{ data }">
-				<uni-list-item
-				 :show-arrow="true" 
-				 :title="data.title" 
-				 :note="'发布时间:'+data.createTime"
-				 :rightText="data.timeLimit?'限时': '不限时'"
-				 link="navigateTo"
-				 :to="'/pages/exam/detail?id='+data.id"
-				 >
-				 </uni-list-item>
+				<!-- 				link="navigateTo"
+				:to="'/pages/exam/detail?id='+data.id" -->
+				 <!-- :clickable="true" @click="funJump(data)" -->
+				<uni-list-item :show-arrow="true" :title="data.title"
+					:note="'关联培训:'+ (data.associate === 1? '是': '否') +' \n 发布时间:'+data.createTime"
+					:rightText="data.timeLimit?'限时': '不限时'" :to="'/pages/exam/detail?id='+data.id" link="navigateTo">
+				</uni-list-item>
 			</template>
 		</yf-more-list>
-		
+
 
 	</view>
 </template>
 
 <script>
-
-	
-	import { checkProcess } from '@/api/exam.js'
+	import {
+		checkProcess
+	} from '@/api/exam.js'
 	export default {
 		data() {
 			return {
 				current: 0,
-				tabs: ['全部','考试中','未开始','已结束'],
+				tabs: ['全部', '考试中', '未开始', '已结束'],
 				queryParams: {
 					title: '',
 					examState: ''
 				}
 			}
 		},
-		onPullDownRefresh(){
+		onPullDownRefresh() {
 			// 加载数据
 			this.$refs.moreList.loadData()
 			this.checkExam()
 		},
-	
+
 		onReachBottom() {
 			// 加载数据
 			this.$refs.moreList.loadData()
 		},
 		onShow() {
-			if(this.$refs.moreList){
+			if (this.$refs.moreList) {
 				this.$refs.moreList.initData()
 			}
 			this.checkExam()
 		},
 
 		methods: {
-			
-			
-			checkExam(){
-				
+			funJump(obj) {
+				if (obj.associate === 1) {
+					uni.showModal({
+						cancelText: "取消", // 取消按钮的文字  
+						confirmText: "确认", // 确认按钮文字 
+						title: '培训提示',
+						content: '该考试已关联培训,是否跳转培训?',
+						success: res => {
+							if (res.confirm) {
+								uni.navigateTo({
+									url: '/pages/course/detail?id=' + obj.courseId
+								})
+							}else{
+								uni.navigateTo({
+									url: '/pages/exam/detail?id=' + obj.id
+								})
+							}
+						}
+					});
+				} else {
+					uni.navigateTo({
+						url: '/pages/exam/detail?id=' + obj.id
+					})
+				}
+			},
+
+			checkExam() {
+
 				checkProcess().then(data => {
-				      if (data && data.id) {
-				      
+					if (data && data.id) {
+
 						uni.showModal({
 							cancelText: "取消", // 取消按钮的文字  
 							confirmText: "确认", // 确认按钮文字 
@@ -84,36 +106,36 @@
 								}
 							}
 						});
-						
-				      }
+
+					}
 				})
-				
+
 			},
 
 			// 考试详情页
 			search(e) {
 				this.queryParams.title = e
 			},
-			
-			changeTab(e){
-				
+
+			changeTab(e) {
+
 				if (this.current != e.currentIndex) {
 					this.current = e.currentIndex;
 				}
-				
+
 				let state = null;
-				if(e.currentIndex!=0){
+				if (e.currentIndex != 0) {
 					state = e.currentIndex - 1
 				}
-				
+
 				this.queryParams.examState = state
 			},
-			
-			 // 继续考试
+
+			// 继续考试
 			continueExam(id) {
-			  uni.redirectTo({
-			  	url: '/pages/exam/exam?id=' + id
-			  });
+				uni.redirectTo({
+					url: '/pages/exam/exam?id=' + id
+				});
 			},
 		}
 	}

+ 7 - 1
exam-06173-uni/pages/index/index.vue

@@ -101,7 +101,13 @@
 		},
 
 		onShow() {
-			this.fetchNoticePaging();
+			if(uni.getStorageSync('token')){
+				this.fetchNoticePaging();
+			}else{
+				getApp().loginCallBack = () => {
+					this.fetchNoticePaging()
+				}
+			}
 		},
 
 		methods: {

+ 11 - 11
exam-06173-uni/pages/login/login.vue

@@ -2,10 +2,10 @@
 	<view class="page-box">
 
 
-
+<!-- 
 			<uni-segmented-control :current="current" :values="items" @clickItem="onClickItem" styleType="button"
 				activeColor="#007aff">
-			</uni-segmented-control>
+			</uni-segmented-control> -->
 
 
 			<view style="margin-top: 30px;">
@@ -39,10 +39,10 @@
 					<button type="primary" @tap="handleLogin">登录</button>
 				</view>
 
-				<view class="login-opt">
+			<!-- 	<view class="login-opt">
 					<a @tap="$navs.toReg">立即注册</a>
 					<a @tap="$navs.toForgot">忘记密码?</a>
-				</view>
+				</view> -->
 
 
 		</view>
@@ -52,29 +52,29 @@
 
 		<view class="other-login">
 
-			<view class="tt">其它登录方式</view>
+			<!-- <view class="tt">其它登录方式</view> -->
 
 
-			<view style="display: flex; align-items: center;">
+			<!-- <view style="display: flex; align-items: center;"> -->
 
 
 
 				<!-- #ifdef MP-WEIXIN -->
-				<view class="types">
+	<!-- 			<view class="types">
 					<image src="../../static/images/we-chat.png" style="width: 35px; height: 35px;" @click="appLoginWx">
 					</image>
 					<view>微信登录</view>
-				</view>
+				</view> -->
 				<!-- #endif -->
 
 
-				<view class="types">
+		<!-- 		<view class="types">
 					<image src="../../static/images/face-id.png" style="width: 35px; height: 35px;"
 						@click="appLoginFace"></image>
 					<view>人脸登录</view>
-				</view>
+				</view> -->
 
-			</view>
+			<!-- </view> -->
 
 
 

+ 1 - 1
exam-06173-vue/.env.demo

@@ -2,4 +2,4 @@
 NODE_ENV = demo
 
 # 演示环境接口
-VUE_APP_BASE_API = 'https://exam-api.yfhl.net'
+VUE_APP_BASE_API = 'http://124.70.18.168:8617'

+ 1 - 1
exam-06173-vue/.env.development

@@ -3,4 +3,4 @@ ENV = 'development'
 # 固定调试端口
 PORT = 9617
 # 开发接口设置
-VUE_APP_BASE_API = 'http://10.155.32.18:8617'
+VUE_APP_BASE_API = 'http://124.70.18.168:8617'

+ 1 - 1
exam-06173-vue/.env.production

@@ -2,4 +2,4 @@
 ENV = 'production'
 
 # 生产环境接口
-VUE_APP_BASE_API = 'http://123.60.213.70:8617'
+VUE_APP_BASE_API = 'http://10.155.32.18:8617'

BIN
exam-06173-vue/dist.rar


+ 4 - 0
exam-06173-vue/public/config/config.js

@@ -0,0 +1,4 @@
+window.__MODE__ = {
+    // 是否在页面切换时显示当前页面 vue 文件所在路径
+    showPagePath: true
+};

+ 20 - 14
exam-06173-vue/public/index.html

@@ -1,16 +1,22 @@
 <!DOCTYPE html>
 <html>
-  <head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <meta name="renderer" content="webkit">
-    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
-    <!-- <link rel="icon" href="<%= BASE_URL %>favicon.png"> -->
-    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <script async src="/tinymce/tinymce.min.js"></script>
-    <title><%= webpackConfig.name %></title>
-  </head>
-  <body>
-    <div id="app"></div>
-  </body>
-</html>
+
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="renderer" content="webkit">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+  <!-- <link rel="icon" href="<%= BASE_URL %>favicon.png"> -->
+  <!-- <link rel="icon" href="<%= BASE_URL %>favicon.ico"> -->
+  <script async src="/tinymce/tinymce.min.js"></script>
+  <script async src="/config/config.js"></script>
+  <title>
+    <%= webpackConfig.name %>
+  </title>
+</head>
+
+<body>
+  <div id="app"></div>
+</body>
+
+</html>

+ 26 - 0
exam-06173-vue/src/App.vue

@@ -5,8 +5,25 @@
 </template>
 
 <script>
+import { Message } from "element-ui";
 export default {
   name: "App",
+  watch: {
+    $route(r) {
+      if (window.__MODE__.showPagePath) {
+        this.$store.state.permission.addRoutes.forEach((pEle) => {
+          if (Array.isArray(pEle.children)) {
+            const findRes = pEle.children.find((cEle) => {
+              return cEle.name === r.name;
+            });
+            if (findRes) {
+              Message.success(`${findRes.meta.title} -> ${findRes.pagePath}`);
+            }
+          }
+        });
+      }
+    },
+  },
 };
 </script>
 
@@ -14,4 +31,13 @@ export default {
 body .el-scrollbar__wrap {
   overflow-x: hidden;
 }
+
+body .el-tabs .el-tabs__item {
+  font-size: 16px;
+  font-weight: 700;
+}
+
+body .el-select-dropdown .el-scrollbar__wrap {
+  overflow: scroll;
+}
 </style>

+ 1 - 1
exam-06173-vue/src/api/archives/index.js

@@ -54,5 +54,5 @@ export function getDepartZgKsDetail(data) {
  * @returns {Promise}
  */
 export function exportBmExcel(data) {
-    return download('/api/ec-depart-total-export', data, '部门统计-导出.xlsx')
+    return download('/api/total/ec/ec-depart-total-export', data, '部门统计-导出.xlsx')
 }

+ 7 - 10
exam-06173-vue/src/api/dashboard/index.js

@@ -1,9 +1,14 @@
 import { get, post } from '@/utils/request'
 
 /**
+ * 首页获取统计数值
+ */
+export function getCttTotal() {
+    return post('/api/course/course/ctt-total')
+}
+
+/**
  * 首页获取当前考试列表
- * @param examId
- * @returns {Promise}
  */
 export function getCurrentExam() {
     return get('/api/index/current/exam')
@@ -11,8 +16,6 @@ export function getCurrentExam() {
 
 /**
  * 首页获取部门培训课时排行
- * @param examId
- * @returns {Promise}
  */
 export function getDepartRank(data) {
     return post('/api/course/course/course-depart-rank', data)
@@ -20,8 +23,6 @@ export function getDepartRank(data) {
 
 /**
  * 首页获取部门考试及格率排行
- * @param examId
- * @returns {Promise}
  */
 export function getPassedRate(data) {
     return post('/api/exam/exam/depart-passed-rate', data)
@@ -29,8 +30,6 @@ export function getPassedRate(data) {
 
 /**
  * 首页获职工培训课时排行top20
- * @param examId
- * @returns {Promise}
  */
 export function getUserRank(data) {
     return post('/api/course/course/course-user-rank', data)
@@ -38,8 +37,6 @@ export function getUserRank(data) {
 
 /**
  * 首页获职考试及格率排行top20
- * @param examId
- * @returns {Promise}
  */
 export function getUserRate(data) {
     return post('/api/exam/exam/user-passed-rate', data)

+ 21 - 0
exam-06173-vue/src/api/exam/form.js

@@ -0,0 +1,21 @@
+import { post } from '@/utils/request'
+
+/**
+ * 获取课程列表
+ */
+export function getTableData() {
+    return post('/api/course/course/paging', {
+        current: 1,
+        size: 50000,
+        params: {
+            title: ''
+        }
+    })
+}
+
+/**
+ * 获取树形可用选项
+ */
+export function getTreeEnable(data) {
+    return post('/api/course/course/course-open-depart', data)
+}

BIN
exam-06173-vue/src/assets/web/images/login3.png


BIN
exam-06173-vue/src/assets/web/images/login4.png


+ 74 - 37
exam-06173-vue/src/components/DepartRefs/index.vue

@@ -1,18 +1,12 @@
 
 <template>
-
   <div>
-
-    <el-input
-      v-model="filterText"
-      placeholder="输入关键字进行过滤"
-    />
-
+    <el-input v-model="filterText" placeholder="输入关键字进行过滤" />
     <el-tree
       v-loading="treeLoading"
       ref="tree"
       :data="treeData"
-      :check-strictly="true"
+      :check-strictly="false"
       :default-checked-keys="deptCodes"
       :props="defaultProps"
       :filter-node-method="filterNode"
@@ -23,67 +17,110 @@
       node-key="deptCode"
       @check-change="handleCheckChange"
     />
-
   </div>
-
 </template>
 
 <script>
-import { fetchTree } from '@/api/sys/depart/depart'
+import { fetchTree } from "@/api/sys/depart/depart";
 export default {
-  name: 'DepartRefs',
+  name: "DepartRefs",
   props: {
-    value: Array
+    value: Array,
+    enableArray: {
+      type: Array,
+      default: () => [],
+    },
   },
   data() {
     return {
       defaultProps: {
-        label: 'deptName'
+        label: "deptName",
+        children: "children",
       },
-      filterText: '',
+      filterText: "",
       treeLoading: false,
       deptCodes: [],
-      treeData: []
-    }
+      treeData: [],
+      enableData: [],
+    };
   },
 
   watch: {
-
     filterText(val) {
-      this.$refs.tree.filter(val)
+      this.$refs.tree.filter(val);
     },
 
     value(val) {
-      this.deptCodes = val
-    }
+      this.deptCodes = val;
+      this.rinseData();
+    },
+
+    enableArray(val) {
+      this.enableData = val;
+      this.rinseData();
+    },
   },
   created() {
     // 初始化赋值
-    this.deptCodes = this.value
+    this.deptCodes = this.value;
+    this.enableData = this.enableArray;
 
-    fetchTree({}).then(response => {
-      this.treeData = response.data
-    })
+    fetchTree({}).then((response) => {
+      this.treeData = response.data;
+      this.rinseData();
+    });
   },
   methods: {
-
     handleCheckChange() {
       // 置空
-      const deptCodes = []
+      const deptCodes = [];
 
-      const nodes = this.$refs.tree.getCheckedNodes()
-      nodes.forEach(function(item) {
-        deptCodes.push(item.deptCode)
-      })
+      const nodes = this.$refs.tree.getCheckedNodes();
+      nodes.forEach((item) => {
+        deptCodes.push(item.deptCode);
+      });
 
-      this.$emit('input', deptCodes)
+      this.$emit("input", deptCodes);
     },
 
     filterNode(value, data) {
-      if (!value) return true
-      return data.deptName.indexOf(value) !== -1
-    }
+      if (!value) return true;
+      return data.deptName.indexOf(value) !== -1;
+    },
 
-  }
-}
+    rinseData() {
+      if (this.enableData.length) {
+        this.treeData.forEach((pEle) => {
+          let pEleFindRes = this.enableData.find((findEle) => {
+            return findEle === pEle.value;
+          });
+          if (!pEleFindRes) {
+            pEle.disabled = true;
+            for (let i = 0; i < this.deptCodes.length; i++) {
+              if (this.deptCodes[i] === pEle.value) {
+                this.deptCodes.splice(i, 1);
+              }
+            }
+          }
+          if (Array.isArray(pEle.children)) {
+            pEle.children.forEach((cEle) => {
+              let cEleFindRes = this.enableData.find((findEle) => {
+                return findEle === cEle.value;
+              });
+              if (!cEleFindRes) {
+                cEle.disabled = true;
+                for (let i = 0; i < this.deptCodes.length; i++) {
+                  if (this.deptCodes[i] === cEle.value) {
+                    this.deptCodes.splice(i, 1);
+                  }
+                }
+              }
+            });
+          }
+        });
+        this.$emit("input", this.deptCodes);
+      }
+    },
+  },
+};
 </script>

+ 23 - 29
exam-06173-vue/src/components/DicListSelect/index.vue

@@ -1,5 +1,4 @@
 <template>
-
   <el-select
     v-model="currentValue"
     :disabled="disabled"
@@ -14,67 +13,62 @@
     @change="handlerChange"
   >
     <el-option
-      v-for="item in dataList"
-      :key="item.value"
+      v-for="(item, index) in dataList"
+      :key="index"
       :label="item.title"
       :value="item.value"
     />
   </el-select>
-
 </template>
 
 <script>
-
-import { fetchTree } from '@/api/sys/dict/value'
+import { fetchTree } from "@/api/sys/dict/value";
 
 export default {
-  name: 'DicListSelect',
+  name: "DicListSelect",
   props: {
     dicCode: String,
     title: String,
     value: String,
     disabled: Boolean,
-    excludes: Array
+    excludes: Array,
   },
   data() {
     return {
       // 下拉选项值
       dataList: [],
-      currentValue: []
-    }
+      currentValue: "",
+    };
   },
 
   watch: {
     // 检测查询变化
-    value: {
-      handler() {
-        this.currentValue = this.value
-      }
-    }
+    value(val) {
+      this.currentValue = val;
+    },
   },
   created() {
-    this.currentValue = this.value
-    this.fetchData()
+    this.currentValue = this.value;
+    this.fetchData();
   },
   methods: {
-
     fetchData() {
-      fetchTree({ dicCode: this.dicCode, excludes: this.excludes }).then(response => {
-        this.dataList = response.data
-      })
+      fetchTree({ dicCode: this.dicCode, excludes: this.excludes }).then(
+        (response) => {
+          this.dataList = response.data;
+        }
+      );
     },
     handlerChange(e) {
-      this.$emit('change', e)
-      this.$emit('input', e)
-    }
-  }
-}
+      this.$emit("change", e);
+      this.$emit("input", e);
+    },
+  },
+};
 </script>
 
 <style scoped>
-
-/deep/
-.el-form-item--medium .el-form-item__content{
+/deep/ .el-form-item--medium .el-form-item__content {
   line-height: 20px;
 }
 </style>

+ 4 - 1
exam-06173-vue/src/components/Tinymce/index.vue

@@ -103,7 +103,10 @@ export default {
         branding: false,
         plugins: plugins,
         end_container_on_empty_block: true,
-        powerpaste_word_import: 'clean',
+        // powerpaste_word_import: 'clean',  //粘贴时为简洁模式
+        powerpaste_word_import: 'propmt', // 粘贴word时 为完整模式
+        // powerpaste_html_import: 'propmt', // 粘贴html时, 为完整模式
+
         code_dialog_height: 450,
         code_dialog_width: 1000,
         advlist_bullet_styles: 'square',

+ 113 - 93
exam-06173-vue/src/layout/components/WebHeader.vue

@@ -1,14 +1,24 @@
 <template>
-
   <el-row type="flex" class="header-bg" justify="center">
-
     <el-col :span="20" style="display: flex; align-items: center">
-
       <div class="col-logo">
         <a href="/">
           <div style="display: flex; flex-direction: row; align-items: center">
             <div v-if="siteData.frontLogo">
-              <img :src="siteData.frontLogo" :alt="siteData.siteName" style="height: 40px;">
+              <!-- <img
+                :src="siteData.frontLogo"
+                :alt="siteData.siteName"
+                style="height: 40px"
+              /> -->
+              <div class="logoBox">
+                <img
+                  v-if="siteData.backLogo"
+                  :src="siteData.backLogo"
+                  class="sidebar-logo"
+                  style="height: 40px"
+                />
+                <h1 class="sidebar-title">{{ siteData.siteName }}</h1>
+              </div>
             </div>
             <div v-else class="site-tt">{{ siteData.siteName }}</div>
           </div>
@@ -28,131 +38,120 @@
             {{ item.title }}
           </el-button>
         </div>
-
       </div>
 
       <div class="right-user">
         <div class="top-avatar">
-          <img v-if="avatar!=null && avatar!==''" :src="avatar">
-          <img v-else src="@/assets/web/avatar.png">
+          <img v-if="avatar != null && avatar !== ''" :src="avatar" />
+          <img v-else src="@/assets/web/avatar.png" />
         </div>
         <div>{{ realName }}</div>
-        <a v-if="roleType===2" class="alink" @click="toAdmin">管理中心</a>
+        <a v-if="roleType === 2" class="alink" @click="toAdmin">管理中心</a>
         <a @click="logout">退出</a>
       </div>
-
     </el-col>
-
   </el-row>
-
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
+import { mapGetters } from "vuex";
 
 export default {
-
   data() {
     return {
       menuList: [
         {
-          url: '/web/course',
-          title: '课程学习'
+          url: "/web/course",
+          title: "课程学习",
         },
         {
-          url: '/web/index',
-          title: '在线考试'
+          url: "/web/index",
+          title: "在线考试",
         },
         {
-          url: '/web/repo',
-          title: '题库训练'
+          url: "/web/repo",
+          title: "题库训练",
         },
         {
-          url: '/web/notice',
-          title: '系统公告'
+          url: "/web/notice",
+          title: "系统公告",
         },
         {
-          url: '/web/uc',
-          title: '用户中心'
-        }
+          url: "/web/uc",
+          title: "用户中心",
+        },
       ],
-      activeIndex: '/web/course'
-    }
+      activeIndex: "/web/course",
+    };
   },
   computed: {
-    ...mapGetters([
-      'avatar',
-      'realName',
-      'siteData',
-      'roleType'
-    ])
+    ...mapGetters(["avatar", "realName", "siteData", "roleType"]),
   },
   created() {
-    this.focusMenu()
+    this.focusMenu();
   },
 
   methods: {
-
     // 选定菜单
     focusMenu() {
-      const activeMenu = this.$route.meta.activeMenu
+      const activeMenu = this.$route.meta.activeMenu;
 
       if (activeMenu) {
-        this.activeIndex = activeMenu
-        return
+        this.activeIndex = activeMenu;
+        return;
       }
-      const path = this.$route.path.split('/')
-      const prefix = path[0] + '/' + path[1] + '/' + path[2]
-      console.log(prefix)
-      this.activeIndex = prefix
+      const path = this.$route.path.split("/");
+      const prefix = path[0] + "/" + path[1] + "/" + path[2];
+      console.log(prefix);
+      this.activeIndex = prefix;
     },
 
     isActive(url) {
       if (this.activeIndex === url) {
-        return 'nav active'
+        return "nav active";
       }
-      return 'nav'
+      return "nav";
     },
 
     navClick(url) {
-      this.activeIndex = url
-      this.$router.push({ path: url })
+      this.activeIndex = url;
+      this.$router.push({ path: url });
     },
 
     async logout() {
-      const that = this
-
-      this.$confirm('确实要退出吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'info'
-      }).then(() => {
-        that.$store.dispatch('user/logout').then(() => {
-          that.$router.push('/login')
-        })
-      }).catch(() => {
+      const that = this;
 
+      this.$confirm("确实要退出吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "info",
       })
+        .then(() => {
+          that.$store.dispatch("user/logout").then(() => {
+            that.$router.push("/login");
+          });
+        })
+        .catch(() => {});
     },
 
     handleUc() {
-      this.$router.push({ name: 'UserCenter' })
+      this.$router.push({ name: "UserCenter" });
     },
 
     toAdmin() {
-      this.$router.push({ path: '/admin/dashboard' })
-    }
-  }
-}
+      this.$router.push({ path: "/admin/dashboard" });
+    },
+  },
+};
 </script>
 
-<style scoped>
-  .header-bg{
-    height: 60px;
-    background: #4377fb;
-  }
+<style lang="scss" scoped>
+.header-bg {
+  height: 60px;
+  background: #4377fb;
+}
 
-.right-user{
+.right-user {
   display: flex;
   justify-content: flex-end;
   flex-direction: row;
@@ -161,41 +160,40 @@ export default {
   width: 250px;
 }
 
-.site-tt{
+.site-tt {
   font-weight: 700;
   font-size: 20px;
   color: #eee;
   flex-grow: 1;
   text-align: left;
-  padding-left: 10px
+  padding-left: 10px;
 }
 
-.right-user a, .right-user div{
+.right-user a,
+.right-user div {
   color: #efefef;
   font-size: 14px;
   font-weight: 500;
   margin-right: 10px;
 }
 
-.right-user a:last-child{
+.right-user a:last-child {
   margin-right: 0px !important;
 }
 
-.right-user a:hover{
+.right-user a:hover {
   color: #ffd550;
 }
 
-/deep/
-.alink {
-  color: #FFD550 !important;
+/deep/ .alink {
+  color: #ffd550 !important;
 }
 
-/deep/
-.alink:hover {
-  color: #F94E3E !important;
+/deep/ .alink:hover {
+  color: #f94e3e !important;
 }
 
-.nav{
+.nav {
   color: #fff;
   border: none;
   background: transparent;
@@ -205,17 +203,17 @@ export default {
   margin-right: 10px;
 }
 
-.active{
+.active {
   color: #000055;
-  background: #FFD550;
+  background: #ffd550;
 }
 
 .nav:hover {
   color: #000055;
-  background: #FFD550;
+  background: #ffd550;
 }
 
-.col-logo{
+.col-logo {
   display: flex;
   align-items: center;
   justify-content: flex-start;
@@ -223,31 +221,53 @@ export default {
   max-width: 200px;
 }
 
-.col-menu{
+.col-menu {
   flex-grow: 1;
   align-items: center;
   text-align: center;
 }
 
-/deep/
-.top-avatar{
+/deep/ .top-avatar {
   text-align: right;
   display: flex;
   align-items: center;
   margin-right: 5px !important;
-
 }
 
-/deep/
-.top-avatar div{
+/deep/ .top-avatar div {
   display: flex;
   align-items: center;
   margin-right: -10px !important;
 }
 
-/deep/
-.top-avatar img{
-  width: 30px; height: 30px; border-radius: 15px;
+/deep/ .top-avatar img {
+  width: 30px;
+  height: 30px;
+  border-radius: 15px;
 }
 
-</style>
+.logoBox {
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+  position: relative;
+
+  .sidebar-logo {
+    margin-right: 0px;
+  }
+
+  .sidebar-title {
+    position: absolute;
+    left: 48px;
+    display: inline-block;
+    margin: 0;
+    color: #fff;
+    font-weight: 600;
+    line-height: 50px;
+    font-size: 18px;
+    font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+    vertical-align: middle;
+    white-space: nowrap;
+  }
+}
+</style>

+ 2 - 2
exam-06173-vue/src/permission.js

@@ -9,9 +9,9 @@ import getPageTitle from '@/utils/get-page-title'
 NProgress.configure({ showSpinner: false })
 
 // 白名单
-const whiteList = ['/login', '/face', '/register', '/forgot', '401', '404', '/cert', '/sync']
+const whiteList = ['/login', '/face', '/register', '/forgot', '401', '404', '/cert', '/sync', '/checkPoint']
 
-router.beforeEach(async(to, from, next) => {
+router.beforeEach(async (to, from, next) => {
   // 进度条
   NProgress.start()
 

+ 8 - 0
exam-06173-vue/src/router/index.js

@@ -52,6 +52,13 @@ export const constantRoutes = [
   },
 
   {
+    path: '/checkPoint',
+    component: () => import('@/views/checkPoint/index'),
+    hidden: true,
+    children: []
+  },
+
+  {
     path: '/face',
     name: 'FaceLogin',
     component: () => import('@/views/login/components/face-login'),
@@ -245,6 +252,7 @@ const createRouter = () => new Router({
   routes: constantRoutes
 })
 
+
 const router = createRouter()
 
 export function resetRouter() {

+ 1 - 0
exam-06173-vue/src/store/modules/permission.js

@@ -30,6 +30,7 @@ export function getAsyncRoutes(routes) {
       } else if (item.component === 'WebLayout') {
         newItem.component = WebLayout
       } else {
+        newItem.pagePath = item.component;
         newItem.component = loadView(item.component)
       }
     }

+ 1 - 1
exam-06173-vue/src/views/admin/course/file/dir.vue

@@ -25,7 +25,7 @@
             <el-table-column prop="fileType_dictText" label="课件类型" align="center" width="200px" />
             <el-table-column label="要求时长*分钟" align="center" width="200px">
               <template v-slot="scope">
-                <el-input-number v-model="scope.row.needLearn" :min="0" :max="99999" size="mini" />
+                <el-input-number v-model="scope.row.needLearn" :min="1" :max="99999" size="mini" />
               </template>
             </el-table-column>
 

+ 201 - 152
exam-06173-vue/src/views/admin/course/file/index.vue

@@ -1,11 +1,12 @@
 <template>
-
   <div>
-
     <div style="display: flex">
       <div style="width: 300px">
         <el-card>
-          <dic-tree v-model="listQuery.params.catId" dic-code="course_file_catalog" />
+          <dic-tree
+            v-model="listQuery.params.catId"
+            dic-code="course_file_catalog"
+          />
         </el-card>
       </div>
       <div style="flex-grow: 1; padding-left: 20px">
@@ -17,24 +18,34 @@
           @edit="handleEdit"
         >
           <template slot="filter-content">
-
-            <dic-list-select v-model="listQuery.params.fileType" dic-code="course_file_type" title="课件类型" />
-            <el-input v-model="listQuery.params.title" placeholder="搜索课件名称" style="width: 200px;" class="filter-item" />
-
+            <dic-list-select
+              v-model="listQuery.params.fileType"
+              dic-code="course_file_type"
+              title="课件类型"
+              class="filter-item"
+            />
+            <el-input
+              v-model="listQuery.params.title"
+              placeholder="搜索课件名称"
+              style="width: 200px"
+              class="filter-item"
+            />
           </template>
 
           <template slot="data-columns">
-
             <el-table-column
               label="课件名称"
               prop="title"
               show-overflow-tooltip
             >
-
               <template slot-scope="scope">
-                <detail-link :id="scope.row.id" :title="scope.row.title" permission="course:file:update" @click="handleEdit" />
+                <detail-link
+                  :id="scope.row.id"
+                  :title="scope.row.title"
+                  permission="course:file:update"
+                  @click="handleEdit"
+                />
               </template>
-
             </el-table-column>
 
             <el-table-column
@@ -63,14 +74,12 @@
               width="120px"
               show-overflow-tooltip
             >
-
               <template v-slot="scope">
-                <span v-if="scope.row.duration===0">无</span>
+                <span v-if="scope.row.duration === 0">无</span>
                 <span v-else>
-                  <sec-format :value="scope.row.duration"/>
+                  <sec-format :value="scope.row.duration" />
                 </span>
               </template>
-
             </el-table-column>
 
             <el-table-column
@@ -87,30 +96,41 @@
               width="180px"
             />
 
-            <el-table-column
-              label="操作"
-              align="center"
-              width="150px"
-            >
-
+            <el-table-column label="操作" align="center" width="150px">
               <template slot-scope="scope">
-                <el-link type="primary" icon="el-icon-view" style="margin-left: 10px" @click="handlePreview(scope.row)">在线预览</el-link>
+                <el-link
+                  type="primary"
+                  icon="el-icon-view"
+                  style="margin-left: 10px"
+                  @click="handlePreview(scope.row)"
+                  >在线预览</el-link
+                >
               </template>
-
             </el-table-column>
-
           </template>
-
         </data-table>
       </div>
     </div>
 
-    <el-dialog :close-on-click-modal="false" :visible.sync="dialogVisible" title="课件管理" width="50%">
-
-      <el-form ref="postForm" :model="postForm" :rules="rules" label-position="left" label-width="120px">
-
+    <el-dialog
+      :close-on-click-modal="false"
+      :visible.sync="dialogVisible"
+      title="课件管理"
+      width="50%"
+    >
+      <el-form
+        ref="postForm"
+        :model="postForm"
+        :rules="rules"
+        label-position="left"
+        label-width="120px"
+      >
         <el-form-item label="课件类型" prop="fileType">
-          <dic-list-select v-model="postForm.fileType" :disabled="isEdit" dic-code="course_file_type" />
+          <dic-list-select
+            v-model="postForm.fileType"
+            :disabled="isEdit"
+            dic-code="course_file_type"
+          />
         </el-form-item>
 
         <el-form-item label="课件名称" prop="title">
@@ -118,101 +138,129 @@
         </el-form-item>
 
         <el-form-item label="课件分类">
-          <dic-catalog-tree v-model="postForm.catId" dic-code="course_file_catalog" />
+          <dic-catalog-tree
+            v-model="postForm.catId"
+            dic-code="course_file_catalog"
+          />
         </el-form-item>
 
         <el-form-item v-if="postForm.fileType" label="上传文件" prop="fileUrl">
-          <file-upload v-model="postForm.fileUrl" :limit="1" :tips="tips" :accept="accept" list-type="file" />
+          <file-upload
+            v-model="postForm.fileUrl"
+            :limit="1"
+            :tips="tips"
+            :accept="accept"
+            list-type="file"
+          />
         </el-form-item>
 
-        <el-form-item v-if="postForm.fileType === '33' && postForm.fileUrl" label="视频时长">
+        <el-form-item
+          v-if="postForm.fileType === '33' && postForm.fileUrl"
+          label="视频时长"
+        >
           <el-input-number v-model="postForm.duration" /> 单位:秒
           <div style="color: #ff4949">
-            <small>MP4视频可以直接读取视频时长,其他格式视频将在提交后异步读取.</small>
+            <small
+              >MP4视频可以直接读取视频时长,其他格式视频将在提交后异步读取.</small
+            >
           </div>
         </el-form-item>
-
       </el-form>
 
       <div slot="footer" class="dialog-footer">
-        <el-alert
-          type="success"
-          style="margin-bottom: 20px"
-        >
+        <el-alert type="success" style="margin-bottom: 20px">
           课件保存后,您可以从列表来预览它!
         </el-alert>
         <el-button @click="dialogVisible = false">取 消</el-button>
-        <el-button :loading="loading" type="primary" @click="handleSave">确 定</el-button>
+        <el-button :loading="loading" type="primary" @click="handleSave"
+          >确 定</el-button
+        >
       </div>
-
     </el-dialog>
 
-    <el-dialog :close-on-click-modal="false" :visible.sync="previewVisible" title="文件预览" width="60%" @close="closePreview">
-
+    <el-dialog
+      :close-on-click-modal="false"
+      :visible.sync="previewVisible"
+      title="文件预览"
+      width="60%"
+      @close="closePreview"
+    >
       <div style="max-height: 650px; overflow-x: hidden; overflow-y: auto">
-        <div v-if="previewData.fileType==='33'">
-          <video-player v-model="previewData.viewUrl" :ref-id="previewData.id" />
+        <div v-if="previewData.fileType === '33'">
+          <video-player
+            v-model="previewData.viewUrl"
+            :ref-id="previewData.id"
+          />
         </div>
-        <pdf-reader v-if="previewData.fileType==='11'" :src="previewData.viewUrl" />
-        <pdf-reader v-if="previewData.fileType==='22'" :src="previewData.fileUrl" />
+        <pdf-reader
+          v-if="previewData.fileType === '11'"
+          :src="previewData.viewUrl"
+        />
+        <pdf-reader
+          v-if="previewData.fileType === '22'"
+          :src="previewData.fileUrl"
+        />
       </div>
     </el-dialog>
 
-    <div v-if="postForm.fileType === '33' && postForm.fileUrl" style="display: none">
-      <video-player v-model="postForm.fileUrl" @loaded="videoLoaded"/>
+    <div
+      v-if="postForm.fileType === '33' && postForm.fileUrl"
+      style="display: none"
+    >
+      <video-player v-model="postForm.fileUrl" @loaded="videoLoaded" />
     </div>
-
   </div>
-
 </template>
 
 <script>
-import DataTable from '@/components/DataTable'
-import DicListSelect from '@/components/DicListSelect'
-import { saveData, fetchDetail } from '@/api/course/file'
-import FileUpload from '@/components/FileUpload'
-import DicCatalogTree from '@/components/DicTreeSelect'
-import { fetchTree } from '@/api/sys/dict/value'
-import DicTree from '@/components/DicTree/index'
-import DetailLink from '@/components/DetailLink'
-import VideoPlayer from '@/components/VideoPlayer'
-import PdfReader from '@/components/PdfReader'
-import SecFormat from '@/components/SecFormat'
+import DataTable from "@/components/DataTable";
+import DicListSelect from "@/components/DicListSelect";
+import { saveData, fetchDetail } from "@/api/course/file";
+import FileUpload from "@/components/FileUpload";
+import DicCatalogTree from "@/components/DicTreeSelect";
+import { fetchTree } from "@/api/sys/dict/value";
+import DicTree from "@/components/DicTree/index";
+import DetailLink from "@/components/DetailLink";
+import VideoPlayer from "@/components/VideoPlayer";
+import PdfReader from "@/components/PdfReader";
+import SecFormat from "@/components/SecFormat";
 
 export default {
-  name: 'CourseFileList',
-  components: { SecFormat, PdfReader, VideoPlayer, DetailLink, DicTree, DicCatalogTree, FileUpload, DicListSelect, DataTable },
+  name: "CourseFileList",
+  components: {
+    SecFormat,
+    PdfReader,
+    VideoPlayer,
+    DetailLink,
+    DicTree,
+    DicCatalogTree,
+    FileUpload,
+    DicListSelect,
+    DataTable,
+  },
   data() {
     return {
-
       dialogVisible: false,
       fileList: [],
       isEdit: false,
 
-      tips: '',
-      accept: '',
+      tips: "",
+      accept: "",
       data: {},
 
       loading: false,
       postForm: {
-        fileType: '',
-        fileUrl: '',
-        needLearn: 0
+        fileType: "",
+        fileUrl: "",
+        needLearn: 0,
       },
 
       rules: {
+        title: [{ required: true, message: "课件名称不能为空!" }],
 
-        title: [
-          { required: true, message: '课件名称不能为空!' }
-        ],
+        fileType: [{ required: true, message: "课件类型不能为空!" }],
 
-        fileType: [
-          { required: true, message: '课件类型不能为空!' }
-        ],
-
-        fileUrl: [
-          { required: true, message: '课件文件必须上传!' }
-        ]
+        fileUrl: [{ required: true, message: "课件文件必须上传!" }],
       },
 
       listQuery: {
@@ -220,31 +268,30 @@ export default {
         size: 10,
         params: {
           courseId: this.courseId,
-          catId: null
-        }
+          catId: null,
+        },
       },
 
       options: {
-
         // 可批量操作
         multi: true,
 
         add: {
           enable: true,
-          permission: 'course:file:add'
+          permission: "course:file:add",
         },
         edit: {
           enable: true,
-          permission: 'course:file:update'
+          permission: "course:file:update",
         },
         delete: {
           enable: true,
-          permission: 'course:file:delete',
-          url: '/api/course/file/delete'
+          permission: "course:file:delete",
+          url: "/api/course/file/delete",
         },
 
         // 列表请求URL
-        listUrl: '/api/course/file/paging'
+        listUrl: "/api/course/file/paging",
       },
 
       previewVisible: false,
@@ -252,110 +299,112 @@ export default {
 
       treeData: [],
       defaultProps: {
-        children: 'children',
-        label: 'title'
-      }
-    }
+        children: "children",
+        label: "title",
+      },
+    };
   },
   watch: {
-    'postForm.fileType': {
+    "postForm.fileType": {
       handler(val) {
-        if (val === '11') {
-          this.tips = '包含doc,docx,xls,xlsx,ppt,pptx等Office类型文件'
-          this.accept = '.doc, .docx, .xls, .xlsx, .ppt, .pptx'
-          this.data = {}
-          this.previewData.fileType = '11'
+        if (val === "11") {
+          this.tips = "包含doc,docx,xls,xlsx,ppt,pptx等Office类型文件";
+          this.accept = ".doc, .docx, .xls, .xlsx, .ppt, .pptx";
+          this.data = {};
+          this.previewData.fileType = "11";
         }
-        if (val === '22') {
-          this.tips = 'PDF文件可以直接在线预览'
-          this.accept = '.pdf'
-          this.data = {}
-          this.previewData.fileType = '22'
+        if (val === "22") {
+          this.tips = "PDF文件可以直接在线预览";
+          this.accept = ".pdf";
+          this.data = {};
+          this.previewData.fileType = "22";
         }
-        if (val === '33') {
-          this.tips = '视频文件,尽可能使用mp4格式兼容性较好,也支持flv,mkv,rm,rmvb等格式'
-          this.accept = '.mp4, .mov, .flv, .mkv, .rm, .rmvb, .webm, .ogv, .avi'
-          this.data = {}
-          this.previewData.fileType = '33'
+        if (val === "33") {
+          this.tips =
+            "视频文件,尽可能使用mp4格式兼容性较好,也支持flv,mkv,rm,rmvb等格式";
+          this.accept = ".mp4, .mov, .flv, .mkv, .rm, .rmvb, .webm, .ogv, .avi";
+          this.data = {};
+          this.previewData.fileType = "33";
         }
-      }
-    }
+      },
+    },
   },
 
   created() {
-    const id = this.$route.params.courseId
+    const id = this.$route.params.courseId;
     if (id !== undefined) {
-      this.listQuery.params.courseId = id
+      this.listQuery.params.courseId = id;
     }
 
-    fetchTree({ dicCode: 'course_file_catalog' }).then(res => {
-      this.treeData = res.data
-    })
+    fetchTree({ dicCode: "course_file_catalog" }).then((res) => {
+      this.treeData = res.data;
+    });
   },
 
   methods: {
-
     handleAdd() {
-      this.postForm = { courseId: this.listQuery.params.courseId }
-      this.dialogVisible = true
-      this.isEdit = false
+      this.postForm = { courseId: this.listQuery.params.courseId };
+      this.dialogVisible = true;
+      this.isEdit = false;
     },
 
     handleEdit(id) {
       // 先清理表单
-      this.postForm = {}
-      this.isEdit = true
-      this.dialogVisible = true
-      fetchDetail(id).then(res => {
-        this.postForm = res.data
-      })
+      this.postForm = {};
+      this.isEdit = true;
+      this.dialogVisible = true;
+      fetchDetail(id).then((res) => {
+        this.postForm = res.data;
+      });
     },
 
     handleSave() {
       this.$refs.postForm.validate((valid) => {
         if (!valid) {
-          return
+          return;
         }
 
-        this.loading = true
+        this.loading = true;
+
+        saveData(this.postForm)
+          .then(() => {
+            this.$message({
+              type: "success",
+              message: "课件保存成功!",
+            });
+            this.dialogVisible = false;
+            this.$refs.pagingTable.getList();
 
-        saveData(this.postForm).then(() => {
-          this.$message({
-            type: 'success',
-            message: '课件保存成功!'
+            this.loading = false;
           })
-          this.dialogVisible = false
-          this.$refs.pagingTable.getList()
-
-          this.loading = false
-        }).catch(err => {
-          console.log(err)
-          this.loading = false
-        })
-      })
+          .catch((err) => {
+            console.log(err);
+            this.loading = false;
+          });
+      });
     },
 
     catalogSelected(node) {
-      console.log('node', node)
-      this.listQuery.params.catId = node.id
+      console.log("node", node);
+      this.listQuery.params.catId = node.id;
     },
 
     handlePreview(data) {
-      this.previewVisible = true
-      this.previewData.fileType = data.fileType
-      this.previewData.viewUrl = data.viewUrl
-      this.previewData.fileUrl = data.fileUrl
+      this.previewVisible = true;
+      this.previewData.fileType = data.fileType;
+      this.previewData.viewUrl = data.viewUrl;
+      this.previewData.fileUrl = data.fileUrl;
     },
 
     closePreview() {
-      this.previewData = {}
+      this.previewData = {};
     },
 
     // 读取视频长度
     videoLoaded(d) {
-      console.log('++++++视频长度' + d)
-      this.postForm['duration'] = parseInt(d)
-    }
-  }
-}
+      console.log("++++++视频长度" + d);
+      this.postForm["duration"] = parseInt(d);
+    },
+  },
+};
 </script>

+ 129 - 93
exam-06173-vue/src/views/admin/course/form.vue

@@ -1,12 +1,15 @@
 <template>
   <div>
-
-    <el-form ref="postForm" :model="postForm" :rules="rules" label-position="left" label-width="120px">
-
+    <el-form
+      ref="postForm"
+      :model="postForm"
+      :rules="rules"
+      label-position="left"
+      label-width="120px"
+    >
       <h3>课程描述</h3>
 
       <el-card>
-
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="课程名称" prop="title">
@@ -15,7 +18,10 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="课程分类">
-              <dic-catalog-tree v-model="postForm.catId" dic-code="course_catalog" />
+              <dic-catalog-tree
+                v-model="postForm.catId"
+                dic-code="course_catalog"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="12">
@@ -37,9 +43,7 @@
           </el-col>
 
           <el-col v-if="postForm.timeLimit" :span="12">
-
             <el-form-item label="学习时间设置">
-
               <el-date-picker
                 v-model="dateValues"
                 style="margin-left: 10px"
@@ -50,23 +54,34 @@
                 start-placeholder="开始时间"
                 end-placeholder="结束时间"
               />
-
             </el-form-item>
           </el-col>
 
           <el-col :span="12">
             <el-form-item label="学完积分">
-              <el-input-number v-model="postForm.points" :min="0" :max="999999" /> <small>学完课程获得积分数量</small>
+              <el-input-number
+                v-model="postForm.points"
+                :min="0"
+                :max="999999"
+              />
+              <small>学完课程获得积分数量</small>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="课程课时">
-              <el-input-number v-model="postForm.periods" :min="0" :max="9999" />
+              <el-input-number
+                v-model="postForm.periods"
+                :min="1"
+                :max="9999"
+              />
             </el-form-item>
           </el-col>
           <el-col :span="24">
             <el-form-item label="课程封面">
-              <file-upload v-model="postForm.cover" tips="请上传大于2:1的宽图" />
+              <file-upload
+                v-model="postForm.cover"
+                tips="请上传大于2:1的宽图"
+              />
             </el-form-item>
           </el-col>
 
@@ -81,36 +96,29 @@
       <h3>权限配置</h3>
       <el-card>
         <el-radio-group v-model="postForm.openType" size="small">
-          <el-radio :label="1">完全公开</el-radio>
+          <!-- <el-radio :label="1">完全公开</el-radio> -->
           <el-radio :label="2">指定部门</el-radio>
           <el-radio :label="3">指定人员</el-radio>
         </el-radio-group>
 
         <div style="padding-top: 20px">
-
-          <div v-if="postForm.openType===1">
-            <el-alert
-              title="开放的,任何人都可以参与学习!"
-              type="warning"
-            />
+          <div v-if="postForm.openType === 1">
+            <el-alert title="开放的,任何人都可以参与学习!" type="warning" />
           </div>
 
-          <div v-if="postForm.openType==2">
+          <div v-if="postForm.openType == 2">
             <depart-refs v-model="postForm.deptCodes" />
           </div>
 
-          <div v-if="postForm.openType==3">
+          <div v-if="postForm.openType == 3">
             <user-refs v-model="postForm.personList" />
           </div>
-
         </div>
-
       </el-card>
 
       <h3>学习防作弊</h3>
 
       <el-card>
-
         <el-form-item label="弹窗防呆校验">
           <el-switch
             v-model="postForm.checkOn"
@@ -119,7 +127,13 @@
           />
           <span v-if="postForm.checkOn">
             &nbsp;每隔&nbsp;
-            <el-input-number v-model="postForm.checkSec" :min="1" :max="99999" label="分钟" size="mini" />
+            <el-input-number
+              v-model="postForm.checkSec"
+              :min="1"
+              :max="99999"
+              label="分钟"
+              size="mini"
+            />
             &nbsp;分钟出验证码,输入正确才可继续学习&nbsp;
           </span>
         </el-form-item>
@@ -143,11 +157,17 @@
         </el-form-item>
 
         <el-form-item label="每日可学时段">
-          <time-range-picker v-model="postForm.dayRule"/>
+          <time-range-picker v-model="postForm.dayRule" />
         </el-form-item>
 
         <el-form-item label="每日学时上限">
-          <el-input-number v-model="postForm.dayLimit" :min="0" :max="1440" size="mini" /> <small>单位:分钟,本门课程每日最大累计学时,超出后无法学习</small>
+          <el-input-number
+            v-model="postForm.dayLimit"
+            :min="0"
+            :max="1440"
+            size="mini"
+          />
+          <small>单位:分钟,本门课程每日最大累计学时,超出后无法学习</small>
         </el-form-item>
 
         <el-form-item label="人脸识别学习">
@@ -156,8 +176,7 @@
             active-color="#13ce66"
             inactive-color="#ff4949"
           />
-          <span>&nbsp;每个课件学习前都需要进行人脸识别&nbsp;
-          </span>
+          <span>&nbsp;每个课件学习前都需要进行人脸识别&nbsp; </span>
         </el-form-item>
 
         <el-form-item label="摄像头抓拍">
@@ -167,8 +186,15 @@
             inactive-color="#ff4949"
           />
 
-          <span v-if="postForm.faceCam">&nbsp;学员开始学习后,每&nbsp;
-            <el-input-number v-model="postForm.faceInterval" :min="1" :max="30" label="分钟" size="mini" />
+          <span v-if="postForm.faceCam"
+            >&nbsp;学员开始学习后,每&nbsp;
+            <el-input-number
+              v-model="postForm.faceInterval"
+              :min="1"
+              :max="30"
+              label="分钟"
+              size="mini"
+            />
             &nbsp;分钟抓拍一张学员照片&nbsp;(仅PC)
           </span>
         </el-form-item>
@@ -179,14 +205,35 @@
             active-color="#13ce66"
             inactive-color="#ff4949"
           />
-          对抓拍图片进行人脸识别,如果连续识别失败超过 <el-input-number v-model="postForm.faceChance" :min="0" :max="99" label="次数" size="mini" /> 次就退出学习(仅PC)
+          对抓拍图片进行人脸识别,如果连续识别失败超过
+          <el-input-number
+            v-model="postForm.faceChance"
+            :min="0"
+            :max="99"
+            label="次数"
+            size="mini"
+          />
+          次就退出学习(仅PC)
         </el-form-item>
-
       </el-card>
 
       <el-row>
         <el-col>
-          <h3>直播日程  <div style="line-height: 32px; font-size: 14px; color: #ff3333; float: right"><a href="https://obsproject.com/zh-cn/download" target="_blank">直播推荐使用OBS进行推流,点此下载</a></div></h3>
+          <h3>
+            直播日程
+            <div
+              style="
+                line-height: 32px;
+                font-size: 14px;
+                color: #ff3333;
+                float: right;
+              "
+            >
+              <a href="https://obsproject.com/zh-cn/download" target="_blank"
+                >直播推荐使用OBS进行推流,点此下载</a
+              >
+            </div>
+          </h3>
 
           <el-card>
             <live-list v-model="postForm.liveList" />
@@ -196,13 +243,11 @@
 
       <el-row>
         <el-col>
-
           <h3>课件列表</h3>
 
           <el-card>
             <dir-list v-model="postForm.dirList" />
           </el-card>
-
         </el-col>
       </el-row>
 
@@ -210,23 +255,20 @@
         <el-button type="primary" @click="submitForm">保存</el-button>
         <el-button type="info" @click="onCancel">返回</el-button>
       </div>
-
     </el-form>
-
   </div>
 </template>
 
 <script>
-
-import { fetchDetail, saveData } from '@/api/course/course'
-import DicCatalogTree from '@/components/DicTreeSelect'
-import Tinymce from '@/components/Tinymce'
-import FileUpload from '@/components/FileUpload'
-import UserRefs from '@/components/UserRefs'
-import DepartRefs from '@/components/DepartRefs'
-import LiveList from '@/views/admin/course/live'
-import DirList from '@/views/admin/course/file/dir'
-import TimeRangePicker from '@/components/TimeRangePicker'
+import { fetchDetail, saveData } from "@/api/course/course";
+import DicCatalogTree from "@/components/DicTreeSelect";
+import Tinymce from "@/components/Tinymce";
+import FileUpload from "@/components/FileUpload";
+import UserRefs from "@/components/UserRefs";
+import DepartRefs from "@/components/DepartRefs";
+import LiveList from "@/views/admin/course/live";
+import DirList from "@/views/admin/course/file/dir";
+import TimeRangePicker from "@/components/TimeRangePicker";
 
 export default {
   components: {
@@ -237,7 +279,7 @@ export default {
     UserRefs,
     FileUpload,
     Tinymce,
-    DicCatalogTree
+    DicCatalogTree,
   },
   data() {
     return {
@@ -246,11 +288,11 @@ export default {
       dateValues: [],
       curIndex: 0,
       postForm: {
-        content: '',
-        catId: '',
+        content: "",
+        catId: "",
         videoDrag: false,
         stepLock: false,
-        lecturerId: '',
+        lecturerId: "",
         periods: 0,
         isMust: false,
         openType: 1,
@@ -258,82 +300,76 @@ export default {
         points: 0,
         dirList: [],
         personList: [],
-        liveList: []
+        liveList: [],
       },
       tableData: [
-        { title: '默认文件夹', fileList: [{ title: '第一个文件夹', fileType: '视频文件' }] }
+        {
+          title: "默认文件夹",
+          fileList: [{ title: "第一个文件夹", fileType: "视频文件" }],
+        },
       ],
       loading: false,
       rules: {
+        title: [{ required: true, message: "课程名称不能为空!" }],
 
-        title: [
-          { required: true, message: '课程名称不能为空!' }
-        ],
-
-        content: [
-          { required: true, message: '课程描述不能为空!' }
-        ]
-      }
-    }
+        content: [{ required: true, message: "课程描述不能为空!" }],
+      },
+    };
   },
 
   watch: {
     dateValues: {
       handler() {
-        this.postForm.startTime = this.dateValues[0]
-        this.postForm.endTime = this.dateValues[1]
-      }
-    }
+        this.postForm.startTime = this.dateValues[0];
+        this.postForm.endTime = this.dateValues[1];
+      },
+    },
   },
 
   created() {
-    const id = this.$route.params.id
+    const id = this.$route.params.id;
     if (id !== undefined) {
-      this.fetchData(id)
+      this.fetchData(id);
     }
   },
   methods: {
-
     fetchData(id) {
-      fetchDetail(id).then(response => {
-        this.postForm = response.data
+      fetchDetail(id).then((response) => {
+        this.postForm = response.data;
         if (this.postForm.startTime && this.postForm.endTime) {
-          this.dateValues[0] = this.postForm.startTime
-          this.dateValues[1] = this.postForm.endTime
+          this.dateValues[0] = this.postForm.startTime;
+          this.dateValues[1] = this.postForm.endTime;
         }
-        this.$refs.editor.setContent(this.postForm.content)
-      })
+        this.$refs.editor.setContent(this.postForm.content);
+      });
     },
     submitForm() {
-      console.log(JSON.stringify(this.postForm))
-
       this.$refs.postForm.validate((valid) => {
         if (!valid) {
-          return
+          return;
         }
 
         saveData(this.postForm).then(() => {
           this.$notify({
-            title: '成功',
-            message: '课程保存成功!',
-            type: 'success',
-            duration: 2000
-          })
-
-          this.$router.push({ name: 'ListCourse' })
-        })
-      })
+            title: "成功",
+            message: "课程保存成功!",
+            type: "success",
+            duration: 2000,
+          });
+
+          this.$router.push({ name: "ListCourse" });
+        });
+      });
     },
 
     onCancel() {
-      this.$router.push({ name: 'ListCourse' })
+      this.$router.push({ name: "ListCourse" });
     },
 
     // 部门开放选择
     treeChange(codes) {
-      this.postForm.deptCodes = codes
-    }
-
-  }
-}
+      this.postForm.deptCodes = codes;
+    },
+  },
+};
 </script>

+ 65 - 86
exam-06173-vue/src/views/admin/course/index.vue

@@ -1,37 +1,39 @@
 <template>
-
-  <data-table
-    ref="pagingTable"
-    :options="options"
-    :list-query="listQuery"
-  >
-
+  <data-table ref="pagingTable" :options="options" :list-query="listQuery">
     <template slot="filter-content">
-
-      <dic-list-select v-model="listQuery.params.isMust" dic-code="course_need" />
-      <dic-catalog-tree v-model="listQuery.params.catId" dic-code="course_catalog" width="200" class="filter-item" style="margin-top: 3px" />
-      <el-input v-model="listQuery.params.title" placeholder="搜索课程" style="width: 200px;" class="filter-item" />
+      <dic-list-select
+        v-model="listQuery.params.isMust"
+        dic-code="course_need"
+        class="filter-item"
+      />
+      <dic-catalog-tree
+        v-model="listQuery.params.catId"
+        dic-code="course_catalog"
+        width="200"
+        class="filter-item"
+        style="margin-top: 3px"
+      />
+      <el-input
+        v-model="listQuery.params.title"
+        placeholder="搜索课程"
+        style="width: 200px"
+        class="filter-item"
+      />
     </template>
 
     <template slot="data-columns">
-
-      <el-table-column
-        label="课程名称"
-        prop="title"
-        show-overflow-tooltip
-      >
-
+      <el-table-column label="课程名称" prop="title" show-overflow-tooltip>
         <template slot-scope="scope">
-          <detail-link :id="scope.row.id" :title="scope.row.title" to="UpdateCourse" permission="course:update" />
+          <detail-link
+            :id="scope.row.id"
+            :title="scope.row.title"
+            to="UpdateCourse"
+            permission="course:update"
+          />
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="分类"
-        prop="catId_dictText"
-        align="center"
-      />
+      <el-table-column label="分类" prop="catId_dictText" align="center" />
 
       <el-table-column
         label="开放类型"
@@ -39,107 +41,84 @@
         align="center"
       />
 
-      <el-table-column
-        label="课时"
-        prop="periods"
-        align="center"
-      />
+      <el-table-column label="课时" prop="periods" align="center" />
 
-      <el-table-column
-        label="创建时间"
-        align="center"
-        prop="createTime"
-      />
+      <el-table-column label="创建时间" align="center" prop="createTime" />
 
-      <el-table-column
-        align="center"
-        label="状态"
-        prop="state_dictText"
-      />
-
-      <el-table-column
-        label="操作"
-        align="center"
-        width="160px"
-      >
+      <el-table-column align="center" label="状态" prop="state_dictText" />
 
+      <el-table-column label="操作" align="center" width="160px">
         <template slot-scope="scope">
-
-          <router-link :to="{ name: 'CourseStat', params: { courseId: scope.row.id }}" style="margin-left: 10px">
+          <router-link
+            :to="{ name: 'CourseStat', params: { courseId: scope.row.id } }"
+            style="margin-left: 10px"
+          >
             <el-link type="primary" icon="el-icon-pie-chart">统计分析</el-link>
           </router-link>
-
         </template>
-
       </el-table-column>
-
     </template>
-
   </data-table>
-
 </template>
 
 <script>
-import DataTable from '@/components/DataTable'
-import DicCatalogTree from '@/components/DicTreeSelect'
-import DicListSelect from '@/components/DicListSelect'
-import DetailLink from '@/components/DetailLink'
+import DataTable from "@/components/DataTable";
+import DicCatalogTree from "@/components/DicTreeSelect";
+import DicListSelect from "@/components/DicListSelect";
+import DetailLink from "@/components/DetailLink";
 
 export default {
-  name: 'QuList',
+  name: "QuList",
   components: { DetailLink, DicListSelect, DicCatalogTree, DataTable },
   data() {
     return {
-
       listQuery: {
         current: 1,
         size: 10,
         params: {
-          title: ''
-        }
+          title: "",
+        },
       },
 
       options: {
-
         // 可批量操作
         multi: true,
 
         add: {
           enable: !this.selectMode,
-          permission: 'course:add',
-          router: { name: 'AddCourse' }
+          permission: "course:add",
+          router: { name: "AddCourse" },
         },
         edit: {
           enable: true,
-          permission: 'course:update',
-          router: { name: 'UpdateCourse', params: { id: '$id' }}
+          permission: "course:update",
+          router: { name: "UpdateCourse", params: { id: "$id" } },
         },
         delete: {
           enable: true,
-          permission: 'course:delete',
-          url: '/api/course/course/delete'
+          permission: "course:delete",
+          url: "/api/course/course/delete",
         },
         // 列表请求URL
-        listUrl: '/api/course/course/paging',
+        listUrl: "/api/course/course/paging",
         // 批量操作列表
         multiActions: [
           {
-            value: 'enable',
-            label: '启用',
-            permission: 'course:update',
-            url: '/api/course/course/state'
-          }, {
-            value: 'disable',
-            label: '禁用',
-            permission: 'course:update',
-            url: '/api/course/course/state'
-          }
-        ]
-      }
-    }
+            value: "enable",
+            label: "启用",
+            permission: "course:update",
+            url: "/api/course/course/state",
+          },
+          {
+            value: "disable",
+            label: "禁用",
+            permission: "course:update",
+            url: "/api/course/course/state",
+          },
+        ],
+      },
+    };
   },
-  methods: {
-
-  }
-}
+  methods: {},
+};
 </script>

+ 289 - 211
exam-06173-vue/src/views/admin/exam/exam/form.vue

@@ -1,36 +1,33 @@
 <template>
   <div>
-
     <el-steps :active="step" simple>
       <el-step title="创建/选择试卷" icon="el-icon-s-claim" />
       <el-step title="考试配置" icon="el-icon-s-ticket" />
       <el-step title="发布考试" icon="el-icon-s-promotion" />
     </el-steps>
 
-    <div v-if="step===1">
-
+    <div v-if="step === 1">
       <h3>选择/创建试卷</h3>
       <el-card>
-
         <el-radio v-model="checkType" :label="1">选择已有试卷创建考试</el-radio>
 
-        <div v-if="checkType===1">
+        <div v-if="checkType === 1">
           <tmpl-list :select-mode="true" @select="handleBack" />
         </div>
-
       </el-card>
 
       <el-card style="margin-top: 20px">
         <el-radio v-model="checkType" :label="2">新建试卷并创建考试</el-radio>
-        <div v-if="checkType===2" style="padding-top: 20px">
+        <div v-if="checkType === 2" style="padding-top: 20px">
           <tmpl-pre-create @confirm="handleCreate" />
         </div>
       </el-card>
-
     </div>
 
-    <div v-if="step===2" style="margin-left: -20px; margin-right: -20px; padding-top: 20px">
-
+    <div
+      v-if="step === 2"
+      style="margin-left: -20px; margin-right: -20px; padding-top: 20px"
+    >
       <join1-form
         :title="createForm.title"
         :cat-id="createForm.catId"
@@ -38,20 +35,21 @@
         :time-type="createForm.timeType"
         @back="handleBack"
       />
-
     </div>
 
-    <div v-if="step===3">
-
-      <el-form ref="postForm" :model="postForm" :rules="rules" label-position="left" label-width="100px">
-
+    <div v-if="step === 3">
+      <el-form
+        ref="postForm"
+        :model="postForm"
+        :rules="rules"
+        label-position="left"
+        label-width="100px"
+      >
         <el-row :gutter="20">
           <el-col :span="18">
-
             <h3>考试设置</h3>
 
             <el-card>
-
               <el-row :gutter="50">
                 <el-col :span="12">
                   <el-form-item label="考试名称" prop="title">
@@ -60,13 +58,19 @@
                 </el-col>
                 <el-col :span="12">
                   <el-form-item label="考试类型" prop="examType">
-                    <dic-list-select v-model="postForm.examType" dic-code="exam_type" />
+                    <dic-list-select
+                      v-model="postForm.examType"
+                      dic-code="exam_type"
+                    />
                   </el-form-item>
                 </el-col>
 
                 <el-col :span="12">
                   <el-form-item label="及格分" prop="qualifyScore">
-                    <el-input-number v-model="postForm.qualifyScore" :max="tmplData.totalScore" />
+                    <el-input-number
+                      v-model="postForm.qualifyScore"
+                      :max="tmplData.totalScore"
+                    />
                   </el-form-item>
                 </el-col>
 
@@ -94,7 +98,9 @@
                 <el-col :span="12">
                   <el-form-item label="最低交卷时长">
                     <el-input-number v-model="postForm.handMin" />
-                    <tool-tip msg="最低答题分钟数,未达到不允许交卷,0为不开启" />
+                    <tool-tip
+                      msg="最低答题分钟数,未达到不允许交卷,0为不开启"
+                    />
                   </el-form-item>
                 </el-col>
 
@@ -111,9 +117,7 @@
                 </el-col>
 
                 <el-col v-if="postForm.timeLimit" :span="12">
-
                   <el-form-item label="考试时间设置">
-
                     <el-date-picker
                       v-model="dateValues"
                       style="margin-left: 10px"
@@ -124,14 +128,48 @@
                       start-placeholder="开始时间"
                       end-placeholder="结束时间"
                     />
-
                   </el-form-item>
                 </el-col>
 
                 <el-col v-if="postForm.timeLimit" :span="12">
                   <el-form-item label="允许迟到时长">
                     <el-input-number v-model="postForm.lateMax" />
-                    <tool-tip msg="允许迟到的分钟数,注意:某段时间都可以考试的长期考试请设置为0" />
+                    <tool-tip
+                      msg="允许迟到的分钟数,注意:某段时间都可以考试的长期考试请设置为0"
+                    />
+                  </el-form-item>
+                </el-col>
+
+                <el-col :span="24">
+                  <el-form-item label="是否关联培训">
+                    <div class="flex">
+                      <el-select
+                        style="width: 75%"
+                        v-model="postForm.courseId"
+                        placeholder="可选择或输入关键字搜索培训课程"
+                        filterable
+                        clearable
+                        @change="getTreeEnableArray"
+                      >
+                        <el-option
+                          v-for="item in courseArray"
+                          :key="item.id"
+                          :label="item.title"
+                          :value="item.id"
+                        >
+                          <span style="float: left">{{ item.title }}</span>
+                          <span
+                            style="
+                              float: right;
+                              color: #8492a6;
+                              font-size: 13px;
+                            "
+                            >{{ item.catId_dictText }}</span
+                          >
+                        </el-option>
+                      </el-select>
+                      <tool-tip msg="关联培训后,未完成学习将无法开始考试" />
+                    </div>
                   </el-form-item>
                 </el-col>
 
@@ -156,7 +194,7 @@
                   </el-form-item>
                 </el-col>
 
-                <el-col v-if="postForm.resultType!==3" :span="24">
+                <el-col v-if="postForm.resultType !== 3" :span="24">
                   <el-form-item label="考后感谢文字">
                     <el-input
                       v-model="postForm.thanks"
@@ -168,56 +206,57 @@
                 </el-col>
 
                 <el-col :span="24">
-
-                  <div style="background: #fbfbfb; padding: 10px; line-height: 36px; font-size: 14px">
-
-                    <div style="font-weight: 700">
-                      考试权限
-                    </div>
+                  <div
+                    style="
+                      background: #fbfbfb;
+                      padding: 10px;
+                      line-height: 36px;
+                      font-size: 14px;
+                    "
+                  >
+                    <div style="font-weight: 700">考试权限</div>
 
                     <el-radio-group v-model="postForm.openType" size="small">
-                      <el-radio :label="1">完全公开</el-radio>
+                      <!-- <el-radio :label="1">完全公开</el-radio> -->
                       <el-radio :label="2">部门开放</el-radio>
                       <el-radio :label="3">指定人员</el-radio>
                       <el-radio :label="9">口令密码</el-radio>
                     </el-radio-group>
 
                     <div style="padding-top: 20px">
-
-                      <div v-if="postForm.openType==1">
+                      <div v-if="postForm.openType == 1">
                         <el-alert
                           title="开放的,任何人都可以进行考试!"
                           type="warning"
                         />
                       </div>
 
-                      <div v-if="postForm.openType==2">
-                        <depart-refs v-model="postForm.deptCodes" />
+                      <div v-if="postForm.openType == 2">
+                        <depart-refs
+                          v-model="postForm.deptCodes"
+                          :enableArray="treeEnableArray"
+                        />
                       </div>
 
-                      <div v-if="postForm.openType==3">
+                      <div v-if="postForm.openType == 3">
                         <user-refs v-model="postForm.personList" />
                       </div>
 
-                      <div v-if="postForm.openType==9">
-                        <el-input v-model="postForm.password" placeholder="输入考试密码" />
+                      <div v-if="postForm.openType == 9">
+                        <el-input
+                          v-model="postForm.password"
+                          placeholder="输入考试密码"
+                        />
                       </div>
-
                     </div>
-
                   </div>
-
                 </el-col>
-
               </el-row>
-
             </el-card>
 
             <h3>防作弊选项</h3>
             <el-card>
-
               <el-row>
-
                 <el-col>
                   <el-form-item label="学员答题设备设置" label-width="200px">
                     <el-radio-group v-model="postForm.answerDevice">
@@ -229,7 +268,6 @@
                 </el-col>
 
                 <el-col>
-
                   <el-form-item label="人脸认证进入考试" label-width="200px">
                     <el-switch
                       v-model="postForm.faceOn"
@@ -239,42 +277,57 @@
 
                     &nbsp;开启后,需要人脸认证通过才可以进入考试
                   </el-form-item>
-
                 </el-col>
 
                 <el-col>
-
-                  <el-form-item label="答题时摄像头拍照监考" label-width="200px">
+                  <el-form-item
+                    label="答题时摄像头拍照监考"
+                    label-width="200px"
+                  >
                     <el-switch
                       v-model="postForm.camOn"
                       active-color="#13ce66"
                       inactive-color="#ff4949"
                     />
 
-                    <span v-if="postForm.camOn">&nbsp;学员开始答题后,每&nbsp;
-                      <el-input-number v-model="postForm.camInterval" :min="1" :max="30" label="秒数" size="mini" />
+                    <span v-if="postForm.camOn"
+                      >&nbsp;学员开始答题后,每&nbsp;
+                      <el-input-number
+                        v-model="postForm.camInterval"
+                        :min="1"
+                        :max="30"
+                        label="秒数"
+                        size="mini"
+                      />
                       &nbsp;分钟抓拍一张学员答题照片&nbsp;
                     </span>
                   </el-form-item>
-
                 </el-col>
 
                 <el-col v-if="postForm.camOn">
-
-                  <el-form-item label="考试过程定时人脸识别" label-width="200px">
+                  <el-form-item
+                    label="考试过程定时人脸识别"
+                    label-width="200px"
+                  >
                     <el-switch
                       v-model="postForm.faceCheck"
                       active-color="#13ce66"
                       inactive-color="#ff4949"
                     />
-                    对抓拍图片进行人脸识别,如果连续识别失败超过 <el-input-number v-model="postForm.faceChance" :min="0" :max="postForm.totalTime/postForm.camInterval" label="次数" size="mini" /> 次就强制交卷
+                    对抓拍图片进行人脸识别,如果连续识别失败超过
+                    <el-input-number
+                      v-model="postForm.faceChance"
+                      :min="0"
+                      :max="postForm.totalTime / postForm.camInterval"
+                      label="次数"
+                      size="mini"
+                    />
+                    次就强制交卷
                   </el-form-item>
-
                 </el-col>
 
                 <el-col>
                   <el-form-item label="切屏后强制交卷" label-width="200px">
-
                     <el-switch
                       v-model="postForm.leaveOn"
                       active-color="#13ce66"
@@ -282,14 +335,25 @@
                     />
                     <span v-if="postForm.leaveOn">
                       &nbsp;学员切换页面超过&nbsp;
-                      <el-input-number v-model="postForm.leaveCount" :min="1" :max="999" label="秒数" size="mini" />&nbsp;次后将被强制交卷,切换到其他页面&nbsp;
-                      <el-input-number v-model="postForm.leaveCheck" :min="5" :max="999" label="秒数" size="mini" />&nbsp;秒后即判定为切屏
+                      <el-input-number
+                        v-model="postForm.leaveCount"
+                        :min="1"
+                        :max="999"
+                        label="秒数"
+                        size="mini"
+                      />&nbsp;次后将被强制交卷,切换到其他页面&nbsp;
+                      <el-input-number
+                        v-model="postForm.leaveCheck"
+                        :min="5"
+                        :max="999"
+                        label="秒数"
+                        size="mini"
+                      />&nbsp;秒后即判定为切屏
                     </span>
                   </el-form-item>
                 </el-col>
 
                 <el-col>
-
                   <el-form-item label="无操作强制交卷" label-width="200px">
                     <el-switch
                       v-model="postForm.actionOn"
@@ -299,96 +363,102 @@
 
                     <span v-if="postForm.actionOn">
                       &nbsp;答题时超过&nbsp;
-                      <el-input-number v-model="postForm.actionInterval" :min="1" :max="999" label="秒数" size="mini" />
+                      <el-input-number
+                        v-model="postForm.actionInterval"
+                        :min="1"
+                        :max="999"
+                        label="秒数"
+                        size="mini"
+                      />
                       &nbsp;秒没有新操作会强制交卷&nbsp;
                     </span>
-
                   </el-form-item>
                 </el-col>
-
               </el-row>
-
             </el-card>
-
           </el-col>
 
           <el-col :span="6">
             <h3>试卷信息</h3>
             <el-card style="font-size: 14px; line-height: 28px">
-
-              <div>
-                试卷标题:<el-link :href="`/#/admin/tmpl/preview/${tmplData.id}`" type="primary" target="_blank">{{ tmplData.title }}</el-link>
-              </div>
-              <div>
-                试卷总分:{{ tmplData.totalScore }}
-              </div>
               <div>
-                试题数量: {{ tmplData.quCount }}
+                试卷标题:<el-link
+                  :href="`/#/admin/tmpl/preview/${tmplData.id}`"
+                  type="primary"
+                  target="_blank"
+                  >{{ tmplData.title }}</el-link
+                >
               </div>
-              <div>
-                出卷人员:{{ tmplData.createBy_dictText }}
-              </div>
-              <div>
-                创建时间:{{ tmplData.createTime }}
-              </div>
-
+              <div>试卷总分:{{ tmplData.totalScore }}</div>
+              <div>试题数量: {{ tmplData.quCount }}</div>
+              <div>出卷人员:{{ tmplData.createBy_dictText }}</div>
+              <div>创建时间:{{ tmplData.createTime }}</div>
             </el-card>
           </el-col>
         </el-row>
 
-        <el-button type="primary" style="margin-top: 20px" @click="nextStep">保存</el-button>
-
+        <el-button type="primary" style="margin-top: 20px" @click="nextStep"
+          >保存</el-button
+        >
       </el-form>
-
     </div>
-
   </div>
 </template>
 
 <script>
-import { fetchDetail, saveData } from '@/api/exam/exam'
-import DicListSelect from '@/components/DicListSelect'
-import ToolTip from '@/components/ToolTip'
-import TmplPreCreate from '@/views/admin/tmpl/components/components/TmplPreCreate'
-import Join1Form from '@/views/admin/tmpl/components/Join1Form'
-import TmplList from '@/views/admin/tmpl'
-import { apiFindSimple } from '@/api/tmpl/tmpl'
-import UserRefs from '@/components/UserRefs'
-import DepartRefs from '@/components/DepartRefs'
-
+import { fetchDetail, saveData } from "@/api/exam/exam";
+import { getTableData, getTreeEnable } from "@/api/exam/form";
+import DicListSelect from "@/components/DicListSelect";
+import ToolTip from "@/components/ToolTip";
+import TmplPreCreate from "@/views/admin/tmpl/components/components/TmplPreCreate";
+import Join1Form from "@/views/admin/tmpl/components/Join1Form";
+import TmplList from "@/views/admin/tmpl";
+import { apiFindSimple } from "@/api/tmpl/tmpl";
+import UserRefs from "@/components/UserRefs";
+import DepartRefs from "@/components/DepartRefs";
+
+let timeStart = new Date()
+let timeEnd = new Date()
+timeEnd.setDate(timeEnd.getDate()+3)
 export default {
-  name: 'ExamDetail',
-  components: { DepartRefs, UserRefs, TmplList, Join1Form, TmplPreCreate, ToolTip, DicListSelect },
+  name: "ExamDetail",
+  components: {
+    DepartRefs,
+    UserRefs,
+    TmplList,
+    Join1Form,
+    TmplPreCreate,
+    ToolTip,
+    DicListSelect,
+  },
   data() {
     return {
-
       step: 1,
       checkType: 1,
 
-      tmplData: {
-
-      },
+      tmplData: {},
 
       createForm: {
         data: {
-          totalScore: 0
+          totalScore: 0,
         },
         title: null,
         joinType: 0,
         catId: null,
-        timeType: 0
+        timeType: 0,
       },
 
-      dateValues: [],
+      dateValues: [timeStart.formatDate("yyyy-MM-dd hh:mm:ss"), timeEnd.formatDate("yyyy-MM-dd hh:mm:ss")],
 
       postForm: {
-        title: '',
+        title: "",
         // 试卷ID
         tmplId: null,
         // 考试部门列表
         departIds: [],
         // 限制考试次数
         chance: 1,
+        timeLimit: true, // 限制考试时间
         totalTime: 30,
         // 分钟数
         camInterval: 5,
@@ -397,6 +467,8 @@ export default {
         // 离开5次每次10秒
         leaveCount: 5,
         leaveCheck: 10,
+        startTime: timeStart.formatDate("yyyy-MM-dd hh:mm:ss"),
+        endTime: timeEnd.formatDate("yyyy-MM-dd hh:mm:ss"),
         capture: 0,
         // 开放权限
         openType: 1,
@@ -405,161 +477,167 @@ export default {
         // 是否截屏
         isCapture: true,
         resultType: 2,
-        thanks: '感谢您的作答!',
+        thanks: "感谢您的作答!",
         personList: [],
         faceOn: false,
         faceCheck: false,
         faceInterval: 0,
-        faceChance: 0
-
+        faceChance: 0,
+        courseId: "",
       },
       rules: {
-        title: [
-          { required: true, message: '考试名称不能为空!' }
-        ],
-
-        open: [
-          { required: true, message: '考试权限不能为空!' }
-        ],
-
-        qualifyScore: [
-          { required: true, message: '及格分不能为空!' }
-        ],
-
-        totalTime: [
-          { required: true, message: '考试时间不能为空!' }
-        ],
-
-        password: [
-          { required: true, message: '考试口令不能为空!' }
-        ],
-        chance: [
-          { required: true, message: '考试次数不能为空,0为不限制!' }
-        ],
-        examType: [
-          { required: true, message: '考试类型必须选择' }
-        ]
-      }
-    }
+        title: [{ required: true, message: "考试名称不能为空!" }],
+
+        open: [{ required: true, message: "考试权限不能为空!" }],
+
+        qualifyScore: [{ required: true, message: "及格分不能为空!" }],
+
+        totalTime: [{ required: true, message: "考试时间不能为空!" }],
+
+        password: [{ required: true, message: "考试口令不能为空!" }],
+        chance: [{ required: true, message: "考试次数不能为空,0为不限制!" }],
+        examType: [{ required: true, message: "考试类型必须选择" }],
+      },
+      courseArray: [],
+      treeEnableArray: [],
+    };
   },
 
   watch: {
     dateValues: {
       handler() {
-        this.postForm.startTime = this.dateValues[0]
-        this.postForm.endTime = this.dateValues[1]
-      }
-    }
+        this.postForm.startTime = this.dateValues[0];
+        this.postForm.endTime = this.dateValues[1];
+      },
+    },
   },
   created() {
     // 选定创建试卷
-    const tmplId = this.$route.params.tmplId
-    if (tmplId !== undefined && tmplId !== '0') {
-      this.handleBack(tmplId)
-      return
+    const tmplId = this.$route.params.tmplId;
+    if (tmplId !== undefined && tmplId !== "0") {
+      this.handleBack(tmplId);
+      return;
     }
 
-    const id = this.$route.params.id
+    const id = this.$route.params.id;
     if (id !== undefined) {
-      this.fetchData(id)
+      this.fetchData(id);
     } else {
-      this.postForm.openType = 1
-      this.postForm.joinType = 1
+      this.postForm.openType = 1;
+      this.postForm.joinType = 1;
     }
+
+    getTableData().then(({ data }) => {
+      this.courseArray = data.records;
+    });
   },
   methods: {
-
+    getTreeEnableArray(courseId) {
+      getTreeEnable({ courseId }).then((res) => {
+        let treeEnableArray = [];
+        res.data.forEach((ele) => {
+          treeEnableArray.push(ele.deptCode);
+        });
+        this.treeEnableArray = treeEnableArray;
+      });
+    },
     nextStep() {
       this.$refs.postForm.validate((valid) => {
         if (!valid) {
-          return
+          return;
         }
-        this.$confirm('确实要提交保存吗?', '提示', {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning'
+        this.$confirm("确实要提交保存吗?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
         }).then(() => {
-          this.submitForm()
-        })
-      })
+          this.submitForm();
+        });
+      });
     },
 
     fetchData(id) {
-      fetchDetail(id).then(response => {
-        this.postForm = response.data
-        this.dateValues[0] = this.postForm.startTime
-        this.dateValues[1] = this.postForm.endTime
-        this.handleBack(this.postForm.tmplId)
-      })
+      fetchDetail(id).then((response) => {
+        this.postForm = response.data;
+        this.dateValues[0] = this.postForm.startTime;
+        this.dateValues[1] = this.postForm.endTime;
+        this.handleBack(this.postForm.tmplId);
+        if(response.data.courseId){
+          this.getTreeEnableArray(response.data.courseId);
+        }
+      });
     },
 
     submitForm() {
       saveData(this.postForm).then(() => {
         this.$notify({
-          title: '成功',
-          message: '考试保存成功!',
-          type: 'success',
-          duration: 2000
-        })
-
-        this.$router.push({ name: 'ListExam' })
-      })
+          title: "成功",
+          message: "考试保存成功!",
+          type: "success",
+          duration: 2000,
+        });
+
+        this.$router.push({ name: "ListExam" });
+      });
     },
 
     handleCreate(data) {
-      this.createForm = data
-      this.step = 2
+      this.createForm = data;
+      this.step = 2;
     },
 
     handleBack(id) {
-      this.step = 3
-      this.postForm.tmplId = id
-      apiFindSimple(id).then(res => {
-        this.tmplData = res.data
+      this.step = 3;
+      this.postForm.tmplId = id;
+      apiFindSimple(id).then((res) => {
+        this.tmplData = res.data;
         if (!this.postForm.title) {
-          this.postForm.title = res.data.title + ' - 考试'
+          this.postForm.title = res.data.title + " - 考试";
         }
 
         if (!this.postForm.qualifyScore) {
-          this.postForm.qualifyScore = res.data.totalScore * 0.6
+          this.postForm.qualifyScore = res.data.totalScore * 0.6;
         }
-      })
-    }
-
-  }
-}
+      });
+    },
+  },
+};
 </script>
 
 <style scoped>
+.score {
+  float: right;
+  font-weight: bold;
+  color: #ff0000;
+}
 
-  .score{
-    float: right; font-weight: bold; color: #ff0000
-  }
-
-  small{
-    color: #666;
-    line-height: 30px;
-    margin-left: 10px;
-  }
-
-  ::v-deep
-  .left-box{
-    height: calc(100vh - 170px);
-    position: fixed;
-    overflow: auto;
-    clear: both;
-  }
-
-  ::v-deep
-  .left-box-normal{
-    top: 170px;
-  }
-
-  ::v-deep
-  .left-box-scrolled{
-    top: 20px;
-    height: calc(100vh - 20px);
-  }
+small {
+  color: #666;
+  line-height: 30px;
+  margin-left: 10px;
+}
+
+.flex {
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+}
 
+::v-deep .left-box {
+  height: calc(100vh - 170px);
+  position: fixed;
+  overflow: auto;
+  clear: both;
+}
+
+::v-deep .left-box-normal {
+  top: 170px;
+}
+
+::v-deep .left-box-scrolled {
+  top: 20px;
+  height: calc(100vh - 20px);
+}
 </style>
 

+ 72 - 94
exam-06173-vue/src/views/admin/exam/exam/index.vue

@@ -1,15 +1,19 @@
 <template>
-
-  <data-table
-    ref="pagingTable"
-    :options="options"
-    :list-query="listQuery"
-  >
+  <data-table ref="pagingTable" :options="options" :list-query="listQuery">
     <template slot="filter-content">
+      <dic-list-select
+        v-model="listQuery.params.examType"
+        dic-code="exam_type"
+        title="选择考试类型"
+        class="filter-item"
+      />
 
-      <dic-list-select v-model="listQuery.params.examType" dic-code="exam_type" title="选择考试类型" />
-
-      <el-select v-model="listQuery.params.openType" class="filter-item" placeholder="开放类型" clearable>
+      <el-select
+        v-model="listQuery.params.openType"
+        class="filter-item"
+        placeholder="开放类型"
+        clearable
+      >
         <el-option
           v-for="item in openTypes"
           :key="item.value"
@@ -34,58 +38,45 @@
         placeholder="考试结束时间"
       />
 
-      <el-input v-model="listQuery.params.title" placeholder="搜索考试名称" style="width: 200px;" class="filter-item" />
-
+      <el-input
+        v-model="listQuery.params.title"
+        placeholder="搜索考试名称"
+        style="width: 200px"
+        class="filter-item"
+      />
     </template>
 
     <template slot="data-columns">
-
-      <el-table-column
-        label="考试名称"
-        prop="title"
-        show-overflow-tooltip
-      >
-
+      <el-table-column label="考试名称" prop="title" show-overflow-tooltip>
         <template slot-scope="scope">
-          <detail-link :id="scope.row.id" :title="scope.row.title" to="UpdateExam" permission="exam:update" />
+          <detail-link
+            :id="scope.row.id"
+            :title="scope.row.title"
+            to="UpdateExam"
+            permission="exam:update"
+          />
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="考试类型"
-        align="center"
-        width="120px"
-      >
+      <el-table-column label="考试类型" align="center" width="120px">
         <template slot-scope="scope">
           {{ scope.row.examType_dictText }}
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="开放权限"
-        align="center"
-        width="120px"
-      >
+      <el-table-column label="开放权限" align="center" width="120px">
         <template slot-scope="scope">
           {{ scope.row.openType | examOpenType }}
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="考试时间"
-        align="center"
-      >
-
+      <el-table-column label="考试时间" align="center">
         <template slot-scope="scope">
           <span v-if="scope.row.timeLimit">
             {{ scope.row.startTime }} ~ {{ scope.row.endTime }}
           </span>
           <span v-else>不限时</span>
         </template>
-
       </el-table-column>
 
       <el-table-column
@@ -102,121 +93,108 @@
         width="100px"
       />
 
-
-
-      <el-table-column
-        label="状态"
-        align="center"
-        width="120px"
-      >
-
+      <el-table-column label="状态" align="center" width="120px">
         <template slot-scope="scope">
           {{ scope.row.state | stateFilter }}
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="操作"
-        align="center"
-        width="200px"
-      >
+      <el-table-column label="操作" align="center" width="200px">
         <template slot-scope="scope">
-          <router-link :to="{ name: 'ExamStat', params: { examId: scope.row.id }}" style="margin-left: 10px">
+          <router-link
+            :to="{ name: 'ExamStat', params: { examId: scope.row.id } }"
+            style="margin-left: 10px"
+          >
             <el-link type="primary" icon="el-icon-pie-chart">统计分析</el-link>
           </router-link>
 
-          <router-link :to="{ name: 'ExamWatch', params: { examId: scope.row.id }}" style="margin-left: 10px">
+          <router-link
+            :to="{ name: 'ExamWatch', params: { examId: scope.row.id } }"
+            style="margin-left: 10px"
+          >
             <el-link type="primary" icon="el-icon-view">监考</el-link>
           </router-link>
-
         </template>
       </el-table-column>
-
     </template>
-
   </data-table>
-
 </template>
 
 <script>
-import DataTable from '@/components/DataTable'
-import DicListSelect from '@/components/DicListSelect'
-import permission from '@/directive/permission/index.js'
-import DetailLink from '@/components/DetailLink' // 权限判断指令
+import DataTable from "@/components/DataTable";
+import DicListSelect from "@/components/DicListSelect";
+import permission from "@/directive/permission/index.js";
+import DetailLink from "@/components/DetailLink"; // 权限判断指令
 
 export default {
-  name: 'ExamList',
+  name: "ExamList",
   components: { DetailLink, DicListSelect, DataTable },
   directives: { permission },
   data() {
     return {
-
       openTypes: [
-        {
-          value: 1,
-          label: '完全开放'
-        },
+        // {
+        //   value: 1,
+        //   label: "完全开放",
+        // },
         {
           value: 2,
-          label: '指定部门'
+          label: "指定部门",
         },
         {
           value: 3,
-          label: '指定人员'
+          label: "指定人员",
         },
         {
           value: 9,
-          label: '口令密码'
-        }
+          label: "口令密码",
+        },
       ],
 
       listQuery: {
         current: 1,
         size: 10,
         params: {
-          title: ''
-        }
+          title: "",
+        },
       },
 
       options: {
         add: {
           enable: true,
-          permission: 'exam:add',
-          router: { name: 'AddExam', params: { tmplId: '0' }}
+          permission: "exam:add",
+          router: { name: "AddExam", params: { tmplId: "0" } },
         },
         edit: {
           enable: true,
-          permission: 'exam:update',
-          router: { name: 'UpdateExam', params: { id: '$id' }}
+          permission: "exam:update",
+          router: { name: "UpdateExam", params: { id: "$id" } },
         },
         delete: {
           enable: true,
-          permission: 'exam:delete',
-          url: '/api/exam/exam/delete'
+          permission: "exam:delete",
+          url: "/api/exam/exam/delete",
         },
         // 可批量操作
         multi: true,
         // 批量操作列表
         multiActions: [
           {
-            value: 'enable',
-            label: '启用',
-            url: '/api/exam/exam/state'
+            value: "enable",
+            label: "启用",
+            url: "/api/exam/exam/state",
           },
           {
-            value: 'disable',
-            label: '禁用',
-            url: '/api/exam/exam/state'
-          }
+            value: "disable",
+            label: "禁用",
+            url: "/api/exam/exam/state",
+          },
         ],
         // 列表请求URL
-        listUrl: '/api/exam/exam/paging'
-      }
-    }
+        listUrl: "/api/exam/exam/paging",
+      },
+    };
   },
-  methods: {
-
-  }
-}
+  methods: {},
+};
 </script>

+ 40 - 65
exam-06173-vue/src/views/admin/exam/review/index.vue

@@ -1,119 +1,94 @@
 <template>
-
-  <data-table
-    ref="pagingTable"
-    :options="options"
-    :list-query="listQuery"
-  >
+  <data-table ref="pagingTable" :options="options" :list-query="listQuery">
     <template slot="filter-content">
+      <dic-list-select
+        v-model="listQuery.params.examType"
+        dic-code="exam_type"
+        title="选择考试类型"
+        class="filter-item"
+      />
 
-      <dic-list-select v-model="listQuery.params.examType" dic-code="exam_type" title="选择考试类型" />
-
-      <el-input v-model="listQuery.params.title" placeholder="搜索考试名称" style="width: 200px;" class="filter-item" />
-
+      <el-input
+        v-model="listQuery.params.title"
+        placeholder="搜索考试名称"
+        style="width: 200px"
+        class="filter-item"
+      />
     </template>
 
     <template slot="data-columns">
-
-      <el-table-column
-        label="考试名称"
-        show-overflow-tooltip
-      >
-
+      <el-table-column label="考试名称" show-overflow-tooltip>
         <template slot-scope="scope">
-          <detail-link :id="scope.row.id" :title="scope.row.title" @click="toReview" />
+          <detail-link
+            :id="scope.row.id"
+            :title="scope.row.title"
+            @click="toReview"
+          />
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="考试类型"
-        align="center"
-      >
+      <el-table-column label="考试类型" align="center">
         <template slot-scope="scope">
           {{ scope.row.openType | examOpenType }}
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="考试时间"
-        width="220px"
-        align="center"
-      >
-
+      <el-table-column label="考试时间" width="220px" align="center">
         <template slot-scope="scope">
           <span v-if="scope.row.timeLimit">
             {{ scope.row.startTime }} ~ {{ scope.row.endTime }}
           </span>
           <span v-else>不限时</span>
         </template>
-
       </el-table-column>
 
-      <el-table-column
-        label="考试人数"
-        prop="examUser"
-        align="center"
-      />
+      <el-table-column label="考试人数" prop="examUser" align="center" />
 
-      <el-table-column
-        label="待阅试卷"
-        prop="unreadPaper"
-        align="center"
-      />
+      <el-table-column label="待阅试卷" prop="unreadPaper" align="center" />
 
-      <el-table-column
-        label="操作"
-        align="center"
-      >
+      <el-table-column label="操作" align="center">
         <template slot-scope="scope">
-
-          <router-link :to="{ name: 'ReviewPaper', params: { examId: scope.row.id }}">
+          <router-link
+            :to="{ name: 'ReviewPaper', params: { examId: scope.row.id } }"
+          >
             <el-link type="primary" icon="el-icon-search">批阅试卷</el-link>
           </router-link>
-
         </template>
-
       </el-table-column>
-
     </template>
-
   </data-table>
-
 </template>
 
 <script>
-import DataTable from '@/components/DataTable'
-import DicListSelect from '@/components/DicListSelect'
-import DetailLink from '@/components/DetailLink'
+import DataTable from "@/components/DataTable";
+import DicListSelect from "@/components/DicListSelect";
+import DetailLink from "@/components/DetailLink";
 
 export default {
-  name: 'ReviewList',
+  name: "ReviewList",
   components: { DetailLink, DicListSelect, DataTable },
   data() {
     return {
-
       listQuery: {
         current: 1,
         size: 10,
         params: {
-          name: ''
-        }
+          name: "",
+        },
       },
 
       options: {
         // 可批量操作
         multi: false,
         // 列表请求URL
-        listUrl: '/api/exam/exam/review-paging'
-      }
-    }
+        listUrl: "/api/exam/exam/review-paging",
+      },
+    };
   },
   methods: {
     toReview(id) {
-      this.$router.push({ name: 'ReviewPaper', params: { examId: id }})
-    }
-  }
-}
+      this.$router.push({ name: "ReviewPaper", params: { examId: id } });
+    },
+  },
+};
 </script>

+ 323 - 226
exam-06173-vue/src/views/admin/paper/paper/detail.vue

@@ -1,108 +1,202 @@
 <template>
   <div v-loading="loading">
-
     <div class="all-box">
-
       <div class="all-box-left">
-
-        <el-card v-if="!loading" :class="{'left-box':true, 'left-box-normal': !scrolled, 'left-box-scrolled': scrolled}" style="width: 250px">
-
-          <div v-for="item in postForm.groupList" :key="item.id" class="group-card">
-            <div v-if="(onlySubj && (item.quType==='4' || item.quType==='99')) || !onlySubj">
+        <el-card
+          v-if="!loading"
+          :class="{
+            'left-box': true,
+            'left-box-normal': !scrolled,
+            'left-box-scrolled': scrolled,
+          }"
+          style="width: 250px"
+        >
+          <div
+            v-for="item in postForm.groupList"
+            :key="item.id"
+            class="group-card"
+          >
+            <div
+              v-if="
+                (onlySubj && (item.quType === '4' || item.quType === '99')) ||
+                !onlySubj
+              "
+            >
               <div style="line-height: 40px">
-                <el-button style="font-size: 14px; font-weight: 700" type="text" @click="goAnchor(item.id)">{{ item.title }}</el-button>
+                <el-button
+                  style="font-size: 14px; font-weight: 700"
+                  type="text"
+                  @click="goAnchor(item.id)"
+                  >{{ item.title }}</el-button
+                >
                 <el-divider />
               </div>
               <div class="group-card-body">
                 <div>
-                  共 <i class="num">{{ item.quCount }}</i> 题,共 <i class="num">{{ item.totalScore }}</i> 分
+                  共 <i class="num">{{ item.quCount }}</i> 题,共
+                  <i class="num">{{ item.totalScore }}</i> 分
                 </div>
               </div>
 
               <div class="card-box">
-                <div v-for="card in item.quList" :key="card.id" class="item" @click="goAnchor(card.id)">
-                  <div :class="{num:true, right: card.isRight, error: !card.isRight, 'current': postForm.state==1 && card.quType=='4'}">{{ card.sort }}</div>
+                <div
+                  v-for="card in item.quList"
+                  :key="card.id"
+                  class="item"
+                  @click="goAnchor(card.id)"
+                >
+                  <div
+                    :class="{
+                      num: true,
+                      right: card.isRight,
+                      error: !card.isRight,
+                      current: postForm.state == 1 && card.quType == '4',
+                    }"
+                  >
+                    {{ card.sort }}
+                  </div>
                 </div>
               </div>
-
             </div>
-
           </div>
-
         </el-card>
-
       </div>
 
       <div class="all-box-center">
-
         <template v-for="item in postForm.groupList">
-
-          <el-card v-if="(onlySubj && (item.quType==='4' || item.quType==='99')) || !onlySubj" :id="item.id" :key="item.id" class="content-card">
-
-            <template v-for="(qu,index) in item.quList">
+          <el-card
+            v-if="
+              (onlySubj && (item.quType === '4' || item.quType === '99')) ||
+              !onlySubj
+            "
+            :id="item.id"
+            :key="item.id"
+            class="content-card"
+          >
+            <template v-for="(qu, index) in item.quList">
               <div v-if="!onlyError || (onlyError && !qu.isRight)" :key="qu.id">
                 <div :id="qu.id" class="list-box">
                   <div class="list-qu">
-                    <qu-item-show :value="qu" :index="index" :state="postForm.state" />
+                    <qu-item-show
+                      :value="qu"
+                      :index="index"
+                      :state="postForm.state"
+                    />
 
                     <div v-if="qu.quType === '99'">
-
                       <!-- 子题目的判卷 -->
-                      <div v-for="(sub,jj) in qu.subList" :key="sub.id" class="list-sub-box">
+                      <div
+                        v-for="(sub, jj) in qu.subList"
+                        :key="sub.id"
+                        class="list-sub-box"
+                      >
                         <div class="list-sub-qu">
-                          <qu-item-show :value="sub" :index="jj" :state="postForm.state" :show-type="true" :sub="true" />
+                          <qu-item-show
+                            :value="sub"
+                            :index="jj"
+                            :state="postForm.state"
+                            :show-type="true"
+                            :sub="true"
+                          />
                         </div>
 
                         <div class="list-sub-opt">
                           <div class="check-box">
-                            <div class="item">判题:
-                              <i :class="{'el-icon-success check-icon': true, 'check-icon-right':sub.isRight}" @click="checkAnswer(sub, true)" />
-                              <i :class="{'el-icon-error check-icon': true, 'check-icon-error':!sub.isRight}" @click="checkAnswer(sub, false)" />
+                            <div class="item">
+                              判题:
+                              <i
+                                :class="{
+                                  'el-icon-success check-icon': true,
+                                  'check-icon-right': sub.isRight,
+                                }"
+                                @click="checkAnswer(sub, true)"
+                              />
+                              <i
+                                :class="{
+                                  'el-icon-error check-icon': true,
+                                  'check-icon-error': !sub.isRight,
+                                }"
+                                @click="checkAnswer(sub, false)"
+                              />
+                            </div>
+                            <div class="item">
+                              得分:<el-input-number
+                                v-model="sub.actualScore"
+                                :precision="1"
+                                :max="sub.score"
+                                size="mini"
+                                style="width: 100px"
+                              />
                             </div>
-                            <div class="item">得分:<el-input-number v-model="sub.actualScore" :precision="1" :max="sub.score" size="mini" style="width: 100px" /></div>
                             <div class="item">总分:{{ sub.score }}</div>
                           </div>
                         </div>
-
                       </div>
-
                     </div>
                   </div>
 
                   <!-- 组合题不需要大题判卷 -->
-                  <div v-if="qu.quType!=='99'" class="list-opt">
-
+                  <div v-if="qu.quType !== '99'" class="list-opt">
                     <div class="check-box">
-                      <div class="item">判题:
-                        <i :class="{'el-icon-success check-icon': true, 'check-icon-right':qu.isRight}" @click="checkAnswer(qu, true)" />
-                        <i :class="{'el-icon-error check-icon': true, 'check-icon-error':!qu.isRight}" @click="checkAnswer(qu, false)" />
+                      <div class="item">
+                        判题:
+                        <i
+                          :class="{
+                            'el-icon-success check-icon': true,
+                            'check-icon-right': qu.isRight,
+                          }"
+                          @click="checkAnswer(qu, true)"
+                        />
+                        <i
+                          :class="{
+                            'el-icon-error check-icon': true,
+                            'check-icon-error': !qu.isRight,
+                          }"
+                          @click="checkAnswer(qu, false)"
+                        />
+                      </div>
+                      <div class="item">
+                        得分:<el-input-number
+                          v-model="qu.actualScore"
+                          :precision="1"
+                          :max="qu.score"
+                          size="mini"
+                          style="width: 100px"
+                        />
                       </div>
-                      <div class="item">得分:<el-input-number v-model="qu.actualScore" :precision="1" :max="qu.score" size="mini" style="width: 100px" /></div>
                       <div class="item">总分:{{ qu.score }}</div>
                     </div>
                   </div>
                 </div>
               </div>
             </template>
-
           </el-card>
-
         </template>
 
         <el-card>
-          <el-input v-model="postForm.remark" type="textarea" placeholder="请输入您的评语!" />
+          <el-input
+            v-model="postForm.remark"
+            type="textarea"
+            placeholder="请输入您的评语!"
+          />
         </el-card>
-
       </div>
 
       <div class="all-box-right">
-
-        <el-card v-if="!loading" :class="{'left-box':true, 'left-box-normal': !scrolled, 'left-box-scrolled': scrolled}" style="width: 200px">
+        <el-card
+          v-if="!loading"
+          :class="{
+            'left-box': true,
+            'left-box-normal': !scrolled,
+            'left-box-scrolled': scrolled,
+          }"
+          style="width: 200px"
+        >
           <div>人员姓名</div>
           <div style="color: #0a84ff">{{ postForm.userId_dictText }}</div>
           <el-divider />
           <div>考试成绩</div>
-          <div style="color: #FF4B50">{{ postForm.userScore }}</div>
+          <div style="color: #ff4b50">{{ postForm.userScore }}</div>
           <el-divider />
           <div>仅看错题</div>
           <div>
@@ -124,25 +218,28 @@
           <el-divider />
           <div>考试状态</div>
           <div>
-            <span v-if="postForm.userScore >= postForm.qualifyScore" style="color: #03DD6D">通过</span>
-            <span v-else style="color: #FF4B50">未通过</span>
+            <span
+              v-if="postForm.userScore >= postForm.qualifyScore"
+              style="color: #03dd6d"
+              >通过</span
+            >
+            <span v-else style="color: #ff4b50">未通过</span>
           </div>
           <el-divider />
-          <el-button type="primary" style="margin-top: 20px" @click="submitForm">提交阅卷</el-button>
+          <el-button type="primary" style="margin-top: 20px" @click="submitForm"
+            >提交阅卷</el-button
+          >
         </el-card>
       </div>
-
     </div>
-
   </div>
 </template>
 
 <script>
-
-import { paperResult } from '@/api/paper/exam'
-import { reviewPaper } from '@/api/paper/paper'
-import { scrollTo } from '@/utils/scroll-to'
-import QuItemShow from '@/views/admin/repo/qu/components/QuItemShow'
+import { paperResult } from "@/api/paper/exam";
+import { reviewPaper } from "@/api/paper/paper";
+import { scrollTo } from "@/utils/scroll-to";
+import QuItemShow from "@/views/admin/repo/qu/components/QuItemShow";
 
 export default {
   components: { QuItemShow },
@@ -153,253 +250,253 @@ export default {
       onlySubj: false,
       scrolled: false,
       // 试卷ID
-      paperId: '',
-      postForm: {
-      },
+      paperId: "",
+      postForm: {},
       hiddenQu: true,
-      loading: false
-    }
+      loading: false,
+    };
   },
 
   watch: {
-
     // 重新计算分数
-    'postForm.groupList': {
+    "postForm.groupList": {
       handler(val) {
-        let userScore = 0
+        let userScore = 0;
         for (let i = 0; i < val.length; i++) {
-          const item = val[i]
+          const item = val[i];
 
-          let groupScore = 0
-          const quList = item.quList
+          let groupScore = 0;
+          const quList = item.quList;
           for (let j = 0; j < quList.length; j++) {
-            const qu = quList[j]
+            const qu = quList[j];
             // 组合题增加组合分数
-            if (qu.quType === '99') {
-              const subList = qu.subList
+            if (qu.quType === "99") {
+              const subList = qu.subList;
               for (let k = 0; k < subList.length; k++) {
-                groupScore = this.$calc.add(subList[k].actualScore, groupScore)
+                groupScore = this.$calc.add(subList[k].actualScore, groupScore);
               }
             } else {
-              groupScore = this.$calc.add(qu.actualScore, groupScore)
+              groupScore = this.$calc.add(qu.actualScore, groupScore);
             }
           }
 
-          item.userScore = this.$calc.add(item.userScore, groupScore)
-          userScore = this.$calc.add(groupScore, userScore)
+          item.userScore = this.$calc.add(item.userScore, groupScore);
+          userScore = this.$calc.add(groupScore, userScore);
         }
 
-        this.postForm.userScore = userScore
+        this.postForm.userScore = userScore;
       },
-      deep: true
-    }
-
+      deep: true,
+    },
   },
 
   mounted() {
     // 监听滚动条
-    window.addEventListener('scroll', () => {
-      let scrollTop = 0
+    window.addEventListener("scroll", () => {
+      let scrollTop = 0;
       if (document.documentElement && document.documentElement.scrollTop) {
-        scrollTop = document.documentElement.scrollTop
+        scrollTop = document.documentElement.scrollTop;
       } else if (document.body) {
-        scrollTop = document.body.scrollTop
+        scrollTop = document.body.scrollTop;
       }
 
       if (scrollTop > 85) {
-        this.scrolled = true
+        this.scrolled = true;
       } else {
-        this.scrolled = false
+        this.scrolled = false;
       }
-    })
+    });
   },
   created() {
-    const id = this.$route.params.paperId
+    const id = this.$route.params.paperId;
     if (id !== undefined) {
-      this.paperId = id
-      this.fetchData(id)
+      this.paperId = id;
+      this.fetchData(id);
     }
   },
 
   methods: {
-
     // 手动判断正确错误
     checkAnswer(qu, isRight) {
       if (isRight) {
-        qu.actualScore = qu.score
+        qu.actualScore = qu.score;
       } else {
-        qu.actualScore = 0
+        qu.actualScore = 0;
       }
 
-      qu.isRight = isRight
+      qu.isRight = isRight;
     },
 
     // 到指定位置
     goAnchor(selector) {
-      const anchor = document.getElementById(selector)
-      const to = anchor.offsetTop + 80
-      scrollTo(to, 600, function() {
-        console.log('滑动到指定位置!')
-      })
+      const anchor = document.getElementById(selector);
+      const to = anchor.offsetTop + 80;
+      scrollTo(to, 600, () => {});
     },
 
     // 判断是否回答
     userAnswer(answerList) {
-      let answer = ''
+      let answer = "";
 
       for (let i = 0; i < answerList.length; i++) {
         if (answerList[i].checked) {
-          answer += answerList[i].abc
+          answer += answerList[i].abc;
         }
       }
 
-      if (answer == '') {
-        answer = '未作答'
+      if (answer == "") {
+        answer = "未作答";
       }
 
-      return answer
+      return answer;
     },
 
     // 获取试卷内容
     fetchData(id) {
-      const params = { id: id }
-      this.loading = true
-      paperResult(params).then(response => {
-        // 试卷内容
-        this.postForm = response.data
-        this.loading = false
-      }).catch(() => {
-        this.loading = false
-      })
+      const params = { id: id };
+      this.loading = true;
+      paperResult(params)
+        .then((response) => {
+          // 试卷内容
+          this.postForm = response.data;
+          this.loading = false;
+        })
+        .catch(() => {
+          this.loading = false;
+        });
     },
 
     handlerShow() {
-      this.hiddenQu = !this.hiddenQu
+      this.hiddenQu = !this.hiddenQu;
     },
 
     submitForm() {
-      this.loading = true
-
-      reviewPaper(this.postForm).then(() => {
-        this.$notify({
-          title: '成功',
-          message: '阅卷成功!',
-          type: 'success',
-          duration: 2000
+      this.loading = true;
+
+      reviewPaper(this.postForm)
+        .then(() => {
+          this.$notify({
+            title: "成功",
+            message: "阅卷成功!",
+            type: "success",
+            duration: 2000,
+          });
+
+          this.$router.push({
+            name: "ReviewPaper",
+            params: { examId: this.postForm.examId },
+          });
+          this.loading = false;
         })
-
-        this.$router.push({ name: 'ReviewPaper', params: { examId: this.postForm.examId }})
-        this.loading = false
-      }).catch(() => {
-        this.loading = false
-      })
-    }
-  }
-}
+        .catch(() => {
+          this.loading = false;
+        });
+    },
+  },
+};
 </script>
 
 <style scoped>
+.all-box {
+  display: flex;
+  flex-direction: row;
+}
+
+.all-box-left {
+  width: 250px;
+  flex: 0 0 250px;
+}
+
+.all-box-center {
+  flex-grow: 1;
+  padding-left: 20px;
+  padding-right: 20px;
+}
+
+.all-box-right {
+  width: 200px;
+  flex: 0 0 200px;
+  text-align: center;
+  line-height: 32px;
+  font-size: 14px;
+  font-weight: 700;
+}
 
-  .all-box{
-    display: flex;
-    flex-direction: row
-  }
-
-  .all-box-left{
-    width: 250px;
-    flex: 0 0 250px
-  }
-
-  .all-box-center{
-    flex-grow: 1;
-    padding-left: 20px;
-    padding-right: 20px
-  }
-
-  .all-box-right{
-
-    width: 200px;
-    flex: 0 0 200px;
-    text-align: center;
-    line-height: 32px;
-    font-size: 14px;
-    font-weight: 700;
-  }
-
-  .group-card{
-    margin-bottom: 15px;
-    line-height: 28px;
-    width: 100%;
-  }
-
-  .group-card-body {
-    line-height: 22px;
-    font-size: 14px;
-  }
-
-  .group-card .num{
-    color: #1890FF;
-  }
-
-  .left-box{
-    height: calc(100vh - 120px);
-    position: fixed;
-    overflow: auto;
-    clear: both;
-  }
-
-  .left-box-normal{
-    top: 103px;
-  }
-
-  .left-box-scrolled{
-    top: 20px;
-    height: calc(100vh - 40px);
-  }
-
-  .content-card{
-    margin-bottom: 20px;
-    line-height: 28px;
-  }
-
-  .check-box{
-    background: #f5f5f5;
-    padding: 20px;
-    line-height: 40px;
-    width: 200px;
-    font-size: 14px;
-    font-weight: 700;
-  }
-
-  .check-box .item{
-    display: flex;
-    flex-direction: row;
-    align-items: center
-  }
-
-  .check-icon{
-    font-size: 28px;
-    color:#ddd;
-    cursor: pointer;
-    margin-right: 10px;
-  }
-
-  .check-icon-right{
-    color: #03DD6D;
-  }
-
-  .check-icon-error{
-    color: #FF4B50;
-  }
-
-  ::v-deep
-  .el-divider--horizontal{
-    margin: 5px 0;
-  }
-
-  .link-item{
-    background: #f5f5f5; margin-bottom: 10px; padding: 10px; border-radius: 10px
-  }
+.group-card {
+  margin-bottom: 15px;
+  line-height: 28px;
+  width: 100%;
+}
+
+.group-card-body {
+  line-height: 22px;
+  font-size: 14px;
+}
+
+.group-card .num {
+  color: #1890ff;
+}
+
+.left-box {
+  height: calc(100vh - 120px);
+  position: fixed;
+  overflow: auto;
+  clear: both;
+}
+
+.left-box-normal {
+  top: 103px;
+}
 
+.left-box-scrolled {
+  top: 20px;
+  height: calc(100vh - 40px);
+}
+
+.content-card {
+  margin-bottom: 20px;
+  line-height: 28px;
+}
+
+.check-box {
+  background: #f5f5f5;
+  padding: 20px;
+  line-height: 40px;
+  width: 200px;
+  font-size: 14px;
+  font-weight: 700;
+}
+
+.check-box .item {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+
+.check-icon {
+  font-size: 28px;
+  color: #ddd;
+  cursor: pointer;
+  margin-right: 10px;
+}
+
+.check-icon-right {
+  color: #03dd6d;
+}
+
+.check-icon-error {
+  color: #ff4b50;
+}
+
+::v-deep .el-divider--horizontal {
+  margin: 5px 0;
+}
+
+.link-item {
+  background: #f5f5f5;
+  margin-bottom: 10px;
+  padding: 10px;
+  border-radius: 10px;
+}
 </style>
 

+ 425 - 0
exam-06173-vue/src/views/admin/paper/paper/view.vue

@@ -0,0 +1,425 @@
+<template>
+  <div v-loading="loading">
+    <div class="all-box">
+      <div class="all-box-left">
+        <el-card
+          v-if="!loading"
+          :class="{
+            'left-box': true,
+            'left-box-normal': !scrolled,
+            'left-box-scrolled': scrolled,
+          }"
+          style="width: 250px"
+        >
+          <div
+            v-for="item in postForm.groupList"
+            :key="item.id"
+            class="group-card"
+          >
+            <div
+              v-if="
+                (onlySubj && (item.quType === '4' || item.quType === '99')) ||
+                !onlySubj
+              "
+            >
+              <div style="line-height: 40px">
+                <el-button
+                  style="font-size: 14px; font-weight: 700"
+                  type="text"
+                  @click="goAnchor(item.id)"
+                  >{{ item.title }}</el-button
+                >
+                <el-divider />
+              </div>
+              <div class="group-card-body">
+                <div>
+                  共 <i class="num">{{ item.quCount }}</i> 题,共
+                  <i class="num">{{ item.totalScore }}</i> 分
+                </div>
+              </div>
+
+              <div class="card-box">
+                <div
+                  v-for="card in item.quList"
+                  :key="card.id"
+                  class="item"
+                  @click="goAnchor(card.id)"
+                >
+                  <div
+                    :class="{
+                      num: true,
+                      right: card.isRight,
+                      error: !card.isRight,
+                      current: postForm.state == 1 && card.quType == '4',
+                    }"
+                  >
+                    {{ card.sort }}
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </el-card>
+      </div>
+
+      <div class="all-box-center">
+        <template v-for="item in postForm.groupList">
+          <el-card
+            v-if="
+              (onlySubj && (item.quType === '4' || item.quType === '99')) ||
+              !onlySubj
+            "
+            :id="item.id"
+            :key="item.id"
+            class="content-card"
+          >
+            <template v-for="(qu, index) in item.quList">
+              <div v-if="!onlyError || (onlyError && !qu.isRight)" :key="qu.id">
+                <div :id="qu.id" class="list-box">
+                  <div class="list-qu">
+                    <qu-item-show
+                      :value="qu"
+                      :index="index"
+                      :state="postForm.state"
+                    />
+
+                    <div v-if="qu.quType === '99'">
+                      <!-- 子题目的判卷 -->
+                      <div
+                        v-for="(sub, jj) in qu.subList"
+                        :key="sub.id"
+                        class="list-sub-box"
+                      >
+                        <div class="list-sub-qu">
+                          <qu-item-show
+                            :value="sub"
+                            :index="jj"
+                            :state="postForm.state"
+                            :show-type="true"
+                            :sub="true"
+                          />
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </template>
+          </el-card>
+        </template>
+      </div>
+
+      <div class="all-box-right">
+        <el-card
+          v-if="!loading"
+          :class="{
+            'left-box': true,
+            'left-box-normal': !scrolled,
+            'left-box-scrolled': scrolled,
+          }"
+          style="width: 200px"
+        >
+          <div>人员姓名</div>
+          <div style="color: #0a84ff">{{ postForm.userId_dictText }}</div>
+          <el-divider />
+          <div>考试成绩</div>
+          <div style="color: #ff4b50">{{ postForm.userScore }}</div>
+          <el-divider />
+          <div>仅看错题</div>
+          <div>
+            <el-switch
+              v-model="onlyError"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+            />
+          </div>
+          <el-divider />
+          <div>仅看主观题</div>
+          <div>
+            <el-switch
+              v-model="onlySubj"
+              active-color="#13ce66"
+              inactive-color="#ff4949"
+            />
+          </div>
+          <el-divider />
+          <div>考试状态</div>
+          <div>
+            <span
+              v-if="postForm.userScore >= postForm.qualifyScore"
+              style="color: #03dd6d"
+              >通过</span
+            >
+            <span v-else style="color: #ff4b50">未通过</span>
+          </div>
+        </el-card>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { paperResult } from "@/api/paper/exam";
+import { reviewPaper } from "@/api/paper/paper";
+import { scrollTo } from "@/utils/scroll-to";
+import QuItemShow from "@/views/admin/repo/qu/components/QuItemShow";
+
+export default {
+  components: { QuItemShow },
+  data() {
+    return {
+      onlyError: false,
+      // 只显示主观题
+      onlySubj: false,
+      scrolled: false,
+      // 试卷ID
+      paperId: "",
+      postForm: {},
+      hiddenQu: true,
+      loading: false,
+    };
+  },
+
+  watch: {
+    // 重新计算分数
+    "postForm.groupList": {
+      handler(val) {
+        let userScore = 0;
+        for (let i = 0; i < val.length; i++) {
+          const item = val[i];
+
+          let groupScore = 0;
+          const quList = item.quList;
+          for (let j = 0; j < quList.length; j++) {
+            const qu = quList[j];
+            // 组合题增加组合分数
+            if (qu.quType === "99") {
+              const subList = qu.subList;
+              for (let k = 0; k < subList.length; k++) {
+                groupScore = this.$calc.add(subList[k].actualScore, groupScore);
+              }
+            } else {
+              groupScore = this.$calc.add(qu.actualScore, groupScore);
+            }
+          }
+
+          item.userScore = this.$calc.add(item.userScore, groupScore);
+          userScore = this.$calc.add(groupScore, userScore);
+        }
+
+        this.postForm.userScore = userScore;
+      },
+      deep: true,
+    },
+  },
+
+  mounted() {
+    // 监听滚动条
+    window.addEventListener("scroll", () => {
+      let scrollTop = 0;
+      if (document.documentElement && document.documentElement.scrollTop) {
+        scrollTop = document.documentElement.scrollTop;
+      } else if (document.body) {
+        scrollTop = document.body.scrollTop;
+      }
+
+      if (scrollTop > 85) {
+        this.scrolled = true;
+      } else {
+        this.scrolled = false;
+      }
+    });
+  },
+  created() {
+    const id = this.$route.params.paperId;
+    if (id !== undefined) {
+      this.paperId = id;
+      this.fetchData(id);
+    }
+  },
+
+  methods: {
+    // 手动判断正确错误
+    checkAnswer(qu, isRight) {
+      if (isRight) {
+        qu.actualScore = qu.score;
+      } else {
+        qu.actualScore = 0;
+      }
+
+      qu.isRight = isRight;
+    },
+
+    // 到指定位置
+    goAnchor(selector) {
+      const anchor = document.getElementById(selector);
+      const to = anchor.offsetTop + 80;
+      scrollTo(to, 600, () => {});
+    },
+
+    // 判断是否回答
+    userAnswer(answerList) {
+      let answer = "";
+
+      for (let i = 0; i < answerList.length; i++) {
+        if (answerList[i].checked) {
+          answer += answerList[i].abc;
+        }
+      }
+
+      if (answer == "") {
+        answer = "未作答";
+      }
+
+      return answer;
+    },
+
+    // 获取试卷内容
+    fetchData(id) {
+      const params = { id: id };
+      this.loading = true;
+      paperResult(params)
+        .then((response) => {
+          // 试卷内容
+          this.postForm = response.data;
+          this.loading = false;
+        })
+        .catch(() => {
+          this.loading = false;
+        });
+    },
+
+    handlerShow() {
+      this.hiddenQu = !this.hiddenQu;
+    },
+
+    submitForm() {
+      this.loading = true;
+
+      reviewPaper(this.postForm)
+        .then(() => {
+          this.$notify({
+            title: "成功",
+            message: "阅卷成功!",
+            type: "success",
+            duration: 2000,
+          });
+
+          this.$router.push({
+            name: "ReviewPaper",
+            params: { examId: this.postForm.examId },
+          });
+          this.loading = false;
+        })
+        .catch(() => {
+          this.loading = false;
+        });
+    },
+  },
+};
+</script>
+
+<style scoped>
+.all-box {
+  display: flex;
+  flex-direction: row;
+}
+
+.all-box-left {
+  width: 250px;
+  flex: 0 0 250px;
+}
+
+.all-box-center {
+  flex-grow: 1;
+  padding-left: 20px;
+  padding-right: 20px;
+}
+
+.all-box-right {
+  width: 200px;
+  flex: 0 0 200px;
+  text-align: center;
+  line-height: 32px;
+  font-size: 14px;
+  font-weight: 700;
+}
+
+.group-card {
+  margin-bottom: 15px;
+  line-height: 28px;
+  width: 100%;
+}
+
+.group-card-body {
+  line-height: 22px;
+  font-size: 14px;
+}
+
+.group-card .num {
+  color: #1890ff;
+}
+
+.left-box {
+  height: calc(100vh - 120px);
+  position: fixed;
+  overflow: auto;
+  clear: both;
+}
+
+.left-box-normal {
+  top: 103px;
+}
+
+.left-box-scrolled {
+  top: 20px;
+  height: calc(100vh - 40px);
+}
+
+.content-card {
+  margin-bottom: 20px;
+  line-height: 28px;
+}
+
+.check-box {
+  background: #f5f5f5;
+  padding: 20px;
+  line-height: 40px;
+  width: 200px;
+  font-size: 14px;
+  font-weight: 700;
+}
+
+.check-box .item {
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+}
+
+.check-icon {
+  font-size: 28px;
+  color: #ddd;
+  cursor: pointer;
+  margin-right: 10px;
+}
+
+.check-icon-right {
+  color: #03dd6d;
+}
+
+.check-icon-error {
+  color: #ff4b50;
+}
+
+::v-deep .el-divider--horizontal {
+  margin: 5px 0;
+}
+
+.link-item {
+  background: #f5f5f5;
+  margin-bottom: 10px;
+  padding: 10px;
+  border-radius: 10px;
+}
+</style>
+

+ 1 - 1
exam-06173-vue/src/views/admin/repo/form.vue

@@ -50,7 +50,7 @@
             <el-card>
 
               <el-radio-group v-model="postForm.openType" size="small">
-                <el-radio :label="1">完全公开</el-radio>
+                <!-- <el-radio :label="1">完全公开</el-radio> -->
                 <el-radio :label="2">部门开放</el-radio>
                 <el-radio :label="3">指定人员</el-radio>
               </el-radio-group>

+ 52 - 30
exam-06173-vue/src/views/admin/stat/total/archives.vue

@@ -57,28 +57,40 @@
           <el-table-column
             prop="ecTotalUser"
             label="应培训人数"
+            sortable
             align="center"
           />
           <el-table-column
             prop="ecActualUser"
             label="实培训人数"
+            sortable
             align="center"
           />
-          <el-table-column prop="pxl" label="培训率" align="center" />
-          <el-table-column prop="rjxs" label="人均学时" align="center" />
-          <el-table-column prop="ecTotalMin" label="累计学时" align="center" />
+          <el-table-column prop="pxl" label="培训率" sortable align="center" >
+            <template slot-scope="scope">{{scope.row.pxl}}%</template>
+          </el-table-column>
+          <el-table-column prop="rjxs" label="人均学时" sortable align="center" >
+            <template slot-scope="scope">{{scope.row.rjxs}}%</template>
+          </el-table-column>
+          <el-table-column prop="ecTotalMin" sortable label="累计学时" align="center" />
           <el-table-column
             prop="ecTotalUser"
             label="应考试人数"
             align="center"
+            sortable
           />
           <el-table-column
             prop="eeActualUser"
             label="实考试人数"
             align="center"
+            sortable
           />
-          <el-table-column prop="ksl" label="考试率" align="center" />
-          <el-table-column prop="kshgl" label="考试合格率" align="center" />
+          <el-table-column prop="ksl" label="考试率" sortable align="center">
+            <template slot-scope="scope">{{scope.row.ksl}}%</template>
+          </el-table-column>
+          <el-table-column prop="kshgl" label="考试合格率" sortable align="center">
+            <template slot-scope="scope">{{scope.row.kshgl}}%</template>
+          </el-table-column>
           <el-table-column
             fixed="right"
             label="操作"
@@ -120,18 +132,24 @@
               prop="courseNum"
               label="参与课程数"
               align="center"
+              sortable
             />
-            <el-table-column prop="totalMin" label="总学时" align="center" />
-            <el-table-column prop="wcl" label="完成率" align="center" />
+            <el-table-column prop="totalMin" label="总学时" sortable align="center" />
+            <el-table-column prop="wcl" label="完成率" sortable align="center">
+              <template slot-scope="scope">{{scope.row.wcl}}%</template>
+            </el-table-column>
           </el-table-column>
           <el-table-column label="考试记录" align="center">
             <el-table-column
               prop="tryCount"
               label="参与考试次数"
               align="center"
+              sortable
             />
-            <el-table-column prop="passed" label="及格次数" align="center" />
-            <el-table-column prop="jgl" label="及格率" align="center" />
+            <el-table-column prop="passed" label="及格次数" sortable align="center" />
+            <el-table-column prop="jgl" label="及格率" sortable align="center">
+              <template slot-scope="scope">{{scope.row.jgl}}%</template>
+            </el-table-column>
           </el-table-column>
           <el-table-column
             fixed="right"
@@ -189,10 +207,10 @@ export default {
         let seriesData = [[], []];
 
         res.data.forEach((ele) => {
-          ele.pxl = `${this.renderNumber(ele.ecActualUser, ele.ecTotalUser)}`;
-          ele.rjxs = `${this.renderNumber(ele.ecActualUser, ele.ecTotalMin)}`;
-          ele.ksl = `${this.renderNumber(ele.eeActualUser, ele.eeTotalUser)}`;
-          ele.kshgl = `${this.renderNumber(ele.eePassUser, ele.eeActualUser)}`;
+          ele.pxl = this.renderNumber(ele.ecActualUser, ele.ecTotalUser, true);
+          ele.ksl = this.renderNumber(ele.eeActualUser, ele.eeTotalUser, true);
+          ele.rjxs = this.renderNumber(ele.ecActualUser, ele.ecTotalMin, true);
+          ele.kshgl = this.renderNumber(ele.eePassUser, ele.eeActualUser, true);
 
           xAxisData.push(ele.deptName);
           seriesData[0].push(
@@ -218,16 +236,16 @@ export default {
       }).then((res) => {
         if (!this.selectDeptCode) {
           res.data.forEach((ele) => {
-            ele.wcl = `${this.renderNumber(ele.learnCourse, ele.courseNum)}`;
-            ele.jgl = `${this.renderNumber(ele.passed / ele.tryCount)}`;
+            ele.wcl = this.renderNumber(ele.learnCourse, ele.courseNum, true);
+            ele.jgl = this.renderNumber(ele.passed, ele.tryCount, true);
           });
           this.zgTableData = res.data;
         } else {
           let zgTableData = [];
           res.data.forEach((ele) => {
             if (ele.deptCode === this.selectDeptCode) {
-              ele.wcl = `${this.renderNumber(ele.learnCourse, ele.courseNum)}`;
-              ele.jgl = `${this.renderNumber(ele.passed / ele.tryCount)}`;
+              ele.wcl = this.renderNumber(ele.learnCourse, ele.courseNum, true);
+              ele.jgl = this.renderNumber(ele.passed, ele.tryCount, true);
               zgTableData.push(ele);
             }
           });
@@ -244,11 +262,7 @@ export default {
         if (!(num1 / num2)) {
           return renderChart ? 0 : "0%";
         } else {
-          return `${
-            renderChart
-              ? parseInt((num1 / num2) * 100)
-              : ((num1 / num2) * 100).toFixed(2) + "%"
-          }`;
+          return renderChart ? parseInt((num1 / num2) * 100) : ((num1 / num2) * 100).toFixed(2) + "%";
         }
       }
     },
@@ -342,19 +356,27 @@ export default {
         const day = days[month + 1];
 
         this.date = [
-          new Date(new Date() - 3600 * 1000 * 24 * 360).formatDate("yyyy-MM") +
+          new Date().formatDate("yyyy-MM") +
             "-01",
           new Date().formatDate("yyyy-MM") + `-${day}`,
         ];
       } else if (radio === "bjd") {
-        const month = (date.getMonth() + 3) % 12;
-        const day = days[month + 1];
-
+        const monthList = [1,4,7,10]
+        const nowDate = new Date()
+        let minMonth = 1;
+        for(let i=0;i<monthList.length;i++){
+          if(nowDate.getMonth()+1 >= monthList[i]){
+            minMonth = monthList[i]
+          }
+        }
+        const maxMonth = minMonth + 2
+        nowDate.setMonth(maxMonth)
+        nowDate.setDate(0)
+        const day = nowDate.getDate()
         this.date = [
-          new Date(new Date() - 3600 * 1000 * 24 * 360).formatDate("yyyy-MM") +
-            "-01",
-          new Date().formatDate("yyyy") +
-            `-${month < 10 ? "0" + month : month}-${day}`,
+          nowDate.formatDate("yyyy")+ `-${(minMonth < 10 ? "0" + minMonth : maxMonth)}-01`,
+            nowDate.formatDate("yyyy") +
+            `-${(maxMonth < 10 ? "0" + maxMonth : maxMonth)}-${day}`,
         ];
       } else if (radio === "jn") {
         this.date = [

+ 7 - 3
exam-06173-vue/src/views/admin/stat/total/detailBm.vue

@@ -28,13 +28,17 @@
             width="120"
             align="center"
           />
-          <el-table-column prop="createTime" label="开始时间" align="center" />
-          <el-table-column prop="finishTime" label="完成时间" align="center" />
+          <el-table-column prop="createTime" label="创建时间" align="center" />
           <el-table-column label="进度" width="200" align="center">
             <template slot-scope="scope">
               <el-progress
                 :percentage="
-                  parseInt((scope.row.passUser / scope.row.actualUser) * 100)
+                  parseInt((scope.row.passUser / scope.row.actualUser) * 100) >
+                  100
+                    ? 100
+                    : parseInt(
+                        (scope.row.passUser / scope.row.actualUser) * 100
+                      )
                 "
               ></el-progress>
             </template>

+ 5 - 2
exam-06173-vue/src/views/admin/stat/total/detailZg.vue

@@ -34,7 +34,10 @@
             <template slot-scope="scope">
               <el-progress
                 :percentage="
-                  parseInt((scope.row.learnMin / scope.row.needLearn) * 100)
+                  parseInt((scope.row.learnMin / scope.row.needLearn) * 100) >
+                  100
+                    ? 100
+                    : parseInt((scope.row.learnMin / scope.row.needLearn) * 100)
                 "
               ></el-progress>
             </template>
@@ -184,7 +187,7 @@ export default {
 
     // 查看试卷
     viewPaper(item) {
-      this.$router.push({ path: `/admin/tmpl/preview/${item.tmplId}` });
+      this.$router.push({ path: `/admin/exam/paperView/${item.paperId}` });
     },
 
     // 重置表格布局

+ 28 - 0
exam-06173-vue/src/views/checkPoint/index.vue

@@ -0,0 +1,28 @@
+<template>
+  <div></div>
+</template>
+
+<script>
+import { Message } from "element-ui";
+export default {
+  created() {
+    const userName = this.$route.query.userName || "";
+    const mark = this.$route.query.mark || "";
+    const postForm = { userName, mark };
+
+    if (!userName || !mark) {
+      Message.error("登录失败,未知用户");
+    } else {
+      this.$store.dispatch("user/login", postForm).then((res) => {
+        // 学员端
+        if (res.roleType === 1) {
+          this.$router.push({ path: "/" });
+        } else {
+          // 其它跳到后台
+          this.$router.push({ path: "/admin/dashboard" });
+        }
+      });
+    }
+  },
+};
+</script>

+ 55 - 32
exam-06173-vue/src/views/dashboard/index.vue

@@ -8,7 +8,7 @@
         </div>
         <div class="r">
           <span class="statisticsTitle">学员总数</span>
-          <span class="statisticsNum">128</span>
+          <span class="statisticsNum">{{ usernum }}</span>
         </div>
       </el-card>
       <el-card class="statisticsItem" @click.native="jump('ExamTmpl')">
@@ -17,7 +17,7 @@
         </div>
         <div class="r">
           <span class="statisticsTitle">试卷总数</span>
-          <span class="statisticsNum">327</span>
+          <span class="statisticsNum">{{ tmplnum }}</span>
         </div>
       </el-card>
       <el-card class="statisticsItem" @click.native="jump('QuList')">
@@ -26,7 +26,7 @@
         </div>
         <div class="r">
           <span class="statisticsTitle">试题总数</span>
-          <span class="statisticsNum">1653</span>
+          <span class="statisticsNum">{{ titlenum }}</span>
         </div>
       </el-card>
       <el-card class="statisticsItem" @click.native="jump('ListCourse')">
@@ -35,7 +35,7 @@
         </div>
         <div class="r">
           <span class="statisticsTitle">课程总数</span>
-          <span class="statisticsNum">695</span>
+          <span class="statisticsNum">{{ coursenum }}</span>
         </div>
       </el-card>
     </div>
@@ -107,7 +107,16 @@
               </div>
               <el-form label-width="90px">
                 <el-form-item label="考试时间:">
-                  <span>{{ item.startTime }}</span>
+                  <el-tooltip
+                    class="item"
+                    effect="dark"
+                    :content="`${item.startTime} - ${item.endTime}`"
+                    placement="top"
+                  >
+                    <span class="ovf"
+                      >{{ item.startTime }} - {{ item.endTime }}</span
+                    >
+                  </el-tooltip>
                 </el-form-item>
                 <el-form-item label="考试时长:">
                   <span>{{ item.totalTime }}</span>
@@ -132,24 +141,12 @@
 
       <el-tabs v-model="tabActive" @tab-click="reLayoutTable">
         <el-tab-pane class="chartItem" label="部门" name="bm">
-          <div
-            id="bmPxChartDom"
-            style="width: 48%; height: 280px; margin-top: 20px"
-          ></div>
-          <div
-            id="bmKsChartDom"
-            style="width: 48%; height: 280px; margin-top: 20px"
-          ></div>
+          <div id="bmPxChartDom" style="width: 48%; height: 280px"></div>
+          <div id="bmKsChartDom" style="width: 48%; height: 280px"></div>
         </el-tab-pane>
         <el-tab-pane class="chartItem" label="职工" name="zg">
-          <div
-            id="zgPxChartDom"
-            style="width: 48%; height: 280px; margin-top: 20px"
-          ></div>
-          <div
-            id="zgKsChartDom"
-            style="width: 48%; height: 280px; margin-top: 20px"
-          ></div>
+          <div id="zgPxChartDom" style="width: 48%; height: 280px"></div>
+          <div id="zgKsChartDom" style="width: 48%; height: 280px"></div>
         </el-tab-pane>
       </el-tabs>
     </div>
@@ -159,6 +156,7 @@
 <script>
 import * as echarts from "echarts";
 import {
+  getCttTotal,
   getCurrentExam,
   getDepartRank,
   getPassedRate,
@@ -169,6 +167,10 @@ export default {
   components: {},
   data() {
     return {
+      usernum: 0,
+      tmplnum: 0,
+      titlenum: 0,
+      coursenum: 0,
       tabActive: "bm",
       radioValue: "2",
       ksList: [],
@@ -180,9 +182,19 @@ export default {
   },
   mounted() {
     this.initChart();
+    this.getCttTotal();
     this.getCurrentExam();
   },
   methods: {
+    // 获取统计数值
+    getCttTotal() {
+      getCttTotal().then(({ data }) => {
+        this.usernum = data.usernum;
+        this.tmplnum = data.tmplnum;
+        this.titlenum = data.titlenum;
+        this.coursenum = data.coursenum;
+      });
+    },
     // 页面跳转
     jump(name, params = {}) {
       this.$router.push({ name, params });
@@ -247,6 +259,9 @@ export default {
           xAxis: {
             type: "category",
             data: xAxisData,
+            axisLabel: {
+              rotate: -40,
+            },
           },
           yAxis: {
             type: "value",
@@ -258,9 +273,7 @@ export default {
               let str = "";
               data.forEach((ele) => {
                 let circle = `<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;left:5px;background-color:${ele.color}"></span>`;
-                str +=
-                  circle +
-                  `${ele.name}: ${ele.value}分钟 <br />`;
+                str += circle + `${ele.name}: ${ele.value}分钟 <br />`;
               });
               return str;
             },
@@ -334,9 +347,7 @@ export default {
               let str = "";
               data.forEach((ele) => {
                 let circle = `<span style="display:inline-block;margin-right:5px;border-radius:50%;width:10px;height:10px;left:5px;background-color:${ele.color}"></span>`;
-                str +=
-                  circle +
-                  `${ele.name}: ${ele.value}% <br />`;
+                str += circle + `${ele.name}: ${ele.value}% <br />`;
               });
               return str;
             },
@@ -394,7 +405,7 @@ export default {
   .statisticsItem {
     margin-left: 20px;
     background: #1890ff;
-    padding: 10px;
+    padding: 5px;
     cursor: pointer;
 
     .el-card__body {
@@ -429,7 +440,7 @@ export default {
         }
 
         .statisticsNum {
-          font-size: 14px;
+          font-size: 18px;
         }
       }
     }
@@ -448,7 +459,7 @@ export default {
 
   .contentItem {
     width: 48%;
-    height: 212px;
+    height: 225px;
 
     .quickBox {
       width: 100%;
@@ -547,8 +558,21 @@ export default {
         }
       }
 
+      .el-card__body {
+        padding: 20px;
+      }
+
       .el-form-item {
-        margin-bottom: 2px;
+        margin-bottom: 0;
+        height: 36px;
+
+        .ovf {
+          display: inline-block;
+          width: 100%;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
       }
     }
   }
@@ -556,7 +580,6 @@ export default {
 
 .chartBox {
   width: 100%;
-  height: 300px;
   margin-top: 50px;
   position: relative;
 

+ 27 - 29
exam-06173-vue/src/views/login/components/third-login.vue

@@ -1,8 +1,10 @@
 <template>
-
-  <div v-if="siteData.wechatLogin || siteData.faceLogin" style="line-height: 35px; margin-top: 10px">
+  <div
+    v-if="false && (siteData.wechatLogin || siteData.faceLogin)"
+    style="line-height: 35px; margin-top: 10px"
+  >
     <div class="title-line">其它方式登录</div>
-    <div style="display: flex;">
+    <div style="display: flex">
       <a v-if="siteData.wechatLogin" class="third-item wechat-icon">
         <svg-icon icon-class="wechat" @click="wechatLogin" />
         <div>微信登录</div>
@@ -14,47 +16,42 @@
       </a>
     </div>
   </div>
-
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
-import { apiGetWechatUrl } from '@/api/ability/login'
+import { mapGetters } from "vuex";
+import { apiGetWechatUrl } from "@/api/ability/login";
 
 export default {
-  name: 'ThirdLogin',
+  name: "ThirdLogin",
 
   data() {
     return {
       loading1: false,
       loading2: false,
-      loginForm: {}
-    }
+      loginForm: {},
+    };
   },
   computed: {
-    ...mapGetters([
-      'siteData'
-    ])
+    ...mapGetters(["siteData"]),
   },
   methods: {
-
     wechatLogin() {
       // 获得跳转地址并跳转
-      apiGetWechatUrl({ state: 'pc' }).then(res => {
-        window.location = res.data.url
-      })
+      apiGetWechatUrl({ state: "pc" }).then((res) => {
+        window.location = res.data.url;
+      });
     },
 
     faceLogin() {
-      this.$router.push({ name: 'FaceLogin' })
-    }
-  }
-}
+      this.$router.push({ name: "FaceLogin" });
+    },
+  },
+};
 </script>
 
 <style scoped>
-
-.third-item{
+.third-item {
   margin-right: 10px;
   color: #888;
   display: flex;
@@ -63,19 +60,20 @@ export default {
   align-items: center;
 }
 
-.third-item .svg-icon{
-  width: 22px; height: 22px;
+.third-item .svg-icon {
+  width: 22px;
+  height: 22px;
   cursor: pointer;
 }
-.third-item div{
- font-size: 12px;
+.third-item div {
+  font-size: 12px;
 }
 
-.wechat-icon :hover{
-  color: #1AAC1A;
+.wechat-icon :hover {
+  color: #1aac1a;
 }
 
-.face-icon :hover{
+.face-icon :hover {
   color: #ff8000;
 }
 </style>

+ 124 - 78
exam-06173-vue/src/views/login/index.vue

@@ -1,20 +1,19 @@
 <template>
-
   <div>
     <el-row>
-
       <el-col :lg="14" :md="10" class="left hidden-sm-and-down">
-        <img src="@/assets/web/images/login2.png" style="height: 45vh">
+        <img src="@/assets/web/images/login2.png" style="height: 45vh" />
       </el-col>
-
       <el-col :lg="10" :md="14" class="right">
-
         <div class="box">
-
           <el-tabs v-model="activeName">
             <el-tab-pane label="账号登录" name="account">
-
-              <el-form v-if="activeName === 'account'" ref="postForm" :model="postForm" :rules="loginRules">
+              <el-form
+                v-if="activeName === 'account'"
+                ref="postForm"
+                :model="postForm"
+                :rules="loginRules"
+              >
                 <el-form-item prop="username">
                   <el-input
                     v-model="postForm.username"
@@ -39,15 +38,23 @@
                 </el-form-item>
 
                 <el-form-item>
-                  <el-button :loading="loading" type="primary" style="width: 100%" @click.native.prevent="accountLogin">登录</el-button>
+                  <el-button
+                    :loading="loading"
+                    type="primary"
+                    style="width: 100%"
+                    @click.native.prevent="accountLogin"
+                    >登录</el-button
+                  >
                 </el-form-item>
-
               </el-form>
-
             </el-tab-pane>
-            <el-tab-pane label="手机登录" name="mobile">
-
-              <el-form v-if="activeName === 'mobile'" ref="postForm" :model="postForm" :rules="loginRules">
+            <el-tab-pane label="手机登录" name="mobile" v-if="false">
+              <el-form
+                v-if="activeName === 'mobile'"
+                ref="postForm"
+                :model="postForm"
+                :rules="loginRules"
+              >
                 <el-form-item prop="mobile">
                   <el-input
                     v-model="postForm.mobile"
@@ -62,33 +69,52 @@
                 </el-form-item>
 
                 <el-form-item>
-                  <el-button :loading="loading" type="primary" style="width: 100%" @click.native.prevent="mobileLogin">登录</el-button>
+                  <el-button
+                    :loading="loading"
+                    type="primary"
+                    style="width: 100%"
+                    @click.native.prevent="mobileLogin"
+                    >登录</el-button
+                  >
                 </el-form-item>
-
               </el-form>
             </el-tab-pane>
-
           </el-tabs>
 
           <div style="text-align: right; line-height: 10px">
             <el-link href="/#/register">立即注册</el-link>
-            <el-link href="/#/forgot" style="margin-left: 10px">忘记密码?</el-link>
+            <el-link href="/#/forgot" style="margin-left: 10px"
+              >忘记密码?</el-link
+            >
           </div>
 
           <login-demo v-if="isDemo" />
 
-          <div v-if="siteData.h5Code || siteData.mpCode" style="line-height: 35px; margin-top: 10px">
+          <div
+            v-if="siteData.h5Code || siteData.mpCode"
+            style="line-height: 35px; margin-top: 10px"
+          >
             <div class="title-line">手机端</div>
-            <el-button v-if="siteData.h5Code" size="mini" round @click="showH5Code">H5学员端</el-button>
-            <el-button v-if="siteData.mpCode" size="mini" type="success" round @click="showMpCode">小程序学员端</el-button>
+            <el-button
+              v-if="siteData.h5Code"
+              size="mini"
+              round
+              @click="showH5Code"
+              >H5学员端</el-button
+            >
+            <el-button
+              v-if="siteData.mpCode"
+              size="mini"
+              type="success"
+              round
+              @click="showMpCode"
+              >小程序学员端</el-button
+            >
           </div>
 
           <third-login />
-
         </div>
-
       </el-col>
-
     </el-row>
 
     <el-dialog
@@ -97,7 +123,10 @@
       style="text-align: center"
     >
       <div class="code-tips">扫码进入H5学员端</div>
-      <img :src="siteData.h5Code" style="width: 300px; border: #ddd 1px solid">
+      <img
+        :src="siteData.h5Code"
+        style="width: 300px; border: #ddd 1px solid"
+      />
     </el-dialog>
 
     <el-dialog
@@ -106,122 +135,139 @@
       style="text-align: center"
     >
       <div class="code-tips">扫码进入小程序学员端</div>
-      <img :src="siteData.mpCode" style="width: 300px; border: #ddd 1px solid">
+      <img
+        :src="siteData.mpCode"
+        style="width: 300px; border: #ddd 1px solid"
+      />
     </el-dialog>
-
   </div>
-
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
-import LoginDemo from './components/demo'
-import YfCaptcha from '@/components/Captcha'
-import SmsInput from '@/components/SmsInput'
-import ThirdLogin from '@/views/login/components/third-login'
+import { mapGetters } from "vuex";
+import LoginDemo from "./components/demo";
+import YfCaptcha from "@/components/Captcha";
+import SmsInput from "@/components/SmsInput";
+import ThirdLogin from "@/views/login/components/third-login";
 
 export default {
   components: { ThirdLogin, SmsInput, YfCaptcha, LoginDemo },
   data() {
     return {
       isDemo: this.$demo,
-      activeName: 'account',
+      activeName: "account",
       loading: false,
       h5Visible: false,
       mpVisible: false,
       wxVisible: false,
       postForm: {
-        smsCode: '',
-        captchaKey: '',
-        captchaValue: ''
+        smsCode: "",
+        captchaKey: "",
+        captchaValue: "",
       },
       loginRules: {
-        username: [{ required: true, trigger: 'blur', message: '用户名不能为空' }],
-        password: [{ required: true, trigger: 'blur', message: '密码不能为空' }],
-        captchaValue: [{ required: true, trigger: 'blur', message: '验证码不能为空' }],
-        smsCode: [{ required: true, trigger: 'blur', message: '短信验证码不能为空' }],
-        mobile: [{ required: true, trigger: 'blur', message: '手机号不能为空' }]
-      }
-    }
+        username: [
+          { required: true, trigger: "blur", message: "用户名不能为空" },
+        ],
+        password: [
+          { required: true, trigger: "blur", message: "密码不能为空" },
+        ],
+        captchaValue: [
+          { required: true, trigger: "blur", message: "验证码不能为空" },
+        ],
+        smsCode: [
+          { required: true, trigger: "blur", message: "短信验证码不能为空" },
+        ],
+        mobile: [
+          { required: true, trigger: "blur", message: "手机号不能为空" },
+        ],
+      },
+    };
   },
 
   computed: {
-    ...mapGetters([
-      'siteData'
-    ])
+    ...mapGetters(["siteData"]),
   },
 
   mounted() {
-    window.addEventListener('keydown', this.keyDown)
+    window.addEventListener("keydown", this.keyDown);
   },
   destroyed() {
-    window.removeEventListener('keydown', this.keyDown, false)
+    window.removeEventListener("keydown", this.keyDown, false);
   },
 
   methods: {
-
     showH5Code() {
-      this.h5Visible = true
+      this.h5Visible = true;
     },
     showMpCode() {
-      this.mpVisible = true
+      this.mpVisible = true;
     },
 
     loginBack(res) {
       // 学员端
       if (res.roleType === 1) {
-        this.$router.push({ path: '/' })
+        this.$router.push({ path: "/" });
       } else {
         // 其它跳到后台
-        this.$router.push({ path: '/admin/dashboard' })
+        this.$router.push({ path: "/admin/dashboard" });
       }
     },
 
     async mobileLogin() {
-      this.$refs.postForm.validate(valid => {
+      this.$refs.postForm.validate((valid) => {
         if (valid) {
-          this.loading = true
-          this.$store.dispatch('user/mobileLogin', this.postForm)
-            .then(res => {
-              this.loginBack(res)
+          this.loading = true;
+          this.$store
+            .dispatch("user/mobileLogin", this.postForm)
+            .then((res) => {
+              this.loginBack(res);
             })
             .catch(() => {
-              this.loading = false
-            })
+              this.loading = false;
+            });
         }
-      })
+      });
     },
 
     accountLogin() {
-      this.$refs.postForm.validate(valid => {
+      this.$refs.postForm.validate((valid) => {
         if (valid) {
-          this.loading = true
-          this.$store.dispatch('user/login', this.postForm)
-            .then(res => {
-              this.loginBack(res)
+          this.loading = true;
+          this.$store
+            .dispatch("user/login", this.postForm)
+            .then((res) => {
+              this.loginBack(res);
             })
             .catch(() => {
-              this.loading = false
-            })
+              this.loading = false;
+            });
         }
-      })
+      });
     },
 
     studentRegister() {
-      this.$router.push({ name: 'Register' })
+      this.$router.push({ name: "Register" });
     },
 
     keyDown(e) {
       if (e.keyCode == 13) {
-        if (this.activeName === 'account') {
-          this.accountLogin()
+        if (this.activeName === "account") {
+          this.accountLogin();
         }
 
-        if (this.activeName === 'mobile') {
-          this.mobileLogin()
+        if (this.activeName === "mobile") {
+          this.mobileLogin();
         }
       }
-    }
-  }
-}
+    },
+  },
+};
 </script>
+
+<style lang="scss" scoped>
+.box {
+  position: relative;
+  z-index: 50;
+}
+</style>

+ 75 - 50
exam-06173-vue/src/views/login/layout/LoginLayout.vue

@@ -1,87 +1,93 @@
 <template>
-
   <div class="login-container">
-
     <el-row :gutter="20" class="top">
-      <el-col :span="6" :offset="3">
+      <el-col :span="6" :offset="1">
         <div style="display: flex; flex-direction: row; align-items: center">
           <a href="/">
             <div v-if="siteData.frontLogo">
-              <img :src="siteData.frontLogo">
+              <img :src="siteData.frontLogo" />
             </div>
-            <div v-else style="font-weight: 700; font-size: 26px; color: #eee; flex-grow: 1; text-align: left; padding-left: 10px">
+            <div
+              v-else
+              style="
+                font-weight: 700;
+                font-size: 26px;
+                color: #eee;
+                flex-grow: 1;
+                text-align: left;
+                padding-left: 10px;
+              "
+            >
               {{ siteData.siteName }}
             </div>
           </a>
         </div>
-
       </el-col>
 
       <el-col :span="12" style="line-height: 60px; text-align: right" />
-
     </el-row>
 
     <el-row :gutter="20" class="content">
       <el-col :span="18" :offset="3">
         <app-main />
       </el-col>
-
+      <!-- <div class="loginImgBox">
+        <img src="@/assets/web/images/login3.png" />
+      </div> -->
     </el-row>
 
     <el-row :gutter="20" class="footer">
-      <el-col :span="18" :offset="3">
+      <!-- <el-col :span="18" :offset="3">
         <div v-html="siteData.copyRight" />
-      </el-col>
+      </el-col> -->
+      <div class="flex">
+        <div v-html="siteData.copyRight" />
+      </div>
     </el-row>
-
   </div>
-
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
-import AppMain from '@/layout/components/AppMain'
+import { mapGetters } from "vuex";
+import AppMain from "@/layout/components/AppMain";
 
 export default {
-  name: 'LoginLayout',
+  name: "LoginLayout",
   components: { AppMain },
 
   data() {
     return {
-      activeIndex: ''
-    }
+      activeIndex: "",
+    };
   },
   computed: {
-    ...mapGetters([
-      'siteData'
-    ])
+    ...mapGetters(["siteData"]),
   },
   methods: {
     isActive(url) {
       if (this.activeIndex === url) {
-        return 'nav active'
+        return "nav active";
       }
-      return 'nav'
-    }
-  }
-}
+      return "nav";
+    },
+  },
+};
 </script>
 
 <style scoped>
 @import "~@/styles/login.css";
 
- ::v-deep
- .app-main {
-   min-height: 84vh;
-   width: 100%;
- }
+::v-deep .app-main {
+  min-height: 84vh;
+  width: 100%;
+}
 
-.header-bg{
+.header-bg {
   height: 60px;
   background: #4377fb;
 }
 
-.right-user{
+.right-user {
   display: flex;
   justify-content: flex-end;
   flex-direction: row;
@@ -89,25 +95,26 @@ export default {
   align-items: center;
 }
 
-.right-user :nth-child(1), .right-user :nth-child(2){
+.right-user :nth-child(1),
+.right-user :nth-child(2) {
   margin-right: 10px;
 }
 
-.right-user a{
+.right-user a {
   color: #efefef;
   font-size: 14px;
   font-weight: 500;
 }
 
-.right-user a:first-child{
+.right-user a:first-child {
   margin-right: 10px;
 }
 
-.right-user a:hover{
+.right-user a:hover {
   color: #ffd550;
 }
 
-.nav{
+.nav {
   color: #333;
   border: none;
   background: transparent;
@@ -118,43 +125,61 @@ export default {
   background: #fff;
 }
 
-.active{
+.active {
   color: #000055;
-  background: #FFD550;
+  background: #ffd550;
 }
 
 .nav:hover {
   color: #000055;
-  background: #FFD550;
+  background: #ffd550;
 }
 
-.col-logo{
-
+.col-logo {
   display: flex;
   align-items: center;
   justify-content: flex-start;
   height: 60px;
 }
 
-/deep/
-.top-avatar{
+/deep/ .top-avatar {
   text-align: right;
   display: flex;
   align-items: center;
   margin-right: 5px !important;
-
 }
 
-/deep/
-.top-avatar div{
+/deep/ .top-avatar div {
   display: flex;
   align-items: center;
   margin-right: -10px !important;
 }
 
-/deep/
-.top-avatar img{
-  width: 30px; height: 30px; border-radius: 15px;
+/deep/ .top-avatar img {
+  width: 30px;
+  height: 30px;
+  border-radius: 15px;
+}
+
+.footer .flex {
+  width: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
+</style>
+
 
+<style lang="scss" scoped>
+.loginImgBox {
+  position: absolute;
+  height: 100%;
+  width: 100%;
+
+  img {
+    width: 100%;
+    height: 100%;
+    background-size: 100% 100%;
+  }
+}
 </style>

+ 86 - 68
exam-06173-vue/src/views/web/course/list.vue

@@ -1,7 +1,5 @@
 <template>
-
   <div>
-
     <el-tabs v-model="listQuery.params.learnState" @tab-click="tabClick">
       <el-tab-pane name="0" label="全部课程" />
       <el-tab-pane name="1" label="未学习" />
@@ -9,16 +7,23 @@
       <el-tab-pane name="3" label="已学完" />
     </el-tabs>
 
-    <web-table
-      ref="pagingTable"
-      :options="options"
-      :list-query="listQuery"
-    >
-
+    <web-table ref="pagingTable" :options="options" :list-query="listQuery">
       <template slot="filter-content">
-
-        <dic-catalog-tree v-model="listQuery.params.catId" dic-code="course_catalog" placeholder="课程分类" width="200" class="filter-item" style="margin-top: 3px" />
-        <dic-list-select v-model="listQuery.params.isMust" dic-code="course_need" title="学习类型" />
+        <dic-catalog-tree
+          v-model="listQuery.params.catId"
+          dic-code="course_catalog"
+          placeholder="课程分类"
+          width="200"
+          class="filter-item"
+          style="margin-top: 3px"
+        />
+        <dic-list-select
+          v-model="listQuery.params.isMust"
+          dic-code="course_need"
+          title="学习类型"
+          class="filter-item"
+          style="margin-top: 3px"
+        />
 
         <el-input
           v-model="listQuery.params.title"
@@ -27,35 +32,46 @@
           prefix-icon="el-icon-search"
           style="width: 200px; margin-left: 10px"
         />
-
       </template>
 
       <template slot="data-columns">
-
         <el-table-column
           label=" "
           prop="title"
           width="150px"
           show-overflow-tooltip
         >
-
           <template slot-scope="scope">
-            <el-image v-if="scope.row.cover!=null && scope.row.cover!=''" :src="scope.row.cover" fit="fill" class="cover" />
-            <el-image v-else :src="require('@/assets/web/images/course_default.jpg')" fit="fill" class="cover" />
+            <el-image
+              v-if="scope.row.cover != null && scope.row.cover != ''"
+              :src="scope.row.cover"
+              fit="fill"
+              class="cover"
+            />
+            <el-image
+              v-else
+              :src="require('@/assets/web/images/course_default.jpg')"
+              fit="fill"
+              class="cover"
+            />
           </template>
-
         </el-table-column>
 
-        <el-table-column
-          label="课程名称"
-          prop="title"
-          show-overflow-tooltip
-        >
+        <el-table-column label="课程名称" prop="title" show-overflow-tooltip>
           <template slot-scope="scope">
-            <detail-link :id="scope.row.id" :title="scope.row.title" @click="handelView" />
-            <el-tag v-if="scope.row.liveCount > 0" style="margin-left: 5px" type="danger" size="mini">直播</el-tag>
+            <detail-link
+              :id="scope.row.id"
+              :title="scope.row.title"
+              @click="handelView"
+            />
+            <el-tag
+              v-if="scope.row.liveCount > 0"
+              style="margin-left: 5px"
+              type="danger"
+              size="mini"
+              >直播</el-tag
+            >
           </template>
-
         </el-table-column>
 
         <el-table-column
@@ -78,23 +94,24 @@
           width="180px"
         >
           <template slot-scope="scope">
-            <el-progress :text-inside="true" :stroke-width="15" :percentage="Number(scope.row.proportion*100).toFixed(0)" color="#c11920" />
+            <el-progress
+              class="progressStyle"
+              :text-inside="true"
+              :stroke-width="15"
+              :percentage="Number(scope.row.proportion * 100).toFixed(0)"
+            />
           </template>
         </el-table-column>
 
-        <el-table-column
-          label="状态"
-          align="center"
-          width="120px"
-        >
-
+        <el-table-column label="状态" align="center" width="120px">
           <template slot-scope="scope">
             <span v-if="scope.row.state == null">未学习</span>
             <span v-else-if="scope.row.state == 0">学习中</span>
-            <span v-else-if="scope.row.state == 1">已学完</span>
+            <span v-else-if="scope.row.state == 1" style="color: #1890ff"
+              >已学完</span
+            >
             <span v-else> -- </span>
           </template>
-
         </el-table-column>
 
         <el-table-column
@@ -105,76 +122,77 @@
         />
       </template>
     </web-table>
-
   </div>
-
 </template>
 
 <script>
-
-import DicListSelect from '@/components/DicListSelect'
-import DetailLink from '@/components/DetailLink'
-import WebTable from '@/components/WebTable'
-import DicCatalogTree from '../../../components/DicTreeSelect'
+import DicListSelect from "@/components/DicListSelect";
+import DetailLink from "@/components/DetailLink";
+import WebTable from "@/components/WebTable";
+import DicCatalogTree from "../../../components/DicTreeSelect";
 
 export default {
-  name: 'UserCourseList',
+  name: "UserCourseList",
   components: { DicCatalogTree, WebTable, DetailLink, DicListSelect },
   props: {
     onlyLearn: {
       type: Boolean,
-      default: false
-    }
+      default: false,
+    },
   },
   data() {
     return {
-
       listQuery: {
         current: 1,
         size: 10,
         params: {
           onlyLearn: this.onlyLearn,
-          learnState: '0'
-        }
+          learnState: "0",
+        },
       },
 
       options: {
         // 列表请求URL
-        listUrl: '/api/course/course/user-paging'
-      }
-    }
+        listUrl: "/api/course/course/user-paging",
+      },
+    };
   },
 
-  created() {
-
-  },
+  created() {},
   methods: {
-
     tabClick(tab) {
-      this.listQuery.params.learnState = tab.name
-      this.$refs.pagingTable.getList()
+      this.listQuery.params.learnState = tab.name;
+      this.$refs.pagingTable.getList();
     },
 
     // 课程详情
     handelView(courseId) {
-      this.$router.push({ name: 'CourseView', params: { courseId: courseId }})
-    }
-
-  }
-}
+      this.$router.push({ name: "CourseView", params: { courseId: courseId } });
+    },
+  },
+};
 </script>
 
 <style scoped>
-
-/deep/
-.el-card__body{
-  padding: 0px
+/deep/ .el-card__body {
+  padding: 0px;
 }
 
-.cover{
+.cover {
   height: 60px;
-  width: 120px
+  width: 120px;
 }
-
 </style>
 
+<style lang="scss">
+.progressStyle {
+  .el-progress-bar__innerText {
+    color: #fff;
+    font-size: 14px;
+  }
+  .el-progress-bar__inner {
+    background-color: unset;
+    background-image: linear-gradient(to right, #3587d8, #6855ff);
+  }
+}
+</style>

+ 81 - 70
exam-06173-vue/src/views/web/exam/list.vue

@@ -1,36 +1,30 @@
 <template>
-
   <div>
-
-    <div v-if="breakShow" style="margin-bottom: 30px; cursor: pointer" @click="continueExam">
-
+    <div
+      v-if="breakShow"
+      style="margin-bottom: 30px; cursor: pointer"
+      @click="continueExam"
+    >
       <el-alert
         :closable="false"
         title="您有正在进行的考试,离线太久考试将被作废哦,点击此处可继续考试!"
         type="error"
       />
-
     </div>
 
-    <el-tabs v-model="listQuery.params.examType" @tab-click="tabClick">
+    <!-- <el-tabs v-model="listQuery.params.examType" @tab-click="tabClick">
       <el-tab-pane name="1" label="正式考试" />
       <el-tab-pane name="2" label="模拟考试" />
-    </el-tabs>
-
-    <web-table
-      ref="pagingTable"
-      :options="options"
-      :list-query="listQuery"
-    >
+    </el-tabs> -->
 
+    <web-table ref="pagingTable" :options="options" :list-query="listQuery">
       <template slot="filter-content">
-
         <el-input
           v-model="listQuery.params.title"
           class="filter-item"
           placeholder="搜索考试名称"
           prefix-icon="el-icon-search"
-          style="width:200px"
+          style="width: 200px"
         />
 
         <el-date-picker
@@ -42,20 +36,33 @@
           start-placeholder="开始日期"
           end-placeholder="结束日期"
         />
+
+        <!-- <dic-list-select
+          class="filter-item"
+          v-model="listQuery.params.examType"
+          dic-code="exam_type"
+        /> -->
       </template>
 
       <template slot="data-columns">
-
-        <el-table-column
-          label="考试名称"
-          show-overflow-tooltip
-        >
+        <el-table-column label="考试名称" show-overflow-tooltip>
           <template slot-scope="scope">
-            <detail-link :id="scope.row.id" :title="scope.row.title" to="CheckExam" />
+            <detail-link
+              :id="scope.row.id"
+              :title="scope.row.title"
+              to="CheckExam"
+            />
           </template>
         </el-table-column>
 
         <el-table-column
+          label="类型"
+          align="center"
+          prop="examType_dictText"
+          width="120px"
+        />
+
+        <el-table-column
           label="时长"
           align="center"
           prop="totalTime"
@@ -76,101 +83,105 @@
           width="120px"
         />
 
-        <el-table-column
-          label="开放时间"
-          align="center"
-        >
-
+        <el-table-column label="开放时间" align="center">
           <template slot-scope="scope">
-            <span v-if="scope.row.timeLimit">{{ scope.row.startTime }} ~ {{ scope.row.endTime }}</span><span v-else>不限时</span>
+            <span v-if="scope.row.timeLimit"
+              >{{ scope.row.startTime }} ~ {{ scope.row.endTime }}</span
+            ><span v-else>不限时</span>
           </template>
-
         </el-table-column>
 
-
-        <el-table-column
-          label="考试状态"
-          align="center"
-          width="120px"
-        >
-
+        <el-table-column label="考试状态" align="center" width="120px">
           <template slot-scope="scope">
-
-            <el-tag v-if="scope.row.state===0" type="success">进行中</el-tag>
-            <el-tag v-if="scope.row.state===1" type="danger" disabled>已禁用</el-tag>
-            <el-tag v-if="scope.row.state===2" type="warning" disabled>未开始</el-tag>
-            <el-tag v-if="scope.row.state===3" disabled>已结束</el-tag>
-
+            <el-tag v-if="scope.row.state === 0" type="success">进行中</el-tag>
+            <el-tag v-if="scope.row.state === 1" type="danger" disabled
+              >已禁用</el-tag
+            >
+            <el-tag v-if="scope.row.state === 2" type="warning" disabled
+              >未开始</el-tag
+            >
+            <el-tag v-if="scope.row.state === 3" disabled>已结束</el-tag>
           </template>
-
         </el-table-column>
 
+        <el-table-column label="关联培训" align="center" width="120px">
+          <template slot-scope="scope">
+            <el-button
+              type="text"
+              size="small"
+              :disabled="scope.row.associate !== 1"
+              :style="`${scope.row.associate === 1 ? 'color:#1890ff;' : ''}`"
+              @click="jump(scope.row)"
+              >{{ scope.row.associate === 1 ? "是" : "否" }}</el-button
+            >
+          </template>
+        </el-table-column>
       </template>
-
     </web-table>
-
   </div>
-
 </template>
 
 <script>
-import { checkProcess } from '@/api/paper/exam'
-import WebTable from '@/components/WebTable'
-import DetailLink from '@/components/DetailLink'
+import { checkProcess } from "@/api/paper/exam";
+import WebTable from "@/components/WebTable";
+import DetailLink from "@/components/DetailLink";
+import DicListSelect from "@/components/DicListSelect";
 
 export default {
-  name: 'OnlineList',
-  components: { DetailLink, WebTable },
+  name: "OnlineList",
+  components: { DetailLink, WebTable, DicListSelect },
   data() {
     return {
-
       detailData: {},
       listQuery: {
         current: 1,
         size: 10,
         params: {
-          examType: '1'
-        }
+          examType: "",
+        },
       },
 
       options: {
         // 列表请求URL
-        listUrl: '/api/exam/exam/online-paging'
+        listUrl: "/api/exam/exam/online-paging",
       },
 
       postForm: {
-        examId: '',
-        password: ''
+        examId: "",
+        password: "",
       },
 
       breakShow: false,
-      breakId: ''
-    }
+      breakId: "",
+    };
   },
 
   created() {
-    checkProcess().then(res => {
+    checkProcess().then((res) => {
       if (res.data && res.data.id) {
-        this.breakShow = true
-        this.breakId = res.data.id
+        this.breakShow = true;
+        this.breakId = res.data.id;
       }
-    })
+    });
   },
   methods: {
-
     tabClick(tab, event) {
-      console.log(tab.name)
-      this.listQuery.params.examType = tab.name
-      this.$refs.pagingTable.getList()
+      this.listQuery.params.examType = tab.name;
+      this.$refs.pagingTable.getList();
     },
 
     /**
      * 继续考试
      */
     continueExam() {
-      this.$router.push({ name: 'StartExam', params: { id: this.breakId }})
-    }
-  }
-}
+      this.$router.push({ name: "StartExam", params: { id: this.breakId } });
+    },
+
+    // 查看课程详情
+    jump(item) {
+      this.$router.push({ path: `/web/course/view/${item.courseId}` });
+    },
+  },
+};
 </script>