dedsudiyu 1 semana atrás
pai
commit
f77b4c6d4e
59 arquivos alterados com 111949 adições e 6357 exclusões
  1. 22 0
      .editorconfig
  2. 39 63
      .env.development
  3. 3 10
      .env.production
  4. 12 0
      .env.staging
  5. 10 0
      .eslintignore
  6. 199 0
      .eslintrc.js
  7. 30 3
      .gitignore
  8. 127 29
      README.md
  9. 10 2
      babel.config.js
  10. 12 0
      bin/build.bat
  11. 12 0
      bin/package.bat
  12. 12 0
      bin/run-web.bat
  13. 35 0
      build/index.js
  14. 11955 5593
      package-lock.json
  15. 111 12
      package.json
  16. 0 5
      postcss.config.js
  17. 1 313
      public/h5player/h5player.min.js
  18. 72 9
      public/h5player/playctrl1/DecodeWorker.js
  19. 171 1
      public/h5player/playctrl1/Decoder.js
  20. 72 9
      public/h5player/playctrl1simd/DecodeWorker.js
  21. 171 1
      public/h5player/playctrl1simd/Decoder.js
  22. 5 5
      public/h5player/playctrl2/Decoder.js
  23. BIN
      public/h5player/playctrl2/Decoder.wasm
  24. 1 1
      public/h5player/playctrl2/Decoder.worker.js
  25. 5 5
      public/h5player/playctrl3/Decoder.js
  26. BIN
      public/h5player/playctrl3/Decoder.wasm
  27. 1 1
      public/h5player/playctrl3/Decoder.worker.js
  28. 96355 0
      public/h5player/static/js/antd.js
  29. 1 0
      public/h5player/static/js/moment.js
  30. 83 19
      public/h5player/transform/libSystemTransform.js
  31. BIN
      public/h5player/transform/libSystemTransform.wasm
  32. 7 1
      public/h5player/transform/systemTransform-worker.js
  33. 46 0
      public/html/ie.html
  34. 699 9
      public/index.html
  35. 2 0
      public/robots.txt
  36. 38 209
      src/App.vue
  37. 56 0
      src/README.md
  38. 8 0
      src/api/index.js
  39. 17 29
      src/components/H5PlayerVideo.vue
  40. 1 21
      src/components/H5PlayerVideoTime/H5PlayerVideoTime.vue
  41. 33 2
      src/components/H5PlayerVideoTime/fullH5PlayerVideo.vue
  42. 227 0
      src/components/fullH5PlayerVideo.vue
  43. 42 3
      src/main.js
  44. 60 0
      src/permission.js
  45. 32 0
      src/router/index.js
  46. 44 0
      src/settings.js
  47. 18 0
      src/store/getters.js
  48. 21 0
      src/store/index.js
  49. 56 0
      src/store/modules/app.js
  50. 20 0
      src/store/modules/plan.js
  51. 58 0
      src/store/modules/settings.js
  52. 183 0
      src/store/modules/tagsView.js
  53. 70 0
      src/store/modules/user.js
  54. 29 0
      src/utils/auth.js
  55. 47 0
      src/views/home.vue
  56. 55 0
      src/views/miniProgramAuthentication/index.vue
  57. 142 0
      src/views/miniProgramPlayback/index.vue
  58. 171 0
      src/views/miniProgramVideo/index.vue
  59. 240 2
      vue.config.js

+ 22 - 0
.editorconfig

@@ -0,0 +1,22 @@
+# 告诉EditorConfig插件,这是根文件,不用继续往上查找
+root = true
+
+# 匹配全部文件
+[*]
+# 设置字符集
+charset = utf-8
+# 缩进风格,可选space、tab
+indent_style = space
+# 缩进的空格数
+indent_size = 2
+# 结尾换行符,可选lf、cr、crlf
+end_of_line = lf
+# 在文件结尾插入新行
+insert_final_newline = true
+# 删除一行中的前后空格
+trim_trailing_whitespace = true
+
+# 匹配md结尾的文件
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false

+ 39 - 63
.env.development

@@ -1,11 +1,10 @@
 # ######################页面标题######################
 
-#西农页面标题
-VUE_APP_TITLE = 实验室安全智慧化管控系统
+VUE_APP_TITLE = 实验室安全智慧化管控中心
 
 # ####################生产环境配置####################
 
-ENV = 'development'
+ENV = 'production'
 
 # #######################版本号#######################
 
@@ -22,80 +21,57 @@ VUE_APP_VERSION_DIFFERENCE_FIELD = 'kuangYeDaXue_nanHu'
 # VUE_APP_VERSION_DIFFERENCE_FIELD = 'suZhouDaXue'
 # VUE_APP_VERSION_DIFFERENCE_FIELD = 'xiBeiNongLinDaXue'
 
-# ####################网接口配置####################
+# ####################网接口配置####################
 
 # 现场
-VUE_APP_BASE_LOCAL_API = '172.16.0.65/api'
-# 现场开发
-# VUE_APP_BASE_LOCAL_API = '10.129.55.200:8080'
-# 43内网
-# VUE_APP_BASE_LOCAL_API = '192.168.1.43/labSystem'
-# 43内网V3地址
-# VUE_APP_BASE_LOCAL_API = '192.168.1.43/api'
-# 1.8内网V3地址
-# VUE_APP_BASE_LOCAL_API = '192.168.1.8/api'
-# 88内网
-# VUE_APP_BASE_LOCAL_API = '192.168.1.88/labSystem'
-# 柴
-# VUE_APP_BASE_LOCAL_API = '192.168.1.9:8080'
+VUE_APP_BASE_API = '172.16.0.65/api'
+
 # 小飞
-# VUE_APP_BASE_LOCAL_API = '192.168.1.17:8080'
-# 志伟
-# VUE_APP_BASE_LOCAL_API = '192.168.1.20:8080'
-# 林总
-# VUE_APP_BASE_LOCAL_API = '192.168.1.24:8080'
-# 高升
-# VUE_APP_BASE_LOCAL_API = '192.168.1.39:8080'
+# VUE_APP_BASE_API = '192.168.1.17:8080'
 
+# 韩
+# VUE_APP_BASE_API = '192.168.1.20:8080'
 
-# ####################外网接口配置####################
+# 柴
+# VUE_APP_BASE_API = '192.168.1.9:8080'
 
-# 现场
-VUE_APP_BASE_API = '172.16.0.65/api'
-# 现场开发
-# VUE_APP_BASE_API = '10.129.55.200:8080'
-# 实验室安全管理系统/开发环境
-# 1.8内网V3地址
+# 1.8外网地址
 # VUE_APP_BASE_API = '192.168.1.8/api'
-# 43内网V3地址
-# VUE_APP_BASE_API = '192.168.1.43/api'
-# 林总
-# VUE_APP_BASE_API = '192.168.1.24:8080'
-# 高升
-# VUE_APP_BASE_API = '192.168.1.39:8080'
+
 # 43外网地址
-# VUE_APP_BASE_API = 'lab.zjznai.com/labAppTest'
-# 43内网V3地址
-# VUE_APP_BASE_API = '192.168.1.43/api'
-# 88服务器
-# VUE_APP_BASE_API = '192.168.1.88/labSystem'
-# VUE_APP_BASE_API = '192.168.1.43:9800'
-# 柴
-# VUE_APP_BASE_API = '192.168.1.9:8080'
-# 志伟
-# VUE_APP_BASE_API = '192.168.1.20:8080'
+# VUE_APP_BASE_API = 'lab.zjznai.com/labapp'
+
+# 开发人员地址
+# VUE_APP_BASE_API = '192.168.1.24:8080'
+
+# ####################内网接口配置####################
+
+# 现场
+VUE_APP_BASE_LOCAL_API = '172.16.0.65/api'
+
 # 小飞
-# VUE_APP_BASE_API = '192.168.1.17:8080'
+# VUE_APP_BASE_LOCAL_API = '192.168.1.17:8080'
+
+# 韩
+# VUE_APP_BASE_LOCAL_API = '192.168.1.20:8080'
+
+# 柴
+# VUE_APP_BASE_LOCAL_API = '192.168.1.9:8080'
+
 # 高升
-# VUE_APP_BASE_API = '192.168.1.39:8080'
+# VUE_APP_BASE_LOCAL_API = '192.168.1.39:8080'
 
+# 1.8内网地址
+# VUE_APP_BASE_LOCAL_API = '192.168.1.8/api'
 
-# 矿大
-# VUE_APP_BASE_API = 'lab.sxitdlc.com/labSystem'
-# 交大
-# VUE_APP_BASE_API = 'lab.sxitdlc.com/jdlabSystem'
-# VUE_APP_BASE_API ='/dev-api'
-# 文昌
-# VUE_APP_BASE_API = 'lab.sxitdlc.com/kdwclabSystem'
-# 暨南大学
-# VUE_APP_BASE_API = 'lab.sxitdlc.com/jndxlabSystem'
-# 化工学院
-# VUE_APP_BASE_API = 'lab.sxitdlc.com/labSaasSystem'
-# 苏大
-# VUE_APP_BASE_API = 'znyj.labcenter.suda.edu.cn/labSystem'
+# 43内网地址
+# VUE_APP_BASE_LOCAL_API = '192.168.1.43/api'
 
+# 开发人员地址
+# VUE_APP_BASE_LOCAL_API = '192.168.1.24:8080'
 
 
 # ####################认证平台版本退出接口####################
 
-VUE_APP_OUT_URL = 'http://192.168.1.43/labSystem/auth/logout'
+VUE_APP_OUT_URL = 'https://labcontrol.nwafu.edu.cn/api/auth/cas/logout/applet'
+

+ 3 - 10
.env.production

@@ -1,6 +1,6 @@
 # ######################页面标题######################
 
-VUE_APP_TITLE = 实验室安全智慧化管控系统
+VUE_APP_TITLE = 实验室安全智慧化管控中心
 
 # ####################生产环境配置####################
 
@@ -14,6 +14,7 @@ VUE_APP_VERSION_NUMBER = 'V3.0'
 
 VUE_APP_RENEWAL_ENCODING = ''
 
+
 # ####################版本差异字段####################
 
 VUE_APP_VERSION_DIFFERENCE_FIELD = 'kuangYeDaXue_nanHu'
@@ -48,16 +49,8 @@ VUE_APP_BASE_LOCAL_API = '172.16.0.65/api'
 # 开发人员地址
 # VUE_APP_BASE_LOCAL_API = '192.168.1.24:8080'
 
-# ####################登录方式####################
-
-# 账户登录
-VUE_APP_LOGIN_TYPE = 'account'
-
-# 统一认证登录
-# VUE_APP_LOGIN_TYPE = 'certification'
-
 
 # ####################认证平台版本退出接口####################
 
-VUE_APP_OUT_URL = 'http://lab.zjznai.com/labapp/auth/cas/logout'
+VUE_APP_OUT_URL = 'https://labcontrol.nwafu.edu.cn/api/auth/cas/logout/applet'
 

+ 12 - 0
.env.staging

@@ -0,0 +1,12 @@
+# 页面标题
+VUE_APP_TITLE = 实验室安全智慧化管控系统
+
+# 生产环境配置
+ENV = 'production'
+
+# ####################接口配置####################
+
+# 实验室安全管理系统/生产环境
+VUE_APP_BASE_API = 'lab.sxitdlc.com/appTest'
+# VUE_APP_BASE_API = '192.168.1.88/labSystem'
+

+ 10 - 0
.eslintignore

