增加新版本web页面
57
install.sh
Normal file
@@ -0,0 +1,57 @@
|
||||
#! /bin/sh
|
||||
|
||||
WORD_DIR=$(cd $(dirname $0); pwd)
|
||||
SERVICE_NAME="wvp"
|
||||
|
||||
# 检查是否为 root 用户
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "提示: 建议使用 root 用户执行此脚本,否则可能权限不足!"
|
||||
read -p "继续?(y/n) " -n 1 -r
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
|
||||
# 当前目录直接搜索(不含子目录)
|
||||
jar_files=(*.jar)
|
||||
|
||||
if [ ${#jar_files[@]} -eq 0 ]; then
|
||||
echo "当前目录无 JAR 文件!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 遍历结果
|
||||
for jar in "${jar_files[@]}"; do
|
||||
echo "找到 JAR 文件: $jar"
|
||||
done
|
||||
|
||||
# 写文件
|
||||
# 生成 Systemd 服务文件内容
|
||||
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
cat << EOF | sudo tee "$SERVICE_FILE" > /dev/null
|
||||
[Unit]
|
||||
Description=${SERVICE_NAME}
|
||||
After=syslog.target
|
||||
|
||||
[Service]
|
||||
User=$USER
|
||||
WorkingDirectory=${WORD_DIR}
|
||||
ExecStart=java -jar ${jar_files}
|
||||
SuccessExitStatus=143
|
||||
Restart=on-failure
|
||||
RestartSec=10s
|
||||
Environment=SPRING_PROFILES_ACTIVE=prod
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# 重载 Systemd 并启动服务
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable "$SERVICE_NAME"
|
||||
sudo systemctl start "$SERVICE_NAME"
|
||||
|
||||
# 验证服务状态
|
||||
echo "服务已安装!执行以下命令查看状态:"
|
||||
echo "sudo systemctl status $SERVICE_NAME"
|
@@ -17,7 +17,6 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -89,7 +88,7 @@ public class MediaController {
|
||||
}
|
||||
|
||||
if (streamInfo != null){
|
||||
return new StreamContent(streamInfo);
|
||||
return new StreamContent(streamInfo);
|
||||
}else {
|
||||
//获取流失败,重启拉流后重试一次
|
||||
streamProxyService.stopByAppAndStream(app,stream);
|
||||
|
@@ -2,4 +2,4 @@ spring:
|
||||
application:
|
||||
name: wvp
|
||||
profiles:
|
||||
active: dev
|
||||
active: 273
|
||||
|
14
web/.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
5
web/.env.development
Normal file
@@ -0,0 +1,5 @@
|
||||
# just a flag
|
||||
ENV = 'development'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/dev-api'
|
6
web/.env.production
Normal file
@@ -0,0 +1,6 @@
|
||||
# just a flag
|
||||
ENV = 'production'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = ''
|
||||
|
8
web/.env.staging
Normal file
@@ -0,0 +1,8 @@
|
||||
NODE_ENV = production
|
||||
|
||||
# just a flag
|
||||
ENV = 'staging'
|
||||
|
||||
# base api
|
||||
VUE_APP_BASE_API = '/stage-api'
|
||||
|
4
web/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
build/*.js
|
||||
src/assets
|
||||
public
|
||||
dist
|
198
web/.eslintrc.js
Normal file
@@ -0,0 +1,198 @@
|
||||
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']
|
||||
}
|
||||
}
|
16
web/.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
.DS_Store
|
||||
node_modules/
|
||||
dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
package-lock.json
|
||||
tests/**/coverage/
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
5
web/.travis.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js: 10
|
||||
script: npm run test
|
||||
notifications:
|
||||
email: false
|
21
web/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-present PanJiaChen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
111
web/README-zh.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# vue-admin-template
|
||||
|
||||
> 这是一个极简的 vue admin 管理后台。它只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。
|
||||
|
||||
[线上地址](http://panjiachen.github.io/vue-admin-template)
|
||||
|
||||
[国内访问](https://panjiachen.gitee.io/vue-admin-template)
|
||||
|
||||
目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`。
|
||||
|
||||
<p align="center">
|
||||
<b>SPONSORED BY</b>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank">
|
||||
<img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Extra
|
||||
|
||||
如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
|
||||
|
||||
## 相关项目
|
||||
|
||||
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
|
||||
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
|
||||
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
|
||||
|
||||
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
|
||||
|
||||
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
|
||||
|
||||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
||||
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
|
||||
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
|
||||
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板,专门针对本项目的文章,算作是一篇文档)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
|
||||
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
|
||||
|
||||
## Build Setup
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone https://github.com/PanJiaChen/vue-admin-template.git
|
||||
|
||||
# 进入项目目录
|
||||
cd vue-admin-template
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
|
||||
npm install --registry=https://registry.npm.taobao.org
|
||||
|
||||
# 启动服务
|
||||
npm run dev
|
||||
```
|
||||
|
||||
浏览器访问 [http://localhost:9528](http://localhost:9528)
|
||||
|
||||
## 发布
|
||||
|
||||
```bash
|
||||
# 构建测试环境
|
||||
npm run build:stage
|
||||
|
||||
# 构建生产环境
|
||||
npm run build:prod
|
||||
```
|
||||
|
||||
## 其它
|
||||
|
||||
```bash
|
||||
# 预览发布环境效果
|
||||
npm run preview
|
||||
|
||||
# 预览发布环境效果 + 静态资源分析
|
||||
npm run preview -- --report
|
||||
|
||||
# 代码格式检查
|
||||
npm run lint
|
||||
|
||||
# 代码格式检查并自动修复
|
||||
npm run lint -- --fix
|
||||
```
|
||||
|
||||
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
||||
|
||||
## 购买贴纸
|
||||
|
||||
你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,我们将获得 2 元的捐赠。
|
||||
|
||||
## Demo
|
||||
|
||||

|
||||
|
||||
## Browsers support
|
||||
|
||||
Modern browsers and Internet Explorer 10+.
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||
| --------- | --------- | --------- | --------- |
|
||||
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
|
||||
|
||||
Copyright (c) 2017-present PanJiaChen
|
99
web/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# vue-admin-template
|
||||
|
||||
English | [简体中文](./README-zh.md)
|
||||
|
||||
> A minimal vue admin template with Element UI & axios & iconfont & permission control & lint
|
||||
|
||||
**Live demo:** http://panjiachen.github.io/vue-admin-template
|
||||
|
||||
|
||||
**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`**
|
||||
|
||||
<p align="center">
|
||||
<b>SPONSORED BY</b>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank">
|
||||
<img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Build Setup
|
||||
|
||||
```bash
|
||||
# clone the project
|
||||
git clone https://github.com/PanJiaChen/vue-admin-template.git
|
||||
|
||||
# enter the project directory
|
||||
cd vue-admin-template
|
||||
|
||||
# install dependency
|
||||
npm install
|
||||
|
||||
# develop
|
||||
npm run dev
|
||||
```
|
||||
|
||||
This will automatically open http://localhost:9528
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
# build for test environment
|
||||
npm run build:stage
|
||||
|
||||
# build for production environment
|
||||
npm run build:prod
|
||||
```
|
||||
|
||||
## Advanced
|
||||
|
||||
```bash
|
||||
# preview the release environment effect
|
||||
npm run preview
|
||||
|
||||
# preview the release environment effect + static resource analysis
|
||||
npm run preview -- --report
|
||||
|
||||
# code format check
|
||||
npm run lint
|
||||
|
||||
# code format check and auto fix
|
||||
npm run lint -- --fix
|
||||
```
|
||||
|
||||
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
|
||||
|
||||
## Demo
|
||||
|
||||

|
||||
|
||||
## Extra
|
||||
|
||||
If you want router permission && generate menu by user roles , you can use this branch [permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control)
|
||||
|
||||
For `typescript` version, you can use [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
|
||||
|
||||
## Related Project
|
||||
|
||||
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
|
||||
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||
|
||||
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template)
|
||||
|
||||
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
|
||||
|
||||
## Browsers support
|
||||
|
||||
Modern browsers and Internet Explorer 10+.
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||
| --------- | --------- | --------- | --------- |
|
||||
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license.
|
||||
|
||||
Copyright (c) 2017-present PanJiaChen
|
14
web/babel.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
// 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.
|
||||
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
|
||||
'plugins': ['dynamic-import-node']
|
||||
}
|
||||
}
|
||||
}
|
35
web/build/index.js
Normal file
@@ -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}`)
|
||||
}
|
24
web/jest.config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
|
||||
'jest-transform-stub',
|
||||
'^.+\\.jsx?$': 'babel-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1'
|
||||
},
|
||||
snapshotSerializers: ['jest-serializer-vue'],
|
||||
testMatch: [
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||
],
|
||||
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
|
||||
coverageDirectory: '<rootDir>/tests/unit/coverage',
|
||||
// 'collectCoverage': true,
|
||||
'coverageReporters': [
|
||||
'lcov',
|
||||
'text-summary'
|
||||
],
|
||||
testURL: 'http://localhost/'
|
||||
}
|
9
web/jsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
57
web/mock/index.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const Mock = require('mockjs')
|
||||
const { param2Obj } = require('./utils')
|
||||
|
||||
const user = require('./user')
|
||||
const table = require('./table')
|
||||
|
||||
const mocks = [
|
||||
...user,
|
||||
...table
|
||||
]
|
||||
|
||||
// for front mock
|
||||
// please use it cautiously, it will redefine XMLHttpRequest,
|
||||
// which will cause many of your third-party libraries to be invalidated(like progress event).
|
||||
function mockXHR() {
|
||||
// mock patch
|
||||
// https://github.com/nuysoft/Mock/issues/300
|
||||
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
|
||||
Mock.XHR.prototype.send = function() {
|
||||
if (this.custom.xhr) {
|
||||
this.custom.xhr.withCredentials = this.withCredentials || false
|
||||
|
||||
if (this.responseType) {
|
||||
this.custom.xhr.responseType = this.responseType
|
||||
}
|
||||
}
|
||||
this.proxy_send(...arguments)
|
||||
}
|
||||
|
||||
function XHR2ExpressReqWrap(respond) {
|
||||
return function(options) {
|
||||
let result = null
|
||||
if (respond instanceof Function) {
|
||||
const { body, type, url } = options
|
||||
// https://expressjs.com/en/4x/api.html#req
|
||||
result = respond({
|
||||
method: type,
|
||||
body: JSON.parse(body),
|
||||
query: param2Obj(url)
|
||||
})
|
||||
} else {
|
||||
result = respond
|
||||
}
|
||||
return Mock.mock(result)
|
||||
}
|
||||
}
|
||||
|
||||
for (const i of mocks) {
|
||||
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mocks,
|
||||
mockXHR
|
||||
}
|
||||
|
81
web/mock/mock-server.js
Normal file
@@ -0,0 +1,81 @@
|
||||
const chokidar = require('chokidar')
|
||||
const bodyParser = require('body-parser')
|
||||
const chalk = require('chalk')
|
||||
const path = require('path')
|
||||
const Mock = require('mockjs')
|
||||
|
||||
const mockDir = path.join(process.cwd(), 'mock')
|
||||
|
||||
function registerRoutes(app) {
|
||||
let mockLastIndex
|
||||
const { mocks } = require('./index.js')
|
||||
const mocksForServer = mocks.map(route => {
|
||||
return responseFake(route.url, route.type, route.response)
|
||||
})
|
||||
for (const mock of mocksForServer) {
|
||||
app[mock.type](mock.url, mock.response)
|
||||
mockLastIndex = app._router.stack.length
|
||||
}
|
||||
const mockRoutesLength = Object.keys(mocksForServer).length
|
||||
return {
|
||||
mockRoutesLength: mockRoutesLength,
|
||||
mockStartIndex: mockLastIndex - mockRoutesLength
|
||||
}
|
||||
}
|
||||
|
||||
function unregisterRoutes() {
|
||||
Object.keys(require.cache).forEach(i => {
|
||||
if (i.includes(mockDir)) {
|
||||
delete require.cache[require.resolve(i)]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// for mock server
|
||||
const responseFake = (url, type, respond) => {
|
||||
return {
|
||||
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
|
||||
type: type || 'get',
|
||||
response(req, res) {
|
||||
console.log('request invoke:' + req.path)
|
||||
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = app => {
|
||||
// parse app.body
|
||||
// https://expressjs.com/en/4x/api.html#req.body
|
||||
app.use(bodyParser.json())
|
||||
app.use(bodyParser.urlencoded({
|
||||
extended: true
|
||||
}))
|
||||
|
||||
const mockRoutes = registerRoutes(app)
|
||||
var mockRoutesLength = mockRoutes.mockRoutesLength
|
||||
var mockStartIndex = mockRoutes.mockStartIndex
|
||||
|
||||
// watch files, hot reload mock server
|
||||
chokidar.watch(mockDir, {
|
||||
ignored: /mock-server/,
|
||||
ignoreInitial: true
|
||||
}).on('all', (event, path) => {
|
||||
if (event === 'change' || event === 'add') {
|
||||
try {
|
||||
// remove mock routes stack
|
||||
app._router.stack.splice(mockStartIndex, mockRoutesLength)
|
||||
|
||||
// clear routes cache
|
||||
unregisterRoutes()
|
||||
|
||||
const mockRoutes = registerRoutes(app)
|
||||
mockRoutesLength = mockRoutes.mockRoutesLength
|
||||
mockStartIndex = mockRoutes.mockStartIndex
|
||||
|
||||
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
|
||||
} catch (error) {
|
||||
console.log(chalk.redBright(error))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
29
web/mock/table.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const Mock = require('mockjs')
|
||||
|
||||
const data = Mock.mock({
|
||||
'items|30': [{
|
||||
id: '@id',
|
||||
title: '@sentence(10, 20)',
|
||||
'status|1': ['published', 'draft', 'deleted'],
|
||||
author: 'name',
|
||||
display_time: '@datetime',
|
||||
pageviews: '@integer(300, 5000)'
|
||||
}]
|
||||
})
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
url: '/vue-admin-template/table/list',
|
||||
type: 'get',
|
||||
response: config => {
|
||||
const items = data.items
|
||||
return {
|
||||
code: 20000,
|
||||
data: {
|
||||
total: items.length,
|
||||
items: items
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
84
web/mock/user.js
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
const tokens = {
|
||||
admin: {
|
||||
token: 'admin-token'
|
||||
},
|
||||
editor: {
|
||||
token: 'editor-token'
|
||||
}
|
||||
}
|
||||
|
||||
const users = {
|
||||
'admin-token': {
|
||||
roles: ['admin'],
|
||||
introduction: 'I am a super administrator',
|
||||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||
name: 'Super Admin'
|
||||
},
|
||||
'editor-token': {
|
||||
roles: ['editor'],
|
||||
introduction: 'I am an editor',
|
||||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
|
||||
name: 'Normal Editor'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = [
|
||||
// user login
|
||||
{
|
||||
url: '/vue-admin-template/user/login',
|
||||
type: 'post',
|
||||
response: config => {
|
||||
const { username } = config.body
|
||||
const token = tokens[username]
|
||||
|
||||
// mock error
|
||||
if (!token) {
|
||||
return {
|
||||
code: 60204,
|
||||
message: 'Account and password are incorrect.'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 20000,
|
||||
data: token
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// get user info
|
||||
{
|
||||
url: '/vue-admin-template/user/info\.*',
|
||||
type: 'get',
|
||||
response: config => {
|
||||
const { token } = config.query
|
||||
const info = users[token]
|
||||
|
||||
// mock error
|
||||
if (!info) {
|
||||
return {
|
||||
code: 50008,
|
||||
message: 'Login failed, unable to get user details.'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 20000,
|
||||
data: info
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// user logout
|
||||
{
|
||||
url: '/vue-admin-template/user/logout',
|
||||
type: 'post',
|
||||
response: _ => {
|
||||
return {
|
||||
code: 20000,
|
||||
data: 'success'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
25
web/mock/utils.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @param {string} url
|
||||
* @returns {Object}
|
||||
*/
|
||||
function param2Obj(url) {
|
||||
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
|
||||
if (!search) {
|
||||
return {}
|
||||
}
|
||||
const obj = {}
|
||||
const searchArr = search.split('&')
|
||||
searchArr.forEach(v => {
|
||||
const index = v.indexOf('=')
|
||||
if (index !== -1) {
|
||||
const name = v.substring(0, index)
|
||||
const val = v.substring(index + 1, v.length)
|
||||
obj[name] = val
|
||||
}
|
||||
})
|
||||
return obj
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
param2Obj
|
||||
}
|
74
web/package.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "vue-admin-template",
|
||||
"version": "4.4.0",
|
||||
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
|
||||
"author": "Pan <panfree23@gmail.com>",
|
||||
"scripts": {
|
||||
"dev": "vue-cli-service serve --host=0.0.0.0",
|
||||
"build:prod": "vue-cli-service build",
|
||||
"build:stage": "vue-cli-service build --mode staging",
|
||||
"preview": "node build/index.js --preview",
|
||||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
||||
"test:ci": "npm run lint && npm run test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wchbrad/vue-easy-tree": "^1.0.13",
|
||||
"@femessage/log-viewer": "^1.5.0",
|
||||
"axios": "^0.24.0",
|
||||
"core-js": "3.6.5",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^4.9.0",
|
||||
"element-ui": "^2.15.14",
|
||||
"js-cookie": "2.2.0",
|
||||
"moment": "^2.29.1",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"ol": "^6.14.1",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"screenfull": "5.1.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"v-charts": "^1.19.0",
|
||||
"vue": "2.6.10",
|
||||
"vue-clipboards": "^1.3.0",
|
||||
"vue-contextmenujs": "^1.4.11",
|
||||
"vue-router": "3.0.6",
|
||||
"vue-ztree-2.0": "^1.0.4",
|
||||
"vuex": "3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "4.4.4",
|
||||
"@vue/cli-plugin-eslint": "4.4.4",
|
||||
"@vue/cli-plugin-unit-jest": "4.4.4",
|
||||
"@vue/cli-service": "4.4.4",
|
||||
"@vue/test-utils": "1.0.0-beta.29",
|
||||
"autoprefixer": "9.5.1",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-jest": "23.6.0",
|
||||
"babel-plugin-dynamic-import-node": "2.3.3",
|
||||
"chalk": "2.4.2",
|
||||
"connect": "3.6.6",
|
||||
"eslint": "6.7.2",
|
||||
"eslint-plugin-vue": "6.2.2",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"mockjs": "1.0.1-beta3",
|
||||
"runjs": "4.3.2",
|
||||
"sass": "1.26.8",
|
||||
"sass-loader": "8.0.2",
|
||||
"script-ext-html-webpack-plugin": "2.1.3",
|
||||
"serve-static": "1.13.2",
|
||||
"svg-sprite-loader": "4.1.3",
|
||||
"svgo": "1.2.2",
|
||||
"vue-template-compiler": "2.6.10"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8.9",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
8
web/postcss.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
'plugins': {
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
'autoprefixer': {}
|
||||
}
|
||||
}
|
BIN
web/public/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
22
web/public/index.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<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><%= webpackConfig.name %></title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="./static/js/jessibuca/jessibuca.js"></script>
|
||||
<script type="text/javascript" src="./static/js/ZLMRTCClient.js"></script>
|
||||
<script type="text/javascript" src="./static/js/config.js"></script>
|
||||
<script type="text/javascript" src="./static/js/h265web/h265webjs-v20221106.js"></script>
|
||||
<script type="text/javascript" src="./static/js/h265web/missile.js"></script>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
BIN
web/public/libDecoder.wasm
Normal file
BIN
web/public/static/images/abl-logo.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
web/public/static/images/arrow.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
web/public/static/images/bg13.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
web/public/static/images/bg14.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
web/public/static/images/bg17.png
Normal file
After Width: | Height: | Size: 876 KiB |
BIN
web/public/static/images/bg18.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
web/public/static/images/bg19.png
Normal file
After Width: | Height: | Size: 3.0 MiB |
BIN
web/public/static/images/gis/camera-offline.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
web/public/static/images/gis/camera.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
web/public/static/images/gis/camera1-offline.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
web/public/static/images/gis/camera1.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
web/public/static/images/gis/camera2-offline.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
web/public/static/images/gis/camera2.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
web/public/static/images/gis/camera3-offline.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
web/public/static/images/gis/camera3.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
web/public/static/images/zlm-logo.png
Normal file
After Width: | Height: | Size: 48 KiB |
8222
web/public/static/js/ZLMRTCClient.js
Normal file
22
web/public/static/js/config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
window.baseUrl = ""
|
||||
|
||||
// map组件全局参数, 注释此内容可以关闭地图功能
|
||||
window.mapParam = {
|
||||
// 开启/关闭地图功能
|
||||
enable: true,
|
||||
// 坐标系 GCJ-02 WGS-84,
|
||||
coordinateSystem: "GCJ-02",
|
||||
// 地图瓦片地址
|
||||
tilesUrl: "http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
|
||||
// 瓦片大小
|
||||
tileSize: 256,
|
||||
// 默认层级
|
||||
zoom:10,
|
||||
// 默认地图中心点
|
||||
center:[116.41020, 39.915119],
|
||||
// 地图最大层级
|
||||
maxZoom:18,
|
||||
// 地图最小层级
|
||||
minZoom: 3
|
||||
}
|
428
web/public/static/js/h265web/h265webjs-v20221106.js
Normal file
97
web/public/static/js/h265web/index.d.ts
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
export interface Web265JsExtraConfig {
|
||||
moovStartFlag?: boolean
|
||||
rawFps?: number
|
||||
autoCrop?: boolean
|
||||
core?: 0 | 1
|
||||
coreProbePart?: number
|
||||
ignoreAudio?: 0 | 1
|
||||
probeSize?: number
|
||||
}
|
||||
|
||||
export interface Web265JsConfig {
|
||||
/**
|
||||
*The type of the file to be played, do not fill in the automatic identification
|
||||
*/
|
||||
type?: 'mp4' | 'hls' | 'ts' | 'raw265' | 'flv'
|
||||
/**
|
||||
* playback window dom id value
|
||||
*/
|
||||
player: string
|
||||
/**
|
||||
* the video window width size
|
||||
*/
|
||||
width: number
|
||||
/**
|
||||
* the video window height size
|
||||
*/
|
||||
height: number
|
||||
/**
|
||||
* player token value
|
||||
*/
|
||||
token: string
|
||||
extInfo?: Web265JsExtraConfig
|
||||
}
|
||||
|
||||
export interface Web265JsMediaInfo {
|
||||
audioNone: boolean
|
||||
durationMs: number
|
||||
fps: number
|
||||
sampleRate: number
|
||||
size: {
|
||||
height: number
|
||||
width: number
|
||||
}
|
||||
videoCodec: 0 | 1
|
||||
isHEVC: boolean
|
||||
videoType: Web265JsConfig['type']
|
||||
}
|
||||
|
||||
interface New265WebJs {
|
||||
onSeekFinish(): void
|
||||
onRender(
|
||||
width: number,
|
||||
height: number,
|
||||
imageBufferY: typeof Uint8Array,
|
||||
imageBufferB: typeof Uint8Array,
|
||||
imageBufferR: typeof Uint8Array
|
||||
): void
|
||||
onLoadFinish(): void
|
||||
onPlayTime(videoPTS: number): void
|
||||
onPlayFinish(): void
|
||||
onCacheProcess(cPts: number): void
|
||||
onReadyShowDone(): void
|
||||
onLoadCache(): void
|
||||
onLoadCacheFinshed(): void
|
||||
onOpenFullScreen(): void
|
||||
onCloseFullScreen(): void
|
||||
do(): void
|
||||
pause(): void
|
||||
isPlaying(): boolean
|
||||
setRenderScreen(state: boolean): void
|
||||
seek(pts: number): void
|
||||
setVoice(volume: number): void
|
||||
mediaInfo(): Web265JsMediaInfo
|
||||
fullScreen(): void
|
||||
closeFullScreen(): void
|
||||
playNextFrame(): void
|
||||
snapshot(): void
|
||||
release(): void
|
||||
setPlaybackRate(rate: number): void
|
||||
getPlaybackRate(): number
|
||||
}
|
||||
|
||||
declare type new265webJsFn = (
|
||||
url: string,
|
||||
config: Web265JsConfig
|
||||
) => New265WebJs
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
new265webjs: new265webJsFn
|
||||
}
|
||||
}
|
||||
|
||||
export default class H265webjsModule {
|
||||
static createPlayer: (url: string, config: Web265JsConfig) => New265WebJs
|
||||
static clear(): void
|
||||
}
|
32
web/public/static/js/h265web/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/*********************************************************
|
||||
* LICENSE: LICENSE-Free_CN.MD
|
||||
*
|
||||
* Author: Numberwolf - ChangYanlong
|
||||
* QQ: 531365872
|
||||
* QQ Group:925466059
|
||||
* Wechat: numberwolf11
|
||||
* Discord: numberwolf#8694
|
||||
* E-Mail: porschegt23@foxmail.com
|
||||
* Github: https://github.com/numberwolf/h265web.js
|
||||
*
|
||||
* 作者: 小老虎(Numberwolf)(常炎隆)
|
||||
* QQ: 531365872
|
||||
* QQ群: 531365872
|
||||
* 微信: numberwolf11
|
||||
* Discord: numberwolf#8694
|
||||
* 邮箱: porschegt23@foxmail.com
|
||||
* 博客: https://www.jianshu.com/u/9c09c1e00fd1
|
||||
* Github: https://github.com/numberwolf/h265web.js
|
||||
*
|
||||
**********************************************************/
|
||||
require('./h265webjs-v20221106');
|
||||
export default class h265webjs {
|
||||
static createPlayer(videoURL, config) {
|
||||
return window.new265webjs(videoURL, config);
|
||||
}
|
||||
|
||||
static clear() {
|
||||
global.STATICE_MEM_playerCount = -1;
|
||||
global.STATICE_MEM_playerIndexPtr = 0;
|
||||
}
|
||||
}
|
BIN
web/public/static/js/h265web/missile-v20221120.wasm
Normal file
7062
web/public/static/js/h265web/missile.js
Normal file
1
web/public/static/js/jessibuca/decoder.js
Normal file
BIN
web/public/static/js/jessibuca/decoder.wasm
Executable file
637
web/public/static/js/jessibuca/jessibuca.d.ts
vendored
Normal file
@@ -0,0 +1,637 @@
|
||||
declare namespace Jessibuca {
|
||||
|
||||
/** 超时信息 */
|
||||
enum TIMEOUT {
|
||||
/** 当play()的时候,如果没有数据返回 */
|
||||
loadingTimeout = 'loadingTimeout',
|
||||
/** 当播放过程中,如果超过timeout之后没有数据渲染 */
|
||||
delayTimeout = 'delayTimeout',
|
||||
}
|
||||
|
||||
/** 错误信息 */
|
||||
enum ERROR {
|
||||
/** 播放错误,url 为空的时候,调用 play 方法 */
|
||||
playError = 'playError',
|
||||
/** http 请求失败 */
|
||||
fetchError = 'fetchError',
|
||||
/** websocket 请求失败 */
|
||||
websocketError = 'websocketError',
|
||||
/** webcodecs 解码 h265 失败 */
|
||||
webcodecsH265NotSupport = 'webcodecsH265NotSupport',
|
||||
/** mediaSource 解码 h265 失败 */
|
||||
mediaSourceH265NotSupport = 'mediaSourceH265NotSupport',
|
||||
/** wasm 解码失败 */
|
||||
wasmDecodeError = 'wasmDecodeError',
|
||||
}
|
||||
|
||||
interface Config {
|
||||
/**
|
||||
* 播放器容器
|
||||
* * 若为 string ,则底层调用的是 document.getElementById('id')
|
||||
* */
|
||||
container: HTMLElement | string;
|
||||
/**
|
||||
* 设置最大缓冲时长,单位秒,播放器会自动消除延迟
|
||||
*/
|
||||
videoBuffer?: number;
|
||||
/**
|
||||
* worker地址
|
||||
* * 默认引用的是根目录下面的decoder.js文件 ,decoder.js 与 decoder.wasm文件必须是放在同一个目录下面。 */
|
||||
decoder?: string;
|
||||
/**
|
||||
* 是否不使用离屏模式(提升渲染能力)
|
||||
*/
|
||||
forceNoOffscreen?: boolean;
|
||||
/**
|
||||
* 是否开启当页面的'visibilityState'变为'hidden'的时候,自动暂停播放。
|
||||
*/
|
||||
hiddenAutoPause?: boolean;
|
||||
/**
|
||||
* 是否有音频,如果设置`false`,则不对音频数据解码,提升性能。
|
||||
*/
|
||||
hasAudio?: boolean;
|
||||
/**
|
||||
* 设置旋转角度,只支持,0(默认),180,270 三个值
|
||||
*/
|
||||
rotate?: boolean;
|
||||
/**
|
||||
* 1. 当为`true`的时候:视频画面做等比缩放后,高或宽对齐canvas区域,画面不被拉伸,但有黑边。 等同于 `setScaleMode(1)`
|
||||
* 2. 当为`false`的时候:视频画面完全填充canvas区域,画面会被拉伸。等同于 `setScaleMode(0)`
|
||||
*/
|
||||
isResize?: boolean;
|
||||
/**
|
||||
* 1. 当为`true`的时候:视频画面做等比缩放后,完全填充canvas区域,画面不被拉伸,没有黑边,但画面显示不全。等同于 `setScaleMode(2)`
|
||||
*/
|
||||
isFullResize?: boolean;
|
||||
/**
|
||||
* 1. 当为`true`的时候:ws协议不检验是否以.flv为依据,进行协议解析。
|
||||
*/
|
||||
isFlv?: boolean;
|
||||
/**
|
||||
* 是否开启控制台调试打
|
||||
*/
|
||||
debug?: boolean;
|
||||
/**
|
||||
* 1. 设置超时时长, 单位秒
|
||||
* 2. 在连接成功之前(loading)和播放中途(heart),如果超过设定时长无数据返回,则回调timeout事件
|
||||
*/
|
||||
timeout?: number;
|
||||
/**
|
||||
* 1. 设置超时时长, 单位秒
|
||||
* 2. 在连接成功之前,如果超过设定时长无数据返回,则回调timeout事件
|
||||
*/
|
||||
heartTimeout?: number;
|
||||
/**
|
||||
* 1. 设置超时时长, 单位秒
|
||||
* 2. 在连接成功之前,如果超过设定时长无数据返回,则回调timeout事件
|
||||
*/
|
||||
loadingTimeout?: number;
|
||||
/**
|
||||
* 是否支持屏幕的双击事件,触发全屏,取消全屏事件
|
||||
*/
|
||||
supportDblclickFullscreen?: boolean;
|
||||
/**
|
||||
* 是否显示网
|
||||
*/
|
||||
showBandwidth?: boolean;
|
||||
/**
|
||||
* 配置操作按钮
|
||||
*/
|
||||
operateBtns?: {
|
||||
/** 是否显示全屏按钮 */
|
||||
fullscreen?: boolean;
|
||||
/** 是否显示截图按钮 */
|
||||
screenshot?: boolean;
|
||||
/** 是否显示播放暂停按钮 */
|
||||
play?: boolean;
|
||||
/** 是否显示声音按钮 */
|
||||
audio?: boolean;
|
||||
/** 是否显示录制按 */
|
||||
record?: boolean;
|
||||
};
|
||||
/**
|
||||
* 开启屏幕常亮,在手机浏览器上, canvas标签渲染视频并不会像video标签那样保持屏幕常亮
|
||||
*/
|
||||
keepScreenOn?: boolean;
|
||||
/**
|
||||
* 是否开启声音,默认是关闭声音播放的
|
||||
*/
|
||||
isNotMute?: boolean;
|
||||
/**
|
||||
* 加载过程中文案
|
||||
*/
|
||||
loadingText?: string;
|
||||
/**
|
||||
* 背景图片
|
||||
*/
|
||||
background?: string;
|
||||
/**
|
||||
* 是否开启MediaSource硬解码
|
||||
* * 视频编码只支持H.264视频(Safari on iOS不支持)
|
||||
* * 不支持 forceNoOffscreen 为 false (开启离屏渲染)
|
||||
*/
|
||||
useMSE?: boolean;
|
||||
/**
|
||||
* 是否开启Webcodecs硬解码
|
||||
* * 视频编码只支持H.264视频 (需在chrome 94版本以上,需要https或者localhost环境)
|
||||
* * 支持 forceNoOffscreen 为 false (开启离屏渲染)
|
||||
* */
|
||||
useWCS?: boolean;
|
||||
/**
|
||||
* 是否开启键盘快捷键
|
||||
* 目前支持的键盘快捷键有:esc -> 退出全屏;arrowUp -> 声音增加;arrowDown -> 声音减少;
|
||||
*/
|
||||
hotKey?: boolean;
|
||||
/**
|
||||
* 在使用MSE或者Webcodecs 播放H265的时候,是否自动降级到wasm模式。
|
||||
* 设置为false 则直接关闭播放,抛出Error 异常,设置为true 则会自动切换成wasm模式播放。
|
||||
*/
|
||||
autoWasm?: boolean;
|
||||
/**
|
||||
* heartTimeout 心跳超时之后自动再播放,不再抛出异常,而直接重新播放视频地址。
|
||||
*/
|
||||
heartTimeoutReplay?: boolean,
|
||||
/**
|
||||
* heartTimeoutReplay 从试次数,超过之后,不再自动播放
|
||||
*/
|
||||
heartTimeoutReplayTimes?: number,
|
||||
/**
|
||||
* loadingTimeout loading之后自动再播放,不再抛出异常,而直接重新播放视频地址。
|
||||
*/
|
||||
loadingTimeoutReplay?: boolean,
|
||||
/**
|
||||
* heartTimeoutReplay 从试次数,超过之后,不再自动播放
|
||||
*/
|
||||
loadingTimeoutReplayTimes?: number
|
||||
/**
|
||||
* wasm解码报错之后,不再抛出异常,而是直接重新播放视频地址。
|
||||
*/
|
||||
wasmDecodeErrorReplay?: boolean,
|
||||
/**
|
||||
* https://github.com/langhuihui/jessibuca/issues/152 解决方案
|
||||
* 例如:WebGL图像预处理默认每次取4字节的数据,但是540x960分辨率下的U、V分量宽度是540/2=270不能被4整除,导致绿屏。
|
||||
*/
|
||||
openWebglAlignment?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
declare class Jessibuca {
|
||||
|
||||
constructor(config?: Jessibuca.Config);
|
||||
|
||||
/**
|
||||
* 是否开启控制台调试打印
|
||||
@example
|
||||
// 开启
|
||||
jessibuca.setDebug(true)
|
||||
// 关闭
|
||||
jessibuca.setDebug(false)
|
||||
*/
|
||||
setDebug(flag: boolean): void;
|
||||
|
||||
/**
|
||||
* 静音
|
||||
@example
|
||||
jessibuca.mute()
|
||||
*/
|
||||
mute(): void;
|
||||
|
||||
/**
|
||||
* 取消静音
|
||||
@example
|
||||
jessibuca.cancelMute()
|
||||
*/
|
||||
cancelMute(): void;
|
||||
|
||||
/**
|
||||
* 留给上层用户操作来触发音频恢复的方法。
|
||||
*
|
||||
* iPhone,chrome等要求自动播放时,音频必须静音,需要由一个真实的用户交互操作来恢复,不能使用代码。
|
||||
*
|
||||
* https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
|
||||
*/
|
||||
audioResume(): void;
|
||||
|
||||
/**
|
||||
*
|
||||
* 设置超时时长, 单位秒
|
||||
* 在连接成功之前和播放中途,如果超过设定时长无数据返回,则回调timeout事件
|
||||
|
||||
@example
|
||||
jessibuca.setTimeout(10)
|
||||
|
||||
jessibuca.on('timeout',function(){
|
||||
//
|
||||
});
|
||||
*/
|
||||
setTimeout(): void;
|
||||
|
||||
/**
|
||||
* @param mode
|
||||
* 0 视频画面完全填充canvas区域,画面会被拉伸 等同于参数 `isResize` 为false
|
||||
*
|
||||
* 1 视频画面做等比缩放后,高或宽对齐canvas区域,画面不被拉伸,但有黑边 等同于参数 `isResize` 为true
|
||||
*
|
||||
* 2 视频画面做等比缩放后,完全填充canvas区域,画面不被拉伸,没有黑边,但画面显示不全 等同于参数 `isFullResize` 为true
|
||||
@example
|
||||
jessibuca.setScaleMode(0)
|
||||
|
||||
jessibuca.setScaleMode(1)
|
||||
|
||||
jessibuca.setScaleMode(2)
|
||||
*/
|
||||
setScaleMode(mode: number): void;
|
||||
|
||||
/**
|
||||
* 暂停播放
|
||||
*
|
||||
* 可以在pause 之后,再调用 `play()`方法就继续播放之前的流。
|
||||
@example
|
||||
jessibuca.pause().then(()=>{
|
||||
console.log('pause success')
|
||||
|
||||
jessibuca.play().then(()=>{
|
||||
|
||||
}).catch((e)=>{
|
||||
|
||||
})
|
||||
|
||||
}).catch((e)=>{
|
||||
console.log('pause error',e);
|
||||
})
|
||||
*/
|
||||
pause(): Promise<void>;
|
||||
|
||||
/**
|
||||
* 关闭视频,不释放底层资源
|
||||
@example
|
||||
jessibuca.close();
|
||||
*/
|
||||
close(): void;
|
||||
|
||||
/**
|
||||
* 关闭视频,释放底层资源
|
||||
@example
|
||||
jessibuca.destroy()
|
||||
*/
|
||||
destroy(): void;
|
||||
|
||||
/**
|
||||
* 清理画布为黑色背景
|
||||
@example
|
||||
jessibuca.clearView()
|
||||
*/
|
||||
clearView(): void;
|
||||
|
||||
/**
|
||||
* 播放视频
|
||||
@example
|
||||
|
||||
jessibuca.play('url').then(()=>{
|
||||
console.log('play success')
|
||||
}).catch((e)=>{
|
||||
console.log('play error',e)
|
||||
})
|
||||
//
|
||||
jessibuca.play()
|
||||
*/
|
||||
play(url?: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* 重新调整视图大小
|
||||
*/
|
||||
resize(): void;
|
||||
|
||||
/**
|
||||
* 设置最大缓冲时长,单位秒,播放器会自动消除延迟。
|
||||
*
|
||||
* 等同于 `videoBuffer` 参数。
|
||||
*
|
||||
@example
|
||||
// 设置 200ms 缓冲
|
||||
jessibuca.setBufferTime(0.2)
|
||||
*/
|
||||
setBufferTime(time: number): void;
|
||||
|
||||
/**
|
||||
* 设置旋转角度,只支持,0(默认) ,180,270 三个值。
|
||||
*
|
||||
* > 可用于实现监控画面小窗和全屏效果,由于iOS没有全屏API,此方法可以模拟页面内全屏效果而且多端效果一致。 *
|
||||
@example
|
||||
jessibuca.setRotate(0)
|
||||
|
||||
jessibuca.setRotate(90)
|
||||
|
||||
jessibuca.setRotate(270)
|
||||
*/
|
||||
setRotate(deg: number): void;
|
||||
|
||||
/**
|
||||
*
|
||||
* 设置音量大小,取值0 — 1
|
||||
*
|
||||
* > 区别于 mute 和 cancelMute 方法,虽然设置setVolume(0) 也能达到 mute方法,但是mute 方法是不调用底层播放音频的,能提高性能。而setVolume(0)只是把声音设置为0 ,以达到效果。
|
||||
* @param volume 当为0时,完全无声;当为1时,最大音量,默认值
|
||||
@example
|
||||
jessibuca.setVolume(0.2)
|
||||
|
||||
jessibuca.setVolume(0)
|
||||
|
||||
jessibuca.setVolume(1)
|
||||
*/
|
||||
setVolume(volume: number): void;
|
||||
|
||||
/**
|
||||
* 返回是否加载完毕
|
||||
@example
|
||||
var result = jessibuca.hasLoaded()
|
||||
console.log(result) // true
|
||||
*/
|
||||
hasLoaded(): boolean;
|
||||
|
||||
/**
|
||||
* 开启屏幕常亮,在手机浏览器上, canvas标签渲染视频并不会像video标签那样保持屏幕常亮。
|
||||
* H5目前在chrome\edge 84, android chrome 84及以上有原生亮屏API, 需要是https页面
|
||||
* 其余平台为模拟实现,此时为兼容实现,并不保证所有浏览器都支持
|
||||
@example
|
||||
jessibuca.setKeepScreenOn()
|
||||
*/
|
||||
setKeepScreenOn(): boolean;
|
||||
|
||||
/**
|
||||
* 全屏(取消全屏)播放视频
|
||||
@example
|
||||
jessibuca.setFullscreen(true)
|
||||
//
|
||||
jessibuca.setFullscreen(false)
|
||||
*/
|
||||
setFullscreen(flag: boolean): void;
|
||||
|
||||
/**
|
||||
*
|
||||
* 截图,调用后弹出下载框保存截图
|
||||
* @param filename 可选参数, 保存的文件名, 默认 `时间戳`
|
||||
* @param format 可选参数, 截图的格式,可选png或jpeg或者webp ,默认 `png`
|
||||
* @param quality 可选参数, 当格式是jpeg或者webp时,压缩质量,取值0 ~ 1 ,默认 `0.92`
|
||||
* @param type 可选参数, 可选download或者base64或者blob,默认`download`
|
||||
|
||||
@example
|
||||
|
||||
jessibuca.screenshot("test","png",0.5)
|
||||
|
||||
const base64 = jessibuca.screenshot("test","png",0.5,'base64')
|
||||
|
||||
const fileBlob = jessibuca.screenshot("test",'blob')
|
||||
*/
|
||||
screenshot(filename?: string, format?: string, quality?: number, type?: string): void;
|
||||
|
||||
/**
|
||||
* 开始录制。
|
||||
* @param fileName 可选,默认时间戳
|
||||
* @param fileType 可选,默认webm,支持webm 和mp4 格式
|
||||
|
||||
@example
|
||||
jessibuca.startRecord('xxx','webm')
|
||||
*/
|
||||
startRecord(fileName: string, fileType: string): void;
|
||||
|
||||
/**
|
||||
* 暂停录制并下载。
|
||||
@example
|
||||
jessibuca.stopRecordAndSave()
|
||||
*/
|
||||
stopRecordAndSave(): void;
|
||||
|
||||
/**
|
||||
* 返回是否正在播放中状态。
|
||||
@example
|
||||
var result = jessibuca.isPlaying()
|
||||
console.log(result) // true
|
||||
*/
|
||||
isPlaying(): boolean;
|
||||
|
||||
/**
|
||||
* 返回是否静音。
|
||||
@example
|
||||
var result = jessibuca.isMute()
|
||||
console.log(result) // true
|
||||
*/
|
||||
isMute(): boolean;
|
||||
|
||||
/**
|
||||
* 返回是否正在录制。
|
||||
@example
|
||||
var result = jessibuca.isRecording()
|
||||
console.log(result) // true
|
||||
*/
|
||||
isRecording(): boolean;
|
||||
|
||||
|
||||
/**
|
||||
* 监听 jessibuca 初始化事件
|
||||
* @example
|
||||
* jessibuca.on("load",function(){console.log('load')})
|
||||
*/
|
||||
on(event: 'load', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 视频播放持续时间,单位ms
|
||||
* @example
|
||||
* jessibuca.on('timeUpdate',function (ts) {console.log('timeUpdate',ts);})
|
||||
*/
|
||||
on(event: 'timeUpdate', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 当解析出视频信息时回调,2个回调参数
|
||||
* @example
|
||||
* jessibuca.on("videoInfo",function(data){console.log('width:',data.width,'height:',data.width)})
|
||||
*/
|
||||
on(event: 'videoInfo', callback: (data: {
|
||||
/** 视频宽 */
|
||||
width: number;
|
||||
/** 视频高 */
|
||||
height: number;
|
||||
}) => void): void;
|
||||
|
||||
/**
|
||||
* 当解析出音频信息时回调,2个回调参数
|
||||
* @example
|
||||
* jessibuca.on("audioInfo",function(data){console.log('numOfChannels:',data.numOfChannels,'sampleRate',data.sampleRate)})
|
||||
*/
|
||||
on(event: 'audioInfo', callback: (data: {
|
||||
/** 声频通道 */
|
||||
numOfChannels: number;
|
||||
/** 采样率 */
|
||||
sampleRate: number;
|
||||
}) => void): void;
|
||||
|
||||
/**
|
||||
* 信息,包含错误信息
|
||||
* @example
|
||||
* jessibuca.on("log",function(data){console.log('data:',data)})
|
||||
*/
|
||||
on(event: 'log', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
* @example
|
||||
* jessibuca.on("error",function(error){
|
||||
if(error === Jessibuca.ERROR.fetchError){
|
||||
//
|
||||
}
|
||||
else if(error === Jessibuca.ERROR.webcodecsH265NotSupport){
|
||||
//
|
||||
}
|
||||
console.log('error:',error)
|
||||
})
|
||||
*/
|
||||
on(event: 'error', callback: (err: Jessibuca.ERROR) => void): void;
|
||||
|
||||
/**
|
||||
* 当前网速, 单位KB 每秒1次,
|
||||
* @example
|
||||
* jessibuca.on("kBps",function(data){console.log('kBps:',data)})
|
||||
*/
|
||||
on(event: 'kBps', callback: (value: number) => void): void;
|
||||
|
||||
/**
|
||||
* 渲染开始
|
||||
* @example
|
||||
* jessibuca.on("start",function(){console.log('start render')})
|
||||
*/
|
||||
on(event: 'start', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 当设定的超时时间内无数据返回,则回调
|
||||
* @example
|
||||
* jessibuca.on("timeout",function(error){console.log('timeout:',error)})
|
||||
*/
|
||||
on(event: 'timeout', callback: (error: Jessibuca.TIMEOUT) => void): void;
|
||||
|
||||
/**
|
||||
* 当play()的时候,如果没有数据返回,则回调
|
||||
* @example
|
||||
* jessibuca.on("loadingTimeout",function(){console.log('timeout')})
|
||||
*/
|
||||
on(event: 'loadingTimeout', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 当播放过程中,如果超过timeout之后没有数据渲染,则抛出异常。
|
||||
* @example
|
||||
* jessibuca.on("delayTimeout",function(){console.log('timeout')})
|
||||
*/
|
||||
on(event: 'delayTimeout', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 当前是否全屏
|
||||
* @example
|
||||
* jessibuca.on("fullscreen",function(flag){console.log('is fullscreen',flag)})
|
||||
*/
|
||||
on(event: 'fullscreen', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 触发播放事件
|
||||
* @example
|
||||
* jessibuca.on("play",function(flag){console.log('play')})
|
||||
*/
|
||||
on(event: 'play', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 触发暂停事件
|
||||
* @example
|
||||
* jessibuca.on("pause",function(flag){console.log('pause')})
|
||||
*/
|
||||
on(event: 'pause', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 触发声音事件,返回boolean值
|
||||
* @example
|
||||
* jessibuca.on("mute",function(flag){console.log('is mute',flag)})
|
||||
*/
|
||||
on(event: 'mute', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 流状态统计,流开始播放后回调,每秒1次。
|
||||
* @example
|
||||
* jessibuca.on("stats",function(s){console.log("stats is",s)})
|
||||
*/
|
||||
on(event: 'stats', callback: (stats: {
|
||||
/** 当前缓冲区时长,单位毫秒 */
|
||||
buf: number;
|
||||
/** 当前视频帧率 */
|
||||
fps: number;
|
||||
/** 当前音频码率,单位byte */
|
||||
abps: number;
|
||||
/** 当前视频码率,单位byte */
|
||||
vbps: number;
|
||||
/** 当前视频帧pts,单位毫秒 */
|
||||
ts: number;
|
||||
}) => void): void;
|
||||
|
||||
/**
|
||||
* 渲染性能统计,流开始播放后回调,每秒1次。
|
||||
* @param performance 0: 表示卡顿,1: 表示流畅,2: 表示非常流程
|
||||
* @example
|
||||
* jessibuca.on("performance",function(performance){console.log("performance is",performance)})
|
||||
*/
|
||||
on(event: 'performance', callback: (performance: 0 | 1 | 2) => void): void;
|
||||
|
||||
/**
|
||||
* 录制开始的事件
|
||||
|
||||
* @example
|
||||
* jessibuca.on("recordStart",function(){console.log("record start")})
|
||||
*/
|
||||
on(event: 'recordStart', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 录制结束的事件
|
||||
|
||||
* @example
|
||||
* jessibuca.on("recordEnd",function(){console.log("record end")})
|
||||
*/
|
||||
on(event: 'recordEnd', callback: () => void): void;
|
||||
|
||||
/**
|
||||
* 录制的时候,返回的录制时长,1s一次
|
||||
|
||||
* @example
|
||||
* jessibuca.on("recordingTimestamp",function(timestamp){console.log("recordingTimestamp is",timestamp)})
|
||||
*/
|
||||
on(event: 'recordingTimestamp', callback: (timestamp: number) => void): void;
|
||||
|
||||
/**
|
||||
* 监听调用play方法 经过 初始化-> 网络请求-> 解封装 -> 解码 -> 渲染 一系列过程的时间消耗
|
||||
* @param event
|
||||
* @param callback
|
||||
*/
|
||||
on(event: 'playToRenderTimes', callback: (times: {
|
||||
playInitStart: number, // 1 初始化
|
||||
playStart: number, // 2 初始化
|
||||
streamStart: number, // 3 网络请求
|
||||
streamResponse: number, // 4 网络请求
|
||||
demuxStart: number, // 5 解封装
|
||||
decodeStart: number, // 6 解码
|
||||
videoStart: number, // 7 渲染
|
||||
playTimestamp: number,// playStart- playInitStart
|
||||
streamTimestamp: number,// streamStart - playStart
|
||||
streamResponseTimestamp: number,// streamResponse - streamStart
|
||||
demuxTimestamp: number, // demuxStart - streamResponse
|
||||
decodeTimestamp: number, // decodeStart - demuxStart
|
||||
videoTimestamp: number,// videoStart - decodeStart
|
||||
allTimestamp: number // videoStart - playInitStart
|
||||
}) => void): void
|
||||
|
||||
/**
|
||||
* 监听方法
|
||||
*
|
||||
@example
|
||||
|
||||
jessibuca.on("load",function(){console.log('load')})
|
||||
*/
|
||||
on(event: string, callback: Function): void;
|
||||
|
||||
}
|
||||
|
||||
export default Jessibuca;
|
1
web/public/static/js/jessibuca/jessibuca.js
Normal file
11
web/src/App.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
130
web/src/api/cloudRecord.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 云端录像API
|
||||
|
||||
export function getPlayPath(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/play/path`,
|
||||
params: {
|
||||
recordId: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryListByData(params) {
|
||||
const { app, stream, year, month, mediaServerId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/date/list`,
|
||||
params: {
|
||||
app: app,
|
||||
stream: stream,
|
||||
year: year,
|
||||
month: month,
|
||||
mediaServerId: mediaServerId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function loadRecord(params) {
|
||||
const { app, stream, date } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/loadRecord`,
|
||||
params: {
|
||||
app: app,
|
||||
stream: stream,
|
||||
date: date
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function seek(params) {
|
||||
const { mediaServerId, app, stream, seek, schema } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/seek`,
|
||||
params: {
|
||||
mediaServerId: mediaServerId,
|
||||
app: app,
|
||||
stream: stream,
|
||||
seek: seek,
|
||||
schema: schema
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function speed(params) {
|
||||
const { mediaServerId, app, stream, speed, schema } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/speed`,
|
||||
params: {
|
||||
mediaServerId: mediaServerId,
|
||||
app: app,
|
||||
stream: stream,
|
||||
speed: speed,
|
||||
schema: schema
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addTask(params) {
|
||||
const { app, stream, mediaServerId, startTime, endTime } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/task/add`,
|
||||
params: {
|
||||
app: app,
|
||||
stream: stream,
|
||||
mediaServerId: mediaServerId,
|
||||
startTime: startTime,
|
||||
endTime: endTime
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryTaskList(params) {
|
||||
const { mediaServerId, isEnd } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/task/list`,
|
||||
params: {
|
||||
mediaServerId: mediaServerId,
|
||||
isEnd: isEnd
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteRecord(ids) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/cloud/record/delete`,
|
||||
data: {
|
||||
ids: ids
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function queryList(params) {
|
||||
const { app, stream, query, startTime, endTime, mediaServerId, page, count, ascOrder } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/list`,
|
||||
params: {
|
||||
app: app,
|
||||
stream: stream,
|
||||
query: query,
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
mediaServerId: mediaServerId,
|
||||
page: page,
|
||||
count: count,
|
||||
ascOrder: ascOrder
|
||||
}
|
||||
})
|
||||
}
|
||||
|
244
web/src/api/commonChannel.js
Normal file
@@ -0,0 +1,244 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 通用通道API
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/update',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/add',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function reset(id) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/common/channel/reset',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryOne(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/common/channel/one',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addDeviceToGroup(params) {
|
||||
const { parentId, businessGroup, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/add`,
|
||||
data: {
|
||||
parentId: parentId,
|
||||
businessGroup: businessGroup,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addToGroup(params) {
|
||||
const { parentId, businessGroup, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/add`,
|
||||
data: {
|
||||
parentId: parentId,
|
||||
businessGroup: businessGroup,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDeviceFromGroup(deviceIds) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteFromGroup(channels) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/delete`,
|
||||
data: {
|
||||
channelIds: channels
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addDeviceToRegion(params) {
|
||||
const { civilCode, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/add`,
|
||||
data: {
|
||||
civilCode: civilCode,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
export function addToRegion(params) {
|
||||
const { civilCode, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/add`,
|
||||
data: {
|
||||
civilCode: civilCode,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDeviceFromRegion(deviceIds) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
export function deleteFromRegion(channels) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/delete`,
|
||||
data: {
|
||||
channelIds: channels
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getCivilCodeList(params) {
|
||||
const { page, count, channelType, query, online, civilCode } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilcode/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online,
|
||||
civilCode: civilCode
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getParentList(params) {
|
||||
const { page, count, channelType, query, online, groupDeviceId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online,
|
||||
groupDeviceId: groupDeviceId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getUnusualParentList(params) {
|
||||
const { page, count, channelType, query, online } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/unusual/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function clearUnusualParentList(params) {
|
||||
const { all, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/parent/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getUnusualCivilCodeList(params) {
|
||||
const { page, count, channelType, query, online } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilCode/unusual/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
channelType: channelType,
|
||||
query: query,
|
||||
online: online
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function clearUnusualCivilCodeList(params) {
|
||||
const { all, channelIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/civilCode/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channelIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getIndustryList() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/common/channel/industry/list'
|
||||
})
|
||||
}
|
||||
|
||||
export function getTypeList() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/common/channel/type/list'
|
||||
})
|
||||
}
|
||||
|
||||
export function getNetworkIdentificationList() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/common/channel/network/identification/list'
|
||||
})
|
||||
}
|
||||
|
||||
export function playChannel(channelId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/common/channel/play',
|
||||
params: {
|
||||
channelId: channelId
|
||||
}
|
||||
})
|
||||
}
|
221
web/src/api/device.js
Normal file
@@ -0,0 +1,221 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 国标设备API
|
||||
|
||||
export function queryDeviceSyncStatus(deviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/${deviceId}/sync_status/`
|
||||
})
|
||||
}
|
||||
|
||||
export function queryDevices(params) {
|
||||
const { page, count, query, status } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/devices`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query,
|
||||
status: status
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteDevice(deviceId) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/device/query/devices/${deviceId}/delete`
|
||||
})
|
||||
}
|
||||
|
||||
export function sync(deviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/devices/${deviceId}/sync`
|
||||
})
|
||||
}
|
||||
|
||||
export function updateDeviceTransport(deviceId, streamMode) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/device/query/transport/${deviceId}/${streamMode}`
|
||||
})
|
||||
}
|
||||
|
||||
export function setGuard(deviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/control/guard/${deviceId}/SetGuard`
|
||||
})
|
||||
}
|
||||
|
||||
export function resetGuard(deviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/control/guard/${deviceId}/ResetGuard`
|
||||
})
|
||||
}
|
||||
|
||||
export function subscribeCatalog(params) {
|
||||
const { id, cycle } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/subscribe/catalog`,
|
||||
params: {
|
||||
id: id,
|
||||
cycle: cycle
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function subscribeMobilePosition(params) {
|
||||
const { id, cycle, interval } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/subscribe/mobile-position`,
|
||||
params: {
|
||||
id: id,
|
||||
cycle: cycle,
|
||||
interval: interval
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryBasicParam(deviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/config/query/${deviceId}/BasicParam`
|
||||
})
|
||||
}
|
||||
|
||||
export function queryChannelOne(params) {
|
||||
const { deviceId, channelDeviceId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/device/query/channel/one',
|
||||
params: {
|
||||
deviceId: deviceId,
|
||||
channelDeviceId: channelDeviceId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryChannels(deviceId, params) {
|
||||
const { page, count, query, online, channelType, catalogUnderDevice } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/devices/${deviceId}/channels`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query,
|
||||
online: online,
|
||||
channelType: channelType,
|
||||
catalogUnderDevice: catalogUnderDevice
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deviceRecord(params) {
|
||||
const { deviceId, channelId, recordCmdStr } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/control/record`,
|
||||
params: {
|
||||
deviceId: deviceId,
|
||||
channelId: channelId,
|
||||
recordCmdStr: recordCmdStr
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function querySubChannels(params, deviceId, parentChannelId) {
|
||||
const { page, count, query, online, channelType } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/sub_channels/${deviceId}/${parentChannelId}/channels`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query,
|
||||
online: online,
|
||||
channelType: channelType
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryChannelTree(params) {
|
||||
const { parentId, page, count } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/tree/channel/${this.deviceId}`,
|
||||
params: {
|
||||
parentId: parentId,
|
||||
page: page,
|
||||
count: count
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function changeChannelAudio(params) {
|
||||
const { channelId, audio } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/device/query/channel/audio`,
|
||||
params: {
|
||||
channelId: channelId,
|
||||
audio: audio
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function updateChannelStreamIdentification(params) {
|
||||
const { deviceDbId, streamIdentification } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/device/query/channel/stream/identification/update/`,
|
||||
params: {
|
||||
deviceDbId: deviceDbId,
|
||||
streamIdentification: streamIdentification
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/device/query/device/update`,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/device/query/device/add`,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function queryDeviceOne(deviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/devices/${deviceId}`
|
||||
})
|
||||
}
|
||||
|
||||
export function queryDeviceTree(params, deviceId) {
|
||||
const { page, count, parentId, onlyCatalog } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/device/query/tree/${deviceId}`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
parentId: parentId,
|
||||
onlyCatalog: onlyCatalog
|
||||
}
|
||||
})
|
||||
}
|
||||
|
218
web/src/api/frontEnd.js
Normal file
@@ -0,0 +1,218 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 前端控制
|
||||
|
||||
export function setSpeedForScan(deviceId, channelDeviceId, scanId, speed) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/set/speed/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
scanId: scanId,
|
||||
speed: speed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function setLeftForScan(deviceId, channelDeviceId, scanId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/set/left/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
scanId: scanId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function setRightForScan(deviceId, channelDeviceId, scanId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/set/right/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
scanId: scanId
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function startScan(deviceId, channelDeviceId, scanId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/start/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
scanId: scanId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function stopScan(deviceId, channelDeviceId, scanId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/stop/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
scanId: scanId
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function queryPreset(deviceId, channelDeviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/query/${deviceId}/${channelDeviceId}`
|
||||
})
|
||||
}
|
||||
|
||||
export function addPointForCruise(deviceId, channelDeviceId, cruiseId, presetId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/point/add/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: cruiseId,
|
||||
presetId: presetId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deletePointForCruise(deviceId, channelDeviceId, cruiseId, presetId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/point/delete/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: cruiseId,
|
||||
presetId: presetId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function setCruiseSpeed(deviceId, channelDeviceId, cruiseId, cruiseSpeed) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/speed/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: cruiseId,
|
||||
speed: cruiseSpeed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function setCruiseTime(deviceId, channelDeviceId, cruiseId, cruiseTime) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/time/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: cruiseId,
|
||||
time: cruiseTime
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function startCruise(deviceId, channelDeviceId, cruiseId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/start/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: cruiseId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function stopCruise(deviceId, channelDeviceId, cruiseId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/stop/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: cruiseId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addPreset(deviceId, channelDeviceId, presetId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/add/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
presetId: presetId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function callPreset(deviceId, channelDeviceId, presetId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/call/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
presetId: presetId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deletePreset(deviceId, channelDeviceId, presetId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/delete/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
presetId: presetId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* command: on 开启, off 关闭
|
||||
*/
|
||||
export function auxiliary(deviceId, channelDeviceId, command, switchId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/auxiliary/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
command: command,
|
||||
switchId: switchId
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* command: on 开启, off 关闭
|
||||
*/
|
||||
export function wiper(deviceId, channelDeviceId, command) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/wiper/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
command: command
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function ptz(deviceId, channelId, command, horizonSpeed, verticalSpeed, zoomSpeed) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/ptz/${deviceId}/${channelId}`,
|
||||
params: {
|
||||
command: command,
|
||||
horizonSpeed: horizonSpeed,
|
||||
verticalSpeed: verticalSpeed,
|
||||
zoomSpeed: zoomSpeed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function iris(deviceId, channelId, command, speed) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/fi/iris/${deviceId}/${channelId}`,
|
||||
params: {
|
||||
command: command,
|
||||
speed: speed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function focus(deviceId, channelDeviceId, command, speed) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/front-end/fi/focus/${deviceId}/${channelDeviceId}`,
|
||||
params: {
|
||||
command: command,
|
||||
speed: speed
|
||||
}
|
||||
})
|
||||
}
|
33
web/src/api/gbRecord.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function query([deviceId, channelId, startTime, endTime]) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/gb_record/query/' + deviceId + '/' + channelId + '?startTime=' + startTime + '&endTime=' + endTime
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function startDownLoad([deviceId, channelId, startTime, endTime, downloadSpeed]) {
|
||||
return request({
|
||||
url: '/api/gb_record/download/start/' + deviceId + '/' + channelId + '?startTime=' + startTime + '&endTime=' +
|
||||
endTime + '&downloadSpeed=' + downloadSpeed
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function stopDownLoad(deviceId, channelId, streamId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/gb_record/download/stop/' + deviceId + '/' + channelId + '/' + streamId
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function queryDownloadProgress([deviceId, channelId, streamId]) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/gb_record/download/progress/${deviceId}/${channelId}/${streamId}`
|
||||
})
|
||||
}
|
||||
|
50
web/src/api/group.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 分组API
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/group/update',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/group/add',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export function getTreeList(params) {
|
||||
const { query, parent, hasChannel } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/group/tree/list`,
|
||||
params: {
|
||||
query: query,
|
||||
parent: parent,
|
||||
hasChannel: hasChannel
|
||||
}
|
||||
})
|
||||
}
|
||||
export function deleteGroup(id) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/group/delete`,
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
export function getPath(params) {
|
||||
const { deviceId, businessGroup } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/group/path`,
|
||||
params: {
|
||||
deviceId: deviceId,
|
||||
businessGroup: businessGroup
|
||||
}
|
||||
})
|
||||
}
|
15
web/src/api/log.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function queryList(params) {
|
||||
const { query, startTime, endTime } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/log/list`,
|
||||
params: {
|
||||
query: query,
|
||||
startTime: startTime,
|
||||
endTime: endTime
|
||||
}
|
||||
})
|
||||
}
|
||||
|
142
web/src/api/platform.js
Normal file
@@ -0,0 +1,142 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/platform/update',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/platform/add',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function exit(deviceGbId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/platform/exit/${deviceGbId}`
|
||||
})
|
||||
}
|
||||
|
||||
export function remove(id) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/platform/delete/`,
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function pushChannel(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/platform/channel/push`,
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getServerConfig() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/platform/server_config`
|
||||
})
|
||||
}
|
||||
|
||||
export function query(params) {
|
||||
const { count, page, query } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/platform/query`,
|
||||
params: {
|
||||
count: count,
|
||||
page: page,
|
||||
query: query
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function getChannelList(params) {
|
||||
const { page, count, query, online, channelType, platformId, hasShare } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/platform/channel/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query,
|
||||
online: online,
|
||||
channelType: channelType,
|
||||
platformId: platformId,
|
||||
hasShare: hasShare
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addChannel(params) {
|
||||
const { platformId, channelIds, all } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/platform/channel/add`,
|
||||
data: {
|
||||
platformId: platformId,
|
||||
channelIds: channelIds,
|
||||
all: all
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function addChannelByDevice(params) {
|
||||
const { platformId, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/platform/channel/device/add`,
|
||||
data: {
|
||||
platformId: platformId,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function removeChannelByDevice(params) {
|
||||
const { platformId, deviceIds } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/platform/channel/device/remove`,
|
||||
data: {
|
||||
platformId: platformId,
|
||||
deviceIds: deviceIds
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function removeChannel(params) {
|
||||
const { platformId, channelIds, all } = params
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/platform/channel/remove`,
|
||||
data: {
|
||||
platformId: platformId,
|
||||
channelIds: channelIds,
|
||||
all: all
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function updateCustomChannel(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/platform/channel/custom/update`,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
28
web/src/api/play.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 实时流播放API
|
||||
|
||||
export function play(deviceId, channelId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/play/start/' + deviceId + '/' + channelId
|
||||
})
|
||||
}
|
||||
export function stop(deviceId, channelId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/play/stop/' + deviceId + "/" + channelId,
|
||||
})
|
||||
}
|
||||
export function broadcastStart(deviceId, channelId, broadcastMode) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/play/broadcast/' + deviceId + '/' + channelId + "?timeout=30&broadcastMode=" + broadcastMode
|
||||
})
|
||||
}
|
||||
export function broadcastStop(deviceId, channelId, ) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/play/broadcast/stop/' + deviceId + '/' + channelId
|
||||
})
|
||||
}
|
34
web/src/api/playback.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 回放流播放API
|
||||
|
||||
export function play([deviceId, channelId, startTime, endTime]) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/playback/start/' + deviceId + '/' + channelId + '?startTime=' + startTime + '&endTime=' + endTime
|
||||
})
|
||||
}
|
||||
export function resume(streamId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/playback/resume/' + streamId
|
||||
})
|
||||
}
|
||||
export function pause(streamId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/playback/pause/' + streamId
|
||||
})
|
||||
}
|
||||
export function setSpeed([streamId, speed]) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/playback/speed/${streamId}/${speed}`
|
||||
})
|
||||
}
|
||||
export function stop(deviceId, channelId, streamId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/playback/stop/' + deviceId + '/' + channelId + '/' + streamId
|
||||
})
|
||||
}
|
85
web/src/api/recordPlan.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getPlan(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/record/plan/get',
|
||||
params: {
|
||||
planId: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addPlan(params) {
|
||||
const { name, planList } = params
|
||||
return request({
|
||||
|
||||
method: 'post',
|
||||
url: '/api/record/plan/add',
|
||||
data: {
|
||||
name: name,
|
||||
planItemList: planList
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function update(params) {
|
||||
const { id, name, planList } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/record/plan/update',
|
||||
data: {
|
||||
id: id,
|
||||
name: name,
|
||||
planItemList: planList
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryList(params) {
|
||||
const { page, count, query } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/record/plan/query`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deletePlan(id) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: '/api/record/plan/delete',
|
||||
params: {
|
||||
planId: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryChannelList(params) {
|
||||
const { page, count, channelType, query, online, planId , hasLink } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/record/plan/channel/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query,
|
||||
online: online,
|
||||
channelType: channelType,
|
||||
planId: planId,
|
||||
hasLink: hasLink
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function linkPlan(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/record/plan/link`,
|
||||
data: data
|
||||
})
|
||||
}
|
84
web/src/api/region.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 行政区划API
|
||||
|
||||
export function getTreeList(params) {
|
||||
const {query, parent, hasChannel} = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/region/tree/list`,
|
||||
params: {
|
||||
query: query,
|
||||
parent: parent,
|
||||
hasChannel: hasChannel
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteRegion(id) {
|
||||
return request({
|
||||
method: "delete",
|
||||
url: `/api/region/delete`,
|
||||
params: {
|
||||
id: id,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function description(civilCode) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/region/description`,
|
||||
params: {
|
||||
civilCode: civilCode,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addByCivilCode(civilCode) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/region/addByCivilCode`,
|
||||
params: {
|
||||
civilCode: civilCode,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryChildListInBase(parent) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: "/api/region/base/child/list",
|
||||
params: {
|
||||
parent: parent,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: "/api/region/update",
|
||||
data: data
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: "/api/region/add",
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function queryPath(deviceId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/region/path`,
|
||||
params: {
|
||||
deviceId: deviceId,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
11
web/src/api/role.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 云端录像API
|
||||
|
||||
export function getAll() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/role/all'
|
||||
})
|
||||
}
|
||||
|
117
web/src/api/server.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 服务API
|
||||
|
||||
export function getOnlineMediaServerList() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/online/list`
|
||||
})
|
||||
}
|
||||
|
||||
export function getMediaServerList() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/list`
|
||||
})
|
||||
}
|
||||
|
||||
export function getMediaServer(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/one/` + id
|
||||
})
|
||||
}
|
||||
|
||||
export function checkMediaServer(params) {
|
||||
const { ip, port, secret, type } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/check`,
|
||||
params: {
|
||||
ip: ip,
|
||||
port: port,
|
||||
secret: secret,
|
||||
type: type
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function checkMediaServerRecord(params) {
|
||||
const { ip, port } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/record/check`,
|
||||
params: {
|
||||
ip: ip,
|
||||
port: port
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function saveMediaServer(formData) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/server/media_server/save`,
|
||||
data: formData
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteMediaServer(id) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/server/media_server/delete`,
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getSystemConfig() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/system/configInfo`
|
||||
})
|
||||
}
|
||||
|
||||
export function getMediaInfo(params) {
|
||||
const { app, stream, mediaServerId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/media_info`,
|
||||
params: {
|
||||
app: app,
|
||||
stream: stream,
|
||||
mediaServerId: mediaServerId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getSystemInfo() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/system/info`
|
||||
})
|
||||
}
|
||||
|
||||
export function getMediaServerLoad() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/load`
|
||||
})
|
||||
}
|
||||
|
||||
export function getResourceInfo() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/resource/info`
|
||||
})
|
||||
}
|
||||
|
||||
export function info() {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/server/info`
|
||||
})
|
||||
}
|
||||
|
85
web/src/api/streamProxy.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 拉流代理API
|
||||
|
||||
export function queryFfmpegCmdList(mediaServerId) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/proxy/ffmpeg_cmd/list`,
|
||||
params: {
|
||||
mediaServerId: mediaServerId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function save(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/proxy/save`,
|
||||
data: data
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/proxy/update`,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/proxy/add`,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function queryList(params) {
|
||||
const { page, count, query, pulling, mediaServerId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/proxy/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query,
|
||||
pulling: pulling,
|
||||
mediaServerId: mediaServerId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function play(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/proxy/start`,
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function stopPlay(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/proxy/stop`,
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function remove(id) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: '/api/proxy/delete',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
80
web/src/api/streamPush.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 推流列表API
|
||||
|
||||
export function saveToGb(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/push/save_to_gb`,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/push/add`,
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/push/update',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function queryList(params) {
|
||||
const { page, count, query, pushing, mediaServerId } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/push/list`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count,
|
||||
query: query,
|
||||
pushing: pushing,
|
||||
mediaServerId: mediaServerId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function play(id) {
|
||||
return request({
|
||||
method: 'get',
|
||||
url: '/api/push/start',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function remove(id) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/push/remove',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function removeFormGb(data) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: '/api/push/remove_form_gb',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function batchRemove(ids) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: '/api/push/batchRemove',
|
||||
data: {
|
||||
ids: ids
|
||||
}
|
||||
})
|
||||
}
|
9
web/src/api/table.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getList(params) {
|
||||
return request({
|
||||
url: '/vue-admin-template/table/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
91
web/src/api/user.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function login(params) {
|
||||
return request({
|
||||
url: '/api/user/login',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
return request({
|
||||
url: '/api/user/logout',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export function getUserInfo() {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/user/userInfo'
|
||||
})
|
||||
}
|
||||
|
||||
export function changePushKey(params) {
|
||||
const { pushKey, userId } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/user/changePushKey',
|
||||
params: {
|
||||
pushKey: pushKey,
|
||||
userId: userId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryList(params) {
|
||||
const { page, count } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/user/users`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function removeById(id) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/user/delete?id=${id}`
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function add(params) {
|
||||
const { username, password, roleId } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/user/add',
|
||||
params: {
|
||||
username: username,
|
||||
password: password,
|
||||
roleId: roleId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function changePassword(params) {
|
||||
const { oldPassword, password } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/user/changePassword',
|
||||
params: {
|
||||
oldPassword: oldPassword,
|
||||
password: password
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function changePasswordForAdmin(params) {
|
||||
const { password, userId } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/user/changePasswordForAdmin',
|
||||
params: {
|
||||
password: password,
|
||||
userId: userId
|
||||
}
|
||||
})
|
||||
}
|
69
web/src/api/userApiKey.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function remark(params) {
|
||||
const { id, remark } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/userApiKey/remark',
|
||||
params: {
|
||||
id: id,
|
||||
remark: remark
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function queryList(params) {
|
||||
const { page, count } = params
|
||||
return request({
|
||||
method: 'get',
|
||||
url: `/api/userApiKey/userApiKeys`,
|
||||
params: {
|
||||
page: page,
|
||||
count: count
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function enable(id) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/userApiKey/enable?id=${id}`
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
export function disable(id) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/userApiKey/disable?id=${id}`
|
||||
})
|
||||
}
|
||||
|
||||
export function reset(id) {
|
||||
return request({
|
||||
method: 'post',
|
||||
url: `/api/userApiKey/reset?id=${id}`
|
||||
})
|
||||
}
|
||||
|
||||
export function remove(id) {
|
||||
return request({
|
||||
method: 'delete',
|
||||
url: `/api/userApiKey/delete?id=${id}`
|
||||
})
|
||||
}
|
||||
|
||||
export function add(params) {
|
||||
const { userId, app, enable, expiresAt, remark } = params
|
||||
return request({
|
||||
method: 'post',
|
||||
url: '/api/userApiKey/add',
|
||||
params: {
|
||||
userId: userId,
|
||||
app: app,
|
||||
enable: enable,
|
||||
expiresAt: expiresAt,
|
||||
remark: remark
|
||||
}
|
||||
})
|
||||
}
|
BIN
web/src/assets/404_images/404.png
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
web/src/assets/404_images/404_cloud.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
web/src/assets/abl-logo.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
web/src/assets/bg.jpg
Normal file
After Width: | Height: | Size: 781 KiB |
BIN
web/src/assets/icons.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
web/src/assets/loading.png
Executable file
After Width: | Height: | Size: 2.7 KiB |
BIN
web/src/assets/login-bg.jpg
Executable file
After Width: | Height: | Size: 4.0 KiB |
BIN
web/src/assets/login-cloud.png
Executable file
After Width: | Height: | Size: 3.3 KiB |
BIN
web/src/assets/logo.png
Executable file
After Width: | Height: | Size: 66 KiB |
BIN
web/src/assets/play.png
Executable file
After Width: | Height: | Size: 546 B |
BIN
web/src/assets/zlm-logo.png
Executable file
After Width: | Height: | Size: 48 KiB |
78
web/src/components/Breadcrumb/index.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
levelList: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
// only show routes with meta.title
|
||||
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
|
||||
const first = matched[0]
|
||||
|
||||
if (!this.isDashboard(first)) {
|
||||
matched = [{ path: '/dashboard', meta: { title: '控制台' }}].concat(matched)
|
||||
}
|
||||
|
||||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||
},
|
||||
isDashboard(route) {
|
||||
const name = route && route.name
|
||||
if (!name) {
|
||||
return false
|
||||
}
|
||||
return name.trim().toLocaleLowerCase() === '控制台'.toLocaleLowerCase()
|
||||
},
|
||||
pathCompile(path) {
|
||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||
const { params } = this.$route
|
||||
var toPath = pathToRegexp.compile(path)
|
||||
return toPath(params)
|
||||
},
|
||||
handleLink(item) {
|
||||
const { redirect, path } = item
|
||||
if (redirect) {
|
||||
this.$router.push(redirect)
|
||||
return
|
||||
}
|
||||
this.$router.push(this.pathCompile(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 8px;
|
||||
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
</style>
|
44
web/src/components/Hamburger/index.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div style="padding: 0 15px;" @click="toggleClick">
|
||||
<svg
|
||||
:class="{'is-active':isActive}"
|
||||
class="hamburger"
|
||||
viewBox="0 0 1024 1024"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="64"
|
||||
height="64"
|
||||
>
|
||||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Hamburger',
|
||||
props: {
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleClick() {
|
||||
this.$emit('toggleClick')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hamburger {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.hamburger.is-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
62
web/src/components/SvgIcon/index.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
||||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
||||
import { isExternal } from '@/utils/validate'
|
||||
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.iconClass)
|
||||
},
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return 'svg-icon ' + this.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
},
|
||||
styleExternalIcon() {
|
||||
return {
|
||||
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover!important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
77
web/src/directive/el-drag-dialog/drag.js
Normal file
@@ -0,0 +1,77 @@
|
||||
export default {
|
||||
bind(el, binding, vnode) {
|
||||
const dialogHeaderEl = el.querySelector('.el-dialog__header')
|
||||
const dragDom = el.querySelector('.el-dialog')
|
||||
dialogHeaderEl.style.cssText += ';cursor:move;'
|
||||
dragDom.style.cssText += ';top:0px;'
|
||||
|
||||
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
|
||||
const getStyle = (function() {
|
||||
if (window.document.currentStyle) {
|
||||
return (dom, attr) => dom.currentStyle[attr]
|
||||
} else {
|
||||
return (dom, attr) => getComputedStyle(dom, false)[attr]
|
||||
}
|
||||
})()
|
||||
|
||||
dialogHeaderEl.onmousedown = (e) => {
|
||||
// 鼠标按下,计算当前元素距离可视区的距离
|
||||
const disX = e.clientX - dialogHeaderEl.offsetLeft
|
||||
const disY = e.clientY - dialogHeaderEl.offsetTop
|
||||
|
||||
const dragDomWidth = dragDom.offsetWidth
|
||||
const dragDomHeight = dragDom.offsetHeight
|
||||
|
||||
const screenWidth = document.body.clientWidth
|
||||
const screenHeight = document.body.clientHeight
|
||||
|
||||
const minDragDomLeft = dragDom.offsetLeft
|
||||
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
|
||||
|
||||
const minDragDomTop = dragDom.offsetTop
|
||||
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight
|
||||
|
||||
// 获取到的值带px 正则匹配替换
|
||||
let styL = getStyle(dragDom, 'left')
|
||||
let styT = getStyle(dragDom, 'top')
|
||||
|
||||
if (styL.includes('%')) {
|
||||
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
|
||||
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)
|
||||
} else {
|
||||
styL = +styL.replace(/\px/g, '')
|
||||
styT = +styT.replace(/\px/g, '')
|
||||
}
|
||||
|
||||
document.onmousemove = function(e) {
|
||||
// 通过事件委托,计算移动的距离
|
||||
let left = e.clientX - disX
|
||||
let top = e.clientY - disY
|
||||
|
||||
// 边界处理
|
||||
if (-(left) > minDragDomLeft) {
|
||||
left = -minDragDomLeft
|
||||
} else if (left > maxDragDomLeft) {
|
||||
left = maxDragDomLeft
|
||||
}
|
||||
|
||||
if (-(top) > minDragDomTop) {
|
||||
top = -minDragDomTop
|
||||
} else if (top > maxDragDomTop) {
|
||||
top = maxDragDomTop
|
||||
}
|
||||
|
||||
// 移动当前元素
|
||||
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
|
||||
|
||||
// emit onDrag event
|
||||
vnode.child.$emit('dragDialog')
|
||||
}
|
||||
|
||||
document.onmouseup = function(e) {
|
||||
document.onmousemove = null
|
||||
document.onmouseup = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
web/src/directive/el-drag-dialog/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import drag from './drag'
|
||||
|
||||
const install = function(Vue) {
|
||||
Vue.directive('el-drag-dialog', drag)
|
||||
}
|
||||
|
||||
if (window.Vue) {
|
||||
window['el-drag-dialog'] = drag
|
||||
Vue.use(install); // eslint-disable-line
|
||||
}
|
||||
|
||||
drag.install = install
|
||||
export default drag
|
9
web/src/icons/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import Vue from 'vue'
|
||||
import SvgIcon from '@/components/SvgIcon'// svg component
|
||||
|
||||
// register globally
|
||||
Vue.component('svg-icon', SvgIcon)
|
||||
|
||||
const req = require.context('./svg', false, /\.svg$/)
|
||||
const requireAll = requireContext => requireContext.keys().map(requireContext)
|
||||
requireAll(req)
|
1
web/src/icons/svg/channelManger.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1743481555402" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4475" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M104.64 0h128v632H337.28v128H232.64V1024h-128v-264H0v-128h104.64V0z m686.72 0h128v264H1024v128h-104.64V1024h-128V392H686.72v-128h104.64V0zM448 0h128v448h104.576v128H576v448H448V576H343.36V448H448z" p-id="4476"></path></svg>
|
After Width: | Height: | Size: 533 B |
1
web/src/icons/svg/cloudRecord.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1744253906048" class="icon" viewBox="0 0 1127 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2691" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M1074.12176 136.4v0.7l-0.5-0.3 0.5-0.4zM1020.82176 170v0.6l-0.5-0.3 0.5-0.3z m0 0" p-id="2692"></path><path d="M1127.52176 95.9v0.8l-0.6-0.3 0.6-0.5z m-59 37.2v0.7l-0.6-0.3 0.6-0.4z m0 0M645.52176 963.3c-72.2 0.1-131.6-56.9-134.3-129V690.9c2.7-72.2 62-129.3 134.3-129.3h7.3c10.6 0.2 20.6 4.9 27.7 13 9.1 10.7 11.1 25.8 5.1 38.5S666.92176 634 652.82176 634h-0.3c-16.1-1-31.9 4.4-44 15.2a60.444 60.444 0 0 0-20.3 41.9v142.8c1.3 32 27.7 57.1 59.7 57.1h244.6l2-20c1.1-31 26.6-55.7 57.7-55.6 7.5-0.1 15.1 1 22.3 3.3l73.6 25.7V680.9l-73.3 25.5c-6.6 2.4-13.7 3.7-20.8 3.7-24 0-45.7-14.1-55.6-36-2.5-6.1-3.9-12.6-4-19.3V636l-104.5-1.6c-19-1.9-33.4-18.3-32.7-37.4 0.8-19.2 16.5-34.3 35.7-34.7h99.7c40.1-1.1 74.3 28.8 78.5 68.7l70-24.3c6.9-2.3 14-3.5 21.1-3.5 32.9-1.1 60.7 24.1 62.8 56.9V864c0 7-1.3 14-4 20.5-6.1 14.8-17.8 26.7-32.7 32.7-15.1 6.3-31.9 6.9-47.4 1.6l-70-24.3c-1.3 18.2-9.6 35-23 47.3-14.9 13.7-34.7 21.4-55 21.4l-247.4 0.1z" p-id="2693"></path><path d="M297.42176 949.8C196.52176 949.1 103.12176 895.9 50.92176 809.4c-44.4-70.9-60.6-155.7-45.3-237.9 13.8-81.3 58.6-153.9 125-202.7 40.3-29.7 87.8-48.1 137.6-53.4 41.5-97.4 117.8-176 214.1-220.1 101-46.4 217-47.2 318.7-2.1 160.3 73.6 261.9 235.3 258.7 411.8 0.8 19.5-10.9 37.4-28.9 44.7-18.1 7.3-38.9 2.4-51.8-12.1-8.2-9.1-12.5-21.1-11.7-33.4 2.3-137.6-76.8-263.8-201.9-321.2-78.6-34.7-168.3-34-246.4 1.9C455.52176 214 403.12176 262.5 368.82176 323.3c72.9 19.7 135.5 66.6 175 131 14 22 8.6 51.2-12.1 66.9-7.7 5.5-17.1 8.5-26.6 8.7-15.8-0.1-30.5-8.4-38.6-21.9-29-47.3-76.1-80.6-130.2-92.5-53.4-11.2-109.1 1-152.9 33.4-46.1 33.8-77.2 84.3-86.7 140.6C85.92176 647 97.12176 706.1 128.12176 755.4c35.8 59.6 100 96.1 169.4 96.7h101.2c26 1.1 46.7 22.5 46.8 48.5 0.2 26.1-20.2 47.7-46.2 49.2h-102z" p-id="2694"></path></svg>
|
After Width: | Height: | Size: 2.0 KiB |
4
web/src/icons/svg/dashboard.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
1
web/src/icons/svg/device.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1743060304116" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="45090" xmlns:xlink="http://www.w3.org/1999/xlink" ><path d="M868 96H156c-33.1 0-60 26.9-60 60v712c0 33.1 26.9 60 60 60h712c33.1 0 60-26.9 60-60V156c0-33.1-26.9-60-60-60zM743.5 691.3c-20.9 20.3-51.3 38.1-91 53.5-39.7 15.4-80 23.1-120.7 23.1-51.8 0-96.9-10.9-135.4-32.6-38.5-21.7-67.4-52.8-86.8-93.2-19.4-40.4-29-84.4-29-131.9 0-51.6 10.8-97.4 32.4-137.5 21.6-40.1 53.2-70.8 94.9-92.2 31.7-16.4 71.3-24.7 118.5-24.7 61.5 0 109.5 12.9 144 38.7 34.6 25.8 56.8 61.4 66.7 106.9L637.8 420c-7-24.3-20.1-43.5-39.3-57.6-19.3-14.1-43.3-21.1-72.1-21.1-43.7 0-78.4 13.8-104.2 41.5-25.8 27.7-38.7 68.8-38.7 123.3 0 58.8 13.1 102.8 39.2 132.2 26.1 29.4 60.3 44.1 102.7 44.1 20.9 0 41.9-4.1 63-12.3 21-8.2 39.1-18.2 54.2-29.9v-62.8H528V494h215.5v197.3z" p-id="45091"></path></svg>
|
After Width: | Height: | Size: 1015 B |
1
web/src/icons/svg/example.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>
|
After Width: | Height: | Size: 497 B |
1
web/src/icons/svg/eye-open.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
web/src/icons/svg/eye.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>
|
After Width: | Height: | Size: 944 B |
1
web/src/icons/svg/form.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z"/></svg>
|
After Width: | Height: | Size: 2.4 KiB |