@@ -0,0 +1,10 @@
+# 忽略build目录下类型为js的文件的语法检查
+build/*.js
+# 忽略src/assets目录下文件的语法检查
+src/assets
+# 忽略public目录下文件的语法检查
+public
+# 忽略当前目录下为js的文件的语法检查
+*.js
+# 忽略当前目录下为vue的文件的语法检查
+*.vue

+ 199 - 0
.eslintrc.js

@@ -0,0 +1,199 @@
+// ESlint 检查配置
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint',
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: ['plugin:vue/recommended', 'eslint:recommended'],
+
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  rules: {
+    "vue/max-attributes-per-line": [2, {
+      "singleline": 10,
+      "multiline": {
+        "max": 1,
+        "allowFirstLine": false
+      }
+    }],
+    "vue/singleline-html-element-content-newline": "off",
+    "vue/multiline-html-element-content-newline":"off",
+    "vue/name-property-casing": ["error", "PascalCase"],
+    "vue/no-v-html": "off",
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 2,
+    'eqeqeq': ["error", "always", {"null": "ignore"}],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 0,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-mixed-spaces-and-tabs': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}

+ 30 - 3
.gitignore

@@ -1,3 +1,30 @@
-/node_modules
-/.idea
-/dist
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+.env.development
+.env.production
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
+/.env.development
+/.env.production
+
+/*.rar
+/public/version.txt
+/.env.development

+ 127 - 29
README.md

@@ -1,29 +1,127 @@
-# default
-
-## Project setup
-```
-npm install
-```
-
-### Compiles and hot-reloads for development
-```
-npm run serve
-```
-
-### Compiles and minifies for production
-```
-npm run build
-```
-
-### Run your tests
-```
-npm run test
-```
-
-### Lints and fixes files
-```
-npm run lint
-```
-
-### Customize configuration
-See [Configuration Reference](https://cli.vuejs.org/config/).
+# 更新日期 2023/07/25
+## 一.开发
+
+    # 安装依赖
+    npm install
+    
+    # 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+    npm install --registry=https://registry.npm.taobao.org
+    
+    # 启动服务
+    npm run dev
+
+浏览器访问 http://localhost:80
+
+## 二.发布
+
+    # 构建测试环境
+    npm run build:stage
+    
+    # 构建生产环境
+    npm run build:prod
+    
+## 三.目录结构&打包配置&懒加载
+### 1.为未来微前端版本铺垫,V3版本从新梳理了各模块关系,从新优化了功能模块配置,各个功能模块的api&asset&views都必须在各自的功能模块文件夹下
+>#### src下的目录结构示意如下
+
+    ├─src
+    │  ├─api                     (接口文件夹下按模块划分)
+    │  │  └─basicsModules        (基础核心模块api)
+    │  │  └─hazardManagement     (危险源模块api)
+    │  ├─assets
+    │  │  └─ZDimages             (静态文件夹下按模块划分)
+    │  │     ├─basicsModules     (基础核心模块静态文件)
+    │  │     └─hazardManagement  (危险源模块静态文件)
+    │  └─views                   (页面文件夹下按模块划分)
+    │     └─basicsModules        (基础核心模块页面文件)
+    │     └─hazardManagement     (危险源模块页面文件)
+    
+### 2.同时优化了懒加载与打包,但是在加入新增模块时需要同时修改打包配置与加载配置文件
+>#### 打包配置在 vue.config.js 文件内
+
+    ├─src
+    │  └─vue.config.js
+
+>#### 配置内容如下自行添加即可
+
+    //基础模块
+    basicsModules: {
+      name: 'chunk-basicsModules',
+      test: resolve('src/views/basicsModules'),
+      priority: 0,
+      minSize: 0,
+      minChunks: 1,
+      enforce:true,
+      reuseExistingChunk: true
+    },
+
+>#### 懒加载配置在 permission.js 文件内
+
+    ├─src
+    │  └─store
+    │    └─modules
+    │      └─permission.js
+    
+>#### 配置内容如下自行添加即可
+
+    if(pathName === 'basicsModules'){
+      return (resolve) => require([`@/views/basicsModules${pathUrl}`], resolve)
+    }else if(pathName === 'hazardManagement'){
+      return (resolve) => require([`@/views/hazardManagement${pathUrl}`], resolve)
+    }
+    
+## 四.二维码相关
+
+### 1.二维码生成规则 
+
+>#### 二维码参数由三部分组成 
+
+##### 微信小程序二维码标识
+
+    需要在微信小程序后台开发配置中配置
+    同时需要在后台配置开发配置中配置 
+    两个配置需要完全一致
+    在用户登录后会存储在local storage中字段为'codeOnlineAdd'
+    
+##### 参数 code
+
+    用于该功能所需参数
+    
+##### 功能标识 type
+
+    用于识别二维码所属功能,用于后续跳转对应后续业务页面
+    
+>##### 示例
+    http://lab.zjznai.com/labAppTest?code=11&type=1
+    微信小程序二维码标识?参数&功能标识
+    
+### 2.功能标识表
+
+| 功能标识 | 功能名称 | 业务字段 | 备注 |
+|  ---- | ---- | ---- | ---- | 
+| type:12 | 化学品终端-扫码双人认证 | doorId,subId,macId,code | 前端生成 - 用于微信公共扫码-双人认证 |
+| type:11 | 化学品终端-扫码单人登录 | code,subId,macId | 前端生成 - 用于微信公共扫码-单人登录 |
+| type:10 | 实验室关联危险源设备 | code | 前端生成 - 小程序专项检查扫码 |
+| type:9 | 化学品 | -- | 安卓生成 - 用于微信公共扫码-查看化学品 |  
+| type:8 | 化学品柜 | -- | 安卓生成 - 用于微信公共扫码-查看化学品柜 |
+| type:7 | 培训课程 | -- | 安卓生成 - 用于微信公共扫码-查看培训课程 |
+| type:6 | 专项检查 | -- | 未知生成 - 未知应用方式 |
+| type:5 | 实验室详情 | code | 前端生成 - 用于微信公共扫码-查看实验室详情,小程序安全检查页面扫码 |
+| type:3 | 危险源列表 | code | 前端生成 - 用于微信公共扫码-查看详情 |
+| type:2 | 安全制度 | code | 前端生成 - 用于微信公共扫码-查看详情 |
+| type:1 | MSDS说明书 | code | 前端生成 - 用于微信公共扫码-查看详情|
+
+    
+## 五.功能角色相关说明
+
+    在遵从数据权限与页面权限的基础上 增加了特定功能角色-在角色页面配置
+    前端取特定功能角色的权限字符匹配对应页面是否拥有特定的功能权限
+    
+### 1.功能角色与对应功能
+
+| 功能标识 | 功能名称 | 功能页面 | 备注 |
+|  ---- | ---- | ---- | ---- | 
+| performEvacuation | 应急疏散操作 | 应急疏散 | 应急疏散页面下所有的硬件操作与疏散操作与此角色关联 |
+| subHardwareControl | 实验室硬件控制 | 实验室列表 | 实验室列表页面硬件控制操作与此角色关联 |
+| subVideo | 实验室监控 | 实验室列表 | 实验室列表页面监控视频与此角色关联 |
+    

+ 10 - 2
babel.config.js

@@ -1,5 +1,13 @@
 module.exports = {
   presets: [
-    '@vue/app'
-  ]
+    // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
+    '@vue/cli-plugin-babel/preset'
+  ],
+  'env': {
+    'development': {
+      // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
+      // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
+      'plugins': ['dynamic-import-node']
+    }
+  }
 }

+ 12 - 0
bin/build.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 打包Web工程,生成dist文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run build:prod
+
+pause

+ 12 - 0
bin/package.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 安装Web工程,生成node_modules文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm install --registry=https://registry.npm.taobao.org
+
+pause

+ 12 - 0
bin/run-web.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 使用 Vue CLI 命令运行 Web 工程。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run dev
+
+pause

+ 35 - 0
build/index.js

@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+const rawArgv = process.argv.slice(2)
+const args = rawArgv.join(' ')
+
+if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
+  const report = rawArgv.includes('--report')
+
+  run(`vue-cli-service build ${args}`)
+
+  const port = 9526
+  const publicPath = config.publicPath
+
+  var connect = require('connect')
+  var serveStatic = require('serve-static')
+  const app = connect()
+
+  app.use(
+    publicPath,
+    serveStatic('./dist', {
+      index: ['index.html', '/']
+    })
+  )
+
+  app.listen(port, function () {
+    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))
+    if (report) {
+      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))
+    }
+
+  })
+} else {
+  run(`vue-cli-service build ${args}`)
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 11955 - 5593
package-lock.json


+ 111 - 12
package.json

@@ -1,19 +1,118 @@
 {
-  "name": "video-preview",
-  "version": "0.1.0",
-  "private": true,
+  "name": "v3-lab-web",
+  "version": "3.1.0",
+  "description": "实验室安全管理系统",
+  "author": "实验室安全",
+  "license": "MIT",
   "scripts": {
-    "serve": "vue-cli-service serve",
-    "build": "vue-cli-service build"
+    "dev": "vue-cli-service serve",
+    "build:prod": "vue-cli-service build",
+    "build:stage": "vue-cli-service build --mode staging",
+    "preview": "node build/index.js --preview",
+    "lint": "eslint --ext .js,.vue src"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "lint-staged"
+    }
+  },
+  "lint-staged": {
+    "src/**/*.{js,vue}": [
+      "eslint --fix",
+      "git add"
+    ]
+  },
+  "keywords": [
+    "vue",
+    "admin",
+    "dashboard",
+    "element-ui",
+    "boilerplate",
+    "admin-template",
+    "management-system"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://gitee.com/y_project/RuoYi-Cloud.git"
   },
   "dependencies": {
-    "axios": "^1.7.2",
-    "core-js": "^2.6.5",
-    "vue": "^2.6.10"
+    "@jiaminghi/data-view": "^2.10.0",
+    "@riophae/vue-treeselect": "0.4.0",
+    "@vue-office/docx": "^1.6.0",
+    "@vue-office/excel": "^1.7.6",
+    "@vue-office/pdf": "^1.6.5",
+    "@vue/composition-api": "^1.7.2",
+    "axios": "0.21.0",
+    "canvas": "^2.8.0",
+    "clipboard": "2.0.6",
+    "core-js": "3.8.1",
+    "echarts": "^5.3.0",
+    "echarts-liquidfill": "^3.1.0",
+    "element-ui": "2.15.5",
+    "file-saver": "^2.0.4",
+    "flv.js": "^1.6.2",
+    "fuse.js": "6.4.3",
+    "highlight.js": "9.18.5",
+    "install": "^0.13.0",
+    "js-base64": "^3.7.2",
+    "js-beautify": "^1.14.9",
+    "js-cookie": "2.2.1",
+    "js-md5": "^0.7.3",
+    "jsencrypt": "3.0.0-rc.1",
+    "jszip": "^3.10.1",
+    "jweixin-sdk": "^1.4.0",
+    "mpegts.js": "^1.7.3",
+    "mqtt": "^4.2.8",
+    "npm": "^8.3.0",
+    "nprogress": "0.2.0",
+    "or": "^0.2.0",
+    "quill": "1.3.7",
+    "screenfull": "5.0.2",
+    "sortablejs": "1.10.2",
+    "spark-md5": "^3.0.1",
+    "three": "^0.148.0",
+    "vue": "2.6.12",
+    "vue-count-to": "1.0.13",
+    "vue-cropper": "^0.5.5",
+    "vue-demi": "^0.14.7",
+    "vue-meta": "^2.4.0",
+    "vue-pdf": "^4.3.0",
+    "vue-qr": "^3.2.2",
+    "vue-router": "3.4.9",
+    "vue-simple-uploader": "^0.7.6",
+    "vue-ueditor-wrap": "^2.5.6",
+    "vue-video-player": "^5.0.2",
+    "vuedraggable": "2.24.3",
+    "vuex": "3.6.0",
+    "wangeditor": "^4.7.9",
+    "weixin-webview-jssdk": "0.0.2"
   },
   "devDependencies": {
-    "@vue/cli-plugin-babel": "^3.8.0",
-    "@vue/cli-service": "^3.8.0",
-    "vue-template-compiler": "^2.6.10"
-  }
+    "@vue/cli-plugin-babel": "4.4.6",
+    "@vue/cli-plugin-eslint": "4.4.6",
+    "@vue/cli-service": "4.4.6",
+    "babel-eslint": "10.1.0",
+    "chalk": "4.1.0",
+    "connect": "3.6.6",
+    "crypto-js": "^4.1.1",
+    "eslint": "7.15.0",
+    "eslint-plugin-vue": "7.2.0",
+    "lint-staged": "10.5.3",
+    "runjs": "4.4.2",
+    "sass": "1.39.0",
+    "sass-loader": "10.1.0",
+    "script-ext-html-webpack-plugin": "2.1.5",
+    "spark-md5": "^3.0.1",
+    "svg-sprite-loader": "5.1.1",
+    "vue-simple-uploader": "^0.7.6",
+    "vue-template-compiler": "2.6.12"
+  },
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions"
+  ]
 }

+ 0 - 5
postcss.config.js

@@ -1,5 +0,0 @@
-module.exports = {
-  plugins: {
-    autoprefixer: {}
-  }
-}

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 313
public/h5player/h5player.min.js


+ 72 - 9
public/h5player/playctrl1/DecodeWorker.js

@@ -17,10 +17,10 @@
     const PLAYM4_NEED_NEET_LOOP = 35; //丢帧需要下个循环
     const PLAYM4_SYS_NOT_SUPPORT = 16; 	// 不支持
 
-    importScripts('Decoder.js');
-    Module.addOnPostRun(function () {
-        postMessage({ 'function': "loaded" });
-    });
+    // importScripts('Decoder.js');
+    // Module.addOnPostRun(function () {
+    //     postMessage({ 'function': "loaded" });
+    // });
 
     var iStreamMode = 0;  // 流模式
 
@@ -47,11 +47,33 @@
         // console.log("nRunTimeModule:"+nRunTimeModule+",nFrameNum:"+nFrameNum+",nErrorCode:"+nErrorCode);
         postMessage({ 'function': "RunTimeInfoCallBack", 'nRunTimeModule': nRunTimeModule, 'nStrVersion': nStrVersion, 'nFrameTimeStamp': nFrameTimeStamp, 'nFrameNum': nFrameNum, 'nErrorCode': nErrorCode });
     }
+	
+	self.JSPlayM4_StreamInfoCallBack = function (nPort, pstStreamInfo, pUser)
+	{
+		let port = nPort;
+        let user = pUser;
+        let nSystemformat = Module.HEAP16[pstStreamInfo >> 1]; //封装类型
+        let nVideoformat = Module.HEAP16[pstStreamInfo + 2 >> 1];//视频编码类型
+        let nAudioformat = Module.HEAP16[pstStreamInfo + 4 >> 1];//音频编码类型
+        let nAudiochannels = Module.HEAP16[pstStreamInfo + 6 >> 1]; //音频通道数
+        let nAudiobitspersample = Module.HEAP32[pstStreamInfo + 8 >> 2];//音频样位率
+        let nAudiosamplesrate = Module.HEAP32[pstStreamInfo + 12 >> 2];//音频采样率
+        let nAudiobitrate = Module.HEAP32[pstStreamInfo + 16 >> 2];//音频比特率,单位:bit
+		//console.log("nSystemformat:" + nSystemformat + ",nVideoformat:" + nVideoformat + ",nAudioformat:" + nAudioformat + ",nAudiochannels:" + nAudiochannels + ",nAudiobitspersample:" + nAudiobitspersample + ",nAudiosamplesrate:" + nAudiosamplesrate + ",nAudiobitrate:" + nAudiobitrate);
+        postMessage({ 'function': "StreamInfoCallBack", 'nSystemformat': nSystemformat, 'nVideoformat': nVideoformat, 'nAudioformat': nAudioformat, 'nAudiochannels': nAudiochannels, 'nAudiobitspersample': nAudiobitspersample, 'nAudiosamplesrate': nAudiosamplesrate, 'nAudiobitrate': nAudiobitrate});
+	}
 
     onmessage = function (event) {
         var eventData = event.data;
         var res = 0;
         switch (eventData.command) {
+            case "importScripts":
+                const decodebase = eventData.data + "Decoder.js"
+                importScripts(decodebase);
+                Module.addOnPostRun(function () {
+                    postMessage({ 'function': "loaded" });
+                });
+                break;
             case "printLog":
                 let downloadFlag = eventData.data;
                 if (downloadFlag === true) {
@@ -206,7 +228,7 @@
                 var nBMPHeight = eventData.height;
                 var pYUVData = eventData.data;
                 var nYUVSize = nBMPWidth * nBMPHeight * 3 / 2;
-                var oJpegCropRect = {
+                var oBMPCropRect = {
                     left: eventData.left,
                     top: eventData.top,
                     right: eventData.right,
@@ -453,7 +475,7 @@
                 Module._SetLostFrameMode(g_nPort, eventData.data, 0);
                 break;
             case "SetDemuxModel":
-                Module._SetDemuxModel(g_nPort, eventData.nIdemuxType, eventData.bTrue);
+                let resSDM = Module._SetDemuxModel(g_nPort, eventData.nIdemuxType, eventData.bTrue);
                 break;
             case "SkipErrorData":
                 Module._SkipErrorData(g_nPort, eventData.bSkip);
@@ -476,6 +498,12 @@
                 break;
             case "SetRunTimeInfoCB":
                 Module._SetRunTimeInfoCallBackEx(g_nPort, eventData.nModuleType, 0);
+                break;
+			case "SetStreamInfoCB":
+                Module._SetStreamInfoCallBack(g_nPort, eventData.nType, 0);
+                break;
+			case "ResetBuffer":
+                Module._JSPlayM4_ResetBuffer(g_nPort, eventData.type);
                 break;
             default:
                 break;
@@ -489,6 +517,7 @@
         var iHour = oFrameInfo.hour;
         var iMinute = oFrameInfo.minute;
         var iSecond = oFrameInfo.second;
+        var iMiSecond = oFrameInfo.misecond
 
         if (iMonth < 10) {
             iMonth = "0" + iMonth;
@@ -505,8 +534,18 @@
         if (iSecond < 10) {
             iSecond = "0" + iSecond;
         }
-
-        return iYear + "-" + iMonth + "-" + iDay + " " + iHour + ":" + iMinute + ":" + iSecond;
+        let osdTime = {};
+
+        osdTime.year = iYear;
+        osdTime.month = iMonth;
+        osdTime.week = 0;
+        osdTime.day = iDay;
+        osdTime.hour = iHour;
+        osdTime.minute = iMinute;
+        osdTime.second = iSecond;
+        osdTime.milliseconds = iMiSecond;
+        return osdTime;
+        //return iYear + "-" + iMonth + "-" + iDay + " " + iHour + ":" + iMinute + ":" + iSecond;
     }
     // 获取帧数据
     function getFrameData() {
@@ -515,7 +554,31 @@
         var res = Module._GetFrameData();
         //var res = fun();
         if (res === PLAYM4_OK) {
-            var oFrameInfo = Module._GetFrameInfo();
+            var iFrameInfo = Module._GetFrameInfo();
+            let oFrameInfo = {};
+            oFrameInfo.frameType = Module.HEAP32[iFrameInfo >> 2];
+            oFrameInfo.frameSize = Module.HEAP32[iFrameInfo + 4 >> 2];
+            oFrameInfo.width = Module.HEAP32[iFrameInfo + 8 >> 2];
+            oFrameInfo.height = Module.HEAP32[iFrameInfo + 12 >> 2];
+            oFrameInfo.timeStamp = Module.HEAP32[iFrameInfo + 16 >> 2];
+            oFrameInfo.frameRate = Module.HEAP32[iFrameInfo + 20 >> 2];
+            oFrameInfo.bitsPerSample = Module.HEAP32[iFrameInfo + 24 >> 2];
+            oFrameInfo.samplesPerSec = Module.HEAP32[iFrameInfo + 28 >> 2];
+            oFrameInfo.channels = Module.HEAP32[iFrameInfo + 32 >> 2];
+            oFrameInfo.frameNum = Module.HEAP32[iFrameInfo + 36 >> 2];
+
+            oFrameInfo.cropLeft = Module.HEAP32[iFrameInfo + 40 >> 2];
+            oFrameInfo.cropRight = Module.HEAP32[iFrameInfo + 44 >> 2];
+            oFrameInfo.cropTop = Module.HEAP32[iFrameInfo + 48 >> 2];
+            oFrameInfo.cropBottom = Module.HEAP32[iFrameInfo + 52 >> 2];
+
+            oFrameInfo.year = Module.HEAP16[iFrameInfo + 64 >> 1];
+            oFrameInfo.month = Module.HEAP16[iFrameInfo + 66 >> 1];
+            oFrameInfo.day = Module.HEAP16[iFrameInfo + 68 >> 1];
+            oFrameInfo.hour = Module.HEAP16[iFrameInfo + 70 >> 1];
+            oFrameInfo.minute = Module.HEAP16[iFrameInfo + 72 >> 1];
+            oFrameInfo.second = Module.HEAP16[iFrameInfo + 74 >> 1];
+            oFrameInfo.misecond = Module.HEAP16[iFrameInfo + 76 >> 1];
             switch (oFrameInfo.frameType) {
                 case AUDIO_TYPE:
                     var iSize = oFrameInfo.frameSize;

Diferenças do arquivo suprimidas por serem muito extensas
+ 171 - 1
public/h5player/playctrl1/Decoder.js


+ 72 - 9
public/h5player/playctrl1simd/DecodeWorker.js

@@ -17,10 +17,10 @@
     const PLAYM4_NEED_NEET_LOOP = 35; //丢帧需要下个循环
     const PLAYM4_SYS_NOT_SUPPORT = 16; 	// 不支持
 
-    importScripts('Decoder.js');
-    Module.addOnPostRun(function () {
-        postMessage({ 'function': "loaded" });
-    });
+    // importScripts('Decoder.js');
+    // Module.addOnPostRun(function () {
+    //     postMessage({ 'function': "loaded" });
+    // });
 
     var iStreamMode = 0;  // 流模式
 
@@ -47,11 +47,33 @@
         // console.log("nRunTimeModule:"+nRunTimeModule+",nFrameNum:"+nFrameNum+",nErrorCode:"+nErrorCode);
         postMessage({ 'function': "RunTimeInfoCallBack", 'nRunTimeModule': nRunTimeModule, 'nStrVersion': nStrVersion, 'nFrameTimeStamp': nFrameTimeStamp, 'nFrameNum': nFrameNum, 'nErrorCode': nErrorCode });
     }
+	
+	self.JSPlayM4_StreamInfoCallBack = function (nPort, pstStreamInfo, pUser)
+	{
+		let port = nPort;
+        let user = pUser;
+        let nSystemformat = Module.HEAP16[pstStreamInfo >> 1]; //封装类型
+        let nVideoformat = Module.HEAP16[pstStreamInfo + 2 >> 1];//视频编码类型
+        let nAudioformat = Module.HEAP16[pstStreamInfo + 4 >> 1];//音频编码类型
+        let nAudiochannels = Module.HEAP16[pstStreamInfo + 6 >> 1]; //音频通道数
+        let nAudiobitspersample = Module.HEAP32[pstStreamInfo + 8 >> 2];//音频样位率
+        let nAudiosamplesrate = Module.HEAP32[pstStreamInfo + 12 >> 2];//音频采样率
+        let nAudiobitrate = Module.HEAP32[pstStreamInfo + 16 >> 2];//音频比特率,单位:bit
+		//console.log("nSystemformat:" + nSystemformat + ",nVideoformat:" + nVideoformat + ",nAudioformat:" + nAudioformat + ",nAudiochannels:" + nAudiochannels + ",nAudiobitspersample:" + nAudiobitspersample + ",nAudiosamplesrate:" + nAudiosamplesrate + ",nAudiobitrate:" + nAudiobitrate);
+        postMessage({ 'function': "StreamInfoCallBack", 'nSystemformat': nSystemformat, 'nVideoformat': nVideoformat, 'nAudioformat': nAudioformat, 'nAudiochannels': nAudiochannels, 'nAudiobitspersample': nAudiobitspersample, 'nAudiosamplesrate': nAudiosamplesrate, 'nAudiobitrate': nAudiobitrate});
+	}
 
     onmessage = function (event) {
         var eventData = event.data;
         var res = 0;
         switch (eventData.command) {
+            case "importScripts":
+                const decodebase = eventData.data + "Decoder.js"
+                importScripts(decodebase);
+                Module.addOnPostRun(function () {
+                    postMessage({ 'function': "loaded" });
+                });
+                break;
             case "printLog":
                 let downloadFlag = eventData.data;
                 if (downloadFlag === true) {
@@ -206,7 +228,7 @@
                 var nBMPHeight = eventData.height;
                 var pYUVData = eventData.data;
                 var nYUVSize = nBMPWidth * nBMPHeight * 3 / 2;
-                var oJpegCropRect = {
+                var oBMPCropRect = {
                     left: eventData.left,
                     top: eventData.top,
                     right: eventData.right,
@@ -453,7 +475,7 @@
                 Module._SetLostFrameMode(g_nPort, eventData.data, 0);
                 break;
             case "SetDemuxModel":
-                Module._SetDemuxModel(g_nPort, eventData.nIdemuxType, eventData.bTrue);
+                let resSDM = Module._SetDemuxModel(g_nPort, eventData.nIdemuxType, eventData.bTrue);
                 break;
             case "SkipErrorData":
                 Module._SkipErrorData(g_nPort, eventData.bSkip);
@@ -476,6 +498,12 @@
                 break;
             case "SetRunTimeInfoCB":
                 Module._SetRunTimeInfoCallBackEx(g_nPort, eventData.nModuleType, 0);
+                break;
+			case "SetStreamInfoCB":
+                Module._SetStreamInfoCallBack(g_nPort, eventData.nType, 0);
+                break;
+			case "ResetBuffer":
+                Module._JSPlayM4_ResetBuffer(g_nPort, eventData.type);
                 break;
             default:
                 break;
@@ -489,6 +517,7 @@
         var iHour = oFrameInfo.hour;
         var iMinute = oFrameInfo.minute;
         var iSecond = oFrameInfo.second;
+        var iMiSecond = oFrameInfo.misecond
 
         if (iMonth < 10) {
             iMonth = "0" + iMonth;
@@ -505,8 +534,18 @@
         if (iSecond < 10) {
             iSecond = "0" + iSecond;
         }
-
-        return iYear + "-" + iMonth + "-" + iDay + " " + iHour + ":" + iMinute + ":" + iSecond;
+        let osdTime = {};
+
+        osdTime.year = iYear;
+        osdTime.month = iMonth;
+        osdTime.week = 0;
+        osdTime.day = iDay;
+        osdTime.hour = iHour;
+        osdTime.minute = iMinute;
+        osdTime.second = iSecond;
+        osdTime.milliseconds = iMiSecond;
+        return osdTime;
+        //return iYear + "-" + iMonth + "-" + iDay + " " + iHour + ":" + iMinute + ":" + iSecond;
     }
     // 获取帧数据
     function getFrameData() {
@@ -515,7 +554,31 @@
         var res = Module._GetFrameData();
         //var res = fun();
         if (res === PLAYM4_OK) {
-            var oFrameInfo = Module._GetFrameInfo();
+            var iFrameInfo = Module._GetFrameInfo();
+            let oFrameInfo = {};
+            oFrameInfo.frameType = Module.HEAP32[iFrameInfo >> 2];
+            oFrameInfo.frameSize = Module.HEAP32[iFrameInfo + 4 >> 2];
+            oFrameInfo.width = Module.HEAP32[iFrameInfo + 8 >> 2];
+            oFrameInfo.height = Module.HEAP32[iFrameInfo + 12 >> 2];
+            oFrameInfo.timeStamp = Module.HEAP32[iFrameInfo + 16 >> 2];
+            oFrameInfo.frameRate = Module.HEAP32[iFrameInfo + 20 >> 2];
+            oFrameInfo.bitsPerSample = Module.HEAP32[iFrameInfo + 24 >> 2];
+            oFrameInfo.samplesPerSec = Module.HEAP32[iFrameInfo + 28 >> 2];
+            oFrameInfo.channels = Module.HEAP32[iFrameInfo + 32 >> 2];
+            oFrameInfo.frameNum = Module.HEAP32[iFrameInfo + 36 >> 2];
+
+            oFrameInfo.cropLeft = Module.HEAP32[iFrameInfo + 40 >> 2];
+            oFrameInfo.cropRight = Module.HEAP32[iFrameInfo + 44 >> 2];
+            oFrameInfo.cropTop = Module.HEAP32[iFrameInfo + 48 >> 2];
+            oFrameInfo.cropBottom = Module.HEAP32[iFrameInfo + 52 >> 2];
+
+            oFrameInfo.year = Module.HEAP16[iFrameInfo + 64 >> 1];
+            oFrameInfo.month = Module.HEAP16[iFrameInfo + 66 >> 1];
+            oFrameInfo.day = Module.HEAP16[iFrameInfo + 68 >> 1];
+            oFrameInfo.hour = Module.HEAP16[iFrameInfo + 70 >> 1];
+            oFrameInfo.minute = Module.HEAP16[iFrameInfo + 72 >> 1];
+            oFrameInfo.second = Module.HEAP16[iFrameInfo + 74 >> 1];
+            oFrameInfo.misecond = Module.HEAP16[iFrameInfo + 76 >> 1];
             switch (oFrameInfo.frameType) {
                 case AUDIO_TYPE:
                     var iSize = oFrameInfo.frameSize;

Diferenças do arquivo suprimidas por serem muito extensas
+ 171 - 1
public/h5player/playctrl1simd/Decoder.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 5 - 5
public/h5player/playctrl2/Decoder.js


BIN
public/h5player/playctrl2/Decoder.wasm


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
public/h5player/playctrl2/Decoder.worker.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 5 - 5
public/h5player/playctrl3/Decoder.js


BIN
public/h5player/playctrl3/Decoder.wasm


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
public/h5player/playctrl3/Decoder.worker.js


Diferenças do arquivo suprimidas por serem muito extensas
+ 96355 - 0
public/h5player/static/js/antd.js


+ 1 - 0
public/h5player/static/js/moment.js

@@ -2328,6 +2328,7 @@
       if (obsOffset) {
           return obsOffsets[obsOffset];
       } else if (militaryOffset) {
+          // the only allowed military tz is Z
           return 0;
       } else {
           var hm = parseInt(numOffset, 10);

Diferenças do arquivo suprimidas por serem muito extensas
+ 83 - 19
public/h5player/transform/libSystemTransform.js


BIN
public/h5player/transform/libSystemTransform.wasm


+ 7 - 1
public/h5player/transform/systemTransform-worker.js

@@ -67,7 +67,13 @@ importScripts('libSystemTransform.js');
                     {
                         console.log("_SysTransRegisterDataCallBack Failed:" + iRet);
                     }
-
+                    if (iTransType === 5) {//转mp4支持私有帧打入
+                        iRet = Module._SysTransEnableCapacity(7)
+                        if(iRet != 0)
+                        {
+                            console.log("_SysTransSetGlobalTime Failed:" + iRet);
+                        }
+                    }
                     iRet = Module._SysTransStart(null, null);
                     if(iRet != 0)
                     {

Diferenças do arquivo suprimidas por serem muito extensas
+ 46 - 0
public/html/ie.html


+ 699 - 9
public/index.html

@@ -1,18 +1,708 @@
 <!DOCTYPE html>
-<html lang="en">
+<html>
   <head>
     <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <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.ico">
-    <title>视频监控</title>
+    <title><%= webpackConfig.name %></title>
+    <meta name="buildUser" content="<%= htmlWebpackPlugin.options.buildUser %>">
+    <meta name="buildTime" content="<%= htmlWebpackPlugin.options.buildTime %>">
+    <meta name="buildEdition" content="<%= htmlWebpackPlugin.options.buildEdition %>">
+    <meta name="renewalEncoding" content="<%= htmlWebpackPlugin.options.renewalEncoding %>">
+    <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
+	  <style>
+    html,
+    body,
+    #app {
+      height: 100%;
+      margin: 0px;
+      padding: 0px;
+    }
+    .chromeframe {
+      margin: 0.2em 0;
+      background: #ccc;
+      color: #000;
+      padding: 0.2em 0;
+    }
+
+    #loader-wrapper {
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      z-index: 999999;
+    }
+
+    #loader {
+      display: block;
+      position: relative;
+      left: 50%;
+      top: 50%;
+      width: 150px;
+      height: 150px;
+      margin: -75px 0 0 -75px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 2s linear infinite;
+      -ms-animation: spin 2s linear infinite;
+      -moz-animation: spin 2s linear infinite;
+      -o-animation: spin 2s linear infinite;
+      animation: spin 2s linear infinite;
+      z-index: 1001;
+    }
+
+    #loader:before {
+      content: "";
+      position: absolute;
+      top: 5px;
+      left: 5px;
+      right: 5px;
+      bottom: 5px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 3s linear infinite;
+      -moz-animation: spin 3s linear infinite;
+      -o-animation: spin 3s linear infinite;
+      -ms-animation: spin 3s linear infinite;
+      animation: spin 3s linear infinite;
+    }
+
+    #loader:after {
+      content: "";
+      position: absolute;
+      top: 15px;
+      left: 15px;
+      right: 15px;
+      bottom: 15px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -moz-animation: spin 1.5s linear infinite;
+      -o-animation: spin 1.5s linear infinite;
+      -ms-animation: spin 1.5s linear infinite;
+      -webkit-animation: spin 1.5s linear infinite;
+      animation: spin 1.5s linear infinite;
+    }
+
+
+    @-webkit-keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+    @keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+
+    #loader-wrapper .loader-section {
+      position: fixed;
+      top: 0;
+      width: 51%;
+      height: 100%;
+      background: #245fba;
+      z-index: 1000;
+      -webkit-transform: translateX(0);
+      -ms-transform: translateX(0);
+      transform: translateX(0);
+    }
+
+    #loader-wrapper .loader-section.section-left {
+      left: 0;
+    }
+
+    #loader-wrapper .loader-section.section-right {
+      right: 0;
+    }
+
+
+    .loaded #loader-wrapper .loader-section.section-left {
+      -webkit-transform: translateX(-100%);
+      -ms-transform: translateX(-100%);
+      transform: translateX(-100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader-wrapper .loader-section.section-right {
+      -webkit-transform: translateX(100%);
+      -ms-transform: translateX(100%);
+      transform: translateX(100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader {
+      opacity: 0;
+      -webkit-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out;
+    }
+
+    .loaded #loader-wrapper {
+      visibility: hidden;
+      -webkit-transform: translateY(-100%);
+      -ms-transform: translateY(-100%);
+      transform: translateY(-100%);
+      -webkit-transition: all 0.3s 1s ease-out;
+      transition: all 0.3s 1s ease-out;
+    }
+
+    .no-js #loader-wrapper {
+      display: none;
+    }
+
+    .no-js h1 {
+      color: #222222;
+    }
+
+    #loader-wrapper .load_title {
+      font-family: 'Open Sans';
+      color: #FFF;
+      font-size: 19px;
+      width: 100%;
+      text-align: center;
+      z-index: 9999999999999;
+      position: absolute;
+      top: 60%;
+      opacity: 1;
+      line-height: 30px;
+    }
+
+    #loader-wrapper .load_title span {
+      font-weight: normal;
+      font-style: italic;
+      font-size: 13px;
+      color: #FFF;
+      opacity: 0.5;
+    }
+    .socket{
+      width: 200px;
+      height: 200px;
+      position: absolute;
+      left: 50%;
+      margin-left: -100px;
+      top: 50%;
+      margin-top: -100px;
+    }
+    .hex-brick{
+      background: #87CEEB;
+      width: 30px;
+      height: 17px;
+      position: absolute;
+      top: 5px;
+      animation-name: fade;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      -webkit-animation-name: fade;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+    }
+    .h2{
+      transform: rotate(60deg);
+      -webkit-transform: rotate(60deg);
+    }
+    .h3{
+      transform: rotate(-60deg);
+      -webkit-transform: rotate(-60deg);
+    }
+    .gel{
+      height: 30px;
+      width: 30px;
+      transition: all .3s;
+      -webkit-transition: all .3s;
+      position: absolute;
+      top: 50%;
+      left: 50%;
+    }
+    .center-gel{
+      margin-left: -15px;
+      margin-top: -15px;
+
+      animation-name: pulse;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      -webkit-animation-name: pulse;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+    }
+    .c1{
+      margin-left: -47px;
+      margin-top: -15px;
+    }
+    .c2{
+      margin-left: -31px;
+      margin-top: -43px;
+    }
+    .c3{
+      margin-left: 1px;
+      margin-top: -43px;
+    }
+    .c4{
+      margin-left: 17px;
+      margin-top: -15px;
+    }
+    .c5{
+      margin-left: -31px;
+      margin-top: 13px;
+    }
+    .c6{
+      margin-left: 1px;
+      margin-top: 13px;
+    }
+    .c7{
+      margin-left: -63px;
+      margin-top: -43px;
+    }
+    .c8{
+      margin-left: 33px;
+      margin-top: -43px;
+    }
+    .c9{
+      margin-left: -15px;
+      margin-top: 41px;
+    }
+    .c10{
+      margin-left: -63px;
+      margin-top: 13px;
+    }
+    .c11{
+      margin-left: 33px;
+      margin-top: 13px;
+    }
+    .c12{
+      margin-left: -15px;
+      margin-top: -71px;
+    }
+    .c13{
+      margin-left: -47px;
+      margin-top: -71px;
+    }
+    .c14{
+      margin-left: 17px;
+      margin-top: -71px;
+    }
+    .c15{
+      margin-left: -47px;
+      margin-top: 41px;
+    }
+    .c16{
+      margin-left: 17px;
+      margin-top: 41px;
+    }
+    .c17{
+      margin-left: -79px;
+      margin-top: -15px;
+    }
+    .c18{
+      margin-left: 49px;
+      margin-top: -15px;
+    }
+    .c19{
+      margin-left: -63px;
+      margin-top: -99px;
+    }
+    .c20{
+      margin-left: 33px;
+      margin-top: -99px;
+    }
+    .c21{
+      margin-left: 1px;
+      margin-top: -99px;
+    }
+    .c22{
+      margin-left: -31px;
+      margin-top: -99px;
+    }
+    .c23{
+      margin-left: -63px;
+      margin-top: 69px;
+    }
+    .c24{
+      margin-left: 33px;
+      margin-top: 69px;
+    }
+    .c25{
+      margin-left: 1px;
+      margin-top: 69px;
+    }
+    .c26{
+      margin-left: -31px;
+      margin-top: 69px;
+    }
+    .c27{
+      margin-left: -79px;
+      margin-top: -15px;
+    }
+    .c28{
+      margin-left: -95px;
+      margin-top: -43px;
+    }
+    .c29{
+      margin-left: -95px;
+      margin-top: 13px;
+    }
+    .c30{
+      margin-left: 49px;
+      margin-top: 41px;
+    }
+    .c31{
+      margin-left: -79px;
+      margin-top: -71px;
+    }
+    .c32{
+      margin-left: -111px;
+      margin-top: -15px;
+    }
+    .c33{
+      margin-left: 65px;
+      margin-top: -43px;
+    }
+    .c34{
+      margin-left: 65px;
+      margin-top: 13px;
+    }
+    .c35{
+      margin-left: -79px;
+      margin-top: 41px;
+    }
+    .c36{
+      margin-left: 49px;
+      margin-top: -71px;
+    }
+    .c37{
+      margin-left: 81px;
+      margin-top: -15px;
+    }
+    .r1{
+      animation-name: pulse;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-delay: .2s;
+      -webkit-animation-name: pulse;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+      -webkit-animation-delay: .2s;
+    }
+    .r2{
+      animation-name: pulse;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-delay: .4s;
+      -webkit-animation-name: pulse;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+      -webkit-animation-delay: .4s;
+    }
+    .r3{
+      animation-name: pulse;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-delay: .6s;
+      -webkit-animation-name: pulse;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+      -webkit-animation-delay: .6s;
+    }
+    .r1 > .hex-brick{
+      animation-name: fade;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-delay: .2s;
+      -webkit-animation-name: fade;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+      -webkit-animation-delay: .2s;
+    }
+    .r2 > .hex-brick{
+      animation-name: fade;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-delay: .4s;
+      -webkit-animation-name: fade;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+      -webkit-animation-delay: .4s;
+    }
+    .r3 > .hex-brick{
+      animation-name: fade;
+      animation-duration: 2s;
+      animation-iteration-count: infinite;
+      animation-delay: .6s;
+      -webkit-animation-name: fade;
+      -webkit-animation-duration: 2s;
+      -webkit-animation-iteration-count: infinite;
+      -webkit-animation-delay: .6s;
+    }
+    @keyframes pulse{
+      0%{
+        -webkit-transform: scale(1);
+        transform: scale(1);
+      }
+      50%{
+        -webkit-transform: scale(0.01);
+        transform: scale(0.01);
+      }
+      100%{
+        -webkit-transform: scale(1);
+        transform: scale(1);
+      }
+    }
+    @keyframes fade{
+      0%{
+        background: #ABF8FF;
+      }
+      50%{
+        background: #90BBBF;
+      }
+      100%{
+        background: #ABF8FF;
+      }
+    }
+    @-webkit-keyframes pulse{
+      0%{
+        -webkit-transform: scale(1);
+        transform: scale(1);
+      }
+      50%{
+        -webkit-transform: scale(0.01);
+        transform: scale(0.01);
+      }
+      100%{
+        -webkit-transform: scale(1);
+        transform: scale(1);
+      }
+    }
+    @-webkit-keyframes fade{
+      0%{
+        background: #ABF8FF;
+      }
+      50%{
+        background: #389CA6;
+      }
+      100%{
+        background: #ABF8FF;
+      }
+    }
+  </style>
   </head>
   <body>
-    <noscript>
-      <strong>We're sorry but default doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
-    </noscript>
-    <div id="app"></div>
-    <!-- built files will be auto injected -->
+    <div id="app">
+	    <div id="loader-wrapper">
+        <div class="socket">
+          <div class="gel center-gel">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c1 r1">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c2 r1">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c3 r1">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c4 r1">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c5 r1">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c6 r1">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c7 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c8 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c9 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c10 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c11 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c12 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c13 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c14 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c15 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c16 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c17 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c18 r2">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c19 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c20 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c21 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c22 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c23 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c24 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c25 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c26 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c28 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c29 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c30 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c31 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c32 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c33 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c34 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c35 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c36 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+          <div class="gel c37 r3">
+            <div class="hex-brick h1"></div>
+            <div class="hex-brick h2"></div>
+            <div class="hex-brick h3"></div>
+          </div>
+        </div>
+		    <!--<div id="loader"></div>-->
+		    <!--<div class="loader-section section-left"></div>-->
+		    <!--<div class="loader-section section-right"></div>-->
+		    <!--<div class="load_title">正在加载系统资源,请耐心等待</div>-->
+      </div>
+	</div>
   </body>
   <script src="./h5player/h5player.min.js" charset="utf-8"></script>
 </html>

+ 2 - 0
public/robots.txt

@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /

+ 38 - 209
src/App.vue

@@ -1,219 +1,48 @@
 <template>
     <div id="app">
-        <p class="null-text" v-if="nullType">{{nullType}}</p>
-        <div class="video-max-box" v-if="buttonType == 1">
-            <H5PlayerVideo class="video-box" v-for="(item,index) in videoList" :key="index"
-                           :videoProps="item" :style="'width:'+item.width+'px;height:'+item.height+'px;'"></H5PlayerVideo>
-        </div>
-        <div class="video-max-box" v-if="buttonType == 2">
-            <H5PlayerVideoTime :videoProps="videoProps"></H5PlayerVideoTime>
-        </div>
+      <router-view/>
     </div>
 </template>
 
 <script>
-    import H5PlayerVideo from './components/H5PlayerVideo.vue';
-    import H5PlayerVideoTime from './components/H5PlayerVideoTime/H5PlayerVideoTime.vue';
-    import { iotCameraFindByCondition,iotCameraGetPlaybackURLs } from "@/api/index";
+  export default  {
+    name:  'App',
+    data(){
+      return{
+      }
+    },
+    metaInfo() {
+      return {
 
-    export default {
-        name: 'app',
-        components: {
-            H5PlayerVideo,
-            H5PlayerVideoTime
-        },
-        data() {
-            return {
-                buttonType: 0,
-                width: null,
-                height: null,
-                videoList: [],
-                nullType:false,
-                //报警视频数据
-                videoProps:null,
-            }
-        },
-        created() {
-            const ratio = 0.5625;
-            const winWidth = window.innerWidth;
-            let width = parseInt(winWidth - 20);
-            let height = parseInt(this.accMul(width, ratio));
-            this.$set(this, 'width', width);
-            this.$set(this, 'height', height)
-        },
-        mounted(){
-            this.getUrl();
-        },
-        methods: {
-            getUrl() {
-                let text = window.location.href;
-                if(text.indexOf('touken') != -1){
-                    this.subVideo(text);
-                }else if(text.indexOf('cameraIndexCode') != -1){
-                    this.warningVideo(text);
-                }else{
-                    this.$set(this,'nullType','参数异常,请联系管理员');
-                }
-            },
-            warningVideo(text){
-                let self = this;
-                if(text.indexOf('cameraIndexCode') == -1){
-                    this.$set(this,'nullType','cameraIndexCode参数异常,请联系管理员');
-                    return
-                }
-                if(text.indexOf('startTime') == -1){
-                    this.$set(this,'nullType','startTime参数异常,请联系管理员');
-                    return
-                }
-                if(text.indexOf('endTime') == -1){
-                    this.$set(this,'nullType','endTime参数异常,请联系管理员');
-                    return
-                }
-                let urlList = text.split("?")[1].split("&");
-                let urlData = {};
-                urlList.forEach((item) => {
-                    urlData[item.split("=")[0]] = item.split("=")[1];
-                });
-                //视频回放流地址
-                let obj = {
-                    cameraIndexCode :urlData.cameraIndexCode, //摄像头编号
-                    protocol:window.location.href.indexOf('https') !== -1?'wss':'ws',
-                    startTime:urlData.startTime,    //开始时间 2025-03-07 09:29:00
-                    endTime :urlData.endTime,    //结束时间
-                }
-                iotCameraGetPlaybackURLs(obj).then(response => {
-                    let newObj = {
-                        width: this.width, //(宽度:非必传-默认600)
-                        height: this.height, //(高度:非必传-默认338)
-                        url: response.data,
-                        cameraIndexCode: obj.cameraIndexCode,
-                    }
-                    this.$set(this,'videoProps',newObj);
-                    this.$nextTick(()=>{
-                        setTimeout(function(){
-                            self.$set(self, 'buttonType', 2);
-                        },1000);
-                    })
-                })
-            },
-            subVideo(text){
-                let self = this;
-                if(text.indexOf('touken') == -1){
-                    this.$set(this,'nullType','touken参数异常,请联系管理员');
-                    return
-                }
-                if(text.indexOf('source') == -1){
-                    this.$set(this,'nullType','source参数异常,请联系管理员');
-                    return
-                }
-                if(text.indexOf('type') == -1){
-                    this.$set(this,'nullType','type参数异常,请联系管理员');
-                    return
-                }
-                let urlList = text.split("?")[1].split("&");
-                let urlData = {};
-                urlList.forEach((item) => {
-                    urlData[item.split("=")[0]] = item.split("=")[1];
-                });
-                localStorage.setItem('touken',urlData.touken)
-                // type 1.楼栋 2.楼层 3.楼道 4.实验室 5.楼道+实验室
-                let obj = {
-                    page:'1',
-                    pageSize:'4',
-                    protocol:window.location.href.indexOf('https') !== -1?'wss':'ws',
-                };
-                if(urlData.type == 1){
-                    obj.buildId = urlData.buildId;
-                }else  if(urlData.type == 2){
-                    obj.floorId = urlData.floorId;
-                }else  if(urlData.type == 3){
-                    obj.passageway = urlData.floorId;
-                }else  if(urlData.type == 4){
-                    obj.subIds = [urlData.subId];
-                }else if(urlData.type == 5){
-                    obj.passageway = urlData.floorId;
-                    obj.subIds = [urlData.subId];
-                }
-                if(urlData.source == '2'){
-                    obj.source = 2;
-                }else if (urlData.source == '5'){
-                    obj.source = 5;
-                }
-                if(urlData.type){
-                    iotCameraFindByCondition(obj).then(response => {
-                        if (!response.data.records[0]){
-                            this.$set(this,'nullType','视频异常,请联系管理员');
-                        }else{
-                            let list = [];
-                            for(let i=0;i<response.data.records.length;i++){
-                                list.push(
-                                    {
-                                        width: this.width, //(宽度:非必传-默认600)
-                                        height: this.height, //(高度:非必传-默认338)
-                                        url: response.data.records[i].streamUrl,
-                                    }
-                                )
-                            }
-                            this.$set(this,'videoList',list)
-                            this.$nextTick(()=>{
-                                setTimeout(function(){
-                                    self.$set(self, 'buttonType', 1);
-                                },1000);
-                            })
-                        }
-                    });
-                }else{
-                    this.$set(this,'nullType','参数异常,请联系管理员');
-                }
-            },
-            //乘法
-            accMul(arg1, arg2) {
-                var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
-                try {
-                    m += s1.split(".")[1].length
-                } catch (e) {
-                }
-                try {
-                    m += s2.split(".")[1].length
-                } catch (e) {
-                }
-                return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
-            },
-        },
-    }
-</script>
-
-<style>
-    html, body {
-        width: 100%;
-        height: 100%;
-    }
+      }
+    },
+    mounted(){
 
-    * {
-        margin: 0;
-        padding: 0;
-    }
+    },
+    methods:{
 
-    #app {
-        font-family: 'Avenir', Helvetica, Arial, sans-serif;
-        -webkit-font-smoothing: antialiased;
-        -moz-osx-font-smoothing: grayscale;
-        text-align: center;
-        color: #2c3e50;
-        width: 100%;
-        height: 100%;
-    }
-    .null-text{
-        text-align: center;
-        font-size:16px;
-        line-height:80px;
-    }
-    .video-max-box {
-        overflow: hidden;
-        padding-top:10px;
-    }
-
-    .video-box {
-        margin: 0 auto 10px;
-    }
+    },
+  }
+</script>
+<style lang="scss">
+  html, body {
+    width: 100%;
+    height: 100%;
+  }
+  * {
+    margin: 0;
+    padding: 0;
+  }
+  #app {
+    font-family: 'Avenir', Helvetica, Arial, sans-serif;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    text-align: center;
+    color: #2c3e50;
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+  }
 </style>

+ 56 - 0
src/README.md

@@ -0,0 +1,56 @@
+## 开发 使用多页面 后端路由设置方法 适配不同学院不同需求
+
+
+
+
+# 针对矿大项目修改      针对布局与疏散图 适配多楼栋 多楼层
+
+views
+  comprehensive
+    laboratoryManagement
+      building
+        indexOne.vue
+      subject
+        indexTwo.vue
+  emergencyManagement
+    evacuation
+      emergencyEvacuation
+        indexOne.vue
+        performEvacuationOne.vue
+  
+静态路由修改项
+  path: '/emergencyEvacuationBig' 地址修改为  emergencyEvacuationBigOne
+  path: '/' 地址修改为  home
+其他修改项
+  *  项目名称修改 => 实验室安全智能监测与控制系统
+  *  取消按钮首页注释  layout => components => Navbar.vue
+        
+        
+        
+        
+        
+# 针对空军四医大项目   实验室-物联设备配置只有传感器与智能门禁
+views
+  comprehensive
+    laboratoryManagement
+      subject
+        indexOne.vue
+    message
+      noticeconfig
+        indexOne.vue
+    system
+      publicConfig
+        indexOne.vue
+    personnel
+      teacher
+        indexOne.vue
+  mine
+    indexOne.vue
+    
+静态路由修改项
+  path: '/login' 地址修改为  loginOne
+  path: '/' 地址修改为  loginOne
+其他修改项
+  *  项目名称修改 => 危化品智能存储管理系统
+  *  按钮首页注释掉  layout => components => Navbar.vue
+

+ 8 - 0
src/api/index.js

@@ -16,3 +16,11 @@ export function iotCameraGetPlaybackURLs(query) {
     params: query
   })
 }
+//根据设备ID获取摄像头流地址
+export function iotCameraGetPreviewURLs(query) {
+  return request({
+    url: '/iot/camera/getPreviewURLs',
+    method: 'get',
+    params: query
+  })
+}

+ 17 - 29
src/components/H5PlayerVideo.vue

@@ -1,8 +1,7 @@
 <template>
     <div class="H5PlayerVideo">
         <div :id="videoData.id" :ref="videoData.id"></div>
-        <p class="full-screen-button" v-if="!fullScreenType" @click="fullScreen"></p>
-        <p class="full-failed-button" v-if="fullScreenType" @click="outFullScreen"></p>
+        <p class="full-screen-button" @click="fullScreen"></p>
     </div>
 </template>
 
@@ -14,7 +13,6 @@
         },
         data() {
             return {
-                fullScreenType:false,
                 videoCover: localStorage.getItem('fileBrowseEnvironment') + localStorage.getItem('videoCover'),
                 videoData: {},
             }
@@ -37,40 +35,30 @@
         methods: {
             //全屏
             fullScreen() {
-                let self = this;
+              let self = this;
+              if(this.$parent.$parent.stopTime){
+                this.$parent.$parent.stopTime(this.videoProps.cameraIndexCode);
+              }else if(this.$parent.stopTime){
+                this.$parent.stopTime(this.videoProps.cameraIndexCode);
+              }else{
                 this.myPlugin.JS_FullScreenDisplay(true).then(
-                    (res) => {
-                        console.info('JS_FullScreenDisplay success');
-                        // do you want...
-                    },
-                    (err) => {
-                        console.info('JS_FullScreenDisplay failed');
-                        // do you want...
-                    }
-                );
-                self.$set(self,'fullScreenType',true);
-            },
-            //退出全屏
-            outFullScreen() {
-                let self = this;
-                this.myPlugin.JS_FullScreenDisplay(false).then(
-                    (res) => {
-                        console.info('JS_FullScreenDisplay success');
-                        // do you want...
-                    },
-                    (err) => {
-                        console.info('JS_FullScreenDisplay failed');
-                        // do you want...
-                    }
+                  (res) => {
+                    // console.info('JS_FullScreenDisplay success');
+                    // do you want...
+                  },
+                  (err) => {
+                    // console.info('JS_FullScreenDisplay failed');
+                    // do you want...
+                  }
                 );
-                self.$set(self,'fullScreenType',false);
+              }
             },
             initH5Player(split) {
                 this.myPlugin = new window.JSPlugin({
                     szId: this.videoData.id, //需要英文字母开头,唯一性,必填
                     szBasePath: '/h5player/', // 必填,与h5player.min.js的引用目录一致 填写的是pulblic下的路径!!!
                     bSupporDoubleClickFull: true,//是否支持双击全屏,默认true
-                    openDebug: true,
+                    openDebug: false,
                     oStyle: {
                         borderSelect: '#000'
                     },

+ 1 - 21
src/components/H5PlayerVideoTime/H5PlayerVideoTime.vue

@@ -1,11 +1,8 @@
 <template>
   <div class="H5PlayerVideoTime">
     <div :id="videoData.id" :ref="videoData.id"></div>
-    <p class="full-screen-button" v-if="!fullScreenType" @click="fullScreen"></p>
-    <p class="full-failed-button" v-if="fullScreenType" @click="outFullScreen"></p>
+    <p class="full-screen-button" @click="fullScreen"></p>
     <timeInput ref="progressBar"  class="timeInput-max-big-box"></timeInput>
-    <!--<p class="full-screen-button" @click="fullScreen"></p>-->
-    <!--<p class="full-failed-button" v-if="fullScreenType" @click="outFullScreen"></p>-->
   </div>
 </template>
 
@@ -21,7 +18,6 @@
     },
     data() {
       return {
-        fullScreenType:false,
         videoCover: localStorage.getItem('fileBrowseEnvironment') + localStorage.getItem('videoCover'),
         videoData: {},
       }
@@ -59,24 +55,8 @@
               // do you want...
             }
           );
-          this.$set(this,'fullScreenType',false);
         }
       },
-      //退出全屏
-      outFullScreen() {
-        let self = this;
-        this.myPlugin.JS_FullScreenDisplay(false).then(
-          (res) => {
-            console.info('JS_FullScreenDisplay success');
-            // do you want...
-          },
-          (err) => {
-            console.info('JS_FullScreenDisplay failed');
-            // do you want...
-          }
-        );
-        self.$set(self,'fullScreenType',false);
-      },
       initH5Player(split) {
         this.myPlugin = new window.JSPlugin({
           szId: this.videoData.id, //需要英文字母开头,唯一性,必填

+ 33 - 2
src/components/H5PlayerVideoTime/fullH5PlayerVideo.vue

@@ -2,7 +2,7 @@
   <div class="fullH5PlayerVideo">
     <div style="height:100%;width:100%;" :id="videoData.id+'full'" :ref="videoData.id"></div>
     <p class="full-failed-button" @click="outFullScreen"></p>
-    <timeInput ref="progressBarTime"></timeInput>
+    <timeInput ref="progressBarTime" class="timeInput-box"></timeInput>
   </div>
 </template>
 
@@ -141,6 +141,23 @@
           () => {
             // console.info('JS_Play success')
             // do you want...
+            //开启声音
+            this.myPlugin.JS_OpenSound().then(
+              () => {
+                console.log('openSound success')
+              },
+              e => {
+                console.error('声音开启失败',e)
+              }
+            )
+            this.myPlugin.JS_Rotate(this.myPlugin.currentWindowIndex, 90).then(
+              () => {
+                console.log('rotate success')
+              },
+              err => {
+                console.error('屏幕旋转失败', err)
+              }
+            )
           },
           (err) => {
             // console.info('JS_Play failed:', err)
@@ -232,9 +249,23 @@
     width: 50px;
     line-height: 30px;
     text-align: center;
-    top: 40px;
+    bottom: 40px;
     right: 40px;
     z-index: 12;
     cursor: pointer;
   }
+  .timeInput-box{
+    /* 固定定位 */
+    position: fixed;
+    left: 0;
+    bottom: 0px;
+    width: 100vh;
+
+    /* 旋转设置 */
+    transform: rotate(-270deg) translateX(-100%);
+    transform-origin: left bottom;
+    /* 防止点击区域问题 */
+    cursor: pointer;
+    z-index: 1000;
+  }
 </style>

+ 227 - 0
src/components/fullH5PlayerVideo.vue

@@ -0,0 +1,227 @@
+<template>
+  <div class="fullH5PlayerVideo">
+    <div style="height:100%;width:100%;" :id="videoData.id+'full'" :ref="videoData.id"></div>
+    <p class="full-failed-button" @click="outFullScreen"></p>
+  </div>
+</template>
+
+<script>
+import { iotCameraGetPreviewURLs } from '@/api/index'
+  export default {
+    name: 'fullH5PlayerVideo',
+    props: {
+      fullVideoProps: {}
+    },
+    data() {
+      return {
+        fullScreenType:false,
+        videoCover: localStorage.getItem('fileBrowseEnvironment') + localStorage.getItem('videoCover'),
+        videoData: {},
+        //全屏相关
+        innerWidth:window.innerWidth,
+        innerHeight:window.innerHeight,
+        myPlugin:null,
+      }
+    },
+    created() {
+    },
+    mounted() {
+      this.iotCameraGetPreviewURLs();
+    },
+    methods: {
+      iotCameraGetPreviewURLs(){
+        let obj = {
+          streamType:0,
+          cameraIndexCode:this.fullVideoProps.cameraIndexCode,
+          protocol: window.location.href.indexOf('https') !== -1 ? 'wss' : 'ws',
+        }
+        iotCameraGetPreviewURLs(obj).then(response => {
+          this.$set(this, 'videoData', {
+            id: 'video_' + this.generateRandomString(),
+            url: response.data
+          })
+          this.$nextTick(() => {
+            this.initH5Player(1)
+            let type = response.data.indexOf('wss') !== -1?1:0;
+            this.initPlayer(this.videoData.url, 0,type)
+          })
+        })
+      },
+      //全屏
+      fullScreen() {
+        let self = this;
+        if(this.$parent.stopTime){
+          this.$parent.stopTime(JSON.parse(JSON.stringify(this.fullVideoProps)));
+        }else{
+          this.myPlugin.JS_FullScreenDisplay(true).then(
+            (res) => {
+              // console.info('JS_FullScreenDisplay success');
+              // do you want...
+            },
+            (err) => {
+              // console.info('JS_FullScreenDisplay failed');
+              // do you want...
+            }
+          );
+          self.$set(self,'fullScreenType',true);
+        }
+      },
+      //退出全屏
+      outFullScreen() {
+        this.$parent.outFullScreen();
+      },
+      initH5Player(split) {
+        this.myPlugin = new window.JSPlugin({
+          szId: this.videoData.id+'full', //需要英文字母开头,唯一性,必填
+          szBasePath: '/h5player/', // 必填,与h5player.min.js的引用目录一致 填写的是pulblic下的路径!!!
+          bSupporDoubleClickFull: false,//是否支持双击全屏,默认true
+          openDebug: false,
+          oStyle: {
+            borderSelect: '#000'
+          },
+          // 当容器div#play_window有固定宽高时,可不传iWidth和iHeight,窗口大小将自适应容器宽高
+          // iWidth: this.innerWidth,
+          // iHeight: this.innerHeight,
+          // 分屏播放,默认最大分屏4*4
+          iMaxSplit: split,
+          iCurrentSplit: split
+        })
+        let iWndNum = 1;
+        let InterruptTime = 5;
+        this.myPlugin.JS_SetInterruptTime(iWndNum, InterruptTime).then(
+          () => {
+            // console.info('JS_SetInterruptTime success');
+            // do you want...
+          },
+          (err) => {
+            // console.info('JS_SetInterruptTime failed');
+            // do you want...
+          }
+        );
+        // 事件回调绑定
+        this.myPlugin.JS_SetWindowControlCallback({
+          windowEventSelect: function (iWndIndex) {  //插件选中窗口回调
+            // console.log('windowSelect callback: ', iWndIndex)
+          },
+          pluginErrorHandler: function (iWndIndex, iErrorCode, oError) {  //插件错误回调
+            // console.log('pluginError callback: ', iWndIndex, iErrorCode, oError)
+          },
+          windowEventOver: function (iWndIndex) {  //鼠标移过回调
+            //console.log(iWndIndex);
+          },
+          windowEventOut: function (iWndIndex) {  //鼠标移出回调
+            //console.log(iWndIndex);
+          },
+          windowEventUp: function (iWndIndex) {  //鼠标mouseup事件回调
+            //console.log(iWndIndex);
+          },
+          windowFullCcreenChange: function (bFull) {  //全屏切换回调
+            // console.log('fullScreen callback: ', bFull)
+          },
+          firstFrameDisplay: function (iWndIndex, iWidth, iHeight) {  //首帧显示回调
+            // console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight)
+          },
+          performanceLack: function () {  //性能不足回调
+            // console.log('performanceLack callback: ')
+          }
+        })
+      },
+      initPlayer(url, index, type) {
+        let self = this;
+        this.myPlugin.JS_Play(url,
+          {
+            playURL: url, // 流媒体播放时必传
+            mode: type?type:0 // 解码类型:0=普通模式; 1=高级模式 默认为0
+            // ...
+          },
+          index //当前窗口下标
+        ).then(
+          () => {
+            // console.info('JS_Play success')
+            // do you want...
+            //开启声音
+            this.myPlugin.JS_OpenSound().then(
+              () => {
+                console.log('openSound success')
+              },
+              e => {
+                console.error('声音开启失败',e)
+              }
+            )
+            this.myPlugin.JS_Rotate(this.myPlugin.currentWindowIndex, 90).then(
+              () => {
+                console.log('rotate success')
+              },
+              err => {
+                console.error('屏幕旋转失败', err)
+              }
+            )
+          },
+          (err) => {
+            // console.info('JS_Play failed:', err)
+            // do you want...
+          }
+        )
+      },
+      //生成随机ID
+      generateRandomString() {
+        let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
+        let randomString = ''
+        for (let i = 0; i < 24; i++) {
+          let randomIndex = Math.floor(Math.random() * chars.length)
+          randomString += chars.charAt(randomIndex)
+        }
+        return randomString
+      },
+      videoOff() {
+        this.myPlugin.JS_StopRealPlayAll().then(
+          () => {
+            // console.info('JS_StopRealPlayAll success')
+            // do you want...
+          },
+          (err) => {
+            // console.info('JS_StopRealPlayAll failed')
+            // do you want...
+          }
+        )
+      }
+    },
+    beforeDestroy() {
+      let self = this
+      self.videoOff()
+    }
+  }
+</script>
+
+<style scoped lang="scss">
+  .fullH5PlayerVideo {
+    z-index:1000;
+    margin: 0;
+    padding: 0;
+    display: inline-block;
+    height: 100%;
+    width:100%;
+    position: fixed;
+    top:0;
+    left:0;
+    * {
+      margin: 0;
+      padding: 0;
+    }
+    /*position: relative;*/
+    .full-failed-button {
+      background: url("../assets/icon_1.png");
+      background-size: 100%;
+      position: fixed;
+      font-size: 20px;
+      height: 50px;
+      width: 50px;
+      line-height: 30px;
+      text-align: center;
+      bottom: 40px;
+      right: 40px;
+      z-index:1001;
+      cursor: pointer;
+    }
+  }
+</style>

+ 42 - 3
src/main.js

@@ -1,8 +1,47 @@
 import Vue from 'vue'
-import App from './App.vue'
+
+import VueRouter from 'vue-router'
+import Cookies from 'js-cookie'
+import App from './App'
+import store from './store'
+import router from './router'
+
+
+Vue.prototype.msgSuccess = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "success", offset:100 });
+}
+
+Vue.prototype.msgError = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "error", offset:100 });
+}
+
+Vue.prototype.msgInfo = function (msg) {
+  this.$message.info(msg);
+}
+
+/**
+ * If you don't want to use mock-server
+ * you want to use MockJs for mock api
+ * you can execute: mockXHR()
+ *
+ * Currently MockJs will be used in the production environment,
+ * please remove it before going online! ! !
+ */
 
 Vue.config.productionTip = false
 
+// 避免路由冗余导航
+const originalPush = VueRouter.prototype.push
+VueRouter.prototype.push = function push(location) {
+  return originalPush.call(this, location).catch(err => err)
+}
+const originalReplace = VueRouter.prototype.replace
+VueRouter.prototype.replace = function replace(location) {
+  return originalReplace.call(this, location).catch(err => err)
+}
 new Vue({
-  render: h => h(App),
-}).$mount('#app')
+  el: '#app',
+  router,
+  store,
+  render: h => h(App)
+})

+ 60 - 0
src/permission.js

@@ -0,0 +1,60 @@
+import router from './router'
+import store from './store'
+import { Message } from 'element-ui'
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+import { getToken } from '@/utils/auth'
+
+NProgress.configure({ showSpinner: false })
+
+const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
+
+router.beforeEach((to, from, next) => {
+  NProgress.start()
+  if (getToken()) {
+    to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
+    /* has token*/
+    if (to.path === '/login') {
+      next({ path: '/' })
+      NProgress.done()
+    } else {
+      if (store.getters.roles.length === 0) {
+        // 判断当前用户是否已拉取完user_info信息
+        store.dispatch('GetInfo').then(() => {
+          store.dispatch('GenerateRoutes').then(accessRoutes => {
+            // 根据roles权限生成可访问的路由表
+            router.addRoutes(accessRoutes) // 动态添加可访问路由表
+            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
+          })
+        }).catch(err => {
+            store.dispatch('LogOut').then(() => {
+              Message.error(err)
+              next({ path: '/' })
+            })
+          })
+      } else {
+        next()
+      }
+    }
+  } else {
+    if(to.path == '/codeHtml' || to.path === '/bigDataLogin'){
+      next()
+      return
+    }
+    // 没有token
+    if (whiteList.indexOf(to.path) !== -1) {
+      // 在免登录白名单,直接进入
+      next()
+    } else {
+      router.replace({
+        path: '/login'
+      })
+      // next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
+      NProgress.done()
+    }
+  }
+})
+
+router.afterEach(() => {
+  NProgress.done()
+})

+ 32 - 0
src/router/index.js

@@ -0,0 +1,32 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+Vue.use(Router)
+// 公共路由
+export const constantRoutes = [
+  {
+    path: '/',
+    component: (resolve) => require(['@/views/home'], resolve),
+    hidden: true
+  },
+  // {
+  //   path: '/miniProgramPlayback',
+  //   component: (resolve) => require(['@/views/miniProgramPlayback/index'], resolve),
+  //   hidden: true
+  // },
+  // {
+  //   path: '/miniProgramVideo',
+  //   component: (resolve) => require(['@/views/miniProgramVideo/index'], resolve),
+  //   hidden: true
+  // },
+  {
+    path: '/miniProgramAuthentication',
+    component: (resolve) => require(['@/views/miniProgramAuthentication/index'], resolve),
+    hidden: true
+  },
+]
+
+export default new Router({
+  mode: 'hash', // 去掉url中的#
+  scrollBehavior: () => ({ y: 0 }),
+  routes: constantRoutes
+})

+ 44 - 0
src/settings.js

@@ -0,0 +1,44 @@
+module.exports = {
+  /**
+   * 侧边栏主题 深色主题theme-dark,浅色主题theme-light
+   */
+  sideTheme: 'theme-dark',
+
+  /**
+   * 是否系统布局配置
+   */
+  showSettings: false,
+
+  /**
+   * 是否显示顶部导航
+   */
+  topNav: true,
+
+  /**
+   * 是否显示 tagsView
+   */
+  tagsView: true,
+
+  /**
+   * 是否固定头部
+   */
+  fixedHeader: false,
+
+  /**
+   * 是否显示logo
+   */
+  sidebarLogo: true,
+
+  /**
+   * 是否显示动态标题
+   */
+  dynamicTitle: false,
+
+  /**
+   * @type {string | array} 'production' | ['production', 'development']
+   * @description Need show err logs component.
+   * The default is only used in the production env
+   * If you want to also use it in dev, you can pass ['production', 'development']
+   */
+  errorLog: 'production'
+}

+ 18 - 0
src/store/getters.js

@@ -0,0 +1,18 @@
+const getters = {
+  sidebar: state => state.app.sidebar,
+  size: state => state.app.size,
+  device: state => state.app.device,
+  visitedViews: state => state.tagsView.visitedViews,
+  cachedViews: state => state.tagsView.cachedViews,
+  token: state => state.user.token,
+  avatar: state => state.user.avatar,
+  name: state => state.user.name,
+  introduction: state => state.user.introduction,
+  roles: state => state.user.roles,
+  permissions: state => state.user.permissions,
+  permission_routes: state => state.permission.routes,
+  topbarRouters:state => state.permission.topbarRouters,
+  defaultRoutes:state => state.permission.defaultRoutes,
+  sidebarRouters:state => state.permission.sidebarRouters,
+}
+export default getters

+ 21 - 0
src/store/index.js

@@ -0,0 +1,21 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import user from './modules/user'
+import tagsView from './modules/tagsView'
+import settings from './modules/settings'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  modules: {
+    app,
+    user,
+    tagsView,
+    settings,
+  },
+  getters
+})
+
+export default store

+ 56 - 0
src/store/modules/app.js

@@ -0,0 +1,56 @@
+import Cookies from 'js-cookie'
+
+const state = {
+  sidebar: {
+    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
+    withoutAnimation: false
+  },
+  device: 'desktop',
+  size: Cookies.get('size') || 'medium'
+}
+
+const mutations = {
+  TOGGLE_SIDEBAR: state => {
+    state.sidebar.opened = !state.sidebar.opened
+    state.sidebar.withoutAnimation = false
+    if (state.sidebar.opened) {
+      Cookies.set('sidebarStatus', 1)
+    } else {
+      Cookies.set('sidebarStatus', 0)
+    }
+  },
+  CLOSE_SIDEBAR: (state, withoutAnimation) => {
+    Cookies.set('sidebarStatus', 0)
+    state.sidebar.opened = false
+    state.sidebar.withoutAnimation = withoutAnimation
+  },
+  TOGGLE_DEVICE: (state, device) => {
+    state.device = device
+  },
+  SET_SIZE: (state, size) => {
+    state.size = size
+    Cookies.set('size', size)
+  }
+}
+
+const actions = {
+  toggleSideBar({ commit }) {
+    commit('TOGGLE_SIDEBAR')
+  },
+  closeSideBar({ commit }, { withoutAnimation }) {
+    commit('CLOSE_SIDEBAR', withoutAnimation)
+  },
+  toggleDevice({ commit }, device) {
+    commit('TOGGLE_DEVICE', device)
+  },
+  setSize({ commit }, size) {
+    commit('SET_SIZE', size)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}

+ 20 - 0
src/store/modules/plan.js

@@ -0,0 +1,20 @@
+const state = {
+  planSensorList: [],
+}
+const mutations = {
+
+}
+
+const actions = {
+  setTitle({ commit }, list) {
+    state.planSensorList = list
+  },
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
+

+ 58 - 0
src/store/modules/settings.js

@@ -0,0 +1,58 @@
+import defaultSettings from '@/settings'
+
+const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
+
+const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
+const state = {
+  title: '',
+  pageName:"",
+  smartAlarmType:0,//柜锁开关 1开启 0关闭
+  theme: storageSetting.theme,
+  sideTheme: storageSetting.sideTheme || sideTheme,
+  showSettings: showSettings,
+  topNav:  storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
+  tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
+  fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
+  sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
+  dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle,
+  planData:{},
+}
+const mutations = {
+  CHANGE_SETTING: (state, { key, value }) => {
+    if (state.hasOwnProperty(key)) {
+      state[key] = value
+    }
+  }
+}
+
+const actions = {
+  // 修改布局设置
+  changeSetting({ commit }, data) {
+    commit('CHANGE_SETTING', data)
+  },
+  // 设置网页标题
+  setTitle({ commit }, title) {
+    state.title = title
+  },
+  // 设置网页标题
+  setPageName({ commit }, title) {
+    state.pageName = title
+  },
+  // 设置预案数据
+  setPlanData({ commit }, data) {
+    state.planData = data
+  },
+  //锁柜启用状态修改
+  // 设置网页标题
+  setSmartAlarmType({ commit }, title) {
+    state.smartAlarmType = title
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
+

+ 183 - 0
src/store/modules/tagsView.js

@@ -0,0 +1,183 @@
+const state = {
+  visitedViews: [],
+  cachedViews: []
+}
+
+const mutations = {
+  ADD_VISITED_VIEW: (state, view) => {
+    if (state.visitedViews.some(v => v.path === view.path)) return
+    state.visitedViews.push(
+      Object.assign({}, view, {
+        title: view.meta.title || 'no-name'
+      })
+    )
+  },
+  ADD_CACHED_VIEW: (state, view) => {
+    if (state.cachedViews.includes(view.name)) return
+    if (!view.meta.noCache) {
+      state.cachedViews.push(view.name)
+    }
+  },
+
+  DEL_VISITED_VIEW: (state, view) => {
+    for (const [i, v] of state.visitedViews.entries()) {
+      if (v.path === view.path) {
+        state.visitedViews.splice(i, 1)
+        break
+      }
+    }
+  },
+  DEL_CACHED_VIEW: (state, view) => {
+    const index = state.cachedViews.indexOf(view.name)
+    index > -1 && state.cachedViews.splice(index, 1)
+  },
+
+  DEL_OTHERS_VISITED_VIEWS: (state, view) => {
+    state.visitedViews = state.visitedViews.filter(v => {
+      return v.meta.affix || v.path === view.path
+    })
+  },
+  DEL_OTHERS_CACHED_VIEWS: (state, view) => {
+    const index = state.cachedViews.indexOf(view.name)
+    if (index > -1) {
+      state.cachedViews = state.cachedViews.slice(index, index + 1)
+    } else {
+      state.cachedViews = []
+    }
+  },
+
+  DEL_ALL_VISITED_VIEWS: state => {
+    // keep affix tags
+    const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
+    state.visitedViews = affixTags
+  },
+  DEL_ALL_CACHED_VIEWS: state => {
+    state.cachedViews = []
+  },
+
+  UPDATE_VISITED_VIEW: (state, view) => {
+    for (let v of state.visitedViews) {
+      if (v.path === view.path) {
+        v = Object.assign(v, view)
+        break
+      }
+    }
+  },
+  
+  DEL_RIGHT_VIEWS: (state, view) => {
+    const index = state.visitedViews.findIndex(v => v.path === view.path)
+    if (index === -1) {
+      return
+    }
+    state.visitedViews = state.visitedViews.filter((item, idx) => {
+      if (idx <= index || (item.meta && item.meta.affix)) {
+        return true
+      }
+      const i = state.cachedViews.indexOf(item.name)
+      if (i > -1) {
+        state.cachedViews.splice(i, 1)
+      }
+      return false
+    })
+  }
+}
+
+const actions = {
+  addView({ dispatch }, view) {
+    dispatch('addVisitedView', view)
+    dispatch('addCachedView', view)
+  },
+  addVisitedView({ commit }, view) {
+    commit('ADD_VISITED_VIEW', view)
+  },
+  addCachedView({ commit }, view) {
+    commit('ADD_CACHED_VIEW', view)
+  },
+
+  delView({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delVisitedView', view)
+      dispatch('delCachedView', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delVisitedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_VISITED_VIEW', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delCachedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_CACHED_VIEW', view)
+      resolve([...state.cachedViews])
+    })
+  },
+
+  delOthersViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delOthersVisitedViews', view)
+      dispatch('delOthersCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delOthersVisitedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_VISITED_VIEWS', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delOthersCachedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_CACHED_VIEWS', view)
+      resolve([...state.cachedViews])
+    })
+  },
+
+  delAllViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delAllVisitedViews', view)
+      dispatch('delAllCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delAllVisitedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_VISITED_VIEWS')
+      resolve([...state.visitedViews])
+    })
+  },
+  delAllCachedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_CACHED_VIEWS')
+      resolve([...state.cachedViews])
+    })
+  },
+
+  updateVisitedView({ commit }, view) {
+    commit('UPDATE_VISITED_VIEW', view)
+  },
+
+  delRightTags({ commit }, view) {
+    return new Promise(resolve => {
+      commit('DEL_RIGHT_VIEWS', view)
+      resolve([...state.visitedViews])
+    })
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}

+ 70 - 0
src/store/modules/user.js

@@ -0,0 +1,70 @@
+import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth'
+import store from '@/store'
+import router from '@/router'
+import md5 from 'js-md5';
+
+const user = {
+  state: {
+    token: getToken(),
+    name: '',
+    avatar: '',
+    roles: [],
+    permissions: [],
+    messageNum:0,
+  },
+
+  mutations: {
+    SET_TOKEN: (state, token) => {
+      state.token = token
+    },
+    SET_EXPIRES_IN: (state, time) => {
+      state.expires_in = time
+    },
+    SET_NAME: (state, name) => {
+      state.name = name
+    },
+    SET_AVATAR: (state, avatar) => {
+      state.avatar = avatar
+    },
+    SET_ROLES: (state, roles) => {
+      state.roles = roles
+    },
+    SET_PERMISSIONS: (state, permissions) => {
+      state.permissions = permissions
+    },
+    SET_MESSAGE_NUM: (state, num) => {
+      state.messageNum = num
+    }
+  },
+
+  actions: {
+    //不调用退出接口直接清除token
+    LogOutNoData({ commit, state }) {
+      return new Promise((resolve, reject) => {
+        commit('SET_TOKEN', '')
+        commit('SET_ROLES', [])
+        commit('SET_PERMISSIONS', [])
+        removeToken()
+        resolve()
+      })
+    },
+    // 前端 登出
+    FedLogOut({ commit }) {
+      return new Promise(resolve => {
+        commit('SET_TOKEN', '')
+        removeToken()
+        resolve()
+      })
+    },
+    //清除登录数据
+    delToken({ commit, state }){
+      localStorage.clear();
+      commit('SET_TOKEN', '')
+      commit('SET_ROLES', [])
+      commit('SET_PERMISSIONS', [])
+      removeToken()
+    },
+  }
+}
+
+export default user

+ 29 - 0
src/utils/auth.js

@@ -0,0 +1,29 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'System-Platform-School-Token'
+
+const ExpiresInKey = 'System-Platform-School-Expires-In'
+
+export function getToken() {
+  return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+  return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+  return Cookies.remove(TokenKey)
+}
+
+export function getExpiresIn() {
+  return Cookies.get(ExpiresInKey) || -1
+}
+
+export function setExpiresIn(time) {
+  return Cookies.set(ExpiresInKey, time)
+}
+
+export function removeExpiresIn() {
+  return Cookies.remove(ExpiresInKey)
+}

+ 47 - 0
src/views/home.vue

@@ -0,0 +1,47 @@
+<!-- 首页 -->
+<template>
+    <div class="home">
+      <miniProgramPlayback v-if="pageType == 'miniProgramPlayback'"></miniProgramPlayback>
+      <miniProgramVideo v-if="pageType == 'miniProgramVideo'"></miniProgramVideo>
+    </div>
+</template>
+<script>
+    import miniProgramPlayback from '@/views/miniProgramPlayback/index.vue';
+    import miniProgramVideo from '@/views/miniProgramVideo/index.vue';
+    export default {
+        name: 'home',
+        components: {
+          miniProgramPlayback,
+          miniProgramVideo,
+        },
+        data() {
+            return {
+              pageType:null,
+            }
+        },
+        created() {
+
+        },
+        mounted() {
+          let text = decodeURIComponent(window.location.href);
+          text = text.split("?")[1]
+          if(text.indexOf('touken') != -1){
+            // this.$router.push({
+            //   path: '/miniProgramVideo'+'?'+text,
+            // });
+            this.$set(this,'pageType','miniProgramVideo');
+          }else if(text.indexOf('cameraIndexCode') != -1){
+            // this.$router.push({
+            //   path: '/miniProgramPlayback'+'?'+text,
+            // });
+            this.$set(this,'pageType','miniProgramPlayback');
+          }
+        },
+        methods: {},
+    }
+</script>
+<style scoped lang="scss">
+    .home{
+
+    }
+</style>

+ 55 - 0
src/views/miniProgramAuthentication/index.vue

@@ -0,0 +1,55 @@
+<!-- 小程序统一认证 -->
+<template>
+  <div class="miniProgramAuthentication">
+
+  </div>
+</template>
+<script>
+  import wx from "weixin-webview-jssdk";
+  export default {
+    name: 'index',
+    data () {
+      return {}
+    },
+    created () {
+      let url = decodeURIComponent(window.location.href);
+      if (url.indexOf('token') != -1) {
+        let list = url.split("?")[1].split("&");
+        let codeData = {};
+        list.forEach((item) => {
+          codeData[item.split("=")[0]] = item.split("=")[1];
+        });
+        wx.miniProgram.navigateTo({
+          url: '/pages/views/login/ssoCertification?token='+codeData.token
+        })
+      } else if (url.indexOf('code') != -1) {
+        //code 异常状态处理
+        if(url.split('=')[1] == '10100'){
+          //当前用户不存在,请联系管理员!
+          wx.miniProgram.navigateTo({
+            url: '/pages/views/login/ssoCertification?code=10100'
+          })
+        }else if(url.split('=')[1] == '500'){
+          //服务异常,请稍候再试!
+          wx.miniProgram.navigateTo({
+            url: '/pages/views/login/ssoCertification?code=500'
+          })
+        }
+      } else {
+        //跳转至认证页面
+        window.location.href = process.env.VUE_APP_OUT_URL;
+      }
+    },
+    mounted () {
+
+    },
+    methods: {
+
+    },
+  }
+</script>
+<style scoped lang="scss">
+  .miniProgramAuthentication{
+
+  }
+</style>

+ 142 - 0
src/views/miniProgramPlayback/index.vue

@@ -0,0 +1,142 @@
+<!-- 小程序视频回放 -->
+<template>
+  <div class="miniProgramPlayback">
+    <p class="null-text" v-if="nullType">{{nullType}}</p>
+    <div class="video-max-box" v-if="buttonType">
+      <H5PlayerVideoTime :videoProps="videoProps"></H5PlayerVideoTime>
+    </div>
+    <fullH5PlayerVideo v-if="fullVideoType" :fullVideoProps="fullVideoProps"></fullH5PlayerVideo>
+  </div>
+</template>
+<script>
+  import H5PlayerVideoTime from '@/components/H5PlayerVideoTime/H5PlayerVideoTime.vue';
+  import fullH5PlayerVideo from '@/components/H5PlayerVideoTime/fullH5PlayerVideo.vue';
+  import { iotCameraFindByCondition,iotCameraGetPlaybackURLs } from "@/api/index";
+  export default {
+    name: 'index',
+    components: {
+      H5PlayerVideoTime,
+      fullH5PlayerVideo,
+    },
+    data () {
+      return {
+        buttonType: false,
+        width: null,
+        height: null,
+        videoList: [],
+        nullType:false,
+        //报警视频数据
+        videoProps:null,
+        //全屏视频参数
+        fullVideoProps:{},
+        fullVideoType:false,
+      }
+    },
+    created () {
+      const ratio = 0.5625;
+      const winWidth = window.innerWidth;
+      let width = parseInt(winWidth - 20);
+      let height = parseInt(this.accMul(width, ratio));
+      this.$set(this, 'width', width);
+      this.$set(this, 'height', height)
+    },
+    mounted () {
+      this.getUrl();
+    },
+    methods: {
+      //全屏开启-关闭轮播
+      stopTime(videoProps){
+        this.$set(this,'fullVideoProps',videoProps);
+        this.$set(this,'fullVideoType',true);
+        this.$set(this,'videoType',0);
+      },
+      //全屏关闭-开启轮播
+      outFullScreen(){
+        this.$set(this,'fullVideoType',false);
+        this.$set(this,'fullVideoProps',{});
+        this.$set(this,'videoType',1);
+      },
+      getUrl() {
+        let text = decodeURIComponent(window.location.href);
+        if(text.indexOf('cameraIndexCode') != -1){
+          this.warningVideo(text);
+        }else{
+          this.$set(this,'nullType','参数异常,请联系管理员');
+        }
+      },
+      warningVideo(text){
+        let self = this;
+        if(text.indexOf('cameraIndexCode') == -1){
+          this.$set(this,'nullType','cameraIndexCode参数异常,请联系管理员');
+          return
+        }
+        if(text.indexOf('startTime') == -1){
+          this.$set(this,'nullType','startTime参数异常,请联系管理员');
+          return
+        }
+        if(text.indexOf('endTime') == -1){
+          this.$set(this,'nullType','endTime参数异常,请联系管理员');
+          return
+        }
+        let urlList = text.split("?")[1].split("&");
+        let urlData = {};
+        urlList.forEach((item) => {
+          urlData[item.split("=")[0]] = item.split("=")[1];
+        });
+        //视频回放流地址
+        let obj = {
+          cameraIndexCode :urlData.cameraIndexCode, //摄像头编号
+          protocol:window.location.href.indexOf('https') !== -1?'wss':'ws',
+          startTime:urlData.startTime,    //开始时间 2025-03-07 09:29:00
+          endTime :urlData.endTime,    //结束时间
+          streamType:0,
+        }
+        iotCameraGetPlaybackURLs(obj).then(response => {
+          let newObj = {
+            width: this.width, //(宽度:非必传-默认600)
+            height: this.height, //(高度:非必传-默认338)
+            url: response.data,
+            cameraIndexCode: obj.cameraIndexCode,
+          }
+          this.$set(this,'videoProps',newObj);
+          this.$nextTick(()=>{
+            setTimeout(function(){
+              self.$set(self, 'buttonType', true);
+            },1000);
+          })
+        })
+      },
+      //乘法
+      accMul(arg1, arg2) {
+        var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
+        try {
+          m += s1.split(".")[1].length
+        } catch (e) {
+        }
+        try {
+          m += s2.split(".")[1].length
+        } catch (e) {
+        }
+        return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
+      },
+    },
+  }
+</script>
+<style scoped lang="scss">
+  .miniProgramPlayback{
+    flex:1;
+    .null-text{
+      text-align: center;
+      font-size:16px;
+      line-height:80px;
+    }
+    .video-max-box {
+      overflow: hidden;
+      padding-top:10px;
+    }
+
+    .video-box {
+      margin: 0 auto 10px;
+    }
+  }
+</style>

+ 171 - 0
src/views/miniProgramVideo/index.vue

@@ -0,0 +1,171 @@
+<!-- 小程序视频监控 -->
+<template>
+  <div class="miniProgramVideo">
+    <p class="null-text" v-if="nullType">{{nullType}}</p>
+    <div class="video-max-box" v-if="buttonType&&!fullVideoType">
+      <H5PlayerVideo class="video-box" v-for="(item,index) in videoList" :key="index"
+                     :videoProps="item" :style="'width:'+item.width+'px;height:'+item.height+'px;'"></H5PlayerVideo>
+    </div>
+    <fullH5PlayerVideo v-if="fullVideoType" :fullVideoProps="fullVideoProps"></fullH5PlayerVideo>
+  </div>
+</template>
+<script>
+  import H5PlayerVideo from '@/components/H5PlayerVideo.vue';
+  import fullH5PlayerVideo from '@/components/fullH5PlayerVideo.vue';
+  import { iotCameraFindByCondition,iotCameraGetPlaybackURLs } from "@/api/index";
+  export default {
+    name: 'index',
+    components: {
+      H5PlayerVideo,
+      fullH5PlayerVideo
+    },
+    data () {
+      return {
+        buttonType: false,
+        width: null,
+        height: null,
+        videoList: [],
+        nullType:false,
+        //报警视频数据
+        videoProps:null,
+        //全屏视频参数
+        fullVideoProps:{},
+        fullVideoType:false,
+      }
+    },
+    created () {
+      const ratio = 0.5625;
+      const winWidth = window.innerWidth;
+      let width = parseInt(winWidth - 20);
+      let height = parseInt(this.accMul(width, ratio));
+      this.$set(this, 'width', width);
+      this.$set(this, 'height', height)
+    },
+    mounted () {
+      this.getUrl();
+    },
+    methods: {
+      //全屏开启-关闭轮播
+      stopTime(cameraIndexCode){
+        this.$set(this,'fullVideoProps',{cameraIndexCode:cameraIndexCode});
+        this.$set(this,'fullVideoType',true);
+      },
+      //全屏关闭-开启轮播
+      outFullScreen(){
+        this.$set(this,'fullVideoType',false);
+        this.$set(this,'fullVideoProps',{});
+      },
+      getUrl() {
+        let text = decodeURIComponent(window.location.href);
+        if(text.indexOf('touken') != -1){
+          this.subVideo(text);
+        }else{
+          this.$set(this,'nullType','参数异常,请联系管理员');
+        }
+      },
+      subVideo(text){
+        let self = this;
+        if(text.indexOf('touken') == -1){
+          this.$set(this,'nullType','touken参数异常,请联系管理员');
+          return
+        }
+        if(text.indexOf('source') == -1){
+          this.$set(this,'nullType','source参数异常,请联系管理员');
+          return
+        }
+        if(text.indexOf('type') == -1){
+          this.$set(this,'nullType','type参数异常,请联系管理员');
+          return
+        }
+        let urlList = text.split("?")[1].split("&");
+        let urlData = {};
+        urlList.forEach((item) => {
+          urlData[item.split("=")[0]] = item.split("=")[1];
+        });
+        localStorage.setItem('touken',urlData.touken)
+        // type 1.楼栋 2.楼层 3.楼道 4.实验室 5.楼道+实验室
+        let obj = {
+          page:'1',
+          pageSize:'4',
+          protocol:window.location.href.indexOf('https') !== -1?'wss':'ws',
+          streamType:1,
+        };
+        if(urlData.type == 1){
+          obj.buildId = urlData.buildId;
+        }else  if(urlData.type == 2){
+          obj.floorId = urlData.floorId;
+        }else  if(urlData.type == 3){
+          obj.passageway = urlData.floorId;
+        }else  if(urlData.type == 4){
+          obj.subIds = [urlData.subId];
+        }else if(urlData.type == 5){
+          obj.passageway = urlData.floorId;
+          obj.subIds = [urlData.subId];
+        }
+        if(urlData.source == '2'){
+          obj.source = 2;
+        }else if (urlData.source == '5'){
+          obj.source = 5;
+        }
+        if(urlData.type){
+          iotCameraFindByCondition(obj).then(response => {
+            if (!response.data.records[0]){
+              this.$set(this,'nullType','视频异常,请联系管理员');
+            }else{
+              let list = [];
+              for(let i=0;i<response.data.records.length;i++){
+                list.push(
+                  {
+                    width: this.width, //(宽度:非必传-默认600)
+                    height: this.height, //(高度:非必传-默认338)
+                    url: response.data.records[i].streamUrl,
+                    cameraIndexCode: response.data.records[i].deviceNo,
+                  }
+                )
+              }
+              this.$set(this,'videoList',list)
+              this.$nextTick(()=>{
+                setTimeout(function(){
+                  self.$set(self, 'buttonType', true);
+                },1000);
+              })
+            }
+          });
+        }else{
+          this.$set(this,'nullType','参数异常,请联系管理员');
+        }
+      },
+      //乘法
+      accMul(arg1, arg2) {
+        var m = 0, s1 = arg1.toString(), s2 = arg2.toString();
+        try {
+          m += s1.split(".")[1].length
+        } catch (e) {
+        }
+        try {
+          m += s2.split(".")[1].length
+        } catch (e) {
+        }
+        return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
+      },
+    },
+  }
+</script>
+<style scoped lang="scss">
+  .miniProgramVideo{
+    flex:1;
+    .null-text{
+      text-align: center;
+      font-size:16px;
+      line-height:80px;
+    }
+    .video-max-box {
+      overflow: hidden;
+      padding-top:10px;
+    }
+
+    .video-box {
+      margin: 0 auto 10px;
+    }
+  }
+</style>

+ 240 - 2
vue.config.js

@@ -1,7 +1,245 @@
+'use strict'
+const path = require('path')
+
+// const ip = '192.168.1.43'
+// const os = require('os')
+// const fs = require("fs")
+// //判断环境
+// let ifaces = os.networkInterfaces()
+// let localityIp = '', result = []
+// for(let dev in ifaces) {
+//   ifaces[dev].forEach(function(details) {
+//     if(localityIp === '' && details.family === 'IPv4' && !details.internal) {
+//       localityIp = details.address
+//       return;
+//     }
+//   })
+// }
+// let getFile = localityIp == ip?false:true
+// /******** 获取git版本信息 ********/
+// const gitHEAD = getFile ? fs.readFileSync('.git/HEAD', 'utf-8').trim() : false
+// const ref = getFile ? gitHEAD.split(': ')[1] : false
+// const develop = getFile ? gitHEAD.split('/')[2] : false
+// const gitVersion = getFile ? fs.readFileSync('.git/' + ref, 'utf-8').trim() : false
+// const buildEdition = develop && gitVersion ? develop + ': ' + gitVersion : '未配置'
+// const myDate = new Date()
+// const buildTime = myDate.getFullYear() +'-'+ (myDate.getMonth()+1) +'-'+ myDate.getDate() +' '+ myDate.getHours() +':'+ myDate.getMinutes();
+// const logsList = getFile ? fs.readFileSync('.git/logs/HEAD', 'utf-8').replace(/\r\n|\r/g, "\n").split("\n") : false
+// const buildUser = getFile ? logsList[logsList.length-2].split(" ")[2] : '未配置'
+// //生成随机版本编码
+// const revision = generateRandomString()
+// process.env.VUE_APP_RENEWAL_ENCODING = revision
+// require('fs').writeFileSync('public/version.txt', revision)
+// function generateRandomString() {
+//   let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+//   let randomString = "";
+//   for (let i = 0; i < 24; i++) {
+//     let randomIndex = Math.floor(Math.random() * chars.length);
+//     randomString += chars.charAt(randomIndex);
+//   }
+//   return randomString;
+// }
+function resolve(dir) {
+  return path.join(__dirname, dir)
+}
+
+const name = process.env.VUE_APP_TITLE || '实验室安全智慧化管控系统' // 网页标题
+
+const port = process.env.port || process.env.npm_config_port || 80 // 端口
+
+// vue.mqttConfig.js说明
+// 官方vue.mqttConfig.js文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
+// 这里只列一部分,具体配置参考文档
 module.exports = {
-  publicPath: "/stream",
+  // 部署生产环境和开发环境下的URL。
+  // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
+  publicPath: process.env.NODE_ENV === "production" ? "./" : "./",
   // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
   outputDir: 'dist',
   // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
-  assetsDir: 'static'
+  assetsDir: 'static',
+  // 是否开启eslint保存检测,有效值:ture | false | 'error'
+  lintOnSave: process.env.NODE_ENV === 'development',
+  // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
+  productionSourceMap: false,
+  // webpack-dev-server 相关配置
+  devServer: {
+    host: '0.0.0.0',
+    port: port,
+    open: true,
+    proxy: {
+      // detail: https://cli.vuejs.org/config/#devserver-proxy
+      [process.env.VUE_APP_BASE_API]: {
+        target: `http://localhost:8080`,
+        changeOrigin: true,
+        pathRewrite: {
+          ['^' + process.env.VUE_APP_BASE_API]: ''
+        }
+      }
+    },
+    disableHostCheck: true,
+  },
+  //修改了sass版本从1.32.0 升级至1.39.0  以解决页面小图标偶发性乱码问题 以下css代码为同步增加
+  css: {
+    loaderOptions: {
+      sass: {
+        sassOptions: {
+          outputStyle: 'expanded'
+        }
+      }
+    }
+  },
+  configureWebpack: {
+    name: name,
+    resolve: {
+      alias: {
+        '@': resolve('src')
+      }
+    }
+  },
+  chainWebpack(config) {
+    config.plugins.delete('preload') // TODO: need test
+    config.plugins.delete('prefetch') // TODO: need test
+
+
+    // 图片转base64
+    // const imagesRule = config.module.rule('images');
+    // imagesRule.uses.clear()        //清除原本的images loader配置
+    // imagesRule
+    //   .test(/\.(jpg|gif|png|svg)$/)
+    //   .exclude
+    //   .add(path.join(__dirname,"../node_modules"))//去除node_modules里的图片转base64配置
+    //   .end()
+    //   .use('url-loader')
+    //   .loader('url-loader')
+    //   .options({name:"img/[name].[hash:8].[ext]",limit: 1})
+
+    //标记打包时间与当前git版本信息
+    // config.plugin('html').tap(args => {
+    //   args[0].buildUser = buildUser;
+    //   args[0].buildTime = buildTime;
+    //   args[0].buildEdition = buildEdition;
+    //   return args
+    // })
+    // set svg-sprite-loader
+    config.module
+      .rule('svg')
+      .exclude.add(resolve('src/assets/icons'))
+      .end()
+    config.module
+      .rule('icons')
+      .test(/\.svg$/)
+      .include.add(resolve('src/assets/icons'))
+      .end()
+      .use('svg-sprite-loader')
+      .loader('svg-sprite-loader')
+      .options({
+        symbolId: 'icon-[name]'
+      })
+      .end()
+
+
+    config
+      .plugin('ScriptExtHtmlWebpackPlugin')
+      .after('html')
+      .use('script-ext-html-webpack-plugin', [{
+        // `runtime` must same as runtimeChunk name. default is `runtime`
+        inline: /runtime\..*\.js$/
+      }])
+      .end()
+    config.optimization.splitChunks({
+      chunks: 'all',
+      cacheGroups: {
+        libs: {
+          name: 'chunk-libs',
+          test: /[\\/]node_modules[\\/]/,
+          priority: 10,
+          chunks: 'initial' // only package third parties that are initially dependent
+        },
+        elementUI: {
+          name: 'chunk-elementUI', // split elementUI into a single package
+          priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+          test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+        },
+        echarts: {
+          name: 'chunk-echarts',
+          priority: 20,
+          test: /[\\/]node_modules[\\/]_?echarts(.*)/
+        },
+        flv: {
+          name: 'chunk-flv',
+          priority: 20,
+          test: /[\\/]node_modules[\\/]_?flv(.*)/
+        },
+        jsBeautify: {
+          name: 'chunk-vue-js-beautify',
+          priority: 20,
+          test: /[\\/]node_modules[\\/]_?js-beautify(.*)/
+        },
+        jsencrypt: {
+          name: 'chunk-vue-jsencrypt',
+          priority: 20,
+          test: /[\\/]node_modules[\\/]_?jsencrypt(.*)/
+        },
+        api: {
+          name: 'chunk-api',
+          test: resolve('src/api'),
+          priority: 0,
+          minSize: 0,
+          minChunks: 1,
+          enforce:true,
+          reuseExistingChunk: true
+        },
+        assets: {
+          name: 'chunk-assets',
+          test: resolve('src/assets'),
+          priority: 0,
+          minSize: 0,
+          minChunks: 1,
+          enforce:true,
+          reuseExistingChunk: true
+        },
+        commons: {
+          name: 'chunk-commons',
+          test: resolve('src/components'),
+          priority: 0,
+          minSize: 0,
+          minChunks: 1,
+          enforce:true,
+          reuseExistingChunk: true
+        },
+        directive: {
+          name: 'chunk-directive',
+          test: resolve('src/directive'),
+          priority: 0,
+          minSize: 0,
+          minChunks: 1,
+          enforce:true,
+          reuseExistingChunk: true
+        },
+        utils: {
+          name: 'chunk-utils',
+          test: resolve('src/utils'),
+          priority: 0,
+          minSize: 0,
+          minChunks: 1,
+          enforce:true,
+          reuseExistingChunk: true
+        },
+        comprehensive: {
+          name: 'chunk-views',
+          test: resolve('src/views'),
+          priority: 0,
+          minSize: 0,
+          minChunks: 1,
+          enforce:true,
+          reuseExistingChunk: true
+        },
+      }
+    })
+    config.optimization.runtimeChunk('single'),{
+      from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
+      to: './', //到根目录下
+    }
+  }
 }