Compare commits
4 Commits
1b3ed3348b
...
8a4beed0c7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a4beed0c7 | ||
|
|
bae2b2524b | ||
|
|
8d97ee613e | ||
|
|
da98101aac |
@ -518,8 +518,8 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
log.info("[目录订阅]成功: {}", device.getDeviceId());
|
||||
if (!subscribeTaskRunner.containsKey(SubscribeTaskForCatalog.getKey(device))) {
|
||||
SIPResponse response = (SIPResponse) event.getResponse();
|
||||
SipTransactionInfo transactionInfoForResonse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForCatalog.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResonse);
|
||||
SipTransactionInfo transactionInfoForResponse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForCatalog.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResponse);
|
||||
if (subscribeTask != null) {
|
||||
subscribeTaskRunner.addSubscribe(subscribeTask);
|
||||
}
|
||||
@ -582,13 +582,13 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
log.info("[移动位置订阅]成功: {}", device.getDeviceId());
|
||||
if (!subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) {
|
||||
SIPResponse response = (SIPResponse) event.getResponse();
|
||||
SipTransactionInfo transactionInfoForResonse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForMobilPosition.getInstance(device, this::catalogSubscribeExpire, transactionInfoForResonse);
|
||||
SipTransactionInfo transactionInfoForResponse = new SipTransactionInfo(response);
|
||||
SubscribeTask subscribeTask = SubscribeTaskForMobilPosition.getInstance(device, this::mobilPositionSubscribeExpire, transactionInfoForResponse);
|
||||
if (subscribeTask != null) {
|
||||
subscribeTaskRunner.addSubscribe(subscribeTask);
|
||||
}
|
||||
}else {
|
||||
subscribeTaskRunner.updateDelay(SubscribeTaskForMobilPosition.getKey(device), (device.getSubscribeCycleForCatalog() * 1000L - 500L) + System.currentTimeMillis());
|
||||
subscribeTaskRunner.updateDelay(SubscribeTaskForMobilPosition.getKey(device), (device.getSubscribeCycleForMobilePosition() * 1000L - 500L) + System.currentTimeMillis());
|
||||
}
|
||||
|
||||
},eventResult -> {
|
||||
@ -874,7 +874,16 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
public void subscribeMobilePosition(int id, int cycle, int interval) {
|
||||
Device device = deviceMapper.query(id);
|
||||
Assert.notNull(device, "未找到设备");
|
||||
Assert.isTrue(device.isOnLine(), "设备已离线");
|
||||
if (!device.isOnLine()) {
|
||||
// 开启订阅
|
||||
device.setSubscribeCycleForMobilePosition(cycle);
|
||||
device.setMobilePositionSubmissionInterval(interval);
|
||||
updateDevice(device);
|
||||
if (subscribeTaskRunner.containsKey(SubscribeTaskForMobilPosition.getKey(device))) {
|
||||
subscribeTaskRunner.removeSubscribe(SubscribeTaskForMobilPosition.getKey(device));
|
||||
}
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备已离线");
|
||||
}
|
||||
|
||||
if (device.getSubscribeCycleForMobilePosition() == cycle) {
|
||||
return;
|
||||
@ -890,6 +899,7 @@ public class DeviceServiceImpl implements IDeviceService, CommandLineRunner {
|
||||
// 开启订阅
|
||||
device.setSubscribeCycleForMobilePosition(cycle);
|
||||
device.setMobilePositionSubmissionInterval(interval);
|
||||
updateDevice(device);
|
||||
if (cycle > 0) {
|
||||
addMobilePositionSubscribe(device, null);
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ public class SubscribeTaskForMobilPosition extends SubscribeTask {
|
||||
public static final String name = "mobilPosition";
|
||||
|
||||
public static SubscribeTask getInstance(Device device, SubscribeCallback callback, SipTransactionInfo transactionInfo) {
|
||||
if (device.getSubscribeCycleForCatalog() <= 0) {
|
||||
if (device.getSubscribeCycleForMobilePosition() <= 0) {
|
||||
return null;
|
||||
}
|
||||
SubscribeTaskForMobilPosition subscribeTaskForMobilPosition = new SubscribeTaskForMobilPosition();
|
||||
|
||||
@ -861,7 +861,7 @@
|
||||
320623,如东县,3206
|
||||
320681,启东市,3206
|
||||
320682,如皋市,3206
|
||||
320684,海门市,3206
|
||||
320684,海门区,3206
|
||||
320685,海安市,3206
|
||||
3207,连云港市,32
|
||||
320703,连云区,3207
|
||||
@ -918,8 +918,6 @@
|
||||
33,浙江省,
|
||||
3301,杭州市,33
|
||||
330102,上城区,3301
|
||||
330103,下城区,3301
|
||||
330104,江干区,3301
|
||||
330105,拱墅区,3301
|
||||
330106,西湖区,3301
|
||||
330108,滨江区,3301
|
||||
@ -927,6 +925,8 @@
|
||||
330110,余杭区,3301
|
||||
330111,富阳区,3301
|
||||
330112,临安区,3301
|
||||
330113,临平区,3301
|
||||
330114,钱塘区,3301
|
||||
330122,桐庐县,3301
|
||||
330127,淳安县,3301
|
||||
330182,建德市,3301
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false,
|
||||
"targets": {
|
||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||
}
|
||||
}],
|
||||
"stage-2"
|
||||
],
|
||||
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
14
web_src/.gitignore
vendored
@ -1,14 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules/
|
||||
/dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
@ -1,14 +0,0 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
"plugins": {
|
||||
"postcss-import": {},
|
||||
"postcss-url": {},
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
"autoprefixer": {},
|
||||
'postcss-pxtorem': {
|
||||
rootValue: 16,
|
||||
propList: ['font-size'] // 只转化font-size
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
# gb_web
|
||||
|
||||
> A Vue.js project
|
||||
|
||||
## Build Setup
|
||||
|
||||
``` bash
|
||||
# install dependencies
|
||||
npm install
|
||||
|
||||
# serve with hot reload at localhost:8080
|
||||
npm run dev
|
||||
|
||||
# build for production with minification
|
||||
npm run build
|
||||
|
||||
# build for production and view the bundle analyzer report
|
||||
npm run build --report
|
||||
```
|
||||
|
||||
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
|
||||
@ -1,41 +0,0 @@
|
||||
'use strict'
|
||||
require('./check-versions')()
|
||||
|
||||
process.env.NODE_ENV = 'production'
|
||||
|
||||
const ora = require('ora')
|
||||
const rm = require('rimraf')
|
||||
const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const webpack = require('webpack')
|
||||
const config = require('../config')
|
||||
const webpackConfig = require('./webpack.prod.conf')
|
||||
|
||||
const spinner = ora('building for production...')
|
||||
spinner.start()
|
||||
|
||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||
if (err) throw err
|
||||
webpack(webpackConfig, (err, stats) => {
|
||||
spinner.stop()
|
||||
if (err) throw err
|
||||
process.stdout.write(stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
|
||||
chunks: false,
|
||||
chunkModules: false
|
||||
}) + '\n\n')
|
||||
|
||||
if (stats.hasErrors()) {
|
||||
console.log(chalk.red(' Build failed with errors.\n'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log(chalk.cyan(' Build complete.\n'))
|
||||
console.log(chalk.yellow(
|
||||
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||
' Opening index.html over file:// won\'t work.\n'
|
||||
))
|
||||
})
|
||||
})
|
||||
@ -1,54 +0,0 @@
|
||||
'use strict'
|
||||
const chalk = require('chalk')
|
||||
const semver = require('semver')
|
||||
const packageConfig = require('../package.json')
|
||||
const shell = require('shelljs')
|
||||
|
||||
function exec (cmd) {
|
||||
return require('child_process').execSync(cmd).toString().trim()
|
||||
}
|
||||
|
||||
const versionRequirements = [
|
||||
{
|
||||
name: 'node',
|
||||
currentVersion: semver.clean(process.version),
|
||||
versionRequirement: packageConfig.engines.node
|
||||
}
|
||||
]
|
||||
|
||||
if (shell.which('npm')) {
|
||||
versionRequirements.push({
|
||||
name: 'npm',
|
||||
currentVersion: exec('npm --version'),
|
||||
versionRequirement: packageConfig.engines.npm
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
const warnings = []
|
||||
|
||||
for (let i = 0; i < versionRequirements.length; i++) {
|
||||
const mod = versionRequirements[i]
|
||||
|
||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||
warnings.push(mod.name + ': ' +
|
||||
chalk.red(mod.currentVersion) + ' should be ' +
|
||||
chalk.green(mod.versionRequirement)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings.length) {
|
||||
console.log('')
|
||||
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
||||
console.log()
|
||||
|
||||
for (let i = 0; i < warnings.length; i++) {
|
||||
const warning = warnings[i]
|
||||
console.log(' ' + warning)
|
||||
}
|
||||
|
||||
console.log()
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 6.7 KiB |
@ -1,101 +0,0 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const config = require('../config')
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
const packageConfig = require('../package.json')
|
||||
|
||||
exports.assetsPath = function (_path) {
|
||||
const assetsSubDirectory = process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsSubDirectory
|
||||
: config.dev.assetsSubDirectory
|
||||
|
||||
return path.posix.join(assetsSubDirectory, _path)
|
||||
}
|
||||
|
||||
exports.cssLoaders = function (options) {
|
||||
options = options || {}
|
||||
|
||||
const cssLoader = {
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap: options.sourceMap
|
||||
}
|
||||
}
|
||||
|
||||
const postcssLoader = {
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: options.sourceMap
|
||||
}
|
||||
}
|
||||
|
||||
// generate loader string to be used with extract text plugin
|
||||
function generateLoaders (loader, loaderOptions) {
|
||||
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
|
||||
|
||||
if (loader) {
|
||||
loaders.push({
|
||||
loader: loader + '-loader',
|
||||
options: Object.assign({}, loaderOptions, {
|
||||
sourceMap: options.sourceMap
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) {
|
||||
return ExtractTextPlugin.extract({
|
||||
use: loaders,
|
||||
fallback: 'vue-style-loader'
|
||||
})
|
||||
} else {
|
||||
return ['vue-style-loader'].concat(loaders)
|
||||
}
|
||||
}
|
||||
|
||||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||
return {
|
||||
css: generateLoaders(),
|
||||
postcss: generateLoaders(),
|
||||
less: generateLoaders('less'),
|
||||
sass: generateLoaders('sass', { indentedSyntax: true }),
|
||||
scss: generateLoaders('sass'),
|
||||
stylus: generateLoaders('stylus'),
|
||||
styl: generateLoaders('stylus')
|
||||
}
|
||||
}
|
||||
|
||||
// Generate loaders for standalone style files (outside of .vue)
|
||||
exports.styleLoaders = function (options) {
|
||||
const output = []
|
||||
const loaders = exports.cssLoaders(options)
|
||||
|
||||
for (const extension in loaders) {
|
||||
const loader = loaders[extension]
|
||||
output.push({
|
||||
test: new RegExp('\\.' + extension + '$'),
|
||||
use: loader
|
||||
})
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
exports.createNotifierCallback = () => {
|
||||
const notifier = require('node-notifier')
|
||||
|
||||
return (severity, errors) => {
|
||||
if (severity !== 'error') return
|
||||
|
||||
const error = errors[0]
|
||||
const filename = error.file && error.file.split('!').pop()
|
||||
|
||||
notifier.notify({
|
||||
title: packageConfig.name,
|
||||
message: severity + ': ' + error.name,
|
||||
subtitle: filename || '',
|
||||
icon: path.join(__dirname, 'logo.png')
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
'use strict'
|
||||
const utils = require('./utils')
|
||||
const config = require('../config')
|
||||
const isProduction = process.env.NODE_ENV === 'production'
|
||||
const sourceMapEnabled = isProduction
|
||||
? config.build.productionSourceMap
|
||||
: config.dev.cssSourceMap
|
||||
|
||||
module.exports = {
|
||||
loaders: utils.cssLoaders({
|
||||
sourceMap: sourceMapEnabled,
|
||||
extract: isProduction
|
||||
}),
|
||||
cssSourceMap: sourceMapEnabled,
|
||||
cacheBusting: config.dev.cacheBusting,
|
||||
transformToRequire: {
|
||||
video: ['src', 'poster'],
|
||||
source: 'src',
|
||||
img: 'src',
|
||||
image: 'xlink:href'
|
||||
}
|
||||
}
|
||||
@ -1,83 +0,0 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const utils = require('./utils')
|
||||
const config = require('../config')
|
||||
const vueLoaderConfig = require('./vue-loader.conf')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
context: path.resolve(__dirname, '../'),
|
||||
entry: {
|
||||
app: './src/main.js'
|
||||
},
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: '[name].js',
|
||||
publicPath: process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsPublicPath
|
||||
: config.dev.assetsPublicPath
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'vue$': 'vue/dist/vue.esm.js',
|
||||
'@': resolve('src'),
|
||||
'@static': resolve('static'),
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: vueLoaderConfig
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('media/[name].[hash:7].[ext]')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
node: {
|
||||
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||
// source contains it (although only uses it if it's native).
|
||||
setImmediate: false,
|
||||
// prevent webpack from injecting mocks to Node native modules
|
||||
// that does not make sense for the client
|
||||
dgram: 'empty',
|
||||
fs: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty',
|
||||
child_process: 'empty'
|
||||
}
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
'use strict'
|
||||
const utils = require('./utils')
|
||||
const webpack = require('webpack')
|
||||
const config = require('../config')
|
||||
const merge = require('webpack-merge')
|
||||
const path = require('path')
|
||||
const baseWebpackConfig = require('./webpack.base.conf')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
const portfinder = require('portfinder')
|
||||
|
||||
const PORT = process.env.PORT && Number(process.env.PORT)
|
||||
|
||||
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
|
||||
},
|
||||
// cheap-module-eval-source-map is faster for development
|
||||
devtool: config.dev.devtool,
|
||||
|
||||
// these devServer options should be customized in /config/index.js
|
||||
devServer: {
|
||||
clientLogLevel: 'warning',
|
||||
historyApiFallback: {
|
||||
rewrites: [
|
||||
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
|
||||
],
|
||||
},
|
||||
hot: true,
|
||||
contentBase: false, // since we use CopyWebpackPlugin.
|
||||
compress: true,
|
||||
host: config.dev.host,
|
||||
port: config.dev.port,
|
||||
open: config.dev.autoOpenBrowser,
|
||||
overlay: config.dev.errorOverlay
|
||||
? { warnings: false, errors: true }
|
||||
: false,
|
||||
publicPath: config.dev.assetsPublicPath,
|
||||
proxy: config.dev.proxyTable,
|
||||
quiet: true, // necessary for FriendlyErrorsPlugin
|
||||
watchOptions: {
|
||||
poll: config.dev.poll,
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': require('../config/dev.env')
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
// https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: 'index.html',
|
||||
inject: true
|
||||
}),
|
||||
// copy custom static assets
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.resolve(__dirname, '../static'),
|
||||
to: config.dev.assetsSubDirectory,
|
||||
ignore: ['.*']
|
||||
}
|
||||
]),
|
||||
new CopyWebpackPlugin([
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml'},
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf'},
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: config.build.assetsSubDirectory + '/js/'},
|
||||
])
|
||||
]
|
||||
})
|
||||
|
||||
module.exports = new Promise((resolve, reject) => {
|
||||
portfinder.basePort = process.env.PORT || config.dev.port
|
||||
portfinder.getPort((err, port) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
// publish the new Port, necessary for e2e tests
|
||||
process.env.PORT = port
|
||||
// add port to devServer config
|
||||
devWebpackConfig.devServer.port = port
|
||||
|
||||
// Add FriendlyErrorsPlugin
|
||||
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
|
||||
compilationSuccessInfo: {
|
||||
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
|
||||
},
|
||||
onErrors: config.dev.notifyOnErrors
|
||||
? utils.createNotifierCallback()
|
||||
: undefined
|
||||
}))
|
||||
|
||||
resolve(devWebpackConfig)
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -1,150 +0,0 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const utils = require('./utils')
|
||||
const webpack = require('webpack')
|
||||
const config = require('../config')
|
||||
const merge = require('webpack-merge')
|
||||
const baseWebpackConfig = require('./webpack.base.conf')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||
|
||||
const env = require('../config/prod.env')
|
||||
|
||||
const webpackConfig = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
extract: true,
|
||||
usePostCSS: true
|
||||
})
|
||||
},
|
||||
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
||||
},
|
||||
plugins: [
|
||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': env
|
||||
}),
|
||||
new UglifyJsPlugin({
|
||||
uglifyOptions: {
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
},
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
parallel: true
|
||||
}),
|
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({
|
||||
filename: utils.assetsPath('css/[name].[contenthash].css'),
|
||||
// Setting the following option to `false` will not extract CSS from codesplit chunks.
|
||||
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
|
||||
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
|
||||
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
|
||||
allChunks: true,
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSPlugin({
|
||||
cssProcessorOptions: config.build.productionSourceMap
|
||||
? { safe: true, map: { inline: false } }
|
||||
: { safe: true }
|
||||
}),
|
||||
// generate dist index.html with correct asset hash for caching.
|
||||
// you can customize output by editing /index.html
|
||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: config.build.index,
|
||||
template: 'index.html',
|
||||
inject: true,
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency'
|
||||
}),
|
||||
// keep module.id stable when vendor modules does not change
|
||||
new webpack.HashedModuleIdsPlugin(),
|
||||
// enable scope hoisting
|
||||
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||
// split vendor js into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
minChunks (module) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
module.resource &&
|
||||
/\.js$/.test(module.resource) &&
|
||||
module.resource.indexOf(
|
||||
path.join(__dirname, '../node_modules')
|
||||
) === 0
|
||||
)
|
||||
}
|
||||
}),
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'manifest',
|
||||
minChunks: Infinity
|
||||
}),
|
||||
// This instance extracts shared chunks from code splitted chunks and bundles them
|
||||
// in a separate chunk, similar to the vendor chunk
|
||||
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'app',
|
||||
async: 'vendor-async',
|
||||
children: true,
|
||||
minChunks: 3
|
||||
}),
|
||||
|
||||
// copy custom static assets
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.resolve(__dirname, '../static'),
|
||||
to: config.build.assetsSubDirectory,
|
||||
ignore: ['.*']
|
||||
}
|
||||
]),
|
||||
new CopyWebpackPlugin([
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml'},
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf'},
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: config.build.assetsSubDirectory + '/js/'},
|
||||
])
|
||||
]
|
||||
})
|
||||
|
||||
if (config.build.productionGzip) {
|
||||
const CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||
|
||||
webpackConfig.plugins.push(
|
||||
new CompressionWebpackPlugin({
|
||||
asset: '[path].gz[query]',
|
||||
algorithm: 'gzip',
|
||||
test: new RegExp(
|
||||
'\\.(' +
|
||||
config.build.productionGzipExtensions.join('|') +
|
||||
')$'
|
||||
),
|
||||
threshold: 10240,
|
||||
minRatio: 0.8
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (config.build.bundleAnalyzerReport) {
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
||||
}
|
||||
|
||||
module.exports = webpackConfig
|
||||
@ -1,8 +0,0 @@
|
||||
'use strict'
|
||||
const merge = require('webpack-merge')
|
||||
const prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
BASE_API: '"/debug"'
|
||||
})
|
||||
@ -1,87 +0,0 @@
|
||||
'use strict'
|
||||
// Template version: 1.3.1
|
||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
dev: {
|
||||
|
||||
// Paths
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
proxyTable: {
|
||||
'/debug': {
|
||||
target: 'http://127.0.0.1:18080',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/debug': '/'
|
||||
}
|
||||
},
|
||||
'/static/snap': {
|
||||
target: 'http://127.0.0.1:18080',
|
||||
changeOrigin: true,
|
||||
// pathRewrite: {
|
||||
// '^/static/snap': '/static/snap'
|
||||
// }
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
// Various Dev Server settings
|
||||
host:"127.0.0.1",
|
||||
useLocalIp: false, // can be overwritten by process.env.HOST
|
||||
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||
autoOpenBrowser: false,
|
||||
errorOverlay: true,
|
||||
notifyOnErrors: true,
|
||||
hot: true,//自动保存
|
||||
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
// https://webpack.js.org/configuration/devtool/#development
|
||||
devtool: 'cheap-module-eval-source-map',
|
||||
|
||||
// If you have problems debugging vue-files in devtools,
|
||||
// set this to false - it *may* help
|
||||
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||
cacheBusting: true,
|
||||
|
||||
cssSourceMap: true
|
||||
},
|
||||
|
||||
build: {
|
||||
// Template for index.html
|
||||
index: path.resolve(__dirname, '../../src/main/resources/static/index.html'),
|
||||
|
||||
// Paths
|
||||
assetsRoot: path.resolve(__dirname, '../../src/main/resources/static/'),
|
||||
assetsSubDirectory: './static',
|
||||
assetsPublicPath: '/',
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
productionSourceMap: true,
|
||||
// https://webpack.js.org/configuration/devtool/#production
|
||||
devtool: '#source-map',
|
||||
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false,
|
||||
productionGzipExtensions: ['js', 'css'],
|
||||
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report
|
||||
}
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
'use strict'
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"'
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>国标28181</title>
|
||||
<link rel="shortcut icon" href="static/favicon.ico" type="image/x-icon">
|
||||
<link rel="stylesheet" type="text/css" href="./static/css/iconfont.css">
|
||||
<link rel="stylesheet" type="text/css" href="./static/css/login.css">
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript" src="./static/js/jessibuca/jessibuca.js"></script>
|
||||
<script type="text/javascript" src="./static/js/EasyWasmPlayer.js"></script>
|
||||
<script type="text/javascript" src="./static/js/liveplayer-lib.min.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/jquery-3.7.1.min.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>
|
||||
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,84 +0,0 @@
|
||||
{
|
||||
"name": "gb_web",
|
||||
"version": "1.0.0",
|
||||
"description": "A Vue.js project",
|
||||
"author": "648540858 <648540858@qq.com>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||
"start": "npm run dev",
|
||||
"build": "node build/build.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.3.0",
|
||||
"@femessage/log-viewer": "^1.5.0",
|
||||
"@liveqing/liveplayer": "^2.7.10",
|
||||
"@wchbrad/vue-easy-tree": "^1.0.12",
|
||||
"axios": "^0.24.0",
|
||||
"byte-weektime-picker": "^1.1.1",
|
||||
"core-js": "^2.6.5",
|
||||
"echarts": "^4.9.0",
|
||||
"element-ui": "^2.15.14",
|
||||
"fingerprintjs2": "^2.1.2",
|
||||
"moment": "^2.29.1",
|
||||
"ol": "^6.14.1",
|
||||
"postcss-pxtorem": "^5.1.1",
|
||||
"screenfull": "5.1.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"uuid": "^8.3.2",
|
||||
"v-charts": "^1.19.0",
|
||||
"vue": "^2.6.11",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-clipboards": "^1.3.0",
|
||||
"vue-contextmenujs": "^1.3.13",
|
||||
"vue-cookies": "^1.8.3",
|
||||
"vue-router": "^3.1.6",
|
||||
"vue-ztree-2.0": "^1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^7.1.2",
|
||||
"babel-core": "^6.22.1",
|
||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
||||
"babel-loader": "^7.1.1",
|
||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||
"babel-plugin-transform-runtime": "^6.22.0",
|
||||
"babel-plugin-transform-vue-jsx": "^3.5.0",
|
||||
"babel-preset-env": "^1.3.2",
|
||||
"babel-preset-stage-2": "^6.22.0",
|
||||
"chalk": "^2.0.1",
|
||||
"copy-webpack-plugin": "^4.6.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"extract-text-webpack-plugin": "^3.0.0",
|
||||
"file-loader": "^1.1.4",
|
||||
"friendly-errors-webpack-plugin": "^1.6.1",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"node-notifier": "^5.1.2",
|
||||
"optimize-css-assets-webpack-plugin": "^3.2.0",
|
||||
"ora": "^1.2.0",
|
||||
"portfinder": "^1.0.13",
|
||||
"postcss-import": "^11.0.0",
|
||||
"postcss-loader": "^2.0.8",
|
||||
"postcss-url": "^7.2.1",
|
||||
"rimraf": "^2.6.0",
|
||||
"semver": "^5.3.0",
|
||||
"shelljs": "^0.8.5",
|
||||
"uglifyjs-webpack-plugin": "^1.1.1",
|
||||
"url-loader": "^0.5.8",
|
||||
"vue-loader": "^13.3.0",
|
||||
"vue-style-loader": "^3.0.1",
|
||||
"vue-template-compiler": "^2.5.2",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-bundle-analyzer": "^2.9.0",
|
||||
"webpack-dev-server": "^2.9.1",
|
||||
"webpack-merge": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
]
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import userService from './components/service/UserService'
|
||||
export default {
|
||||
name: 'app',
|
||||
data(){
|
||||
return {
|
||||
isLogin: false,
|
||||
excludeLoginCheck: ["/play/wasm", "/play/rtc"],
|
||||
userInfo: { //保存用户信息
|
||||
nick: null,
|
||||
ulevel: null,
|
||||
uid: null,
|
||||
portrait: null
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (userService.getToken() == null){
|
||||
console.log(22222)
|
||||
console.log(this.$route.path)
|
||||
try {
|
||||
if (this.excludeLoginCheck && this.excludeLoginCheck.length > 0) {
|
||||
for (let i = 0; i < this.excludeLoginCheck.length; i++) {
|
||||
if (this.$route.path.startsWith(this.excludeLoginCheck[i])){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
//如果没有登录状态则跳转到登录页
|
||||
this.$router.push('/login');
|
||||
}
|
||||
},
|
||||
|
||||
mounted(){
|
||||
//组件开始挂载时获取用户信息
|
||||
// this.getUserInfo();
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
components: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
margin: 0 0;
|
||||
background-color: #e9eef3;
|
||||
height: 100%;
|
||||
}
|
||||
.el-header,
|
||||
.el-footer {
|
||||
/* background-color: #b3c0d1; */
|
||||
color: #333;
|
||||
text-align: center;
|
||||
line-height: 60px;
|
||||
}
|
||||
.el-main {
|
||||
background-color: #f0f2f5;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
/*定义滚动条轨道 内阴影+圆角*/
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 4px;
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
|
||||
/*定义滑块 内阴影+圆角*/
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
background-color: #c8c8c8;
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .1);
|
||||
}
|
||||
.table-header {
|
||||
color: #727272;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 546 B |
|
Before Width: | Height: | Size: 48 KiB |
@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<div id="ChannelEdit" v-loading="locading" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<el-page-header @back="close" content="编辑通道"></el-page-header>
|
||||
</div>
|
||||
<div class="page-header-btn">
|
||||
<div style="display: inline;">
|
||||
<el-button icon="el-icon-close" size="mini" style="font-size: 20px; color: #000;" type="text" @click="close" ></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<CommonChannelEdit ref="commonChannelEdit" :id="id" :saveSuccess="close" :cancel="close"></CommonChannelEdit>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CommonChannelEdit from './common/CommonChannelEdit'
|
||||
|
||||
export default {
|
||||
name: "channelEdit",
|
||||
props: [ 'id', 'closeEdit'],
|
||||
components: {
|
||||
CommonChannelEdit,
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
close: function () {
|
||||
this.closeEdit()
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,307 +0,0 @@
|
||||
<template>
|
||||
<div id="app" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<div >云端录像</div>
|
||||
</div>
|
||||
|
||||
<div class="page-header-btn">
|
||||
搜索:
|
||||
<el-input @input="initData" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="search" clearable></el-input>
|
||||
开始时间:
|
||||
<el-date-picker
|
||||
v-model="startTime"
|
||||
type="datetime"
|
||||
size="mini"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
@change="initData"
|
||||
placeholder="选择日期时间">
|
||||
</el-date-picker>
|
||||
结束时间:
|
||||
<el-date-picker
|
||||
v-model="endTime"
|
||||
type="datetime"
|
||||
size="mini"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
@change="initData"
|
||||
placeholder="选择日期时间">
|
||||
</el-date-picker>
|
||||
节点选择:
|
||||
<el-select size="mini" @change="initData" style="width: 16rem; margin-right: 1rem;"
|
||||
v-model="mediaServerId" placeholder="请选择" >
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<!-- <el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteRecord()">批量删除</el-button>-->
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" :loading="loading"
|
||||
@click="initData()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--设备列表-->
|
||||
<el-table size="medium" :data="recordList" style="width: 100%" :height="$tableHeght">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column prop="app" label="应用名">
|
||||
</el-table-column>
|
||||
<el-table-column prop="stream" label="流ID" width="380">
|
||||
</el-table-column>
|
||||
<el-table-column label="开始时间">
|
||||
<template v-slot:default="scope">
|
||||
{{formatTimeStamp(scope.row.startTime)}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间">
|
||||
<template v-slot:default="scope">
|
||||
{{formatTimeStamp(scope.row.endTime)}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时长">
|
||||
<template v-slot:default="scope">
|
||||
<el-tag v-if="Vue.prototype.$myServerId !== scope.row.serverId" style="border-color: #ecf1af">{{formatTime(scope.row.timeLen)}}</el-tag>
|
||||
<el-tag v-if="Vue.prototype.$myServerId === scope.row.serverId">{{formatTime(scope.row.timeLen)}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fileName" label="文件名称">
|
||||
</el-table-column>
|
||||
<el-table-column prop="mediaServerId" label="流媒体">
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button size="medium" icon="el-icon-video-play" type="text" @click="play(scope.row)">播放
|
||||
</el-button>
|
||||
<el-button size="medium" icon="el-icon-download" type="text" @click="downloadFile(scope.row)">下载
|
||||
</el-button>
|
||||
<!-- <el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c"-->
|
||||
<!-- @click="deleteRecord(scope.row)">删除-->
|
||||
<!-- </el-button>-->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
<el-dialog
|
||||
:title="playerTitle"
|
||||
:visible.sync="showPlayer"
|
||||
width="50%">
|
||||
<easyPlayer ref="recordVideoPlayer" :videoUrl="videoUrl" :height="false" ></easyPlayer>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import MediaServer from './service/MediaServer'
|
||||
import easyPlayer from './common/easyPlayer.vue'
|
||||
import moment from 'moment'
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
uiHeader,easyPlayer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
showPlayer: false,
|
||||
playerTitle: '',
|
||||
videoUrl: '',
|
||||
playerStyle: {
|
||||
"margin": "auto",
|
||||
"margin-bottom": "20px",
|
||||
"width": window.innerWidth/2 + "px",
|
||||
"height": this.winHeight/2 + "px",
|
||||
},
|
||||
mediaServerList: [], // 滅体节点列表
|
||||
mediaServerId: "", // 媒体服务
|
||||
mediaServerPath: null, // 媒体服务地址
|
||||
recordList: [], // 设备列表
|
||||
chooseRecord: null, // 媒体服务
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
winHeight: window.innerHeight - 250,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
loading: false,
|
||||
mediaServerObj: new MediaServer(),
|
||||
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
Vue() {
|
||||
return Vue
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.getMediaServerList();
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('recordVideoPlayer');
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.getRecordList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getRecordList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getRecordList();
|
||||
},
|
||||
getMediaServerList: function () {
|
||||
let that = this;
|
||||
that.mediaServerObj.getOnlineMediaServerList((data) => {
|
||||
that.mediaServerList = data.data;
|
||||
})
|
||||
},
|
||||
setMediaServerPath: function (serverId) {
|
||||
let that = this;
|
||||
let i;
|
||||
for (i = 0; i < that.mediaServerList.length; i++) {
|
||||
if (serverId === that.mediaServerList[i].id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let port = that.mediaServerList[i].httpPort;
|
||||
if (location.protocol === "https:" && that.mediaServerList[i].httpSSlPort) {
|
||||
port = that.mediaServerList[i].httpSSlPort
|
||||
}
|
||||
that.mediaServerPath = location.protocol + "//" + that.mediaServerList[i].streamIp + ":" + port
|
||||
console.log(that.mediaServerPath)
|
||||
},
|
||||
getRecordList: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/list`,
|
||||
params: {
|
||||
app: '',
|
||||
stream: '',
|
||||
query: this.search,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime,
|
||||
mediaServerId: this.mediaServerId,
|
||||
page: this.currentPage,
|
||||
count: this.count
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.recordList = res.data.data.list;
|
||||
}
|
||||
this.loading = false;
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
play(row) {
|
||||
console.log(row)
|
||||
this.chooseRecord = row;
|
||||
this.showPlayer = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/play/path`,
|
||||
params: {
|
||||
recordId: row.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
if (location.protocol === "https:") {
|
||||
this.videoUrl = res.data.data.httpsPath;
|
||||
}else {
|
||||
this.videoUrl = res.data.data.httpPath;
|
||||
}
|
||||
console.log(222 )
|
||||
console.log(this.videoUrl )
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
downloadFile(file){
|
||||
console.log(file)
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/play/path`,
|
||||
params: {
|
||||
recordId: file.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
const link = document.createElement('a');
|
||||
link.target = "_blank";
|
||||
if (res.data.code === 0) {
|
||||
if (location.protocol === "https:") {
|
||||
link.href = res.data.data.httpsPath + "&save_name=" + file.fileName;
|
||||
}else {
|
||||
link.href = res.data.data.httpPath + "&save_name=" + file.fileName;
|
||||
}
|
||||
link.click();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
deleteRecord() {
|
||||
// TODO
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url: `/record_proxy/api/record/delete`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count
|
||||
}
|
||||
}).then(function (res) {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.recordList = res.data.data.list;
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
formatTime(time) {
|
||||
const h = parseInt(time / 3600 / 1000)
|
||||
const minute = parseInt((time - h * 3600 * 1000) / 60 / 1000)
|
||||
let second = Math.ceil((time - h * 3600 * 1000 - minute * 60 * 1000) / 1000)
|
||||
if (second < 0) {
|
||||
second = 0;
|
||||
}
|
||||
return (h > 0 ? h + `小时` : '') + (minute > 0 ? minute + '分' : '') + (second > 0 ? second + '秒' : '')
|
||||
},
|
||||
formatTimeStamp(time) {
|
||||
return moment.unix(time/1000).format('yyyy-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@ -1,710 +0,0 @@
|
||||
<template>
|
||||
<div id="recordDetail" style="width: 100%">
|
||||
<div class="page-header" style="margin-bottom: 0">
|
||||
<div class="page-title">
|
||||
<el-page-header @back="backToList" content="云端录像"></el-page-header>
|
||||
</div>
|
||||
|
||||
<div class="page-header-btn" v-if="!this.$route.params.mediaServerId" style="padding-right: 1rem">
|
||||
<!-- 节点选择:-->
|
||||
<!-- <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerId" placeholder="请选择" >-->
|
||||
<!-- <el-option-->
|
||||
<!-- key="undefined"-->
|
||||
<!-- label="全部"-->
|
||||
<!-- value="undefined">-->
|
||||
<!-- </el-option>-->
|
||||
<!-- <el-option-->
|
||||
<!-- v-for="item in mediaServerList"-->
|
||||
<!-- :key="item"-->
|
||||
<!-- :label="item"-->
|
||||
<!-- :value="item">-->
|
||||
<!-- </el-option>-->
|
||||
<!-- </el-select>-->
|
||||
<b>节点:</b> {{ mediaServerId }}
|
||||
</div>
|
||||
<div v-if="this.$route.params.mediaServerId" style="margin-right: 1rem;">
|
||||
<span>流媒体:{{ this.$route.params.mediaServerId }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-container>
|
||||
<el-aside width="260px">
|
||||
<div class="record-list-box-box">
|
||||
<div style="margin-top: 20px">
|
||||
<el-date-picker size="mini" v-model="chooseDate" :picker-options="pickerOptions" type="date"
|
||||
value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker>
|
||||
<!-- <el-button :disabled="!mediaServerId" size="mini" type="primary" icon="fa fa-cloud-download" style="margin: auto; margin-left: 12px " title="裁剪合并" @click="drawerOpen"></el-button>-->
|
||||
</div>
|
||||
<div class="record-list-box" :style="recordListStyle">
|
||||
<ul v-if="detailFiles.length >0" class="infinite-list record-list" v-infinite-scroll="infiniteScroll" >
|
||||
<li v-for="(item,index) in detailFiles" :key="index" class="infinite-list-item record-list-item" >
|
||||
<el-tag v-if="choosedFile !== item.fileName" @click="chooseFile(item)">
|
||||
<i class="el-icon-video-camera" ></i>
|
||||
{{ getFileShowName(item) }}
|
||||
</el-tag>
|
||||
<el-tag type="danger" v-if="choosedFile === item.fileName">
|
||||
<i class="el-icon-video-camera" ></i>
|
||||
{{ getFileShowName(item) }}
|
||||
</el-tag>
|
||||
<a class="el-icon-download" @click="downloadFile(item)" style="color: #409EFF;font-weight: 600;margin-left: 10px;"
|
||||
target="_blank"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="detailFiles.length === 0" class="record-list-no-val">暂无数据</div>
|
||||
</div>
|
||||
|
||||
|
||||
</el-aside>
|
||||
<el-main style="padding: 22px">
|
||||
<div class="playBox" :style="playerStyle">
|
||||
<player ref="recordVideoPlayer" :videoUrl="videoUrl" :height="true" style="width: 100%" ></player>
|
||||
</div>
|
||||
<div class="player-option-box" >
|
||||
<el-slider
|
||||
class="playtime-slider"
|
||||
v-model="playTime"
|
||||
id="playtimeSlider"
|
||||
:disabled="detailFiles.length === 0"
|
||||
:min="sliderMIn"
|
||||
:max="sliderMax"
|
||||
:format-tooltip="playTimeFormat"
|
||||
@change="playTimeChange"
|
||||
:marks="playTimeSliderMarks">
|
||||
</el-slider>
|
||||
<div class="slider-val-box">
|
||||
<div class="slider-val" v-for="(item,index) of detailFiles" :key="index" :style="'width:' + getDataWidth(item) + '%; left:' + getDataLeft(item) + '%'"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-main>
|
||||
</el-container>
|
||||
<el-drawer
|
||||
title="录像下载"
|
||||
:visible.sync="drawer"
|
||||
:direction="direction"
|
||||
:before-close="drawerClose">
|
||||
<div class="drawer-box">
|
||||
<el-button icon="el-icon-plus" size="mini" type="primary" @click="addTask"></el-button>
|
||||
<el-tabs type="border-card" style="height: 100%" v-model="tabVal" @tab-click="tabClick">
|
||||
<el-tab-pane name="running">
|
||||
<span slot="label"><i class="el-icon-scissors"></i>进行中</span>
|
||||
<ul class="task-list">
|
||||
<li class="task-list-item" v-for="(item,index) in taskListForRuning" :key="index">
|
||||
<div class="task-list-item-box">
|
||||
<span>{{ item.startTime.substr(10) }}-{{item.endTime.substr(10)}}</span>
|
||||
<el-progress :percentage="(parseFloat(item.percentage)*100).toFixed(1)"></el-progress>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="ended">
|
||||
<span slot="label"><i class="el-icon-finished"></i>已完成</span>
|
||||
<ul class="task-list">
|
||||
<li class="task-list-item" v-for="(item, index) in taskListEnded" :key="index">
|
||||
<div class="task-list-item-box" style="height: 2rem;line-height: 2rem;">
|
||||
<span>{{ item.startTime.substr(10) }}-{{item.endTime.substr(10)}}</span>
|
||||
<a class="el-icon-download download-btn" :href="getFileBasePath() + '/download.html?url=download/' "
|
||||
target="_blank">
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<el-dialog title="选择时间段" :visible.sync="showTaskBox">
|
||||
<el-date-picker
|
||||
type="datetimerange"
|
||||
v-model="taskTimeRange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="HH:mm:ss"
|
||||
placeholder="选择时间范围">
|
||||
</el-date-picker>
|
||||
<el-button size="mini" type="primary" @click="addTaskToServer">确认</el-button>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
// TODO 根据查询的时间列表设置滑轨的最大值与最小值,
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import player from './common/easyPlayer.vue'
|
||||
import moment from 'moment'
|
||||
import axios from "axios";
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
uiHeader, player
|
||||
},
|
||||
// props: [ 'mediaServerId',],
|
||||
data() {
|
||||
return {
|
||||
app: this.$route.params.app,
|
||||
stream: this.$route.params.stream,
|
||||
mediaServerId: this.$route.params.mediaServerId,
|
||||
dateFilesObj: [],
|
||||
mediaServerList: [],
|
||||
detailFiles: [],
|
||||
loading: false,
|
||||
chooseDate: null,
|
||||
videoUrl: null,
|
||||
choosedFile: null,
|
||||
queryDate: new Date(),
|
||||
currentPage: 1,
|
||||
count: 1000000, // TODO 分页导致滑轨视频有效值无法获取完全
|
||||
total: 0,
|
||||
direction: "ltr",
|
||||
drawer: false,
|
||||
showTaskBox: false,
|
||||
taskTimeRange: [],
|
||||
taskListEnded: [],
|
||||
taskListForRuning: [],
|
||||
sliderMIn: 0,
|
||||
sliderMax: 86400,
|
||||
autoPlay: true,
|
||||
taskUpdate: null,
|
||||
tabVal: "running",
|
||||
recordListStyle: {
|
||||
height: this.winHeight + "px",
|
||||
overflow: "auto",
|
||||
margin: "10px auto 10px auto"
|
||||
},
|
||||
playerStyle: {
|
||||
"margin": "auto",
|
||||
"margin-bottom": "20px",
|
||||
"height": this.winHeight + "px",
|
||||
},
|
||||
timeFormat:'00:00:00',
|
||||
winHeight: window.innerHeight - 240,
|
||||
playTime: 0,
|
||||
playTimeSliderMarks: {
|
||||
0: "00:00",
|
||||
3600: "01:00",
|
||||
7200: "02:00",
|
||||
10800: "03:00",
|
||||
14400: "04:00",
|
||||
18000: "05:00",
|
||||
21600: "06:00",
|
||||
25200: "07:00",
|
||||
28800: "08:00",
|
||||
32400: "09:00",
|
||||
36000: "10:00",
|
||||
39600: "11:00",
|
||||
43200: "12:00",
|
||||
46800: "13:00",
|
||||
50400: "14:00",
|
||||
54000: "15:00",
|
||||
57600: "16:00",
|
||||
61200: "17:00",
|
||||
64800: "18:00",
|
||||
68400: "19:00",
|
||||
72000: "20:00",
|
||||
75600: "21:00",
|
||||
79200: "22:00",
|
||||
82800: "23:00",
|
||||
86400: "24:00",
|
||||
},
|
||||
pickerOptions:{
|
||||
cellClassName:(date) =>{
|
||||
// 通过显示一个点标识这一天有录像
|
||||
let time = moment(date).format('YYYY-MM-DD')
|
||||
if (this.dateFilesObj[time]){
|
||||
return "data-picker-true"
|
||||
}else {
|
||||
return "data-picker-false"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.recordListStyle.height = this.winHeight + "px";
|
||||
this.playerStyle["height"] = this.winHeight + "px";
|
||||
// 查询当年有视频的日期
|
||||
this.getDateInYear(()=>{
|
||||
if (Object.values(this.dateFilesObj).length > 0){
|
||||
this.chooseDate = Object.values(this.dateFilesObj)[Object.values(this.dateFilesObj).length -1];
|
||||
this.dateChange();
|
||||
}
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('recordVideoPlayer');
|
||||
},
|
||||
methods: {
|
||||
dateChange(){
|
||||
this.playTime = 0;
|
||||
this.detailFiles = [];
|
||||
this.currentPage = 1;
|
||||
this.sliderMIn= 0;
|
||||
this.sliderMax= 86400;
|
||||
let chooseFullDate = new Date(this.chooseDate +" " + this.timeFormat);
|
||||
if (chooseFullDate.getFullYear() !== this.queryDate.getFullYear()
|
||||
|| chooseFullDate.getMonth() !== this.queryDate.getMonth()){
|
||||
this.queryDate = chooseFullDate;
|
||||
this.getDateInYear()
|
||||
}
|
||||
this.queryRecordDetails(()=>{
|
||||
if (this.detailFiles.length > 0){
|
||||
console.log(this.detailFiles)
|
||||
let timeForFile = this.getTimeForFile(this.detailFiles[0]);
|
||||
let lastTimeForFile = this.getTimeForFile(this.detailFiles[this.detailFiles.length - 1]);
|
||||
let timeNum = timeForFile[0].getTime() - new Date(this.chooseDate + " " + this.timeFormat).getTime()
|
||||
console.log(timeNum)
|
||||
let lastTimeNum = lastTimeForFile[1].getTime() - new Date(this.chooseDate + " " + this.timeFormat).getTime()
|
||||
|
||||
this.playTime = parseInt(timeNum/1000)
|
||||
this.sliderMIn = parseInt(timeNum/1000 - timeNum/1000%(60*60))
|
||||
console.log(this.sliderMIn )
|
||||
this.sliderMax = parseInt(lastTimeNum/1000 - lastTimeNum/1000%(60*60)) + 60*60
|
||||
console.log(this.sliderMax )
|
||||
}
|
||||
});
|
||||
},
|
||||
infiniteScroll(){
|
||||
if (this.total > this.detailFiles.length) {
|
||||
this.currentPage ++;
|
||||
this.queryRecordDetails();
|
||||
}
|
||||
},
|
||||
queryRecordDetails: function (callback){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/list`,
|
||||
params: {
|
||||
app: this.app,
|
||||
stream: this.stream,
|
||||
startTime: this.chooseDate + " 00:00:00",
|
||||
endTime: this.chooseDate + " 23:59:59",
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
mediaServerId: this.mediaServerId
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.detailFiles = this.detailFiles.concat(res.data.data.list);
|
||||
let temp = new Set()
|
||||
for (let i = 0; i < this.detailFiles.length; i++) {
|
||||
temp.add(this.detailFiles[i].mediaServerId)
|
||||
}
|
||||
this.mediaServerList = Array.from(temp)
|
||||
if (this.mediaServerList.length === 1) {
|
||||
this.mediaServerId = this.mediaServerList[0]
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
if (callback) callback();
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
chooseFile(file){
|
||||
console.log(file)
|
||||
if (file == null) {
|
||||
this.videoUrl = "";
|
||||
this.choosedFile = "";
|
||||
}else {
|
||||
this.choosedFile = file.fileName;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/play/path`,
|
||||
params: {
|
||||
recordId: file.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
if (location.protocol === "https:") {
|
||||
this.videoUrl = res.data.data.httpsPath;
|
||||
}else {
|
||||
this.videoUrl = res.data.data.httpPath;
|
||||
}
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
downloadFile(file){
|
||||
console.log(file)
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/play/path`,
|
||||
params: {
|
||||
recordId: file.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
const link = document.createElement('a');
|
||||
link.target = "_blank";
|
||||
if (res.data.code === 0) {
|
||||
if (location.protocol === "https:") {
|
||||
link.href = res.data.data.httpsPath + "&save_name=" + file.fileName;
|
||||
}else {
|
||||
link.href = res.data.data.httpPath + "&save_name=" + file.fileName;
|
||||
}
|
||||
link.click();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
backToList() {
|
||||
this.$router.back()
|
||||
},
|
||||
getFileShowName(item) {
|
||||
return moment(item.startTime).format('HH:mm:ss') + "-" + moment(item.endTime).format('HH:mm:ss')
|
||||
},
|
||||
chooseMediaChange() {
|
||||
|
||||
},
|
||||
getRecordList() {
|
||||
|
||||
},
|
||||
|
||||
getFileBasePath(item) {
|
||||
let basePath = ""
|
||||
if (axios.defaults.baseURL.startsWith("http")) {
|
||||
basePath = `${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}`
|
||||
}else {
|
||||
basePath = `${window.location.origin}${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}`
|
||||
}
|
||||
return basePath;
|
||||
},
|
||||
|
||||
getDataWidth(item){
|
||||
let timeForFile = this.getTimeForFile(item);
|
||||
let result = (timeForFile[2])/((this.sliderMax - this.sliderMIn)*1000)
|
||||
return result*100
|
||||
},
|
||||
getDataLeft(item){
|
||||
let timeForFile = this.getTimeForFile(item);
|
||||
let differenceTime = timeForFile[0].getTime() - new Date(this.chooseDate + " " + this.timeFormat).getTime()
|
||||
return parseFloat((differenceTime - this.sliderMIn * 1000)/((this.sliderMax - this.sliderMIn)*1000))*100 ;
|
||||
},
|
||||
playTimeChange(val){
|
||||
let minTime = this.getTimeForFile(this.detailFiles[0])[0]
|
||||
let maxTime = this.getTimeForFile(this.detailFiles[this.detailFiles.length - 1])[1];
|
||||
this.chooseFile(null);
|
||||
let timeMilli = new Date(this.chooseDate + " " + this.timeFormat).getTime() + val*1000
|
||||
if (timeMilli >= minTime.getTime() && timeMilli <= maxTime.getTime()){
|
||||
for (let i = 0; i < this.detailFiles.length; i++) {
|
||||
let timeForFile = this.getTimeForFile(this.detailFiles[i]);
|
||||
if (timeMilli >= timeForFile[0].getTime() && timeMilli <= timeForFile[1].getTime()){
|
||||
// TODO 当前未按照实际时间偏移,仅仅是找到对应的文静播放
|
||||
this.chooseFile(this.detailFiles[i])
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getTimeForFile(file){
|
||||
console.log(file)
|
||||
let starTime = new Date(file.startTime * 1000);
|
||||
let endTime = new Date(file.endTime * 1000);
|
||||
if(this.checkIsOver24h(starTime,endTime)){
|
||||
endTime = new Date(this.chooseDate + " " + "23:59:59");
|
||||
}
|
||||
return [starTime, endTime, endTime.getTime() - starTime.getTime()];
|
||||
},
|
||||
checkIsOver24h(starTime,endTime){
|
||||
return starTime > endTime;
|
||||
},
|
||||
playTimeFormat(val){
|
||||
let h = parseInt(val/3600);
|
||||
let m = parseInt((val - h*3600)/60);
|
||||
let s = parseInt(val - h*3600 - m*60);
|
||||
|
||||
let hStr = h;
|
||||
let mStr = m;
|
||||
let sStr = s;
|
||||
if (h < 10) {
|
||||
hStr = "0" + hStr;
|
||||
}
|
||||
if (m < 10) {
|
||||
mStr = "0" + mStr;s
|
||||
}
|
||||
if (s < 10) {
|
||||
sStr = "0" + sStr;
|
||||
}
|
||||
return hStr + ":" + mStr + ":" + sStr
|
||||
},
|
||||
deleteRecord(){
|
||||
// TODO
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url:`/record_proxy/${that.mediaServerId}/api/record/delete`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.recordList = res.data.data.list;
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
getDateInYear(callback){
|
||||
this.dateFilesObj = {};
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/date/list`,
|
||||
params: {
|
||||
app: this.app,
|
||||
stream: this.stream,
|
||||
year: this.queryDate.getFullYear(),
|
||||
month: this.queryDate.getMonth() + 1,
|
||||
mediaServerId: this.mediaServerId,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
if (res.data.data.length > 0) {
|
||||
for (let i = 0; i < res.data.data.length; i++) {
|
||||
this.dateFilesObj[res.data.data[i]] = res.data.data[i]
|
||||
}
|
||||
|
||||
console.log(this.dateFilesObj)
|
||||
}
|
||||
}
|
||||
if(callback)callback();
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
tabClick(){
|
||||
this.getTaskList(this.tabVal === "ended")
|
||||
},
|
||||
drawerClose(){
|
||||
this.drawer = false;
|
||||
if (this.taskUpdate != null) {
|
||||
window.clearInterval(this.taskUpdate)
|
||||
}
|
||||
},
|
||||
drawerOpen(){
|
||||
this.drawer = true;
|
||||
if (this.taskUpdate != null) {
|
||||
window.clearInterval(this.taskUpdate)
|
||||
}
|
||||
this.taskUpdate = setInterval(()=>{
|
||||
this.getTaskList(this.tabVal === "ended")
|
||||
}, 1000)
|
||||
},
|
||||
addTask(){
|
||||
this.showTaskBox = true;
|
||||
let startTimeStr = this.chooseDate + " " + this.detailFiles[0].fileName.substring(0, 8);
|
||||
let endTimeStr = this.chooseDate + " " + this.detailFiles[this.detailFiles.length - 1].fileName.substring(9, 17);
|
||||
this.taskTimeRange[0] = new Date(startTimeStr)
|
||||
this.taskTimeRange[1] = new Date(endTimeStr)
|
||||
},
|
||||
addTaskToServer(){
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/cloud/record/task/add`,
|
||||
params: {
|
||||
app: this.app,
|
||||
stream: this.stream,
|
||||
mediaServerId: this.mediaServerId,
|
||||
startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
|
||||
endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'),
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0 ) {
|
||||
that.showTaskBox = false
|
||||
that.getTaskList(false);
|
||||
}else {
|
||||
that.$message.error(res.data.msg);
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
handleTabClick() {
|
||||
this.getTaskList(this.tabVal === "ended")
|
||||
},
|
||||
getTaskList(isEnd){
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/cloud/record/task/list`,
|
||||
params: {
|
||||
mediaServerId: this.mediaServerId,
|
||||
isEnd: isEnd,
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0) {
|
||||
if (isEnd){
|
||||
that.taskListEnded = res.data.data;
|
||||
}else {
|
||||
that.taskListForRuning = res.data.data;
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
goBack(){
|
||||
this.$router.push('/cloudRecord');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.el-slider__runway {
|
||||
background-color:rgba(206, 206, 206, 0.47) !important;
|
||||
}
|
||||
.el-slider__bar {
|
||||
background-color: rgba(153, 153, 153, 0) !important;
|
||||
}
|
||||
.playtime-slider {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
}
|
||||
.data-picker-true{
|
||||
|
||||
}
|
||||
.data-picker-true:after{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background-color: #606060;
|
||||
border-radius: 4px;
|
||||
left: 45%;
|
||||
top: 74%;
|
||||
|
||||
}
|
||||
.data-picker-false{
|
||||
|
||||
}
|
||||
.slider-val-box{
|
||||
height: 6px;
|
||||
position: relative;
|
||||
top: -22px;
|
||||
}
|
||||
.slider-val{
|
||||
height: 6px;
|
||||
background-color: #007CFF;
|
||||
position: absolute;
|
||||
}
|
||||
.record-list-box-box{
|
||||
width: 250px;
|
||||
float: left;
|
||||
}
|
||||
.record-list-box{
|
||||
overflow: auto;
|
||||
width: 220px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-top: 0px;
|
||||
padding: 1rem 0;
|
||||
background-color: #FFF;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.record-list{
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: #FFF;
|
||||
|
||||
}
|
||||
.record-list-no-val {
|
||||
position: absolute;
|
||||
color: #9f9f9f;
|
||||
top: 50%;
|
||||
left: 110px;
|
||||
}
|
||||
.record-list-item{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin: 0.5rem 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.record-list-option {
|
||||
width: 10px;
|
||||
float: left;
|
||||
margin-top: 39px;
|
||||
|
||||
}
|
||||
.drawer-box{
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.task-list{
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.task-list-item{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
.task-list-item-box{
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
color: #555;
|
||||
}
|
||||
.download-btn{
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
background: #FFF;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border: 1px solid #DCDFE6;
|
||||
border-top-color: rgb(220, 223, 230);
|
||||
border-right-color: rgb(220, 223, 230);
|
||||
border-bottom-color: rgb(220, 223, 230);
|
||||
border-left-color: rgb(220, 223, 230);
|
||||
border-top-color: rgb(220, 223, 230);
|
||||
border-right-color: rgb(220, 223, 230);
|
||||
border-bottom-color: rgb(220, 223, 230);
|
||||
border-left-color: rgb(220, 223, 230);
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
-webkit-transition: .1s;
|
||||
transition: .1s;
|
||||
font-weight: 500;
|
||||
padding: 7px 14px;
|
||||
font-size: 0.875rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
border-radius: 3px;
|
||||
color: #FFF;
|
||||
background-color: #409EFF;
|
||||
border-color: #409EFF;
|
||||
float: right;
|
||||
}
|
||||
.download-btn:hover{
|
||||
background: #66b1ff;
|
||||
border-color: #66b1ff;
|
||||
color: #FFF;
|
||||
}
|
||||
.time-box{
|
||||
}
|
||||
</style>
|
||||
@ -1,557 +0,0 @@
|
||||
<template>
|
||||
<div id="app" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">设备列表</div>
|
||||
<div class="page-header-btn">
|
||||
搜索:
|
||||
<el-input @input="initData" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
在线状态:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="initData" v-model="online" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="在线" value="true"></el-option>
|
||||
<el-option label="离线" value="false"></el-option>
|
||||
</el-select>
|
||||
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="add">添加设备
|
||||
</el-button>
|
||||
<el-button icon="el-icon-info" size="mini" style="margin-right: 1rem;" type="primary" @click="showInfo()">平台信息
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading"
|
||||
@click="getDeviceList()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--设备列表-->
|
||||
<el-table size="medium" :data="deviceList" style="width: 100%;font-size: 12px;" :height="$tableHeght" header-row-class-name="table-header">
|
||||
<el-table-column prop="name" label="名称" min-width="160">
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceId" label="设备编号" min-width="160" >
|
||||
</el-table-column>
|
||||
<el-table-column label="地址" min-width="160" >
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag v-if="scope.row.hostAddress" size="medium">{{ scope.row.hostAddress }}</el-tag>
|
||||
<el-tag v-if="!scope.row.hostAddress" size="medium">未知</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="manufacturer" label="厂家" min-width="100" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="transport" label="信令传输模式" min-width="100" >
|
||||
</el-table-column>
|
||||
<el-table-column label="流传输模式" min-width="160" >
|
||||
<template v-slot:default="scope">
|
||||
<el-select size="mini" @change="transportChange(scope.row)" v-model="scope.row.streamMode" placeholder="请选择" style="width: 120px">
|
||||
<el-option key="UDP" label="UDP" value="UDP"></el-option>
|
||||
<el-option key="TCP-ACTIVE" label="TCP主动模式" value="TCP-ACTIVE"></el-option>
|
||||
<el-option key="TCP-PASSIVE" label="TCP被动模式" value="TCP-PASSIVE"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="通道数" min-width="100" >
|
||||
<template v-slot:default="scope">
|
||||
<span style="font-size: 1rem">{{scope.row.channelCount}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.onLine && Vue.prototype.$myServerId !== scope.row.serverId" style="border-color: #ecf1af">在线</el-tag>
|
||||
<el-tag size="medium" v-if="scope.row.onLine && Vue.prototype.$myServerId === scope.row.serverId">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="!scope.row.onLine">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订阅" min-width="260" >
|
||||
<template v-slot:default="scope">
|
||||
<el-checkbox label="目录" :checked="scope.row.subscribeCycleForCatalog > 0" @change="(e)=>subscribeForCatalog(scope.row.id, e)"></el-checkbox>
|
||||
<el-checkbox label="位置" :checked="scope.row.subscribeCycleForMobilePosition > 0" @change="(e)=>subscribeForMobilePosition(scope.row.id, e)"></el-checkbox>
|
||||
<el-checkbox label="报警" disabled :checked="scope.row.subscribeCycleForAlarm > 0"></el-checkbox>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="keepaliveTime" label="最近心跳" min-width="140" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="registerTime" label="最近注册" min-width="140">
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="300" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button type="text" size="medium" v-bind:disabled="scope.row.online===0" icon="el-icon-refresh" @click="refDevice(scope.row)"
|
||||
@mouseover="getTooltipContent(scope.row.deviceId)">刷新
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button type="text" size="medium" icon="el-icon-video-camera"
|
||||
@click="showChannelList(scope.row)">通道
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">编辑</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-dropdown @command="(command)=>{moreClick(command, scope.row)}">
|
||||
<el-button size="medium" type="text" >
|
||||
操作<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="delete" style="color: #f56c6c">
|
||||
删除</el-dropdown-item>
|
||||
<el-dropdown-item command="setGuard" v-bind:disabled="!scope.row.onLine">
|
||||
布防</el-dropdown-item>
|
||||
<el-dropdown-item command="resetGuard" v-bind:disabled="!scope.row.onLine">
|
||||
撤防</el-dropdown-item>
|
||||
<el-dropdown-item command="syncBasicParam" v-bind:disabled="!scope.row.onLine">
|
||||
基础配置同步</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
<deviceEdit ref="deviceEdit"></deviceEdit>
|
||||
<syncChannelProgress ref="syncChannelProgress"></syncChannelProgress>
|
||||
<configInfo ref="configInfo"></configInfo>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import deviceEdit from './dialog/deviceEdit.vue'
|
||||
import syncChannelProgress from './dialog/SyncChannelProgress.vue'
|
||||
import configInfo from "./dialog/configInfo.vue";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
configInfo,
|
||||
uiHeader,
|
||||
deviceEdit,
|
||||
syncChannelProgress,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
deviceList: [], //设备列表
|
||||
currentDevice: {}, //当前操作设备对象
|
||||
searchSrt: "",
|
||||
online: null,
|
||||
videoComponentList: [],
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
currentDeviceChannelsLength: 0,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
getDeviceListLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
Vue() {
|
||||
return Vue
|
||||
},
|
||||
getcurrentDeviceChannels: function () {
|
||||
let data = this.currentDevice['channelMap'];
|
||||
let channels = null;
|
||||
if (data) {
|
||||
channels = Object.keys(data).map(key => {
|
||||
return data[key];
|
||||
});
|
||||
this.currentDeviceChannelsLength = channels.length;
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.updateLooper = setInterval(this.getDeviceList, 10000);
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('videojs');
|
||||
clearTimeout(this.updateLooper);
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.currentPage = 1;
|
||||
this.total= 0;
|
||||
this.getDeviceList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getDeviceList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getDeviceList();
|
||||
},
|
||||
getDeviceList: function () {
|
||||
this.getDeviceListLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/query/devices`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
status: this.online,
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.deviceList = res.data.data.list;
|
||||
}
|
||||
this.getDeviceListLoading = false;
|
||||
}).catch( (error)=> {
|
||||
console.error(error);
|
||||
this.getDeviceListLoading = false;
|
||||
});
|
||||
},
|
||||
deleteDevice: function (row) {
|
||||
let msg = "确定删除此设备?"
|
||||
if (row.online !== 0) {
|
||||
msg = "在线设备删除后仍可通过注册再次上线。<br/>如需彻底删除请先将设备离线。<br/><strong>确定删除此设备?</strong>"
|
||||
}
|
||||
this.$confirm(msg, '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
center: true,
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url: `/api/device/query/devices/${row.deviceId}/delete`
|
||||
}).then((res) => {
|
||||
this.getDeviceList();
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
showChannelList: function (row) {
|
||||
this.$router.push(`/channelList/${row.deviceId}/0`);
|
||||
},
|
||||
showDevicePosition: function (row) {
|
||||
this.$router.push(`/map?deviceId=${row.deviceId}`);
|
||||
},
|
||||
|
||||
//gb28181平台对接
|
||||
//刷新设备信息
|
||||
refDevice: function (itemData) {
|
||||
console.log("刷新对应设备:" + itemData.deviceId);
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/device/query/devices/' + itemData.deviceId + '/sync'
|
||||
}).then((res) => {
|
||||
console.log("刷新设备结果:" + JSON.stringify(res));
|
||||
if (res.data.code !== 0) {
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
} else {
|
||||
if (res.data.data && res.data.data.errorMsg) {
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: res.data.data.errorMsg,
|
||||
type: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.$refs.syncChannelProgress.openDialog(itemData.deviceId, ()=>{
|
||||
console.log(32322)
|
||||
this.initData()
|
||||
})
|
||||
}
|
||||
that.initData()
|
||||
}).catch((e) => {
|
||||
console.error(e)
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: e,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
getTooltipContent: async function (deviceId) {
|
||||
let result = "";
|
||||
await this.$axios({
|
||||
method: 'get',
|
||||
async: false,
|
||||
url: `/api/device/query/${deviceId}/sync_status/`,
|
||||
}).then((res) => {
|
||||
if (res.data.code == 0) {
|
||||
if (res.data.data.errorMsg !== null) {
|
||||
result = res.data.data.errorMsg
|
||||
} else if (res.data.msg !== null) {
|
||||
result = res.data.msg
|
||||
} else {
|
||||
result = `同步中...[${res.data.data.current}/${res.data.data.total}]`;
|
||||
}
|
||||
}
|
||||
})
|
||||
return result;
|
||||
},
|
||||
transportChange: function (row) {
|
||||
console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `);
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: '/api/device/query/transport/' + row.deviceId + '/' + row.streamMode
|
||||
}).then(function (res) {
|
||||
|
||||
}).catch(function (e) {
|
||||
});
|
||||
},
|
||||
edit: function (row) {
|
||||
this.$refs.deviceEdit.openDialog(row, () => {
|
||||
this.$refs.deviceEdit.close();
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "设备修改成功,通道字符集将在下次更新生效",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(this.getDeviceList, 200)
|
||||
|
||||
})
|
||||
},
|
||||
add: function () {
|
||||
this.$refs.deviceEdit.openDialog(null, () => {
|
||||
this.$refs.deviceEdit.close();
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "添加成功",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(this.getDeviceList, 200)
|
||||
|
||||
})
|
||||
},
|
||||
showInfo: function (){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/server/system/configInfo`,
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.serverId = res.data.data.addOn.serverId;
|
||||
this.$refs.configInfo.openDialog(res.data.data)
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
});
|
||||
},
|
||||
moreClick: function (command, itemData) {
|
||||
if (command === "setGuard") {
|
||||
this.setGuard(itemData)
|
||||
}else if (command === "resetGuard") {
|
||||
this.resetGuard(itemData)
|
||||
}else if (command === "delete") {
|
||||
this.deleteDevice(itemData)
|
||||
}else if (command === "syncBasicParam") {
|
||||
this.syncBasicParam(itemData)
|
||||
}
|
||||
},
|
||||
setGuard: function (itemData) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/control/guard/${itemData.deviceId}/SetGuard`,
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "布防成功"
|
||||
})
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
},
|
||||
resetGuard: function (itemData) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/control/guard/${itemData.deviceId}/ResetGuard`,
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "撤防成功"
|
||||
})
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
},
|
||||
subscribeForCatalog: function (data, value) {
|
||||
console.log(data)
|
||||
console.log(value)
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/query/subscribe/catalog`,
|
||||
params: {
|
||||
id: data,
|
||||
cycle: value?60:0
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: value?"订阅成功":"取消订阅成功"
|
||||
})
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
|
||||
},
|
||||
subscribeForMobilePosition: function (data, value) {
|
||||
console.log(data)
|
||||
console.log(value)
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/query/subscribe/mobile-position`,
|
||||
params: {
|
||||
id: data,
|
||||
cycle: value?60:0,
|
||||
interval: value?5:0
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: value?"订阅成功":"取消订阅成功"
|
||||
})
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
},
|
||||
syncBasicParam: function (data) {
|
||||
console.log(data)
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/config/query/${data.deviceId}/BasicParam`,
|
||||
params: {
|
||||
// channelId: data.deviceId
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: `配置已同步,当前心跳间隔: ${res.data.data.BasicParam.HeartBeatInterval} 心跳间隔:${res.data.data.BasicParam.HeartBeatCount}`
|
||||
})
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.videoList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 10rem;
|
||||
margin-right: 1rem;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-item-img:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background-image: url("../assets/loading.png");
|
||||
background-size: cover;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
line-height: 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: 14.4rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,547 +0,0 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<div class="page-header" >
|
||||
<div class="page-title">
|
||||
<el-page-header @back="goBack" content="国标录像"></el-page-header>
|
||||
</div>
|
||||
</div>
|
||||
<el-container>
|
||||
<el-aside width="300px">
|
||||
<div class="record-list-box-box">
|
||||
<el-date-picker size="mini" v-model="chooseDate" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker>
|
||||
<div class="record-list-box" v-loading="recordsLoading" :style="recordListStyle">
|
||||
<ul v-if="detailFiles.length >0" class="infinite-list record-list" >
|
||||
<li v-for="item in detailFiles" class="infinite-list-item record-list-item" >
|
||||
|
||||
<el-tag v-if="chooseFile != item" @click="checkedFile(item)">
|
||||
<i class="el-icon-video-camera" ></i>
|
||||
{{ moment(item.startTime).format('HH:mm:ss')}}-{{ moment(item.endTime).format('HH:mm:ss')}}
|
||||
</el-tag>
|
||||
<el-tag v-if="chooseFile == item" type="danger" >
|
||||
<i class="el-icon-video-camera" ></i>
|
||||
{{ moment(item.startTime).format('HH:mm:ss')}}-{{ moment(item.endTime).format('HH:mm:ss')}}
|
||||
</el-tag>
|
||||
<i style="color: #409EFF;margin-left: 5px;" class="el-icon-download" @click="downloadRecord(item)" ></i>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div size="mini" v-if="detailFiles.length ==0" class="record-list-no-val" >暂无数据</div>
|
||||
</div>
|
||||
|
||||
</el-aside>
|
||||
<el-main style="padding-bottom: 10px;">
|
||||
<div class="playBox" :style="playerBoxStyle">
|
||||
<player ref="recordVideoPlayer"
|
||||
:videoUrl="videoUrl"
|
||||
:error="videoError"
|
||||
:message="videoError"
|
||||
:hasAudio="hasAudio"
|
||||
style="max-height: 100%"
|
||||
:height="playerHeight"
|
||||
fluent autoplay live ></player>
|
||||
</div>
|
||||
<div class="player-option-box">
|
||||
<div>
|
||||
<el-button-group >
|
||||
<el-time-picker
|
||||
size="mini"
|
||||
is-range
|
||||
align="left"
|
||||
v-model="timeRange"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
@change="timePickerChange"
|
||||
placeholder="选择时间范围">
|
||||
</el-time-picker>
|
||||
</el-button-group>
|
||||
|
||||
<el-button-group >
|
||||
<el-button size="mini" class="iconfont icon-zanting" title="暂停" @click="gbPause()"></el-button>
|
||||
<el-button size="mini" class="iconfont icon-kaishi" title="开始" @click="gbPlay()"></el-button>
|
||||
<el-dropdown size="mini" title="播放倍速" @command="gbScale">
|
||||
<el-button size="mini">
|
||||
倍速 <i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="(item,index) in downloadSpeedArray" :key="index" :command="item">{{item}}倍速</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-button size="mini" class="iconfont icon-xiazai1" title="下载选定录像" @click="downloadRecord()"></el-button>
|
||||
<el-button v-if="sliderMIn === 0 && sliderMax === 86400" size="mini" class="iconfont icon-slider" title="放大滑块" @click="setSliderFit()"></el-button>
|
||||
<el-button v-if="sliderMIn !== 0 || sliderMax !== 86400" size="mini" class="iconfont icon-slider-right" title="恢复滑块" @click="setSliderFit()"></el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
<el-slider
|
||||
class="playtime-slider"
|
||||
v-model="playTime"
|
||||
id="playtimeSlider"
|
||||
:disabled="detailFiles.length === 0"
|
||||
:min="sliderMIn"
|
||||
:max="sliderMax"
|
||||
:range="true"
|
||||
:format-tooltip="playTimeFormat"
|
||||
@change="playTimeChange"
|
||||
:marks="playTimeSliderMarks">
|
||||
</el-slider>
|
||||
<div class="slider-val-box">
|
||||
<div class="slider-val" v-for="item of detailFiles" :style="'width:' + getDataWidth(item) + '%; left:' + getDataLeft(item) + '%'"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-main>
|
||||
</el-container>
|
||||
<recordDownload ref="recordDownload"></recordDownload>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import player from './common/jessibuca.vue'
|
||||
import moment from 'moment'
|
||||
import recordDownload from './dialog/recordDownload.vue'
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
uiHeader, player,recordDownload
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
deviceId: this.$route.params.deviceId,
|
||||
channelId: this.$route.params.channelId,
|
||||
downloadSpeedArray: [0.25, 0.5, 1, 2, 4],
|
||||
recordsLoading: false,
|
||||
streamId: "",
|
||||
hasAudio: false,
|
||||
detailFiles: [],
|
||||
chooseDate: null,
|
||||
videoUrl: null,
|
||||
chooseFile: null,
|
||||
streamInfo: null,
|
||||
app: null,
|
||||
mediaServerId: null,
|
||||
ssrc: null,
|
||||
|
||||
sliderMIn: 0,
|
||||
sliderMax: 86400,
|
||||
autoPlay: true,
|
||||
taskUpdate: null,
|
||||
tabVal: "running",
|
||||
recordListStyle: {
|
||||
height: this.winHeight + "px",
|
||||
overflow: "auto",
|
||||
margin: "10px auto 10px auto"
|
||||
},
|
||||
playerBoxStyle: {
|
||||
"margin": "0 auto 20px auto",
|
||||
"height": this.winHeight + "px",
|
||||
},
|
||||
playerHeight: this.winHeight,
|
||||
winHeight: window.innerHeight - 240,
|
||||
playTime: null,
|
||||
timeRange: null,
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
playTimeSliderMarks: {
|
||||
0: "00:00",
|
||||
3600: "01:00",
|
||||
7200: "02:00",
|
||||
10800: "03:00",
|
||||
14400: "04:00",
|
||||
18000: "05:00",
|
||||
21600: "06:00",
|
||||
25200: "07:00",
|
||||
28800: "08:00",
|
||||
32400: "09:00",
|
||||
36000: "10:00",
|
||||
39600: "11:00",
|
||||
43200: "12:00",
|
||||
46800: "13:00",
|
||||
50400: "14:00",
|
||||
54000: "15:00",
|
||||
57600: "16:00",
|
||||
61200: "17:00",
|
||||
64800: "18:00",
|
||||
68400: "19:00",
|
||||
72000: "20:00",
|
||||
75600: "21:00",
|
||||
79200: "22:00",
|
||||
82800: "23:00",
|
||||
86400: "24:00",
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.recordListStyle.height = this.winHeight + "px";
|
||||
this.playerBoxStyle["height"] = this.winHeight + "px";
|
||||
this.chooseDate = moment().format('YYYY-MM-DD')
|
||||
this.dateChange();
|
||||
this.getDownloadSpeedArray()
|
||||
window.addEventListener('beforeunload', this.stopPlayRecord)
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('recordVideoPlayer');
|
||||
window.removeEventListener('beforeunload', this.stopPlayRecord)
|
||||
},
|
||||
methods: {
|
||||
dateChange(){
|
||||
if (!this.chooseDate) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setTime(this.chooseDate + " 00:00:00", this.chooseDate + " 23:59:59");
|
||||
this.recordsLoading = true;
|
||||
this.detailFiles = [];
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/gb_record/query/' + this.deviceId + '/' + this.channelId + '?startTime=' + this.startTime + '&endTime=' + this.endTime
|
||||
}).then((res)=>{
|
||||
this.recordsLoading = false;
|
||||
if(res.data.code === 0) {
|
||||
// 处理时间信息
|
||||
this.detailFiles = res.data.data.recordList;
|
||||
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
}).catch((e)=> {
|
||||
this.recordsLoading = false;
|
||||
// that.videoHistory.searchHistoryResult = falsificationData.recordData;
|
||||
});
|
||||
},
|
||||
moment: function (v) {
|
||||
return moment(v)
|
||||
},
|
||||
setTime: function (startTime, endTime){
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
let start = (new Date(this.startTime).getTime() - new Date(this.chooseDate + " 00:00:00").getTime())/1000;
|
||||
let end = (new Date(this.endTime).getTime() - new Date(this.chooseDate + " 00:00:00").getTime())/1000;
|
||||
console.log(start)
|
||||
console.log(end)
|
||||
this.playTime = [start, end];
|
||||
this.timeRange = [startTime, endTime];
|
||||
},
|
||||
videoError: function (e) {
|
||||
console.log("播放器错误:" + JSON.stringify(e));
|
||||
},
|
||||
checkedFile(file){
|
||||
this.chooseFile = file;
|
||||
this.setTime(file.startTime, file.endTime);
|
||||
// 开始回放
|
||||
this.playRecord()
|
||||
},
|
||||
playRecord: function () {
|
||||
|
||||
if (this.streamId !== "") {
|
||||
this.stopPlayRecord(()=> {
|
||||
this.streamId = "";
|
||||
this.playRecord();
|
||||
})
|
||||
} else {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/playback/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + this.startTime + '&endTime=' +
|
||||
this.endTime
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.streamInfo = res.data.data;
|
||||
this.app = this.streamInfo.app;
|
||||
this.streamId = this.streamInfo.stream;
|
||||
this.mediaServerId = this.streamInfo.mediaServerId;
|
||||
this.ssrc = this.streamInfo.ssrc;
|
||||
this.videoUrl = this.getUrlByStreamInfo();
|
||||
this.hasAudio = this.streamInfo.tracks && this.streamInfo.tracks.length > 1
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
getDownloadSpeedArray(){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/device/query/channel/one',
|
||||
params: {
|
||||
deviceId: this.deviceId,
|
||||
channelDeviceId: this.channelId,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0 && res.data.data.downloadSpeed) {
|
||||
let speedArray = res.data.data.downloadSpeed.split('/');
|
||||
|
||||
speedArray.forEach(item => {
|
||||
if (parseInt(item) > 4) {
|
||||
this.downloadSpeedArray.push(parseInt(item));
|
||||
console.log(this.downloadSpeedArray);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
gbPlay(){
|
||||
console.log('前端控制:播放');
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/playback/resume/' + this.streamId
|
||||
}).then((res)=> {
|
||||
this.$refs["recordVideoPlayer"].play(this.videoUrl)
|
||||
});
|
||||
},
|
||||
gbPause(){
|
||||
console.log('前端控制:暂停');
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/playback/pause/' + this.streamId
|
||||
}).then(function (res) {});
|
||||
},
|
||||
gbScale(command){
|
||||
console.log('前端控制:倍速 ' + command);
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/playback/speed/${this.streamId }/${command}`
|
||||
}).then(function (res) {});
|
||||
},
|
||||
downloadRecord: function (row) {
|
||||
if (!row) {
|
||||
let startTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + this.playTime[0]*1000).format("YYYY-MM-DD HH:mm:ss");
|
||||
let endTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + this.playTime[1]*1000).format("YYYY-MM-DD HH:mm:ss");
|
||||
console.log(startTimeStr);
|
||||
console.log(endTimeStr);
|
||||
row = {
|
||||
startTime: startTimeStr,
|
||||
endTime: endTimeStr
|
||||
}
|
||||
}
|
||||
if (this.streamId !== "") {
|
||||
this.stopPlayRecord(()=> {
|
||||
this.streamId = "";
|
||||
this.downloadRecord(row);
|
||||
})
|
||||
}else {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/gb_record/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
|
||||
row.endTime + '&downloadSpeed='+ this.downloadSpeedArray[this.downloadSpeedArray.length - 1]
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
let streamInfo = res.data.data;
|
||||
this.$refs.recordDownload.openDialog(this.deviceId, this.channelId, streamInfo.app, streamInfo.stream, streamInfo.mediaServerId);
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
stopDownloadRecord: function (callback) {
|
||||
this.$refs["recordVideoPlayer"].pause();
|
||||
this.videoUrl = '';
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId
|
||||
}).then((res)=> {
|
||||
if (callback) callback(res)
|
||||
});
|
||||
},
|
||||
stopPlayRecord: function (callback) {
|
||||
console.log("停止录像回放")
|
||||
if (this.streamId !== "") {
|
||||
this.$refs["recordVideoPlayer"].pause();
|
||||
this.videoUrl = '';
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
|
||||
}).then(function (res) {
|
||||
if (callback) callback()
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
getDataWidth(item){
|
||||
let timeForFile = this.getTimeForFile(item);
|
||||
let result = (timeForFile[2])/((this.sliderMax - this.sliderMIn)*1000)
|
||||
return result*100
|
||||
},
|
||||
getDataLeft(item){
|
||||
let timeForFile = this.getTimeForFile(item);
|
||||
let differenceTime = timeForFile[0].getTime() - new Date(this.chooseDate + " 00:00:00").getTime()
|
||||
return parseFloat((differenceTime - this.sliderMIn * 1000)/((this.sliderMax - this.sliderMIn)*1000))*100 ;
|
||||
},
|
||||
getUrlByStreamInfo(){
|
||||
if (location.protocol === "https:") {
|
||||
this.videoUrl = this.streamInfo["wss_flv"]
|
||||
}else {
|
||||
this.videoUrl = this.streamInfo["ws_flv"]
|
||||
}
|
||||
return this.videoUrl;
|
||||
|
||||
},
|
||||
timePickerChange: function (val){
|
||||
this.setTime(val[0], val[1])
|
||||
},
|
||||
playTimeChange(val){
|
||||
console.log(val)
|
||||
|
||||
let startTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + val[0]*1000).format("YYYY-MM-DD HH:mm:ss");
|
||||
let endTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + val[1]*1000).format("YYYY-MM-DD HH:mm:ss");
|
||||
|
||||
this.setTime(startTimeStr, endTimeStr)
|
||||
|
||||
this.playRecord();
|
||||
},
|
||||
setSliderFit() {
|
||||
if (this.sliderMIn === 0 && this.sliderMax === 86400) {
|
||||
if (this.detailFiles.length > 0){
|
||||
let timeForFile = this.getTimeForFile(this.detailFiles[0]);
|
||||
let lastTimeForFile = this.getTimeForFile(this.detailFiles[this.detailFiles.length - 1]);
|
||||
let timeNum = timeForFile[0].getTime() - new Date(this.chooseDate + " " + "00:00:00").getTime()
|
||||
let lastTimeNum = lastTimeForFile[1].getTime() - new Date(this.chooseDate + " " + "00:00:00").getTime()
|
||||
|
||||
this.playTime = parseInt(timeNum/1000)
|
||||
this.sliderMIn = parseInt(timeNum/1000 - timeNum/1000%(60*60))
|
||||
this.sliderMax = parseInt(lastTimeNum/1000 - lastTimeNum/1000%(60*60)) + 60*60
|
||||
|
||||
this.playTime = [this.sliderMIn, this.sliderMax];
|
||||
}
|
||||
}else {
|
||||
this.sliderMIn = 0;
|
||||
this.sliderMax = 86400;
|
||||
}
|
||||
},
|
||||
getTimeForFile(file){
|
||||
let startTime = new Date(file.startTime);
|
||||
let endTime = new Date(file.endTime);
|
||||
return [startTime, endTime, endTime.getTime() - startTime.getTime()];
|
||||
},
|
||||
playTimeFormat(val){
|
||||
let h = parseInt(val/3600);
|
||||
let m = parseInt((val - h*3600)/60);
|
||||
let s = parseInt(val - h*3600 - m*60);
|
||||
|
||||
let hStr = h;
|
||||
let mStr = m;
|
||||
let sStr = s;
|
||||
if (h < 10) {
|
||||
hStr = "0" + hStr;
|
||||
}
|
||||
if (m < 10) {
|
||||
mStr = "0" + mStr;s
|
||||
}
|
||||
if (s < 10) {
|
||||
sStr = "0" + sStr;
|
||||
}
|
||||
return hStr + ":" + mStr + ":" + sStr
|
||||
},
|
||||
goBack(){
|
||||
// 如果正在进行录像回放则,发送停止
|
||||
if (this.streamId !== "") {
|
||||
this.stopPlayRecord(()=> {
|
||||
this.streamId = "";
|
||||
})
|
||||
}
|
||||
window.history.go(-1);
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.el-slider__runway {
|
||||
background-color:rgba(206, 206, 206, 0.47) !important;
|
||||
}
|
||||
.el-slider__bar {
|
||||
background-color: rgba(153, 153, 153, 0) !important;
|
||||
}
|
||||
.playtime-slider {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
}
|
||||
.data-picker-true{
|
||||
|
||||
}
|
||||
.data-picker-true:after{
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background-color: #606060;
|
||||
border-radius: 4px;
|
||||
left: 45%;
|
||||
top: 74%;
|
||||
|
||||
}
|
||||
.data-picker-false{
|
||||
|
||||
}
|
||||
.slider-val-box{
|
||||
height: 6px;
|
||||
position: relative;
|
||||
top: -22px;
|
||||
}
|
||||
.slider-val{
|
||||
height: 6px;
|
||||
background-color: #007CFF;
|
||||
position: absolute;
|
||||
}
|
||||
.record-list-box-box{
|
||||
width: 250px;
|
||||
float: left;
|
||||
}
|
||||
.record-list-box{
|
||||
overflow: auto;
|
||||
width: 220px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-top: 0px;
|
||||
padding: 1rem 0;
|
||||
background-color: #FFF;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.record-list{
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: #FFF;
|
||||
|
||||
}
|
||||
.record-list-no-val {
|
||||
position: absolute;
|
||||
color: #9f9f9f;
|
||||
top: 50%;
|
||||
left: 110px;
|
||||
}
|
||||
.record-list-item{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin: 0.5rem 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.record-list-option {
|
||||
width: 10px;
|
||||
float: left;
|
||||
margin-top: 39px;
|
||||
|
||||
}
|
||||
.player-option-box{
|
||||
padding: 0 20px;
|
||||
}
|
||||
</style>
|
||||
@ -1,250 +0,0 @@
|
||||
/**
|
||||
* 经纬度转换
|
||||
*/
|
||||
export default {
|
||||
PI: 3.1415926535897932384626,
|
||||
//PI: 3.14159265358979324,
|
||||
x_pi: (3.1415926535897932384626 * 3000.0) / 180.0,
|
||||
delta: function (lat, lng) {
|
||||
// Krasovsky 1940
|
||||
//
|
||||
// a = 6378245.0, 1/f = 298.3
|
||||
// b = a * (1 - f)
|
||||
// ee = (a^2 - b^2) / a^2;
|
||||
var a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
|
||||
var ee = 0.00669342162296594323; // ee: 椭球的偏心率。
|
||||
var dLat = this.transformLat(lng - 105.0, lat - 35.0);
|
||||
var dLng = this.transformLng(lng - 105.0, lat - 35.0);
|
||||
var radLat = (lat / 180.0) * this.PI;
|
||||
var magic = Math.sin(radLat);
|
||||
magic = 1 - ee * magic * magic;
|
||||
var sqrtMagic = Math.sqrt(magic);
|
||||
dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * this.PI);
|
||||
dLng = (dLng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * this.PI);
|
||||
return {
|
||||
lat: dLat,
|
||||
lng: dLng
|
||||
};
|
||||
},
|
||||
/**
|
||||
* WGS-84 to GCJ-02 GPS坐标转中国坐标
|
||||
* @param {number} wgsLat GPS纬度
|
||||
* @param {number} wgsLng GPS经度
|
||||
* @return {object} 返回中国坐标经纬度对象
|
||||
*/
|
||||
GPSToChina: function (wgsLat, wgsLng) {
|
||||
if (this.outOfChina(wgsLat, wgsLng)) return {
|
||||
lat: wgsLat,
|
||||
lng: wgsLng
|
||||
};
|
||||
var d = this.delta(wgsLat, wgsLng);
|
||||
return {
|
||||
lat: Number(wgsLat) + Number(d.lat),
|
||||
lng: Number(wgsLng) + Number(d.lng)
|
||||
};
|
||||
},
|
||||
/**
|
||||
* GCJ-02 to WGS-84 中国标准坐标转GPS坐标
|
||||
* @param {number} gcjLat 中国标准坐标纬度
|
||||
* @param {number} gcjLng 中国标准坐标经度
|
||||
* @return {object} 返回GPS经纬度对象
|
||||
*/
|
||||
chinaToGPS: function (gcjLat, gcjLng) {
|
||||
if (this.outOfChina(gcjLat, gcjLng)) return {
|
||||
lat: gcjLat,
|
||||
lng: gcjLng
|
||||
};
|
||||
var d = this.delta(gcjLat, gcjLng);
|
||||
return {
|
||||
lat: Number(gcjLat) - Number(d.lat),
|
||||
lng: Number(gcjLng) - Number(d.lng)
|
||||
};
|
||||
},
|
||||
/**
|
||||
* GCJ-02 to WGS-84 exactly 中国标准坐标转GPS坐标(精确)
|
||||
* @param {number} gcjLat 中国标准坐标纬度
|
||||
* @param {number} gcjLng 中国标准坐标经度
|
||||
* @return {object} 返回GPS经纬度对象(精确)
|
||||
*/
|
||||
chinaToGPSExact: function (gcjLat, gcjLng) {
|
||||
var initDelta = 0.01;
|
||||
var threshold = 0.000000001;
|
||||
var dLat = initDelta,
|
||||
dLng = initDelta;
|
||||
var mLat = gcjLat - dLat,
|
||||
mLng = gcjLng - dLng;
|
||||
var pLat = gcjLat + dLat,
|
||||
pLng = gcjLng + dLng;
|
||||
var wgsLat,
|
||||
wgsLng,
|
||||
i = 0;
|
||||
while (1) {
|
||||
wgsLat = (mLat + pLat) / 2;
|
||||
wgsLng = (mLng + pLng) / 2;
|
||||
var tmp = this.gcj_encrypt(wgsLat, wgsLng);
|
||||
dLat = tmp.lat - gcjLat;
|
||||
dLng = tmp.lng - gcjLng;
|
||||
if (Math.abs(dLat) < threshold && Math.abs(dLng) < threshold) break;
|
||||
|
||||
if (dLat > 0) pLat = wgsLat;
|
||||
else mLat = wgsLat;
|
||||
if (dLng > 0) pLng = wgsLng;
|
||||
else mLng = wgsLng;
|
||||
|
||||
if (++i > 10000) break;
|
||||
}
|
||||
//console.log(i);
|
||||
return {
|
||||
lat: wgsLat,
|
||||
lng: wgsLng
|
||||
};
|
||||
},
|
||||
/**
|
||||
* GCJ-02 to BD-09 中国标准坐标转百度坐标(精确)
|
||||
* @param {number} gcjLat 中国标准坐标纬度
|
||||
* @param {number} gcjLng 中国标准坐标经度
|
||||
* @return {object} 返回百度经纬度对象
|
||||
*/
|
||||
chinaToBaidu: function (gcjLat, gcjLng) {
|
||||
var x = gcjLng,
|
||||
y = gcjLat;
|
||||
var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * this.x_pi);
|
||||
var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * this.x_pi);
|
||||
var bdLng = z * Math.cos(theta) + 0.0065;
|
||||
var bdLat = z * Math.sin(theta) + 0.006;
|
||||
return {
|
||||
lat: bdLat,
|
||||
lng: bdLng
|
||||
};
|
||||
},
|
||||
/**
|
||||
* BD-09 to GCJ-02 百度坐标转中国标准坐标
|
||||
* @param {number} bdLat 百度坐标纬度
|
||||
* @param {number} bdLng 百度坐标经度
|
||||
* @return {object} 返回中国标准经纬度对象
|
||||
*/
|
||||
baiduToChina: function (bdLat, bdLng) {
|
||||
var x = bdLng - 0.0065,
|
||||
y = bdLat - 0.006;
|
||||
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_pi);
|
||||
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_pi);
|
||||
var gcjLng = z * Math.cos(theta);
|
||||
var gcjLat = z * Math.sin(theta);
|
||||
return {
|
||||
lat: gcjLat,
|
||||
lng: gcjLng
|
||||
};
|
||||
},
|
||||
/**
|
||||
* BD-09 to GCJ-02 百度坐标转gps坐标
|
||||
* @param {number} bdLat 百度坐标纬度
|
||||
* @param {number} bdLng 百度坐标经度
|
||||
* @return {object} 返回gps经纬度对象
|
||||
*/
|
||||
baiduToGPS: function (bdLat, bdLng) {
|
||||
let china = this.baiduToChina(bdLat, bdLng);
|
||||
return this.chinaToGPS(china.lat, china.lng);
|
||||
},
|
||||
/**
|
||||
* WGS-84 to to BD-09 GPS坐标转Baidu坐标
|
||||
* @param {number} gpsLat GPS纬度
|
||||
* @param {number} gpsLng GPS经度
|
||||
* @return {object} 返回百度经纬度对象
|
||||
*/
|
||||
GPSToBaidu: function (gpsLat, gpsLng) {
|
||||
var china = this.GPSToChina(gpsLat, gpsLng);
|
||||
return this.chinaToBaidu(china.lat, china.lng);
|
||||
},
|
||||
/**
|
||||
* WGS-84 to Web mercator GPS坐标转墨卡托坐标
|
||||
* @param {number} wgsLat GPS纬度
|
||||
* @param {number} wgsLng GPS经度
|
||||
* @return {object} 返回墨卡托经纬度对象
|
||||
*/
|
||||
GPSToMercator: function (wgsLat, wgsLng) {
|
||||
var x = (wgsLng * 20037508.34) / 180;
|
||||
var y = Math.log(Math.tan(((90 + wgsLat) * this.PI) / 360)) / (this.PI / 180);
|
||||
y = (y * 20037508.34) / 180;
|
||||
return {
|
||||
lat: y,
|
||||
lng: x
|
||||
};
|
||||
/*
|
||||
if ((Math.abs(wgsLng) > 180 || Math.abs(wgsLat) > 90))
|
||||
return null;
|
||||
var x = 6378137.0 * wgsLng * 0.017453292519943295;
|
||||
var a = wgsLat * 0.017453292519943295;
|
||||
var y = 3189068.5 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
|
||||
return {'lat' : y, 'lng' : x};
|
||||
//*/
|
||||
},
|
||||
/**
|
||||
* Web mercator to WGS-84 墨卡托坐标转GPS坐标
|
||||
* @param {number} mercatorLat 墨卡托纬度
|
||||
* @param {number} mercatorLng 墨卡托经度
|
||||
* @return {object} 返回GPS经纬度对象
|
||||
*/
|
||||
mercatorToGPS: function (mercatorLat, mercatorLng) {
|
||||
var x = (mercatorLng / 20037508.34) * 180;
|
||||
var y = (mercatorLat / 20037508.34) * 180;
|
||||
y = (180 / this.PI) * (2 * Math.atan(Math.exp((y * this.PI) / 180)) - this.PI / 2);
|
||||
return {
|
||||
lat: y,
|
||||
lng: x
|
||||
};
|
||||
/*
|
||||
if (Math.abs(mercatorLng) < 180 && Math.abs(mercatorLat) < 90)
|
||||
return null;
|
||||
if ((Math.abs(mercatorLng) > 20037508.3427892) || (Math.abs(mercatorLat) > 20037508.3427892))
|
||||
return null;
|
||||
var a = mercatorLng / 6378137.0 * 57.295779513082323;
|
||||
var x = a - (Math.floor(((a + 180.0) / 360.0)) * 360.0);
|
||||
var y = (1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * mercatorLat) / 6378137.0)))) * 57.295779513082323;
|
||||
return {'lat' : y, 'lng' : x};
|
||||
//*/
|
||||
},
|
||||
/**
|
||||
* 两点之间的距离
|
||||
* @param {number} latA 起点纬度
|
||||
* @param {number} lngA 起点经度
|
||||
* @param {number} latB 终点纬度
|
||||
* @param {number} lngB 终点经度
|
||||
* @return {number} 返回距离(米)
|
||||
*/
|
||||
distance: function (latA, lngA, latB, lngB) {
|
||||
var earthR = 6371000;
|
||||
var x = Math.cos((latA * this.PI) / 180) * Math.cos((latB * this.PI) / 180) * Math.cos(((lngA - lngB) * this.PI) / 180);
|
||||
var y = Math.sin((latA * this.PI) / 180) * Math.sin((latB * this.PI) / 180);
|
||||
var s = x + y;
|
||||
if (s > 1) s = 1;
|
||||
if (s < -1) s = -1;
|
||||
var alpha = Math.acos(s);
|
||||
var distance = alpha * earthR;
|
||||
return distance;
|
||||
},
|
||||
/**
|
||||
* 是否在中国之外
|
||||
* @param {number} lat 纬度
|
||||
* @param {number} lng 经度
|
||||
* @return {boolean]} 返回结果真或假
|
||||
*/
|
||||
outOfChina: function (lat, lng) {
|
||||
if (lat < 72.004 || lat > 137.8347) return true;
|
||||
if (lng < 0.8293 || lng > 55.8271) return true;
|
||||
return false;
|
||||
},
|
||||
transformLat: function (x, y) {
|
||||
var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
|
||||
ret += ((20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0) / 3.0;
|
||||
ret += ((20.0 * Math.sin(y * this.PI) + 40.0 * Math.sin((y / 3.0) * this.PI)) * 2.0) / 3.0;
|
||||
ret += ((160.0 * Math.sin((y / 12.0) * this.PI) + 320 * Math.sin((y * this.PI) / 30.0)) * 2.0) / 3.0;
|
||||
return ret;
|
||||
},
|
||||
transformLng: function (x, y) {
|
||||
var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
|
||||
ret += ((20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0) / 3.0;
|
||||
ret += ((20.0 * Math.sin(x * this.PI) + 40.0 * Math.sin((x / 3.0) * this.PI)) * 2.0) / 3.0;
|
||||
ret += ((150.0 * Math.sin((x / 12.0) * this.PI) + 300.0 * Math.sin((x / 30.0) * this.PI)) * 2.0) / 3.0;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<div class="login" id="login">
|
||||
<div class="limiter">
|
||||
<div class="container-login100">
|
||||
<div class="wrap-login100">
|
||||
<span class="login100-form-title p-b-26">WVP视频平台</span>
|
||||
<span class="login100-form-title p-b-48">
|
||||
<i class="fa fa-video-camera"></i>
|
||||
</span>
|
||||
|
||||
<div class="wrap-input100 validate-input" data-validate = "Valid email is: a@b.c">
|
||||
<input :class="'input100 ' + (username==''?'':'has-val')" type="text" v-model="username" name="username">
|
||||
<span class="focus-input100" data-placeholder="用户名"></span>
|
||||
</div>
|
||||
|
||||
<div class="wrap-input100 validate-input" data-validate="Enter password">
|
||||
<span class="btn-show-pass">
|
||||
<i :class="'fa ' + (!showPassword?'fa-eye':'fa-eye-slash')" @click="showPassword = !showPassword"></i>
|
||||
</span>
|
||||
<input :class="'input100 ' + (password==''?'':'has-val')" :type="(!showPassword?'password':'text')" v-model="password" name="password">
|
||||
<span class="focus-input100" data-placeholder="密码"></span>
|
||||
</div>
|
||||
|
||||
<div class="container-login100-form-btn">
|
||||
<div class="wrap-login100-form-btn" :class="{'login-loading': isLoging}" v-loading="isLoging" element-loading-background="rgb(0 0 0 / 0%);" element-loading-custom-class="login-loading-class">
|
||||
<div class="login100-form-bgbtn"></div>
|
||||
<button class="login100-form-btn" @click="login">登录</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import crypto from 'crypto'
|
||||
import userService from "./service/UserService";
|
||||
export default {
|
||||
name: 'Login',
|
||||
data(){
|
||||
return {
|
||||
isLoging: false,
|
||||
showPassword: false,
|
||||
loginLoading: false,
|
||||
username: '',
|
||||
password: ''
|
||||
}
|
||||
},
|
||||
created(){
|
||||
var that = this;
|
||||
document.onkeydown = function(e) {
|
||||
var key = window.event.keyCode;
|
||||
if (key == 13) {
|
||||
that.login();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
|
||||
//登录逻辑
|
||||
login(){
|
||||
if(this.username!='' && this.password!=''){
|
||||
this.toLogin();
|
||||
}
|
||||
},
|
||||
|
||||
//登录请求
|
||||
toLogin(){
|
||||
//需要想后端发送的登录参数
|
||||
let loginParam = {
|
||||
username: this.username,
|
||||
password: crypto.createHash('md5').update(this.password, "utf8").digest('hex')
|
||||
}
|
||||
var that = this;
|
||||
//设置在登录状态
|
||||
this.isLoging = true;
|
||||
let timeoutTask = setTimeout(()=>{
|
||||
that.$message.error("登录超时");
|
||||
that.isLoging = false;
|
||||
}, 1000)
|
||||
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:"/api/user/login",
|
||||
params: loginParam
|
||||
}).then(function (res) {
|
||||
window.clearTimeout(timeoutTask)
|
||||
console.log(res);
|
||||
console.log("登录成功");
|
||||
if (res.data.code === 0 ) {
|
||||
userService.setUser(res.data.data)
|
||||
//登录成功后
|
||||
that.cancelEnterkeyDefaultAction();
|
||||
that.$router.push('/');
|
||||
}else{
|
||||
that.isLoging = false;
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: '登录失败,用户名或密码错误',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error)
|
||||
window.clearTimeout(timeoutTask)
|
||||
that.$message.error(error.response.data.msg);
|
||||
that.isLoging = false;
|
||||
});
|
||||
},
|
||||
cancelEnterkeyDefaultAction: function() {
|
||||
document.onkeydown = function(e) {
|
||||
var key = window.event.keyCode;
|
||||
if (key == 13) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,189 +0,0 @@
|
||||
<template>
|
||||
<div id="mediaServerManger" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">节点列表</div>
|
||||
<div class="page-header-btn">
|
||||
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="add">添加节点</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="num" v-for="item in mediaServerList" :key="item.id">
|
||||
<el-card shadow="hover" :body-style="{ padding: '0px'}" class="server-card">
|
||||
<div v-if="item.type === 'zlm'" class="card-img-zlm"></div>
|
||||
<div v-if="item.type === 'abl'" class="card-img-abl"></div>
|
||||
<div style="padding: 14px;text-align: left">
|
||||
<span style="font-size: 16px">{{item.id}}</span>
|
||||
<el-button v-if="!item.defaultServer" icon="el-icon-edit" style="padding: 0;float: right;" type="text" @click="edit(item)">编辑</el-button>
|
||||
<el-button v-if="item.defaultServer" icon="el-icon-edit" style="padding: 0;float: right;" type="text" @click="edit(item)">查看</el-button>
|
||||
<el-button v-if="!item.defaultServer" icon="el-icon-delete" style="margin-right: 10px;padding: 0;float: right;" type="text" @click="del(item)">移除</el-button>
|
||||
<div style="margin-top: 13px; line-height: 12px; ">
|
||||
<span style="font-size: 14px; color: #999; margin-top: 5px; ">{{item.ip}}</span>
|
||||
<span style="font-size: 14px; color: #999; margin-top: 5px; float: right;">{{item.createTime}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<i v-if="item.status" class="iconfont icon-online server-card-status-online" title="在线"></i>
|
||||
<i v-if="!item.status" class="iconfont icon-online server-card-status-offline" title="离线"></i>
|
||||
<i v-if="item.defaultServer" class="server-card-default" >默认</i>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<mediaServerEdit ref="mediaServerEdit" ></mediaServerEdit>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import MediaServer from './service/MediaServer'
|
||||
import mediaServerEdit from './dialog/MediaServerEdit'
|
||||
export default {
|
||||
name: 'mediaServerManger',
|
||||
components: {
|
||||
uiHeader,mediaServerEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mediaServerObj : new MediaServer(),
|
||||
mediaServerList: [], //设备列表
|
||||
winHeight: window.innerHeight - 200,
|
||||
updateLooper: false,
|
||||
currentPage:1,
|
||||
count:15,
|
||||
num: this.getNumberByWidth(),
|
||||
total:0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.updateLooper = setInterval(this.initData, 2000);
|
||||
},
|
||||
destroyed() {
|
||||
clearTimeout(this.updateLooper);
|
||||
},
|
||||
methods: {
|
||||
initData: function() {
|
||||
this.getServerList()
|
||||
},
|
||||
currentChange: function(val){
|
||||
this.currentPage = val;
|
||||
this.getServerList();
|
||||
},
|
||||
handleSizeChange: function(val){
|
||||
this.count = val;
|
||||
this.getServerList();
|
||||
},
|
||||
getServerList: function(){
|
||||
this.mediaServerObj.getMediaServerList((data)=>{
|
||||
this.mediaServerList = data.data;
|
||||
})
|
||||
},
|
||||
add: function (){
|
||||
this.$refs.mediaServerEdit.openDialog(null, this.initData)
|
||||
},
|
||||
edit: function (row){
|
||||
this.$refs.mediaServerEdit.openDialog(row, this.initData)
|
||||
},
|
||||
del: function (row){
|
||||
this.$confirm('确认删除此节点?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.mediaServerObj.delete(row.id, (data)=>{
|
||||
if (data.code === 0) {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
}).catch(() => {
|
||||
});
|
||||
|
||||
},
|
||||
getNumberByWidth(){
|
||||
let candidateNums = [1, 2, 3, 4, 6, 8, 12, 24]
|
||||
let clientWidth = window.innerWidth - 30;
|
||||
let interval = 20;
|
||||
let itemWidth = 360;
|
||||
let num = (clientWidth + interval)/(itemWidth + interval)
|
||||
let result = Math.ceil(24/num);
|
||||
let resultVal = 24;
|
||||
for (let i = 0; i < candidateNums.length; i++) {
|
||||
let value = candidateNums[i]
|
||||
if (i + 1 >= candidateNums.length) {
|
||||
return 24;
|
||||
}
|
||||
if (value <= result && candidateNums[i + 1] > result ) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return resultVal;
|
||||
},
|
||||
dateFormat: function(/** timestamp=0 **/) {
|
||||
var ts = arguments[0] || 0;
|
||||
var t,y,m,d,h,i,s;
|
||||
t = ts ? new Date(ts*1000) : new Date();
|
||||
y = t.getFullYear();
|
||||
m = t.getMonth()+1;
|
||||
d = t.getDate();
|
||||
h = t.getHours();
|
||||
i = t.getMinutes();
|
||||
s = t.getSeconds();
|
||||
// 可根据需要在这里定义时间格式
|
||||
return y+'-'+(m<10?'0'+m:m)+'-'+(d<10?'0'+d:d)+' '+(h<10?'0'+h:h)+':'+(i<10?'0'+i:i)+':'+(s<10?'0'+s:s);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.server-card{
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.card-img-zlm{
|
||||
width: 200px; height: 200px;
|
||||
background: url('~@static/images/zlm-logo.png') no-repeat center;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.card-img-abl{
|
||||
width: 200px; height: 200px;
|
||||
background: url('~@static/images/abl-logo.jpg') no-repeat center;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.server-card-status-online{
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
color: #3caf36;
|
||||
font-size: 18px;
|
||||
}
|
||||
.server-card-status-offline{
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
color: #808080;
|
||||
font-size: 18px;
|
||||
}
|
||||
.server-card-default{
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
color: #808080;
|
||||
font-size: 18px;
|
||||
}
|
||||
.server-card:hover {
|
||||
border: 1px solid #adadad;
|
||||
}
|
||||
</style>
|
||||
@ -1,314 +0,0 @@
|
||||
<template>
|
||||
<div id="PlatformEdit" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<el-page-header @back="close" content="添加上级平台"></el-page-header>
|
||||
</div>
|
||||
<div class="page-header-btn">
|
||||
<div style="display: inline;">
|
||||
<el-button icon="el-icon-close" size="mini" style="font-size: 20px; color: #000;" type="text" @click="close" ></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="shared" style="text-align: right; margin-top: 1rem; background-color: #FFFFFF; padding-top: 2rem;">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="11">
|
||||
<el-form ref="platform1" :rules="rules" :model="value" size="medium" label-width="160px">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="value.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SIP服务国标编码" prop="serverGBId">
|
||||
<el-input v-model="value.serverGBId" clearable @input="serverGBIdChange"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SIP服务国标域" prop="serverGBDomain">
|
||||
<el-input v-model="value.serverGBDomain" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SIP服务IP" prop="serverIp">
|
||||
<el-input v-model="value.serverIp" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SIP服务端口" prop="serverPort">
|
||||
<el-input v-model="value.serverPort" clearable type="number"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备国标编号" prop="deviceGBId">
|
||||
<el-input v-model="value.deviceGBId" clearable @input="deviceGBIdChange"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="本地IP" prop="deviceIp">
|
||||
<el-select v-model="value.deviceIp" placeholder="请选择与上级相通的网卡" style="width: 100%">
|
||||
<el-option
|
||||
v-for="ip in deviceIps"
|
||||
:key="ip"
|
||||
:label="ip"
|
||||
:value="ip">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="本地端口" prop="devicePort">
|
||||
<el-input v-model="value.devicePort" :disabled="true" type="number"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="SIP认证用户名" prop="username">
|
||||
<el-input v-model="value.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SIP认证密码" prop="password">
|
||||
<el-input v-model="value.password"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="注册周期(秒)" prop="expires">
|
||||
<el-input v-model="value.expires"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="心跳周期(秒)" prop="keepTimeout">
|
||||
<el-input v-model="value.keepTimeout"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form ref="platform2" :rules="rules" :model="value" size="medium" label-width="160px">
|
||||
<el-form-item label="SDP发流IP" prop="sendStreamIp">
|
||||
<el-input v-model="value.sendStreamIp"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="信令传输" prop="transport">
|
||||
<el-select
|
||||
v-model="value.transport"
|
||||
style="width: 100%"
|
||||
placeholder="请选择信令传输方式"
|
||||
>
|
||||
<el-option label="UDP" value="UDP"></el-option>
|
||||
<el-option label="TCP" value="TCP"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="保密属性" >
|
||||
<el-select v-model="value.secrecy" style="width: 100%" placeholder="请选择保密属性">
|
||||
<el-option label="不涉密" :value="0"></el-option>
|
||||
<el-option label="涉密" :value="1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="目录分组" prop="catalogGroup">
|
||||
<el-select
|
||||
v-model="value.catalogGroup"
|
||||
style="width: 100%"
|
||||
placeholder="请选择目录分组"
|
||||
>
|
||||
<el-option label="1" value="1"></el-option>
|
||||
<el-option label="2" value="2"></el-option>
|
||||
<el-option label="4" value="4"></el-option>
|
||||
<el-option label="8" value="8"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="字符集" prop="characterSet">
|
||||
<el-select
|
||||
v-model="value.characterSet"
|
||||
style="width: 100%"
|
||||
placeholder="请选择字符集"
|
||||
>
|
||||
<el-option label="GB2312" value="GB2312"></el-option>
|
||||
<el-option label="UTF-8" value="UTF-8"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="行政区划" prop="civilCode">
|
||||
<el-input v-model="value.civilCode" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="平台厂商" prop="manufacturer">
|
||||
<el-input v-model="value.manufacturer" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="平台型号" prop="model">
|
||||
<el-input v-model="value.model" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="平台安装地址" prop="address">
|
||||
<el-input v-model="value.address" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他选项" >
|
||||
<div style="text-align: left">
|
||||
<el-checkbox label="启用" v-model="value.enable" @change="checkExpires"></el-checkbox>
|
||||
<!-- <el-checkbox label="云台控制" v-model="value.ptz"></el-checkbox>-->
|
||||
<el-checkbox label="RTCP保活" v-model="value.rtcp" @change="rtcpCheckBoxChange"></el-checkbox>
|
||||
<el-checkbox label="消息通道" v-model="value.asMessageChannel"></el-checkbox>
|
||||
<el-checkbox label="主动推送通道" v-model="value.autoPushChannel"></el-checkbox>
|
||||
<el-checkbox label="推送平台信息" :true-label="1" :false-label="0" v-model="value.catalogWithPlatform"></el-checkbox>
|
||||
<el-checkbox label="推送分组信息" :true-label="1" :false-label="0" v-model="value.catalogWithGroup"></el-checkbox>
|
||||
<el-checkbox label="推送行政区划" :true-label="1" :false-label="0" v-model="value.catalogWithRegion"></el-checkbox>
|
||||
</div>
|
||||
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSubmit">{{
|
||||
onSubmit_text
|
||||
}}
|
||||
</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "platformEdit",
|
||||
props: [ 'value', 'closeEdit', 'deviceIps'],
|
||||
components: {
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
watch: {
|
||||
value(newValue, oldValue){
|
||||
this.streamProxy = newValue;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
var deviceGBIdRules = async (rule, value, callback) => {
|
||||
console.log(value);
|
||||
if (value === "") {
|
||||
callback(new Error("请输入设备国标编号"));
|
||||
} else {
|
||||
var exit = await this.deviceGBIdExit(value);
|
||||
if (exit) {
|
||||
callback(new Error("设备国标编号格式错误或已存在"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
onSubmit_text: "保存",
|
||||
|
||||
rules: {
|
||||
name: [{required: true, message: "请输入平台名称", trigger: "blur"}],
|
||||
serverGBId: [
|
||||
{required: true, message: "请输入SIP服务国标编码", trigger: "blur"},
|
||||
],
|
||||
serverGBDomain: [
|
||||
{required: true, message: "请输入SIP服务国标域", trigger: "blur"},
|
||||
],
|
||||
serverIp: [{required: true, message: "请输入SIP服务IP", trigger: "blur"}],
|
||||
serverPort: [{required: true, message: "请输入SIP服务端口", trigger: "blur"}],
|
||||
deviceGBId: [{validator: deviceGBIdRules, trigger: "blur"}],
|
||||
username: [{required: false, message: "请输入SIP认证用户名", trigger: "blur"}],
|
||||
password: [{required: false, message: "请输入SIP认证密码", trigger: "blur"}],
|
||||
expires: [{required: true, message: "请输入注册周期", trigger: "blur"}],
|
||||
keepTimeout: [{required: true, message: "请输入心跳周期", trigger: "blur"}],
|
||||
transport: [{required: true, message: "请选择信令传输", trigger: "blur"}],
|
||||
characterSet: [{required: true, message: "请选择编码字符集", trigger: "blur"}],
|
||||
deviceIp: [{required: true, message: "请选择本地IP", trigger: "blur"}],
|
||||
},
|
||||
|
||||
saveLoading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onSubmit: function () {
|
||||
this.saveLoading = true;
|
||||
if (this.value.id) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/platform/update",
|
||||
data: this.value
|
||||
}).then((res) => {
|
||||
this.saveLoading = false;
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: "success",
|
||||
});
|
||||
this.showDialog = false;
|
||||
if (this.closeEdit) {
|
||||
this.closeEdit();
|
||||
}
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.saveLoading = false;
|
||||
console.log(error);
|
||||
});
|
||||
}else {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/platform/add",
|
||||
data: this.value
|
||||
}).then((res) => {
|
||||
this.saveLoading = false;
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: "success",
|
||||
});
|
||||
if (this.closeEdit) {
|
||||
this.closeEdit();
|
||||
}
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.saveLoading = false;
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
serverGBIdChange: function () {
|
||||
if (this.value.serverGBId.length > 10) {
|
||||
this.value.serverGBDomain = this.value.serverGBId.substr(0, 10);
|
||||
}
|
||||
},
|
||||
deviceGBIdChange: function () {
|
||||
this.value.username = this.value.deviceGBId;
|
||||
},
|
||||
checkExpires: function () {
|
||||
if (this.value.enable && this.value.expires === "0") {
|
||||
this.value.expires = "3600";
|
||||
}
|
||||
},
|
||||
rtcpCheckBoxChange: function (result) {
|
||||
if (result) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "开启RTCP保活需要上级平台支持,可以避免无效推流",
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
},
|
||||
deviceGBIdExit: async function (deviceGbId) {
|
||||
let result = false;
|
||||
await this.$axios({
|
||||
method:"get",
|
||||
url:`/api/platform/exit/${deviceGbId}`
|
||||
}).then((res)=> {
|
||||
result = res.data;
|
||||
}).catch((error)=> {
|
||||
console.log(error);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
close: function () {
|
||||
this.closeEdit()
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,306 +0,0 @@
|
||||
<template>
|
||||
<div id="app" style="width: 100%">
|
||||
<div v-if="!platform">
|
||||
<div class="page-header">
|
||||
<div class="page-title">上级平台列表</div>
|
||||
<div class="page-header-btn">
|
||||
搜索:
|
||||
<el-input @input="getPlatformList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary"
|
||||
@click="addParentPlatform">添加
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--设备列表-->
|
||||
<el-table size="medium" :data="platformList" style="width: 100%" :height="$tableHeght" :loading="loading">
|
||||
<el-table-column prop="name" label="名称"></el-table-column>
|
||||
<el-table-column prop="serverGBId" label="平台编号" min-width="200"></el-table-column>
|
||||
<el-table-column label="是否启用" min-width="80">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.enable && Vue.prototype.$myServerId !== scope.row.serverId" style="border-color: #ecf1af">已启用</el-tag>
|
||||
<el-tag size="medium" v-if="scope.row.enable && Vue.prototype.$myServerId === scope.row.serverId">已启用</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="80">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.status">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="!scope.row.status">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="地址" min-width="160">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium">{{ scope.row.serverIp }}:{{ scope.row.serverPort }}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceGBId" label="设备国标编号" min-width="200"></el-table-column>
|
||||
<el-table-column prop="transport" label="信令传输模式" min-width="120"></el-table-column>
|
||||
<el-table-column prop="channelCount" label="通道数" min-width="120"></el-table-column>
|
||||
<el-table-column label="订阅信息" min-width="120" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<i v-if="scope.row.alarmSubscribe" style="font-size: 20px" title="报警订阅"
|
||||
class="iconfont icon-gbaojings subscribe-on "></i>
|
||||
<i v-if="!scope.row.alarmSubscribe" style="font-size: 20px" title="报警订阅"
|
||||
class="iconfont icon-gbaojings subscribe-off "></i>
|
||||
<i v-if="scope.row.catalogSubscribe" title="目录订阅" class="iconfont icon-gjichus subscribe-on"></i>
|
||||
<i v-if="!scope.row.catalogSubscribe" title="目录订阅" class="iconfont icon-gjichus subscribe-off"></i>
|
||||
<i v-if="scope.row.mobilePositionSubscribe" title="位置订阅"
|
||||
class="iconfont icon-gxunjians subscribe-on"></i>
|
||||
<i v-if="!scope.row.mobilePositionSubscribe" title="位置订阅"
|
||||
class="iconfont icon-gxunjians subscribe-off"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" min-width="240" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="editPlatform(scope.row)">编辑</el-button>
|
||||
<el-button size="medium" icon="el-icon-share" type="text" @click="chooseChannel(scope.row)">通道共享
|
||||
</el-button>
|
||||
<el-button size="medium" icon="el-icon-top" type="text" :loading="pushChannelLoading"
|
||||
@click="pushChannel(scope.row)">推送通道
|
||||
</el-button>
|
||||
<el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c"
|
||||
@click="deletePlatform(scope.row)">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<platformEdit ref="platformEdit" v-if="platform" v-model="platform" :closeEdit="closeEdit"
|
||||
:device-ips="deviceIps"></platformEdit>
|
||||
<shareChannel ref="shareChannel"></shareChannel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import shareChannel from './dialog/shareChannel.vue'
|
||||
import platformEdit from './PlatformEdit.vue'
|
||||
import streamProxyEdit from "./dialog/StreamProxyEdit.vue";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
streamProxyEdit,
|
||||
uiHeader,
|
||||
shareChannel,
|
||||
platformEdit
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
platformList: [], //设备列表
|
||||
deviceIps: [], //设备列表
|
||||
defaultPlatform: null,
|
||||
platform: null,
|
||||
pushChannelLoading: false,
|
||||
searchSrt: "",
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
Vue() {
|
||||
return Vue
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.updateLooper = setInterval(this.initData, 10000);
|
||||
},
|
||||
destroyed() {
|
||||
clearTimeout(this.updateLooper);
|
||||
},
|
||||
methods: {
|
||||
addParentPlatform: function () {
|
||||
this.platform = this.defaultPlatform;
|
||||
},
|
||||
editPlatform: function (platform) {
|
||||
this.platform = platform;
|
||||
},
|
||||
closeEdit: function () {
|
||||
this.platform = null;
|
||||
this.getPlatformList()
|
||||
},
|
||||
deletePlatform: function (platform) {
|
||||
this.$confirm('确认删除?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.deletePlatformCommit(platform)
|
||||
})
|
||||
},
|
||||
deletePlatformCommit: function (platform) {
|
||||
this.loading = true;
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url: `/api/platform/delete/`,
|
||||
params: {
|
||||
id: platform.id
|
||||
}
|
||||
}).then((res) => {
|
||||
this.loading = false;
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: '删除成功',
|
||||
});
|
||||
this.initData()
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.loading = false;
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error,
|
||||
});
|
||||
});
|
||||
},
|
||||
chooseChannel: function (platform) {
|
||||
this.$refs.shareChannel.openDialog(platform.id, this.initData)
|
||||
},
|
||||
pushChannel: function (row) {
|
||||
this.pushChannelLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/platform/channel/push`,
|
||||
params: {
|
||||
id: row.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
this.pushChannelLoading = false;
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: '推送成功',
|
||||
});
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.pushChannelLoading = false;
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error,
|
||||
});
|
||||
});
|
||||
},
|
||||
initData: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/platform/server_config`
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.deviceIps = res.data.data.deviceIp.split(',');
|
||||
this.defaultPlatform = {
|
||||
id: null,
|
||||
enable: true,
|
||||
ptz: true,
|
||||
rtcp: false,
|
||||
asMessageChannel: false,
|
||||
autoPushChannel: false,
|
||||
name: null,
|
||||
serverGBId: null,
|
||||
serverGBDomain: null,
|
||||
serverIp: null,
|
||||
serverPort: null,
|
||||
deviceGBId: res.data.data.username,
|
||||
deviceIp: this.deviceIps[0],
|
||||
devicePort: res.data.data.devicePort,
|
||||
username: res.data.data.username,
|
||||
password: res.data.data.password,
|
||||
expires: 3600,
|
||||
keepTimeout: 60,
|
||||
transport: "UDP",
|
||||
characterSet: "GB2312",
|
||||
startOfflinePush: false,
|
||||
customGroup: false,
|
||||
catalogWithPlatform: 0,
|
||||
catalogWithGroup: 0,
|
||||
catalogWithRegion: 0,
|
||||
manufacturer: null,
|
||||
model: null,
|
||||
address: null,
|
||||
secrecy: 1,
|
||||
catalogGroup: 1,
|
||||
civilCode: null,
|
||||
sendStreamIp: res.data.data.sendStreamIp,
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
this.getPlatformList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getPlatformList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getPlatformList();
|
||||
},
|
||||
getPlatformList: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/platform/query`,
|
||||
params: {
|
||||
count: this.count,
|
||||
page: this.currentPage,
|
||||
query: this.searchSrt
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.platformList = res.data.data.list;
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
},
|
||||
refresh: function () {
|
||||
this.initData();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.subscribe-on {
|
||||
color: #409EFF;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.subscribe-off {
|
||||
color: #afafb3;
|
||||
font-size: 18px;
|
||||
}
|
||||
</style>
|
||||
@ -1,235 +0,0 @@
|
||||
<template>
|
||||
<div id="recordPLan" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<div >录像计划</div>
|
||||
</div>
|
||||
<div class="page-header-btn">
|
||||
<div style="display: inline;">
|
||||
搜索:
|
||||
<el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
<el-button size="mini" type="primary" @click="add()">
|
||||
添加
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" @click="getRecordPlanList()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-table size="medium" ref="recordPlanListTable" :data="recordPlanList" :height="$tableHeght" style="width: 100%"
|
||||
header-row-class-name="table-header" >
|
||||
<el-table-column type="selection" width="55" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="名称" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="channelCount" label="关联通道" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="updateTime" label="更新时间">
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间">
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="300" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button size="medium" icon="el-icon-link" type="text" @click="link(scope.row)">关联通道</el-button>
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">编辑</el-button>
|
||||
<el-button size="medium" icon="el-icon-delete" style="color: #f56c6c" type="text" @click="deletePlan(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
<editRecordPlan ref="editRecordPlan"></editRecordPlan>
|
||||
<LinkChannelRecord ref="linkChannelRecord"></LinkChannelRecord>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import EditRecordPlan from "./dialog/editRecordPlan.vue";
|
||||
import LinkChannelRecord from "./dialog/linkChannelRecord.vue";
|
||||
|
||||
export default {
|
||||
name: 'recordPLan',
|
||||
components: {
|
||||
EditRecordPlan,
|
||||
LinkChannelRecord,
|
||||
uiHeader,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
recordPlanList: [],
|
||||
searchSrt: "",
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.initData();
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.getRecordPlanList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.initData();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getRecordPlanList();
|
||||
},
|
||||
getRecordPlanList: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/record/plan/query`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.recordPlanList = res.data.data.list;
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.recordPlanListTable.doLayout();
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
getSnap: function (row) {
|
||||
let baseUrl = window.baseUrl ? window.baseUrl : "";
|
||||
return ((process.env.NODE_ENV === 'development') ? process.env.BASE_API : baseUrl) + '/api/device/query/snap/' + this.deviceId + '/' + row.deviceId;
|
||||
},
|
||||
search: function () {
|
||||
this.currentPage = 1;
|
||||
this.total = 0;
|
||||
this.initData();
|
||||
},
|
||||
refresh: function () {
|
||||
this.initData();
|
||||
},
|
||||
add: function () {
|
||||
this.$refs.editRecordPlan.openDialog(null, ()=>{
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
edit: function (plan) {
|
||||
this.$refs.editRecordPlan.openDialog(plan, ()=>{
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
link: function (plan) {
|
||||
this.$refs.linkChannelRecord.openDialog(plan.id, ()=>{
|
||||
this.initData()
|
||||
})
|
||||
},
|
||||
deletePlan: function (plan) {
|
||||
this.$confirm('确定删除?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url: "/api/record/plan/delete",
|
||||
params: {
|
||||
planId: plan.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
});
|
||||
this.initData();
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.videoList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 10rem;
|
||||
margin-right: 1rem;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-item-img:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background-image: url("../assets/loading.png");
|
||||
background-size: cover;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
line-height: 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: 14.4rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,260 +0,0 @@
|
||||
<template>
|
||||
<div id="StreamProxyEdit" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<el-page-header @back="close" content="编辑拉流代理信息"></el-page-header>
|
||||
</div>
|
||||
<div class="page-header-btn">
|
||||
<div style="display: inline;">
|
||||
<el-button icon="el-icon-close" size="mini" style="font-size: 20px; color: #000;" type="text" @click="close" ></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tabs tab-position="left" style="background-color: #FFFFFF; padding-top: 1rem">
|
||||
<el-tab-pane label="拉流代理信息">
|
||||
<el-form ref="streamProxy" :rules="rules" :model="streamProxy" label-width="140px" style="width: 50%; margin: 0 auto">
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select
|
||||
v-model="streamProxy.type"
|
||||
style="width: 100%"
|
||||
placeholder="请选择代理类型"
|
||||
>
|
||||
<el-option key="默认" label="默认" value="default"></el-option>
|
||||
<el-option key="FFmpeg" label="FFmpeg" value="ffmpeg"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="应用名" prop="app">
|
||||
<el-input v-model="streamProxy.app" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流ID" prop="stream">
|
||||
<el-input v-model="streamProxy.stream" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="拉流地址" prop="url">
|
||||
<el-input v-model="streamProxy.srcUrl" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="超时时间(秒)" prop="timeoutMs">
|
||||
<el-input v-model="streamProxy.timeout" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="节点选择" prop="rtpType">
|
||||
<el-select
|
||||
v-model="streamProxy.relatesMediaServerId"
|
||||
@change="mediaServerIdChange"
|
||||
style="width: 100%"
|
||||
placeholder="请选择拉流节点"
|
||||
>
|
||||
<el-option key="auto" label="自动选择" value=""></el-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="FFmpeg命令模板" prop="ffmpegCmdKey" v-if="streamProxy.type=='ffmpeg'">
|
||||
<el-select
|
||||
v-model="streamProxy.ffmpegCmdKey"
|
||||
style="width: 100%"
|
||||
placeholder="请选择FFmpeg命令模板"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in Object.keys(ffmpegCmdList)"
|
||||
:key="item"
|
||||
:label="ffmpegCmdList[item]"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="拉流方式(RTSP)" prop="rtspType">
|
||||
<el-select
|
||||
v-model="streamProxy.rtspType"
|
||||
style="width: 100%"
|
||||
placeholder="请选择拉流方式"
|
||||
>
|
||||
<el-option label="TCP" value="0"></el-option>
|
||||
<el-option label="UDP" value="1"></el-option>
|
||||
<el-option label="组播" value="2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="无人观看" prop="noneReader" >
|
||||
<el-radio-group v-model="streamProxy.noneReader">
|
||||
<el-radio :label="0">不做处理</el-radio>
|
||||
<el-radio :label="1">停用</el-radio>
|
||||
<el-radio :label="2">移除</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item label="其他选项">
|
||||
<div style="float: left;">
|
||||
<el-checkbox label="启用" v-model="streamProxy.enable" ></el-checkbox>
|
||||
<el-checkbox label="开启音频" v-model="streamProxy.enableAudio" ></el-checkbox>
|
||||
<el-checkbox label="录制" v-model="streamProxy.enableMp4" ></el-checkbox>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit" :loading="saveLoading" >保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="国标通道配置" v-if="streamProxy.id">
|
||||
<CommonChannelEdit ref="commonChannelEdit" :dataForm="streamProxy" :cancel="close"></CommonChannelEdit>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CommonChannelEdit from './common/CommonChannelEdit'
|
||||
import MediaServer from "./service/MediaServer";
|
||||
|
||||
export default {
|
||||
name: "channelEdit",
|
||||
props: [ 'value', 'closeEdit'],
|
||||
components: {
|
||||
CommonChannelEdit,
|
||||
},
|
||||
created() {
|
||||
console.log(this.streamProxy)
|
||||
this.mediaServer.getOnlineMediaServerList((data)=>{
|
||||
this.mediaServerList = data.data;
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
value(newValue, oldValue){
|
||||
this.streamProxy = newValue;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
saveLoading: false,
|
||||
streamProxy: this.value,
|
||||
mediaServer: new MediaServer(),
|
||||
mediaServerList:{},
|
||||
ffmpegCmdList:{},
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
||||
app: [{ required: true, message: "请输入应用名", trigger: "blur" }],
|
||||
stream: [{ required: true, message: "请输入流ID", trigger: "blur" }],
|
||||
srcUrl: [{ required: true, message: "请输入要代理的流", trigger: "blur" }],
|
||||
timeout: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }],
|
||||
ffmpegCmdKey: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onSubmit: function () {
|
||||
console.log(typeof this.streamProxy.noneReader)
|
||||
this.saveLoading = true;
|
||||
this.noneReaderHandler();
|
||||
if (this.streamProxy.id) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url:`/api/proxy/update`,
|
||||
data: this.streamProxy
|
||||
}).then((res)=> {
|
||||
this.saveLoading = false;
|
||||
if (typeof (res.data.code) != "undefined" && res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
});
|
||||
this.streamProxy = res.data.data
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
this.saveLoading = false;
|
||||
}).catch((error) =>{
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
this.saveLoading = false;
|
||||
}).finally(()=>{
|
||||
console.log("finally==finally")
|
||||
this.saveLoading = false;
|
||||
})
|
||||
}else {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url:`/api/proxy/add`,
|
||||
data: this.streamProxy
|
||||
}).then((res)=> {
|
||||
this.saveLoading = false;
|
||||
if (typeof (res.data.code) != "undefined" && res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
});
|
||||
this.streamProxy = res.data.data
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) =>{
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
this.saveLoading = false;
|
||||
}).finally(()=>{
|
||||
this.saveLoading = false;
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
close: function () {
|
||||
this.closeEdit()
|
||||
},
|
||||
mediaServerIdChange:function (){
|
||||
if (this.streamProxy.relatesMediaServerId !== "auto"){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/proxy/ffmpeg_cmd/list`,
|
||||
params: {
|
||||
mediaServerId: this.streamProxy.relatesMediaServerId
|
||||
}
|
||||
}).then((res)=> {
|
||||
this.ffmpegCmdList = res.data.data;
|
||||
this.streamProxy.ffmpegCmdKey = Object.keys(res.data.data)[0];
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
noneReaderHandler: function() {
|
||||
console.log(this.streamProxy)
|
||||
if (!this.streamProxy.noneReader || this.streamProxy.noneReader === 0 ) {
|
||||
this.streamProxy.enableDisableNoneReader = false;
|
||||
this.streamProxy.enableRemoveNoneReader = false;
|
||||
}else if (this.streamProxy.noneReader === 1){
|
||||
this.streamProxy.enableDisableNoneReader = true;
|
||||
this.streamProxy.enableRemoveNoneReader = false;
|
||||
}else if (this.streamProxy.noneReader ===2){
|
||||
this.streamProxy.enableDisableNoneReader = false;
|
||||
this.streamProxy.enableRemoveNoneReader = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,405 +0,0 @@
|
||||
<template>
|
||||
<div id="streamProxyList" style="width: 100%">
|
||||
|
||||
<div v-if="!streamProxy">
|
||||
<div class="page-header">
|
||||
<div class="page-title">拉流代理列表</div>
|
||||
<div class="page-header-btn">
|
||||
搜索:
|
||||
<el-input @input="getStreamProxyList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
流媒体:
|
||||
<el-select size="mini" @change="getStreamProxyList" style="margin-right: 1rem;" v-model="mediaServerId"
|
||||
placeholder="请选择" default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
拉流状态:
|
||||
<el-select size="mini" style="margin-right: 1rem;" @change="getStreamProxyList" v-model="pulling" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="正在拉流" value="true"></el-option>
|
||||
<el-option label="尚未拉流" value="false"></el-option>
|
||||
</el-select>
|
||||
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStreamProxy">添加代理</el-button>
|
||||
<el-button v-if="false" icon="el-icon-search" size="mini" style="margin-right: 1rem;" type="primary" @click="addOnvif">搜索ONVIF</el-button>
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<devicePlayer ref="devicePlayer"></devicePlayer>
|
||||
<el-table size="medium" :data="streamProxyList" style="width: 100%" :height="$tableHeght" >
|
||||
<el-table-column prop="app" label="流应用名" min-width="120" show-overflow-tooltip/>
|
||||
<el-table-column prop="stream" label="流ID" min-width="120" show-overflow-tooltip/>
|
||||
<el-table-column label="流地址" min-width="250" show-overflow-tooltip >
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.srcUrl" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
|
||||
{{scope.row.srcUrl}}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="mediaServerId" label="流媒体" min-width="180" ></el-table-column>
|
||||
<el-table-column label="代理方式" width="100" >
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
{{scope.row.type === "default"? "默认":"FFMPEG代理"}}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="gbDeviceId" label="国标编码" min-width="180" show-overflow-tooltip/>
|
||||
<el-table-column label="拉流状态" min-width="120" >
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.pulling && Vue.prototype.$myServerId !== scope.row.serverId" style="border-color: #ecf1af">正在拉流</el-tag>
|
||||
<el-tag size="medium" v-if="scope.row.pulling && Vue.prototype.$myServerId === scope.row.serverId">正在拉流</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="!scope.row.pulling">尚未拉流</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="启用" min-width="120" >
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.enable && Vue.prototype.$myServerId !== scope.row.serverId" style="border-color: #ecf1af">已启用</el-tag>
|
||||
<el-tag size="medium" v-if="scope.row.enable && Vue.prototype.$myServerId === scope.row.serverId">已启用</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="150" show-overflow-tooltip/>
|
||||
<el-table-column label="操作" width="400" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button size="medium" :loading="scope.row.playLoading" icon="el-icon-video-play" type="text" @click="play(scope.row)">播放</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-switch-button" style="color: #f56c6c" type="text" v-if="scope.row.pulling" @click="stopPlay(scope.row)">停止</el-button>
|
||||
<el-divider direction="vertical" v-if="scope.row.pulling" ></el-divider>
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c" @click="deleteStreamProxy(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
<streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit>
|
||||
<onvifEdit ref="onvifEdit" ></onvifEdit>
|
||||
<StreamProxyEdit v-if="streamProxy" v-model="streamProxy" :closeEdit="closeEdit" ></StreamProxyEdit>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import streamProxyEdit from './dialog/StreamProxyEdit.vue'
|
||||
import onvifEdit from './dialog/onvifEdit.vue'
|
||||
import devicePlayer from './dialog/devicePlayer.vue'
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import StreamProxyEdit from "./StreamProxyEdit";
|
||||
import MediaServer from "./service/MediaServer";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
name: 'streamProxyList',
|
||||
components: {
|
||||
devicePlayer,
|
||||
streamProxyEdit,
|
||||
onvifEdit,
|
||||
StreamProxyEdit,
|
||||
uiHeader
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
streamProxyList: [],
|
||||
currentPusher: {}, //当前操作设备对象
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
currentDeviceChannelsLenth:0,
|
||||
currentPage:1,
|
||||
count:15,
|
||||
total:0,
|
||||
streamProxy: null,
|
||||
searchSrt: "",
|
||||
mediaServerId: "",
|
||||
pulling: "",
|
||||
mediaServerObj: new MediaServer(),
|
||||
mediaServerList: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
Vue() {
|
||||
return Vue
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.startUpdateList()
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('videojs');
|
||||
clearTimeout(this.updateLooper);
|
||||
},
|
||||
methods: {
|
||||
initData: function() {
|
||||
this.getStreamProxyList();
|
||||
this.mediaServerObj.getOnlineMediaServerList((data) => {
|
||||
this.mediaServerList = data.data;
|
||||
})
|
||||
},
|
||||
startUpdateList: function (){
|
||||
this.updateLooper = setInterval(()=>{
|
||||
if (!this.streamProxy) {
|
||||
this.getStreamProxyList()
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
},
|
||||
currentChange: function(val){
|
||||
this.currentPage = val;
|
||||
this.getStreamProxyList();
|
||||
},
|
||||
handleSizeChange: function(val){
|
||||
this.count = val;
|
||||
this.getStreamProxyList();
|
||||
},
|
||||
getStreamProxyList: function() {
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/proxy/list`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count,
|
||||
query: this.searchSrt,
|
||||
pulling: this.pulling,
|
||||
mediaServerId: this.mediaServerId,
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
for (let i = 0; i < res.data.data.list.length; i++) {
|
||||
res.data.data.list[i]["playLoading"] = false;
|
||||
}
|
||||
that.streamProxyList = res.data.data.list;
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
addStreamProxy: function(){
|
||||
// this.$refs.streamProxyEdit.openDialog(null, this.initData)
|
||||
this.streamProxy = {
|
||||
type: "default",
|
||||
dataType: 3,
|
||||
noneReader: 1,
|
||||
enable: true,
|
||||
enableAudio: true,
|
||||
mediaServerId: "",
|
||||
timeout: 10,
|
||||
}
|
||||
},
|
||||
addOnvif: function(){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/onvif/search?timeout=3000`,
|
||||
}).then((res) =>{
|
||||
if (res.data.code === 0 ){
|
||||
if (res.data.data.length > 0) {
|
||||
this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
|
||||
if (url != null) {
|
||||
this.$refs.onvifEdit.close();
|
||||
this.$refs.streamProxyEdit.openDialog({type: "default", url: url, srcUrl: url}, this.initData())
|
||||
}
|
||||
})
|
||||
}else {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "未找到可用设备"
|
||||
});
|
||||
}
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
});
|
||||
|
||||
},
|
||||
edit: function(row){
|
||||
if (row.enableDisableNoneReader) {
|
||||
this.$set(row, "noneReader", 1)
|
||||
}else if (row.enableRemoveNoneReader) {
|
||||
this.$set(row, "noneReader", 2)
|
||||
}else {
|
||||
this.$set(row, "noneReader", 0)
|
||||
}
|
||||
this.streamProxy = row
|
||||
this.$set(this.streamProxy, "rtspType", row.rtspType)
|
||||
},
|
||||
closeEdit: function(row){
|
||||
this.streamProxy = null
|
||||
},
|
||||
play: function(row){
|
||||
row.playLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/proxy/start`,
|
||||
params: {
|
||||
id: row.id,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$refs.devicePlayer.openDialog("streamPlay", null, null, {
|
||||
streamInfo: res.data.data,
|
||||
hasAudio: true
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "获取地址失败:" + res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
}).finally(()=>{
|
||||
row.playLoading = false;
|
||||
})
|
||||
|
||||
},
|
||||
stopPlay: function(row){
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/proxy/stop`,
|
||||
params: {
|
||||
id: row.id,
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0) {
|
||||
|
||||
}else {
|
||||
that.$message.error(res.data.msg);
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
},
|
||||
queryCloudRecords: function (row) {
|
||||
|
||||
this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
|
||||
},
|
||||
deleteStreamProxy: function(row){
|
||||
this.$confirm('确定删除此代理吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method:"delete",
|
||||
url:"/api/proxy/delete",
|
||||
params:{
|
||||
id: row.id,
|
||||
}
|
||||
}).then((res)=>{
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "删除成功"
|
||||
})
|
||||
this.initData()
|
||||
}).catch((error) =>{
|
||||
console.log(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
refresh: function (){
|
||||
this.initData();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.videoList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 10rem;
|
||||
margin-right: 1rem;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-item-img:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background-image: url("../assets/loading.png");
|
||||
background-size: cover;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
line-height: 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: 14.4rem;
|
||||
}
|
||||
.cpoy-btn {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
@ -1,136 +0,0 @@
|
||||
<template>
|
||||
<div id="ChannelEdit" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<el-page-header @back="close" content="编辑推流信息"></el-page-header>
|
||||
</div>
|
||||
<div class="page-header-btn">
|
||||
<div style="display: inline;">
|
||||
<el-button icon="el-icon-close" size="mini" style="font-size: 20px; color: #000;" type="text" @click="close" ></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tabs tab-position="left">
|
||||
<el-tab-pane label="推流信息编辑" style="background-color: #FFFFFF; padding: 1rem">
|
||||
<el-divider content-position="center">基础信息</el-divider>
|
||||
<el-form ref="streamPushForm" status-icon label-width="160px" class="channel-form" v-loading="locading">
|
||||
<el-form-item label="应用名" >
|
||||
<el-input v-model="streamPush.app" placeholder="请输入应用名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流ID" >
|
||||
<el-input v-model="streamPush.stream" placeholder="请输入流ID"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-divider content-position="center">策略</el-divider>
|
||||
<el-form ref="streamPushForm" status-icon label-width="160px" v-loading="locading">
|
||||
<el-form-item style="text-align: left">
|
||||
<el-checkbox v-model="streamPush.startOfflinePush">拉起离线推流</el-checkbox>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
<el-form style="text-align: right">
|
||||
<el-form-item >
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="国标通道配置" v-if="streamPush.id">
|
||||
<CommonChannelEdit ref="commonChannelEdit" :dataForm="streamPush" :cancel="close"></CommonChannelEdit>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CommonChannelEdit from './common/CommonChannelEdit'
|
||||
|
||||
export default {
|
||||
name: "channelEdit",
|
||||
props: [ 'streamPush', 'closeEdit'],
|
||||
components: {
|
||||
CommonChannelEdit,
|
||||
},
|
||||
created() {
|
||||
console.log(this.streamPush)
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
locading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onSubmit: function () {
|
||||
console.log(this.streamPush)
|
||||
this.locading = true
|
||||
if (this.streamPush.id) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/push/update",
|
||||
data: this.streamPush
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: '保存成功',
|
||||
});
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
}).finally(()=>{
|
||||
this.locading = false
|
||||
})
|
||||
}else {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/push/add",
|
||||
data: this.streamPush
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: '保存成功',
|
||||
});
|
||||
|
||||
this.streamPush = res.data.data
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
}).finally(()=>{
|
||||
this.locading = false
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
close: function () {
|
||||
this.closeEdit()
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,384 +0,0 @@
|
||||
<template>
|
||||
<div id="streamPushList" style="width: 100%">
|
||||
<div v-if="!streamPush">
|
||||
<div class="page-header">
|
||||
<div class="page-title">推流列表</div>
|
||||
<div class="page-header-btn">
|
||||
搜索:
|
||||
<el-input @input="getPushList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
流媒体:
|
||||
<el-select size="mini" @change="getPushList" style="margin-right: 1rem;" v-model="mediaServerId"
|
||||
placeholder="请选择" default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
推流状态:
|
||||
<el-select size="mini" style="margin-right: 1rem;" @change="getPushList" v-model="pushing" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="推流中" value="true"></el-option>
|
||||
<el-option label="已停止" value="false"></el-option>
|
||||
</el-select>
|
||||
<el-button icon="el-icon-upload2" size="mini" style="margin-right: 1rem;" type="primary" @click="importChannel">
|
||||
通道导入
|
||||
</el-button>
|
||||
<el-button icon="el-icon-download" size="mini" style="margin-right: 1rem;" type="primary">
|
||||
<a style="color: #FFFFFF; text-align: center; text-decoration: none" href="/static/file/推流通道导入.zip"
|
||||
download='推流通道导入.zip'>下载模板</a>
|
||||
</el-button>
|
||||
<el-button icon="el-icon-delete" size="mini" style="margin-right: 1rem;"
|
||||
:disabled="multipleSelection.length === 0" type="danger" @click="batchDel">移除
|
||||
</el-button>
|
||||
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStream">添加
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table size="medium" ref="pushListTable" :data="pushList" style="width: 100%" :height="$tableHeght" :loading="loading"
|
||||
@selection-change="handleSelectionChange" :row-key="(row)=> row.app + row.stream">
|
||||
<el-table-column type="selection" :reserve-selection="true" min-width="55">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbName" label="名称" min-width="200">
|
||||
</el-table-column>
|
||||
<el-table-column prop="app" label="应用名" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column prop="stream" label="流ID" min-width="200">
|
||||
</el-table-column>
|
||||
<el-table-column label="推流状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<el-tag size="medium" v-if="scope.row.pushing && Vue.prototype.$myServerId !== scope.row.serverId" style="border-color: #ecf1af">推流中</el-tag>
|
||||
<el-tag size="medium" v-if="scope.row.pushing && Vue.prototype.$myServerId === scope.row.serverId">推流中</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="!scope.row.pushing">已停止</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbDeviceId" label="国标编码" min-width="200" >
|
||||
</el-table-column>
|
||||
<el-table-column label="位置信息" min-width="200">
|
||||
<template v-slot:default="scope">
|
||||
<span size="medium" v-if="scope.row.gbLongitude && scope.row.gbLatitude">{{scope.row.gbLongitude}}<br/>{{scope.row.gbLatitude}}</span>
|
||||
<span size="medium" v-if="!scope.row.gbLongitude || !scope.row.gbLatitude">无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="mediaServerId" label="流媒体" min-width="200" >
|
||||
</el-table-column>
|
||||
<el-table-column label="开始时间" min-width="200">
|
||||
<template v-slot:default="scope">
|
||||
<el-button-group>
|
||||
{{ scope.row.pushTime == null? "-":scope.row.pushTime }}
|
||||
</el-button-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
<el-table-column label="操作" min-width="360" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button size="medium" :loading="scope.row.playLoading" icon="el-icon-video-play" @click="playPush(scope.row)" type="text">播放
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-delete" type="text" @click="deletePush(scope.row.id)" style="color: #f56c6c" >删除</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-position" type="text" @click="edit(scope.row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
<devicePlayer ref="devicePlayer"></devicePlayer>
|
||||
<addStreamTOGB ref="addStreamTOGB"></addStreamTOGB>
|
||||
<importChannel ref="importChannel"></importChannel>
|
||||
<stream-push-edit v-if="streamPush" :streamPush="streamPush" :closeEdit="closeEdit"></stream-push-edit>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import devicePlayer from './dialog/devicePlayer.vue'
|
||||
import addStreamTOGB from './dialog/pushStreamEdit.vue'
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import importChannel from './dialog/importChannel.vue'
|
||||
import MediaServer from './service/MediaServer'
|
||||
import StreamPushEdit from "./StreamPushEdit";
|
||||
import ChannelEdit from "./ChannelEdit.vue";
|
||||
import Vue from "vue";
|
||||
|
||||
export default {
|
||||
name: 'streamPushList',
|
||||
components: {
|
||||
ChannelEdit,
|
||||
StreamPushEdit,
|
||||
devicePlayer,
|
||||
addStreamTOGB,
|
||||
uiHeader,
|
||||
importChannel,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pushList: [], //设备列表
|
||||
currentPusher: {}, //当前操作设备对象
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
currentDeviceChannelsLenth: 0,
|
||||
mediaServerObj: new MediaServer(),
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
searchSrt: "",
|
||||
pushing: "",
|
||||
mediaServerId: "",
|
||||
mediaServerList: [],
|
||||
multipleSelection: [],
|
||||
loading: false,
|
||||
streamPush: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
Vue() {
|
||||
return Vue
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.updateLooper = setInterval(this.getPushList, 2000);
|
||||
},
|
||||
destroyed() {
|
||||
clearTimeout(this.updateLooper);
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.loading = true;
|
||||
this.mediaServerObj.getOnlineMediaServerList((data) => {
|
||||
this.mediaServerList = data.data;
|
||||
})
|
||||
this.getPushList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getPushList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getPushList();
|
||||
},
|
||||
getPushList: function () {
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/push/list`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count,
|
||||
query: that.searchSrt,
|
||||
pushing: that.pushing,
|
||||
mediaServerId: that.mediaServerId,
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.pushList = res.data.data.list;
|
||||
that.pushList.forEach(e => {
|
||||
that.$set(e, "location", "");
|
||||
that.$set(e, "playLoading", false);
|
||||
if (e.gbLongitude && e.gbLatitude) {
|
||||
that.$set(e, "location", e.gbLongitude + "," + e.gbLatitude);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
}).finally(()=>{
|
||||
this.loading = false;
|
||||
})
|
||||
},
|
||||
|
||||
playPush: function (row) {
|
||||
row.playLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/push/start',
|
||||
params: {
|
||||
id: row.id
|
||||
}
|
||||
}).then((res) =>{
|
||||
if (res.data.code === 0 ) {
|
||||
this.$refs.devicePlayer.openDialog("streamPlay", null, null, {
|
||||
streamInfo: res.data.data,
|
||||
hasAudio: true
|
||||
});
|
||||
}else {
|
||||
this.$message.error(res.data.msg);
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
}).finally(()=>{
|
||||
row.playLoading = false;
|
||||
})
|
||||
},
|
||||
deletePush: function (id) {
|
||||
this.$confirm(`确定删除通道?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.loading = true;
|
||||
this.$axios({
|
||||
method: "post",
|
||||
url: "/api/push/remove",
|
||||
params: {
|
||||
id: id,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.initData()
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
edit: function (row) {
|
||||
this.streamPush = row
|
||||
},
|
||||
// 结束编辑
|
||||
closeEdit: function (){
|
||||
this.streamPush = null
|
||||
this.getPushList()
|
||||
},
|
||||
removeFromGB: function (row) {
|
||||
let that = this;
|
||||
that.$axios({
|
||||
method: "delete",
|
||||
url: "/api/push/remove_form_gb",
|
||||
data: row
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
that.initData()
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
},
|
||||
queryCloudRecords: function (row) {
|
||||
|
||||
this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
|
||||
},
|
||||
importChannel: function () {
|
||||
this.$refs.importChannel.openDialog(() => {
|
||||
|
||||
})
|
||||
},
|
||||
addStream: function (){
|
||||
// this.$refs.addStreamTOGB.openDialog(null, this.initData);
|
||||
this.streamPush = {}
|
||||
},
|
||||
batchDel: function () {
|
||||
this.$confirm(`确定删除选中的${this.multipleSelection.length}个通道?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
let ids = []
|
||||
for (let i = 0; i < this.multipleSelection.length; i++) {
|
||||
ids.push(this.multipleSelection[i].id)
|
||||
}
|
||||
let that = this;
|
||||
that.$axios({
|
||||
method: "delete",
|
||||
url: "/api/push/batchRemove",
|
||||
data: {
|
||||
ids: ids
|
||||
}
|
||||
}).then((res) => {
|
||||
this.initData();
|
||||
this.$refs.pushListTable.clearSelection();
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
},
|
||||
handleSelectionChange: function (val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
refresh: function () {
|
||||
this.initData();
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.videoList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 10rem;
|
||||
margin-right: 1rem;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-item-img:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background-image: url("../assets/loading.png");
|
||||
background-size: cover;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
line-height: 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: 14.4rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,303 +0,0 @@
|
||||
<template>
|
||||
<div id="app" style="width: 100%">
|
||||
<div class="page-header" style="margin-bottom: 0">
|
||||
<div class="page-title">
|
||||
<el-page-header @back="goBack" content="ApiKey列表"></el-page-header>
|
||||
</div>
|
||||
<div class="page-header-btn">
|
||||
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addUserApiKey">
|
||||
添加ApiKey
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--ApiKey列表-->
|
||||
<el-table size="medium" :data="userList" style="width: 100%;font-size: 12px;" :height="winHeight"
|
||||
header-row-class-name="table-header">
|
||||
<el-table-column prop="user.username" label="用户名" min-width="120"/>
|
||||
<el-table-column prop="app" label="应用名" min-width="160"/>
|
||||
<el-table-column label="ApiKey" :show-overflow-tooltip="true" min-width="300">
|
||||
<template #default="scope">
|
||||
<!-- <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.apiKey" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>-->
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.apiKey" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
|
||||
<span>{{scope.row.apiKey}}</span>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="enable" label="启用" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.enable">
|
||||
启用
|
||||
</el-tag>
|
||||
<el-tag v-else type="info">
|
||||
停用
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="expiredAt" label="过期时间" width="160"/>
|
||||
<el-table-column prop="remark" label="备注信息" min-width="160"/>
|
||||
<el-table-column label="操作" min-width="260" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button v-if="scope.row.enable"
|
||||
size="medium" icon="el-icon-circle-close" type="text" @click="disableUserApiKey(scope.row)">
|
||||
停用
|
||||
</el-button>
|
||||
<el-button v-else
|
||||
size="medium" icon="el-icon-circle-check" type="text" @click="enableUserApiKey(scope.row)">
|
||||
启用
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-refresh" type="text" @click="resetUserApiKey(scope.row)">
|
||||
重置
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="remarkUserApiKey(scope.row)">
|
||||
备注
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-delete" type="text" @click="deleteUserApiKey(scope.row)"
|
||||
style="color: #f56c6c">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<addUserApiKey ref="addUserApiKey"></addUserApiKey>
|
||||
<remarkUserApiKey ref="remarkUserApiKey"></remarkUserApiKey>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import addUserApiKey from "./dialog/addUserApiKey.vue";
|
||||
import remarkUserApiKey from './dialog/remarkUserApiKey.vue'
|
||||
|
||||
export default {
|
||||
name: 'userApiKeyManager',
|
||||
components: {
|
||||
uiHeader,
|
||||
addUserApiKey,
|
||||
remarkUserApiKey
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userList: [], //设备列表
|
||||
currentUser: {}, //当前操作设备对象
|
||||
winHeight: window.innerHeight - 200,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
getUserApiKeyListLoading: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initParam();
|
||||
this.initData();
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.back()
|
||||
},
|
||||
initParam() {
|
||||
this.userId = this.$route.params.userId;
|
||||
},
|
||||
initData() {
|
||||
this.getUserApiKeyList();
|
||||
},
|
||||
currentChange(val) {
|
||||
this.currentPage = val;
|
||||
this.getUserApiKeyList();
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.count = val;
|
||||
this.getUserApiKeyList();
|
||||
},
|
||||
getUserApiKeyList() {
|
||||
let that = this;
|
||||
this.getUserApiKeyListLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/userApiKey/userApiKeys`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.userList = res.data.data.list;
|
||||
}
|
||||
that.getUserApiKeyListLoading = false;
|
||||
}).catch((error) => {
|
||||
that.getUserApiKeyListLoading = false;
|
||||
});
|
||||
},
|
||||
addUserApiKey() {
|
||||
this.$refs.addUserApiKey.openDialog(this.userId, () => {
|
||||
this.$refs.addUserApiKey.close();
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "ApiKey添加成功",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(this.getUserApiKeyList, 200)
|
||||
})
|
||||
},
|
||||
remarkUserApiKey(row) {
|
||||
this.$refs.remarkUserApiKey.openDialog(row.id, () => {
|
||||
this.$refs.remarkUserApiKey.close();
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "备注修改成功",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(this.getUserApiKeyList, 200)
|
||||
})
|
||||
},
|
||||
enableUserApiKey(row) {
|
||||
let msg = "确定启用此ApiKey?"
|
||||
if (row.online !== 0) {
|
||||
msg = "<strong>确定启用此ApiKey?</strong>"
|
||||
}
|
||||
this.$confirm(msg, '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
center: true,
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/userApiKey/enable?id=${row.id}`
|
||||
}).then((res) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '启用成功',
|
||||
type: 'success'
|
||||
});
|
||||
this.getUserApiKeyList();
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '启用失败',
|
||||
type: 'error'
|
||||
});
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
disableUserApiKey(row) {
|
||||
let msg = "确定停用此ApiKey?"
|
||||
if (row.online !== 0) {
|
||||
msg = "<strong>确定停用此ApiKey?</strong>"
|
||||
}
|
||||
this.$confirm(msg, '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
center: true,
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/userApiKey/disable?id=${row.id}`
|
||||
}).then((res) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '停用成功',
|
||||
type: 'success'
|
||||
});
|
||||
this.getUserApiKeyList();
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '停用失败',
|
||||
type: 'error'
|
||||
});
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
resetUserApiKey(row) {
|
||||
let msg = "确定重置此ApiKey?"
|
||||
if (row.online !== 0) {
|
||||
msg = "<strong>确定重置此ApiKey?</strong>"
|
||||
}
|
||||
this.$confirm(msg, '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
center: true,
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/userApiKey/reset?id=${row.id}`
|
||||
}).then((res) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '重置成功',
|
||||
type: 'success'
|
||||
});
|
||||
this.getUserApiKeyList();
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '重置失败',
|
||||
type: 'error'
|
||||
});
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
deleteUserApiKey(row) {
|
||||
let msg = "确定删除此ApiKey?"
|
||||
if (row.online !== 0) {
|
||||
msg = "<strong>确定删除此ApiKey?</strong>"
|
||||
}
|
||||
this.$confirm(msg, '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
center: true,
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url: `/api/userApiKey/delete?id=${row.id}`
|
||||
}).then((res) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '删除成功',
|
||||
type: 'success'
|
||||
});
|
||||
this.getUserApiKeyList();
|
||||
}).catch((error) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '删除失败',
|
||||
type: 'error'
|
||||
});
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@ -1,241 +0,0 @@
|
||||
<template>
|
||||
|
||||
<div id="app" style="width: 100%">
|
||||
<div class="page-header">
|
||||
|
||||
<div class="page-title">用户列表</div>
|
||||
<div class="page-header-btn">
|
||||
<el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addUser">
|
||||
添加用户
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--用户列表-->
|
||||
<el-table size="medium" :data="userList" style="width: 100%;font-size: 12px;" :height="$tableHeght"
|
||||
header-row-class-name="table-header">
|
||||
<el-table-column prop="username" label="用户名" min-width="160"/>
|
||||
<el-table-column prop="pushKey" label="pushkey" min-width="160"/>
|
||||
<el-table-column prop="role.name" label="类型" min-width="160"/>
|
||||
<el-table-column label="操作" min-width="450" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="edit(scope.row)">修改密码</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="changePushKey(scope.row)">修改pushkey</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-edit" type="text" @click="showUserApiKeyManager(scope.row)">管理ApiKey</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-delete" type="text" @click="deleteUser(scope.row)"
|
||||
style="color: #f56c6c">删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<changePasswordForAdmin ref="changePasswordForAdmin"></changePasswordForAdmin>
|
||||
<changePushKey ref="changePushKey"></changePushKey>
|
||||
<addUser ref="addUser"></addUser>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import changePasswordForAdmin from './dialog/changePasswordForAdmin.vue'
|
||||
import changePushKey from './dialog/changePushKey.vue'
|
||||
import addUser from '../components/dialog/addUser.vue'
|
||||
|
||||
export default {
|
||||
name: 'userManager',
|
||||
components: {
|
||||
uiHeader,
|
||||
changePasswordForAdmin,
|
||||
changePushKey,
|
||||
addUser
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userList: [], //设备列表
|
||||
currentUser: {}, //当前操作设备对象
|
||||
|
||||
videoComponentList: [],
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
currentUserLenth: 0,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
getUserListLoading: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
this.updateLooper = setInterval(this.initData, 10000);
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('videojs');
|
||||
clearTimeout(this.updateLooper);
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.getUserList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getUserList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getUserList();
|
||||
},
|
||||
getUserList: function () {
|
||||
let that = this;
|
||||
this.getUserListLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/user/users`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.userList = res.data.data.list;
|
||||
}
|
||||
that.getUserListLoading = false;
|
||||
}).catch(function (error) {
|
||||
that.getUserListLoading = false;
|
||||
});
|
||||
|
||||
},
|
||||
edit: function (row) {
|
||||
this.$refs.changePasswordForAdmin.openDialog(row, () => {
|
||||
this.$refs.changePasswordForAdmin.close();
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "密码修改成功",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(this.getUserList, 200)
|
||||
|
||||
})
|
||||
},
|
||||
deleteUser: function (row) {
|
||||
let msg = "确定删除此用户?"
|
||||
if (row.online !== 0) {
|
||||
msg = "<strong>确定删除此用户?</strong>"
|
||||
}
|
||||
this.$confirm(msg, '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
center: true,
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url: `/api/user/delete?id=${row.id}`
|
||||
}).then((res) => {
|
||||
this.getUserList();
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
changePushKey: function (row) {
|
||||
this.$refs.changePushKey.openDialog(row, () => {
|
||||
this.$refs.changePushKey.close();
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "pushKey修改成功",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(this.getUserList, 200)
|
||||
|
||||
})
|
||||
},
|
||||
addUser: function () {
|
||||
// this.$refs.addUser.openDialog()
|
||||
this.$refs.addUser.openDialog( () => {
|
||||
this.$refs.addUser.close();
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "用户添加成功",
|
||||
type: "success",
|
||||
});
|
||||
setTimeout(this.getUserList, 200)
|
||||
|
||||
})
|
||||
},
|
||||
showUserApiKeyManager: function (row) {
|
||||
this.$router.push(`/userApiKeyManager/${row.id}`)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.videoList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 10rem;
|
||||
margin-right: 1rem;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-item-img:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background-image: url("../assets/loading.png");
|
||||
background-size: cover;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
line-height: 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: 14.4rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,669 +0,0 @@
|
||||
<template>
|
||||
<div id="channelList" style="width: 100%">
|
||||
<div v-if="!editId">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<el-page-header @back="showDevice" content="通道列表"></el-page-header>
|
||||
</div>
|
||||
<div class="page-header-btn">
|
||||
<div v-if="!showTree" style="display: inline;">
|
||||
搜索:
|
||||
<el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
|
||||
通道类型:
|
||||
<el-select size="mini" @change="search" style="width: 8rem; margin-right: 1rem;" v-model="channelType" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="设备" value="false"></el-option>
|
||||
<el-option label="子目录" value="true"></el-option>
|
||||
</el-select>
|
||||
在线状态:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="在线" value="true"></el-option>
|
||||
<el-option label="离线" value="false"></el-option>
|
||||
</el-select>
|
||||
码流类型重置:
|
||||
<el-select size="mini" style="width: 16rem; margin-right: 1rem;" @change="subStreamChange" v-model="subStream"
|
||||
placeholder="请选择码流类型" default-first-option >
|
||||
<el-option label="stream:0(主码流)" value="stream:0"></el-option>
|
||||
<el-option label="stream:1(子码流)" value="stream:1"></el-option>
|
||||
<el-option label="streamnumber:0(主码流-2022)" value="streamnumber:0"></el-option>
|
||||
<el-option label="streamnumber:1(子码流-2022)" value="streamnumber:1"></el-option>
|
||||
<el-option label="streamprofile:0(主码流-大华)" value="streamprofile:0"></el-option>
|
||||
<el-option label="streamprofile:1(子码流-大华)" value="streamprofile:1"></el-option>
|
||||
<el-option label="streamMode:main(主码流-水星+TP-LINK)" value="streamMode:main"></el-option>
|
||||
<el-option label="streamMode:sub(子码流-水星+TP-LINK)" value="streamMode:sub"></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table size="medium" ref="channelListTable" :data="deviceChannelList" :height="$tableHeght"
|
||||
header-row-class-name="table-header">
|
||||
<el-table-column prop="name" label="名称" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceId" label="编号" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column label="快照" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<el-image
|
||||
:src="getSnap(scope.row)"
|
||||
:preview-src-list="getBigSnap(scope.row)"
|
||||
@error="getSnapErrorEvent(scope.row.deviceId, scope.row.channelId)"
|
||||
:fit="'contain'"
|
||||
style="width: 60px">
|
||||
<div slot="error" class="image-slot">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
</div>
|
||||
</el-image>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column prop="subCount" label="子节点数" min-width="100">-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column prop="manufacturer" label="厂家" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column label="位置信息" min-width="150">
|
||||
<template v-slot:default="scope">
|
||||
<span size="medium" v-if="scope.row.longitude && scope.row.latitude">{{scope.row.longitude}}<br/>{{scope.row.latitude}}</span>
|
||||
<span size="medium" v-if="!scope.row.longitude || !scope.row.latitude">无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ptzType" label="云台类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div >{{ scope.row.ptzTypeText }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开启音频" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<el-switch @change="updateChannel(scope.row)" v-model="scope.row.hasAudio" active-color="#409EFF">
|
||||
</el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="码流类型" min-width="180">
|
||||
<template v-slot:default="scope">
|
||||
<el-select size="mini" style="margin-right: 1rem;" @change="channelSubStreamChange(scope.row)" v-model="scope.row.streamIdentification"
|
||||
placeholder="请选择码流类型" default-first-option >
|
||||
<el-option label="stream:0(主码流)" value="stream:0"></el-option>
|
||||
<el-option label="stream:1(子码流)" value="stream:1"></el-option>
|
||||
<el-option label="streamnumber:0(主码流-2022)" value="streamnumber:0"></el-option>
|
||||
<el-option label="streamnumber:1(子码流-2022)" value="streamnumber:1"></el-option>
|
||||
<el-option label="streamprofile:0(主码流-大华)" value="streamprofile:0"></el-option>
|
||||
<el-option label="streamprofile:1(子码流-大华)" value="streamprofile:1"></el-option>
|
||||
<el-option label="streamMode:main(主码流-水星+TP-LINK)" value="streamMode:main"></el-option>
|
||||
<el-option label="streamMode:sub(子码流-水星+TP-LINK)" value="streamMode:sub"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.status === 'ON'">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="scope.row.status !== 'ON'">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="340" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-play"
|
||||
type="text" :loading="scope.row.playLoading" @click="sendDevicePush(scope.row)">播放
|
||||
</el-button>
|
||||
<el-button size="medium" v-bind:disabled="device == null || device.online === 0"
|
||||
icon="el-icon-switch-button"
|
||||
type="text" style="color: #f56c6c" v-if="!!scope.row.streamId"
|
||||
@click="stopDevicePush(scope.row)">停止
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button
|
||||
size="medium"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-button size="medium" icon="el-icon-s-open" type="text"
|
||||
v-if="scope.row.subCount > 0 || scope.row.parental === 1 || scope.row.deviceId.length <= 8"
|
||||
@click="changeSubchannel(scope.row)">查看
|
||||
</el-button>
|
||||
<el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1 || scope.row.deviceId.length <= 8" direction="vertical"></el-divider>
|
||||
<el-dropdown @command="(command)=>{moreClick(command, scope.row)}">
|
||||
<el-button size="medium" type="text" >
|
||||
更多<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="records" v-bind:disabled="device == null || device.online === 0">
|
||||
设备录像</el-dropdown-item>
|
||||
<el-dropdown-item command="cloudRecords" v-bind:disabled="device == null || device.online === 0" >
|
||||
云端录像</el-dropdown-item>
|
||||
<el-dropdown-item command="record" v-bind:disabled="device == null || device.online === 0" >
|
||||
设备录像控制-开始</el-dropdown-item>
|
||||
<el-dropdown-item command="stopRecord" v-bind:disabled="device == null || device.online === 0" >
|
||||
设备录像控制-停止</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<devicePlayer ref="devicePlayer"></devicePlayer>
|
||||
<channel-edit v-if="editId" :id="editId" :closeEdit="closeEdit"></channel-edit>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import devicePlayer from './dialog/devicePlayer.vue'
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import DeviceService from "./service/DeviceService";
|
||||
import DeviceTree from "./common/DeviceTree";
|
||||
import ChannelEdit from "./ChannelEdit";
|
||||
|
||||
export default {
|
||||
name: 'channelList',
|
||||
components: {
|
||||
devicePlayer,
|
||||
uiHeader,
|
||||
DeviceTree,
|
||||
ChannelEdit,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
deviceService: new DeviceService(),
|
||||
device: null,
|
||||
deviceId: this.$route.params.deviceId,
|
||||
parentChannelId: this.$route.params.parentChannelId,
|
||||
deviceChannelList: [],
|
||||
videoComponentList: [],
|
||||
currentPlayerInfo: {}, //当前播放对象
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
searchSrt: "",
|
||||
channelType: "",
|
||||
online: "",
|
||||
subStream: "",
|
||||
winHeight: window.innerHeight - 200,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
beforeUrl: "/deviceList",
|
||||
showTree: false,
|
||||
editId: null,
|
||||
loadSnap: {},
|
||||
ptzTypes: {
|
||||
0: "未知",
|
||||
1: "球机",
|
||||
2: "半球",
|
||||
3: "固定枪机",
|
||||
4: "遥控枪机"
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.deviceId) {
|
||||
this.deviceService.getDevice(this.deviceId, (result) => {
|
||||
this.device = result;
|
||||
|
||||
}, (error) => {
|
||||
console.log("获取设备信息失败")
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
this.initData();
|
||||
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('videojs');
|
||||
clearTimeout(this.updateLooper);
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
if (typeof (this.parentChannelId) == "undefined" || this.parentChannelId == 0) {
|
||||
this.getDeviceChannelList();
|
||||
} else {
|
||||
this.showSubchannels();
|
||||
}
|
||||
},
|
||||
initParam: function () {
|
||||
this.deviceId = this.$route.params.deviceId;
|
||||
this.parentChannelId = this.$route.params.parentChannelId;
|
||||
this.currentPage = 1;
|
||||
this.count = 15;
|
||||
if (this.parentChannelId == "" || this.parentChannelId == 0) {
|
||||
this.beforeUrl = "/deviceList"
|
||||
}
|
||||
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.initData();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getDeviceChannelList();
|
||||
},
|
||||
getDeviceChannelList: function () {
|
||||
let that = this;
|
||||
if (typeof (this.$route.params.deviceId) == "undefined") return;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/query/devices/${this.$route.params.deviceId}/channels`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count,
|
||||
query: that.searchSrt,
|
||||
online: that.online,
|
||||
channelType: that.channelType
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.deviceChannelList = res.data.data.list;
|
||||
that.deviceChannelList.forEach(e => {
|
||||
e.ptzType = e.ptzType + "";
|
||||
that.$set(e, "playLoading", false);
|
||||
});
|
||||
// 防止出现表格错位
|
||||
that.$nextTick(() => {
|
||||
that.$refs.channelListTable.doLayout();
|
||||
})
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
|
||||
//通知设备上传媒体流
|
||||
sendDevicePush: function (itemData) {
|
||||
let deviceId = this.deviceId;
|
||||
let channelId = itemData.deviceId;
|
||||
itemData.playLoading = true;
|
||||
console.log("通知设备推流1:" + deviceId + " : " + channelId);
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/play/start/' + deviceId + '/' + channelId,
|
||||
params: {
|
||||
isSubStream: this.isSubStream
|
||||
}
|
||||
}).then((res) =>{
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
|
||||
setTimeout(() => {
|
||||
let snapId = deviceId + "_" + channelId;
|
||||
this.loadSnap[deviceId + channelId] = 0;
|
||||
this.getSnapErrorEvent(snapId)
|
||||
}, 5000)
|
||||
itemData.streamId = res.data.data.stream;
|
||||
this.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
|
||||
streamInfo: res.data.data,
|
||||
hasAudio: itemData.hasAudio
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.initData();
|
||||
}, 1000)
|
||||
|
||||
} else {
|
||||
this.$message.error(res.data.msg);
|
||||
}
|
||||
}).catch(function (e) {
|
||||
console.error(e)
|
||||
// that.$message.error("请求超时");
|
||||
}).finally(()=>{
|
||||
itemData.playLoading = false;
|
||||
})
|
||||
},
|
||||
moreClick: function (command, itemData) {
|
||||
if (command === "records") {
|
||||
this.queryRecords(itemData)
|
||||
}else if (command === "cloudRecords") {
|
||||
this.queryCloudRecords(itemData)
|
||||
}else if (command === "record") {
|
||||
this.startRecord(itemData)
|
||||
}else if (command === "stopRecord") {
|
||||
this.stopRecord(itemData)
|
||||
}
|
||||
},
|
||||
queryRecords: function (itemData) {
|
||||
let deviceId = this.deviceId;
|
||||
let channelId = itemData.deviceId;
|
||||
|
||||
this.$router.push(`/gbRecordDetail/${deviceId}/${channelId}`)
|
||||
},
|
||||
queryCloudRecords: function (itemData) {
|
||||
let deviceId = this.deviceId;
|
||||
let channelId = itemData.deviceId;
|
||||
|
||||
this.$router.push(`/cloudRecordDetail/rtp/${deviceId}_${channelId}`)
|
||||
},
|
||||
startRecord: function (itemData) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/control/record`,
|
||||
params: {
|
||||
deviceId: this.deviceId,
|
||||
channelId: itemData.deviceId,
|
||||
recordCmdStr: "Record"
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "开始录像成功"
|
||||
})
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
},
|
||||
stopRecord: function (itemData) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/control/record`,
|
||||
params: {
|
||||
deviceId: this.deviceId,
|
||||
channelId: itemData.deviceId,
|
||||
recordCmdStr: "StopRecord"
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "停止录像成功"
|
||||
})
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error.message
|
||||
})
|
||||
});
|
||||
},
|
||||
stopDevicePush: function (itemData) {
|
||||
var that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/play/stop/' + this.deviceId + "/" + itemData.deviceId,
|
||||
params: {
|
||||
isSubStream: this.isSubStream
|
||||
}
|
||||
}).then(function (res) {
|
||||
that.initData();
|
||||
}).catch(function (error) {
|
||||
if (error.response.status === 402) { // 已经停止过
|
||||
that.initData();
|
||||
} else {
|
||||
console.log(error)
|
||||
}
|
||||
});
|
||||
},
|
||||
getSnap: function (row) {
|
||||
let baseUrl = window.baseUrl ? window.baseUrl : "";
|
||||
return ((process.env.NODE_ENV === 'development') ? process.env.BASE_API : baseUrl) + '/api/device/query/snap/' + this.deviceId + '/' + row.deviceId;
|
||||
},
|
||||
getBigSnap: function (row) {
|
||||
return [this.getSnap(row)]
|
||||
},
|
||||
getSnapErrorEvent: function (deviceId, channelId) {
|
||||
|
||||
if (typeof (this.loadSnap[deviceId + channelId]) != "undefined") {
|
||||
console.log("下载截图" + this.loadSnap[deviceId + channelId])
|
||||
if (this.loadSnap[deviceId + channelId] > 5) {
|
||||
delete this.loadSnap[deviceId + channelId];
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
let url = (process.env.NODE_ENV === 'development' ? "debug" : "") + '/api/device/query/snap/' + deviceId + '/' + channelId
|
||||
this.loadSnap[deviceId + channelId]++
|
||||
document.getElementById(deviceId + channelId).setAttribute("src", url + '?' + new Date().getTime())
|
||||
}, 1000)
|
||||
|
||||
}
|
||||
},
|
||||
showDevice: function () {
|
||||
this.$router.push(this.beforeUrl).then(() => {
|
||||
this.initParam();
|
||||
this.initData();
|
||||
})
|
||||
},
|
||||
changeSubchannel(itemData) {
|
||||
this.beforeUrl = this.$router.currentRoute.path;
|
||||
|
||||
var url = `/${this.$router.currentRoute.name}/${this.$router.currentRoute.params.deviceId}/${itemData.deviceId}`
|
||||
this.$router.push(url).then(() => {
|
||||
this.searchSrt = "";
|
||||
this.channelType = "";
|
||||
this.online = "";
|
||||
this.initParam();
|
||||
this.initData();
|
||||
})
|
||||
},
|
||||
showSubchannels: function (channelId) {
|
||||
if (!this.showTree) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/query/sub_channels/${this.deviceId}/${this.parentChannelId}/channels`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
online: this.online,
|
||||
channelType: this.channelType
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.deviceChannelList = res.data.data.list;
|
||||
this.deviceChannelList.forEach(e => {
|
||||
e.ptzType = e.ptzType + "";
|
||||
});
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.channelListTable.doLayout();
|
||||
})
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
} else {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/query/tree/channel/${this.deviceId}`,
|
||||
params: {
|
||||
parentId: this.parentChannelId,
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.total;
|
||||
this.deviceChannelList = res.data.list;
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.channelListTable.doLayout();
|
||||
})
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
search: function () {
|
||||
this.currentPage = 1;
|
||||
this.total = 0;
|
||||
this.initData();
|
||||
},
|
||||
updateChannel: function (row) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/device/query/channel/audio`,
|
||||
params: {
|
||||
channelId: row.id,
|
||||
audio: row.hasAudio
|
||||
}
|
||||
}).then(function (res) {
|
||||
console.log(JSON.stringify(res));
|
||||
});
|
||||
},
|
||||
subStreamChange: function () {
|
||||
this.$confirm('确定重置所有通道的码流类型?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/device/query/channel/stream/identification/update/`,
|
||||
params: {
|
||||
deviceDbId: this.device.id,
|
||||
streamIdentification: this.subStream
|
||||
|
||||
}
|
||||
}).then((res)=> {
|
||||
console.log(JSON.stringify(res));
|
||||
this.initData()
|
||||
}).finally(()=>{
|
||||
this.subStream = ""
|
||||
})
|
||||
}).catch(() => {
|
||||
this.subStream = ""
|
||||
});
|
||||
|
||||
},
|
||||
channelSubStreamChange: function (row) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/device/query/channel/stream/identification/update/`,
|
||||
params: {
|
||||
deviceDbId: row.deviceDbId,
|
||||
id: row.id,
|
||||
streamIdentification: row.streamIdentification
|
||||
}
|
||||
}).then(function (res) {
|
||||
console.log(JSON.stringify(res));
|
||||
});
|
||||
},
|
||||
refresh: function () {
|
||||
this.initData();
|
||||
},
|
||||
switchTree: function () {
|
||||
this.showTree = true;
|
||||
this.deviceChannelList = [];
|
||||
this.parentChannelId = 0;
|
||||
this.currentPage = 1;
|
||||
|
||||
},
|
||||
switchList: function () {
|
||||
this.showTree = false;
|
||||
this.deviceChannelList = [];
|
||||
this.parentChannelId = 0;
|
||||
this.currentPage = 1;
|
||||
this.initData();
|
||||
},
|
||||
treeNodeClickEvent: function (device, data, isCatalog) {
|
||||
console.log(device)
|
||||
if (!!!data.channelId) {
|
||||
this.parentChannelId = device.deviceId;
|
||||
} else {
|
||||
this.parentChannelId = data.channelId;
|
||||
}
|
||||
this.initData();
|
||||
},
|
||||
// 编辑
|
||||
handleEdit(row) {
|
||||
this.editId = row.id
|
||||
},
|
||||
// 结束编辑
|
||||
closeEdit: function (){
|
||||
this.editId = null
|
||||
this.getDeviceChannelList()
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.videoList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 10rem;
|
||||
margin-right: 1rem;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-item-img:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background-image: url("../assets/loading.png");
|
||||
background-size: cover;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
line-height: 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: 14.4rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,425 +0,0 @@
|
||||
<template>
|
||||
<div id="CommonChannelEdit" v-loading="locading" style="width: 100%">
|
||||
<el-form ref="passwordForm" status-icon label-width="160px" class="channel-form">
|
||||
<div class="form-box">
|
||||
<el-form-item label="名称" >
|
||||
<el-input v-model="form.gbName" placeholder="请输入通道名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="编码" >
|
||||
<el-input v-model="form.gbDeviceId" placeholder="请输入通道编码">
|
||||
<template v-slot:append>
|
||||
<el-button @click="buildDeviceIdCode(form.gbDeviceId)">生成</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备厂商" >
|
||||
<el-input v-model="form.gbManufacturer" placeholder="请输入设备厂商"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备型号" >
|
||||
<el-input v-model="form.gbModel" placeholder="请输入设备型号"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="行政区域" >
|
||||
<el-input v-model="form.gbCivilCode" placeholder="请输入行政区域">
|
||||
<template v-slot:append>
|
||||
<el-button @click="chooseCivilCode()">选择</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="安装地址" >
|
||||
<el-input v-model="form.gbAddress" placeholder="请输入安装地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="子设备" >
|
||||
<el-select v-model="form.gbParental" style="width: 100%" placeholder="请选择是否有子设备">
|
||||
<el-option label="有" :value="1"></el-option>
|
||||
<el-option label="无" :value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="父节点编码" >
|
||||
<el-input v-model="form.gbParentId" placeholder="请输入父节点编码或选择所属虚拟组织">
|
||||
<template v-slot:append>
|
||||
<el-button @click="chooseGroup()">选择</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备状态" >
|
||||
<el-select v-model="form.gbStatus" style="width: 100%" placeholder="请选择设备状态">
|
||||
<el-option label="在线" value="ON"></el-option>
|
||||
<el-option label="离线" value="OFF"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="经度" >
|
||||
<el-input v-model="form.gbLongitude" placeholder="请输入经度"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="纬度" >
|
||||
<el-input v-model="form.gbLatitude" placeholder="请输入纬度"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="云台类型" >
|
||||
<el-select v-model="form.gbPtzType" style="width: 100%" placeholder="请选择云台类型">
|
||||
<el-option label="球机" :value="1"></el-option>
|
||||
<el-option label="半球" :value="2"></el-option>
|
||||
<el-option label="固定枪机" :value="3"></el-option>
|
||||
<el-option label="遥控枪机" :value="4"></el-option>
|
||||
<el-option label="遥控半球" :value="5"></el-option>
|
||||
<el-option label="多目设备的全景/拼接通道" :value="6"></el-option>
|
||||
<el-option label="多目设备的分割通道" :value="7"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item label="警区" >
|
||||
<el-input v-model="form.gbBlock" placeholder="请输入警区"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备归属" >
|
||||
<el-input v-model="form.gbOwner" placeholder="请输入设备归属"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="信令安全模式" >
|
||||
<el-select v-model="form.gbSafetyWay" style="width: 100%" placeholder="请选择信令安全模式">
|
||||
<el-option label="不采用" :value="0"></el-option>
|
||||
<el-option label="S/MIME签名" :value="2"></el-option>
|
||||
<el-option label="S/MIME加密签名同时采用" :value="3"></el-option>
|
||||
<el-option label="数字摘要" :value="4"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="注册方式" >
|
||||
<el-select v-model="form.gbRegisterWay" style="width: 100%" placeholder="请选择注册方式">
|
||||
<el-option label="IETFRFC3261标准" :value="1"></el-option>
|
||||
<el-option label="基于口令的双向认证" :value="2"></el-option>
|
||||
<el-option label="基于数字证书的双向认证注册" :value="3"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="证书序列号" >
|
||||
<el-input type="number" v-model="form.gbCertNum" placeholder="请输入证书序列号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="证书有效标识" >
|
||||
<el-select v-model="form.gbCertifiable" style="width: 100%" placeholder="请选择证书有效标识">
|
||||
<el-option label="有效" :value="1"></el-option>
|
||||
<el-option label="无效" :value="0"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="无效原因码" >
|
||||
<el-input type="errCode" v-model="form.gbCertNum" placeholder="请输入无效原因码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="证书终止有效期" >
|
||||
<el-date-picker
|
||||
v-model="form.gbEndTime"
|
||||
type="datetime"
|
||||
placeholder="选择日期时间"
|
||||
style="width: 100%">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="保密属性" >
|
||||
<el-select v-model="form.gbSecrecy" style="width: 100%" placeholder="请选择保密属性">
|
||||
<el-option label="不涉密" :value="0"></el-option>
|
||||
<el-option label="涉密" :value="1"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="IP地址" >
|
||||
<el-input v-model="form.gbIpAddress" placeholder="请输入IP地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="端口" >
|
||||
<el-input type="number" v-model="form.gbPort" placeholder="请输入端口"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备口令" >
|
||||
<el-input v-model="form.gbPassword" placeholder="请输入设备口令"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item label="业务分组编号" >
|
||||
<el-input v-model="form.gbBusinessGroupId" placeholder="请输入业务分组编号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="位置类型" >
|
||||
<el-select v-model="form.gbPositionType" style="width: 100%" placeholder="请选择位置类型">
|
||||
<el-option label="省际检查站" :value="1"></el-option>
|
||||
<el-option label="党政机关" :value="2"></el-option>
|
||||
<el-option label="车站码头" :value="3"></el-option>
|
||||
<el-option label="中心广场" :value="4"></el-option>
|
||||
<el-option label="体育场馆" :value="5"></el-option>
|
||||
<el-option label="商业中心" :value="6"></el-option>
|
||||
<el-option label="宗教场所" :value="7"></el-option>
|
||||
<el-option label="校园周边" :value="8"></el-option>
|
||||
<el-option label="治安复杂区域" :value="9"></el-option>
|
||||
<el-option label="交通干线" :value="10"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="室外/室内" >
|
||||
<el-select v-model="form.gbRoomType" style="width: 100%" placeholder="请选择位置类型">
|
||||
<el-option label="室外" :value="1"></el-option>
|
||||
<el-option label="室内" :value="2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="用途" >
|
||||
<el-select v-model="form.gbUseType" style="width: 100%" placeholder="请选择位置类型">
|
||||
<el-option label="治安" :value="1"></el-option>
|
||||
<el-option label="交通" :value="2"></el-option>
|
||||
<el-option label="重点" :value="3"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="补光" >
|
||||
<el-select v-model="form.gbSupplyLightType" style="width: 100%" placeholder="请选择位置类型">
|
||||
<el-option label="无补光" :value="1"></el-option>
|
||||
<el-option label="红外补光" :value="2"></el-option>
|
||||
<el-option label="白光补光" :value="3"></el-option>
|
||||
<el-option label="激光补光" :value="4"></el-option>
|
||||
<el-option label="其他" :value="9"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="监视方位" >
|
||||
<el-select v-model="form.gbDirectionType" style="width: 100%" placeholder="请选择位置类型">
|
||||
<el-option label="东(西向东)" :value="1"></el-option>
|
||||
<el-option label="西(东向西)" :value="2"></el-option>
|
||||
<el-option label="南(北向南)" :value="3"></el-option>
|
||||
<el-option label="北(南向北)" :value="4"></el-option>
|
||||
<el-option label="东南(西北到东南)" :value="5"></el-option>
|
||||
<el-option label="东北(西南到东北)" :value="6"></el-option>
|
||||
<el-option label="西南(东北到西南)" :value="7"></el-option>
|
||||
<el-option label="西北(东南到西北)" :value="8"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="分辨率" >
|
||||
<el-input v-model="form.gbResolution" placeholder="请输入分辨率"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="下载倍速" >
|
||||
<el-select v-model="form.gbDownloadSpeedArray" multiple style="width: 100%" placeholder="请选择位置类型">
|
||||
<el-option label="1倍速" value="1"></el-option>
|
||||
<el-option label="2倍速" value="2"></el-option>
|
||||
<el-option label="4倍速" value="4"></el-option>
|
||||
<el-option label="8倍速" value="8"></el-option>
|
||||
<el-option label="16倍速" value="16"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="空域编码能力" >
|
||||
<el-select v-model="form.gbSvcSpaceSupportMod" style="width: 100%" placeholder="请选择空域编码能力">
|
||||
<el-option label="1级增强" value="1"></el-option>
|
||||
<el-option label="2级增强" value="2"></el-option>
|
||||
<el-option label="3级增强" value="3"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="时域编码能力" >
|
||||
<el-select v-model="form.gbSvcTimeSupportMode" style="width: 100%" placeholder="请选择空域编码能力">
|
||||
<el-option label="1级增强" value="1"></el-option>
|
||||
<el-option label="2级增强" value="2"></el-option>
|
||||
<el-option label="3级增强" value="3"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button v-if="cancel" @click="cancelSubmit">取消</el-button>
|
||||
<el-button v-if="form.dataType === 1" @click="reset">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-form>
|
||||
<channelCode ref="channelCode"></channelCode>
|
||||
<chooseCivilCode ref="chooseCivilCode"></chooseCivilCode>
|
||||
<chooseGroup ref="chooseGroup"></chooseGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import channelCode from './../dialog/channelCode'
|
||||
import ChooseCivilCode from "../dialog/chooseCivilCode.vue";
|
||||
import ChooseGroup from "../dialog/chooseGroup.vue";
|
||||
|
||||
export default {
|
||||
name: "CommonChannelEdit",
|
||||
props: [ 'id', 'dataForm', 'saveSuccess', 'cancel'],
|
||||
components: {
|
||||
ChooseCivilCode,
|
||||
ChooseGroup,
|
||||
channelCode,
|
||||
},
|
||||
created() {
|
||||
// 获取完整信息
|
||||
if (this.id) {
|
||||
this.getCommonChannel()
|
||||
}else {
|
||||
if(!this.dataForm.gbDeviceId) {
|
||||
this.dataForm.gbDeviceId = ""
|
||||
}
|
||||
console.log(this.dataForm)
|
||||
this.form = this.dataForm
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
locading: false,
|
||||
form: {},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onSubmit: function () {
|
||||
this.locading = true
|
||||
if (this.form.gbDownloadSpeedArray) {
|
||||
this.form.gbDownloadSpeed = this.form.gbDownloadSpeedArray.join("/")
|
||||
}
|
||||
if (this.form.gbId) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/common/channel/update",
|
||||
data: this.form
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
});
|
||||
if (this.saveSuccess) {
|
||||
this.saveSuccess()
|
||||
}
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
}).finally(()=>{
|
||||
this.locading = false
|
||||
})
|
||||
}else {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/common/channel/add",
|
||||
data: this.form
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
});
|
||||
this.form = res.data.data
|
||||
if (this.saveSuccess) {
|
||||
this.saveSuccess()
|
||||
}
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
}).finally(()=>{
|
||||
this.locading = false
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
reset: function () {
|
||||
this.$confirm("确定重置为默认内容?", '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.locading = true
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/common/channel/reset",
|
||||
params: {
|
||||
id: this.form.gbId
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "重置成功 已保存"
|
||||
});
|
||||
this.getCommonChannel()
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
}).finally(()=>{
|
||||
this.locading = false
|
||||
})
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
getCommonChannel:function () {
|
||||
this.locading = true
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/common/channel/one",
|
||||
params: {
|
||||
id: this.id
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
if (res.data.data.gbDownloadSpeed) {
|
||||
res.data.data.gbDownloadSpeedArray = res.data.data.gbDownloadSpeed.split("/")
|
||||
}
|
||||
this.form = res.data.data;
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
}).finally(()=>{
|
||||
this.locading = false
|
||||
})
|
||||
},
|
||||
buildDeviceIdCode: function (deviceId){
|
||||
|
||||
this.$refs.channelCode.openDialog(code=>{
|
||||
console.log(this.form)
|
||||
console.log("code===> " + code)
|
||||
this.form.gbDeviceId = code;
|
||||
console.log("code22===> " + code)
|
||||
}, deviceId);
|
||||
},
|
||||
chooseCivilCode: function (){
|
||||
this.$refs.chooseCivilCode.openDialog(code=>{
|
||||
this.form.gbCivilCode = code;
|
||||
});
|
||||
},
|
||||
chooseGroup: function (){
|
||||
this.$refs.chooseGroup.openDialog((deviceId, businessGroupId)=>{
|
||||
this.form.gbBusinessGroupId = businessGroupId;
|
||||
this.form.gbParentId = deviceId;
|
||||
});
|
||||
},
|
||||
cancelSubmit: function (){
|
||||
if(this.cancel) {
|
||||
this.cancel()
|
||||
}
|
||||
}
|
||||
// getDeviceChannel:function (callback) {
|
||||
// this.$axios({
|
||||
// method: 'get',
|
||||
// url: "/api/device/query/channel/raw",
|
||||
// params: {
|
||||
// id: this.id
|
||||
// }
|
||||
// }).then((res) => {
|
||||
// if (res.data.code === 0) {
|
||||
// if(callback) {
|
||||
// callback(res.data.data)
|
||||
// }
|
||||
// }
|
||||
// }).catch((error) => {
|
||||
// console.error(error)
|
||||
// }).finally(()=>[
|
||||
// this.locading = false
|
||||
// ])
|
||||
// }
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<div id="DeviceTree" style="width: 100%;height: 100%; background-color: #FFFFFF; overflow: auto">
|
||||
<el-container>
|
||||
<el-header>
|
||||
<div style="display: grid; grid-template-columns: auto auto">
|
||||
<div >通道列表</div>
|
||||
<div >
|
||||
<el-switch
|
||||
v-model="showRegion"
|
||||
active-color="#13ce66"
|
||||
inactive-color="rgb(64, 158, 255)"
|
||||
active-text="行政区划"
|
||||
inactive-text="业务分组">
|
||||
</el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-header>
|
||||
<el-main style="background-color: #ffffff;">
|
||||
<RegionTree v-if="showRegion" ref="regionTree" :edit="false" :showHeader="false" :hasChannel="true" :clickEvent="treeNodeClickEvent" ></RegionTree>
|
||||
<GroupTree v-if="!showRegion" ref="groupTree" :edit="false" :showHeader="false" :hasChannel="true" :clickEvent="treeNodeClickEvent" ></GroupTree>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DeviceService from "../service/DeviceService.js";
|
||||
import RegionTree from "./RegionTree.vue";
|
||||
import GroupTree from "./GroupTree.vue";
|
||||
|
||||
export default {
|
||||
name: 'DeviceTree',
|
||||
components: {GroupTree, RegionTree},
|
||||
data() {
|
||||
return {
|
||||
showRegion: true,
|
||||
deviceService: new DeviceService(),
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
isLeaf: 'isLeaf'
|
||||
}
|
||||
};
|
||||
},
|
||||
props: ['device', 'onlyCatalog', 'clickEvent', 'contextMenuEvent'],
|
||||
methods: {
|
||||
handleClick: function (tab, event){
|
||||
},
|
||||
treeNodeClickEvent: function (data){
|
||||
|
||||
if (data.leaf) {
|
||||
console.log(23111)
|
||||
console.log(data)
|
||||
if (this.clickEvent){
|
||||
this.clickEvent(data.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
// if (this.jessibuca) {
|
||||
// this.jessibuca.destroy();
|
||||
// }
|
||||
// this.playing = false;
|
||||
// this.loaded = false;
|
||||
// this.performance = "";
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.device-tree-main-box{
|
||||
text-align: left;
|
||||
}
|
||||
.device-online{
|
||||
color: #252525;
|
||||
}
|
||||
.device-offline{
|
||||
color: #727272;
|
||||
}
|
||||
</style>
|
||||
@ -1,393 +0,0 @@
|
||||
<template>
|
||||
<div id="DeviceTree">
|
||||
<div v-if="showHeader" class="page-header" style="margin-bottom: 1rem;">
|
||||
<div class="page-title">业务分组</div>
|
||||
<div class="page-header-btn">
|
||||
<div style="display: inline;">
|
||||
<el-input @input="search" style="visibility:hidden; margin-right: 1rem; width: 12rem;" size="mini"
|
||||
placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
|
||||
<el-checkbox v-model="showCode">显示编号</el-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showHeader" style="height: 2rem; background-color: #FFFFFF"></div>
|
||||
<div>
|
||||
<el-alert v-if="showAlert && edit" title="操作提示" description="你可以使用右键菜单管理节点" type="info" style="text-align: left"></el-alert>
|
||||
<vue-easy-tree
|
||||
class="flow-tree"
|
||||
ref="veTree"
|
||||
node-key="treeId"
|
||||
:height="treeHeight?treeHeight:'78vh'"
|
||||
lazy
|
||||
style="padding: 0 0 2rem 0.5rem"
|
||||
:load="loadNode"
|
||||
:data="treeData"
|
||||
:props="props"
|
||||
:default-expanded-keys="['']"
|
||||
@node-contextmenu="contextmenuEventHandler"
|
||||
@node-click="nodeClickHandler"
|
||||
>
|
||||
<template v-slot:default="{ node, data }">
|
||||
<span class="custom-tree-node">
|
||||
<span v-if="node.data.type === 0 && chooseId !== node.data.deviceId" style="color: #409EFF" class="iconfont icon-bianzubeifen3"></span>
|
||||
<span v-if="node.data.type === 0 && chooseId === node.data.deviceId" style="color: #c60135;" class="iconfont icon-bianzubeifen3"></span>
|
||||
<span v-if="node.data.type === 1 && node.data.status === 'ON'" style="color: #409EFF" class="iconfont icon-shexiangtou2"></span>
|
||||
<span v-if="node.data.type === 1 && node.data.status !== 'ON'" style="color: #808181" class="iconfont icon-shexiangtou2"></span>
|
||||
<span style=" padding-left: 1px" v-if="node.data.deviceId !=='' && showCode" :title="node.data.deviceId">{{ node.label }}(编号:{{ node.data.deviceId }})</span>
|
||||
<span style=" padding-left: 1px" v-if="node.data.deviceId ==='' || !showCode" :title="node.data.deviceId">{{ node.label }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</vue-easy-tree>
|
||||
</div>
|
||||
<groupEdit ref="groupEdit"></groupEdit>
|
||||
<gbDeviceSelect ref="gbDeviceSelect"></gbDeviceSelect>
|
||||
<gbChannelSelect ref="gbChannelSelect" dataType="group"></gbChannelSelect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueEasyTree from "@wchbrad/vue-easy-tree";
|
||||
import groupEdit from './../dialog/groupEdit'
|
||||
import gbDeviceSelect from './../dialog/GbDeviceSelect'
|
||||
import GbChannelSelect from "../dialog/GbChannelSelect.vue";
|
||||
|
||||
export default {
|
||||
name: 'DeviceTree',
|
||||
components: {
|
||||
GbChannelSelect,
|
||||
VueEasyTree, groupEdit, gbDeviceSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
props: {
|
||||
label: "name",
|
||||
id: "treeId"
|
||||
},
|
||||
showCode: false,
|
||||
showAlert: true,
|
||||
searchSrt: "",
|
||||
chooseId: "",
|
||||
treeData: [],
|
||||
}
|
||||
},
|
||||
props: ['edit','enableAddChannel', 'clickEvent', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToGroup', 'treeHeight'],
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
|
||||
},
|
||||
loadNode: function (node, resolve) {
|
||||
if (node.level === 0) {
|
||||
resolve([{
|
||||
treeId: "",
|
||||
deviceId: "",
|
||||
name: "根资源组",
|
||||
isLeaf: false,
|
||||
type: 0
|
||||
}]);
|
||||
} else {
|
||||
if (node.data.leaf) {
|
||||
resolve([]);
|
||||
return
|
||||
}
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/group/tree/list`,
|
||||
params: {
|
||||
query: this.searchSrt,
|
||||
parent: node.data.id,
|
||||
hasChannel: this.hasChannel
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
if (res.data.data.length > 0) {
|
||||
this.showAlert = false
|
||||
}
|
||||
resolve(res.data.data);
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
reset: function () {
|
||||
this.$forceUpdate();
|
||||
},
|
||||
contextmenuEventHandler: function (event, data, node, element) {
|
||||
if (!this.edit) {
|
||||
return;
|
||||
}
|
||||
if (node.data.type === 0) {
|
||||
let menuItem = [
|
||||
{
|
||||
label: "刷新节点",
|
||||
icon: "el-icon-refresh",
|
||||
disabled: false,
|
||||
onClick: () => {
|
||||
this.refreshNode(node);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "新建节点",
|
||||
icon: "el-icon-plus",
|
||||
disabled: false,
|
||||
onClick: () => {
|
||||
this.addGroup(data.id, node);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "编辑节点",
|
||||
icon: "el-icon-edit",
|
||||
disabled: node.level === 1,
|
||||
onClick: () => {
|
||||
this.editGroup(data, node);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "删除节点",
|
||||
icon: "el-icon-delete",
|
||||
disabled: node.level === 1,
|
||||
divided: true,
|
||||
onClick: () => {
|
||||
this.$confirm('确定删除?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.removeGroup(data.id, node)
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
if (this.enableAddChannel) {
|
||||
menuItem.push(
|
||||
{
|
||||
label: "添加设备",
|
||||
icon: "el-icon-plus",
|
||||
disabled: node.level <= 2,
|
||||
onClick: () => {
|
||||
this.addChannelFormDevice(data.id, node)
|
||||
}
|
||||
},
|
||||
)
|
||||
menuItem.push(
|
||||
{
|
||||
label: "移除设备",
|
||||
icon: "el-icon-delete",
|
||||
disabled: node.level <= 2,
|
||||
divided: true,
|
||||
onClick: () => {
|
||||
this.removeChannelFormDevice(data.id, node)
|
||||
}
|
||||
},
|
||||
)
|
||||
menuItem.push(
|
||||
{
|
||||
label: "添加通道",
|
||||
icon: "el-icon-plus",
|
||||
disabled: node.level <= 2,
|
||||
onClick: () => {
|
||||
this.addChannel(data.id, node)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
this.$contextmenu({
|
||||
items: menuItem,
|
||||
event, // 鼠标事件信息
|
||||
customClass: "custom-class", // 自定义菜单 class
|
||||
zIndex: 3000, // 菜单样式 z-index
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
removeGroup: function (id, node) {
|
||||
this.$axios({
|
||||
method: "delete",
|
||||
url: `/api/group/delete`,
|
||||
params: {
|
||||
id: node.data.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
console.log("移除成功")
|
||||
node.parent.loaded = false
|
||||
node.parent.expand();
|
||||
if (this.onChannelChange) {
|
||||
this.onChannelChange(node.data.deviceId)
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
addChannelFormDevice: function (id, node) {
|
||||
this.$refs.gbDeviceSelect.openDialog((rows) => {
|
||||
let deviceIds = []
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
deviceIds.push(rows[i].id)
|
||||
}
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/add`,
|
||||
data: {
|
||||
parentId: node.data.deviceId,
|
||||
businessGroup: node.data.businessGroup,
|
||||
deviceIds: deviceIds,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
})
|
||||
if (this.onChannelChange) {
|
||||
this.onChannelChange()
|
||||
}
|
||||
console.log(node)
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
this.loading = false
|
||||
});
|
||||
})
|
||||
},
|
||||
removeChannelFormDevice: function (id, node) {
|
||||
this.$refs.gbDeviceSelect.openDialog((rows) => {
|
||||
let deviceIds = []
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
deviceIds.push(rows[i].id)
|
||||
}
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/group/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
})
|
||||
if (this.onChannelChange) {
|
||||
this.onChannelChange()
|
||||
}
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
this.loading = false
|
||||
});
|
||||
})
|
||||
},
|
||||
addChannel: function (id, node) {
|
||||
this.$refs.gbChannelSelect.openDialog((data) => {
|
||||
console.log("选择的数据")
|
||||
console.log(data)
|
||||
this.addChannelToGroup(node.data.deviceId, node.data.businessGroup, data)
|
||||
})
|
||||
},
|
||||
refreshNode: function (node) {
|
||||
console.log(node)
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
},
|
||||
refresh: function (id) {
|
||||
console.log("刷新节点: " + id)
|
||||
// 查询node
|
||||
let node = this.$refs.veTree.getNode(id)
|
||||
if (node) {
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
}
|
||||
},
|
||||
addGroup: function (id, node) {
|
||||
this.$refs.groupEdit.openDialog({
|
||||
id: 0,
|
||||
name: "",
|
||||
deviceId: "",
|
||||
civilCode: "",
|
||||
parentDeviceId: node.level > 2 ? node.data.deviceId : "",
|
||||
parentId: node.data.id,
|
||||
businessGroup: node.level > 2 ? node.data.businessGroup : node.data.deviceId,
|
||||
}, form => {
|
||||
console.log(node)
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
}, id);
|
||||
},
|
||||
editGroup: function (id, node) {
|
||||
console.log(node)
|
||||
this.$refs.groupEdit.openDialog(node.data, form => {
|
||||
console.log(node)
|
||||
node.parent.loaded = false
|
||||
node.parent.expand();
|
||||
}, id);
|
||||
},
|
||||
nodeClickHandler: function (data, node, tree) {
|
||||
this.chooseId = data.deviceId;
|
||||
if (this.clickEvent) {
|
||||
this.clickEvent(data)
|
||||
}
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
// if (this.jessibuca) {
|
||||
// this.jessibuca.destroy();
|
||||
// }
|
||||
// this.playing = false;
|
||||
// this.loaded = false;
|
||||
// this.performance = "";
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.device-tree-main-box {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.device-online {
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
.device-offline {
|
||||
color: #727272;
|
||||
}
|
||||
|
||||
.custom-tree-node .el-radio__label {
|
||||
padding-left: 4px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,263 +0,0 @@
|
||||
<template>
|
||||
<div id="mapContainer" ref="mapContainer" style="width: 100%;height: 100%;"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'ol/ol.css';
|
||||
import Map from 'ol/Map';
|
||||
import OSM from 'ol/source/OSM';
|
||||
import XYZ from 'ol/source/XYZ';
|
||||
import VectorSource from 'ol/source/Vector';
|
||||
import Tile from 'ol/layer/Tile';
|
||||
import VectorLayer from 'ol/layer/Vector';
|
||||
import Style from 'ol/style/Style';
|
||||
import Stroke from 'ol/style/Stroke';
|
||||
import Icon from 'ol/style/Icon';
|
||||
import View from 'ol/View';
|
||||
import Feature from 'ol/Feature';
|
||||
import Overlay from 'ol/Overlay';
|
||||
import {Point, LineString} from 'ol/geom';
|
||||
import {get as getProj, fromLonLat} from 'ol/proj';
|
||||
import {ZoomSlider, Zoom} from 'ol/control';
|
||||
import {containsCoordinate} from 'ol/extent';
|
||||
|
||||
import {v4} from 'uuid'
|
||||
|
||||
let olMap = null;
|
||||
|
||||
export default {
|
||||
name: 'MapComponent',
|
||||
data() {
|
||||
return {
|
||||
|
||||
|
||||
};
|
||||
},
|
||||
created(){
|
||||
this.$nextTick(() => {
|
||||
setTimeout(()=>{
|
||||
this.init()
|
||||
}, 100)
|
||||
})
|
||||
|
||||
},
|
||||
props: [],
|
||||
mounted () {
|
||||
|
||||
},
|
||||
methods: {
|
||||
init(){
|
||||
|
||||
let center = fromLonLat([116.41020, 39.915119]);
|
||||
if (mapParam.center) {
|
||||
center = fromLonLat(mapParam.center);
|
||||
}
|
||||
const view = new View({
|
||||
center: center,
|
||||
zoom: mapParam.zoom || 10,
|
||||
projection: this.projection,
|
||||
maxZoom: mapParam.maxZoom || 19,
|
||||
minZoom: mapParam.minZoom || 1,
|
||||
});
|
||||
let tileLayer = null;
|
||||
if (mapParam.tilesUrl) {
|
||||
tileLayer = new Tile({
|
||||
source: new XYZ({
|
||||
projection: getProj("EPSG:3857"),
|
||||
wrapX: false,
|
||||
tileSize: 256 || mapParam.tileSize,
|
||||
url: mapParam.tilesUrl
|
||||
})
|
||||
})
|
||||
}else {
|
||||
tileLayer = new Tile({
|
||||
preload: 4,
|
||||
source: new OSM(),
|
||||
})
|
||||
}
|
||||
olMap = new Map({
|
||||
target: this.$refs.mapContainer, // 容器ID
|
||||
layers: [tileLayer], // 默认图层
|
||||
view: view, // 视图
|
||||
controls:[ // 控件
|
||||
// new ZoomSlider(),
|
||||
new Zoom(),
|
||||
] ,
|
||||
})
|
||||
console.log(3222)
|
||||
},
|
||||
setCenter(point){
|
||||
|
||||
},
|
||||
zoomIn(zoom){
|
||||
|
||||
},
|
||||
zoomOut(zoom){
|
||||
|
||||
},
|
||||
centerAndZoom(point,zoom,callback){
|
||||
var zoom_ = olMap.getView().getZoom();
|
||||
zoom = zoom|| zoom_;
|
||||
var duration = 600;
|
||||
olMap.getView().setCenter(fromLonLat(point))
|
||||
olMap.getView().animate({
|
||||
zoom: zoom ,
|
||||
duration: duration
|
||||
});
|
||||
},
|
||||
panTo(point, zoom){
|
||||
let duration = 800;
|
||||
|
||||
olMap.getView().cancelAnimations()
|
||||
olMap.getView().animate({
|
||||
center: fromLonLat(point),
|
||||
duration: duration
|
||||
});
|
||||
if (!containsCoordinate(olMap.getView().calculateExtent(), fromLonLat(point))) {
|
||||
olMap.getView().animate({
|
||||
zoom: olMap.getView().getZoom() - 1,
|
||||
duration: duration / 2
|
||||
}, {
|
||||
zoom: zoom || olMap.getView().getZoom(),
|
||||
duration: duration / 2
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
fit(layer){
|
||||
let extent = layer.getSource().getExtent();
|
||||
if (extent) {
|
||||
olMap.getView().fit(extent,{
|
||||
duration : 600,
|
||||
padding: [100, 100, 100, 100]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
openInfoBox(position, content, offset){
|
||||
let id = v4()
|
||||
// let infoBox = document.createElement("div");
|
||||
// infoBox.innerHTML = content ;
|
||||
// infoBox.setAttribute("infoBoxId", id)
|
||||
let overlay = new Overlay({
|
||||
id:id,
|
||||
autoPan:true,
|
||||
autoPanAnimation:{
|
||||
duration: 250
|
||||
},
|
||||
element: content,
|
||||
positioning:"bottom-center",
|
||||
offset:offset,
|
||||
// className:overlayStyle.className
|
||||
});
|
||||
olMap.addOverlay(overlay);
|
||||
overlay.setPosition(fromLonLat(position));
|
||||
return id;
|
||||
},
|
||||
closeInfoBox(id){
|
||||
olMap.getOverlayById(id).setPosition(undefined)
|
||||
// olMap.removeOverlay(olMap.getOverlayById(id))
|
||||
},
|
||||
/**
|
||||
* 添加图层
|
||||
* @param data
|
||||
* [
|
||||
* {
|
||||
*
|
||||
* position: [119.1212,45,122],
|
||||
* image: {
|
||||
* src:"/images/123.png",
|
||||
* anchor: [0.5, 0.5]
|
||||
*
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* ]
|
||||
*/
|
||||
addLayer(data, clickEvent){
|
||||
let style = new Style();
|
||||
if (data.length > 0) {
|
||||
let features = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let feature = new Feature(new Point(fromLonLat(data[i].position)));
|
||||
feature.customData = data[i].data;
|
||||
let cloneStyle = style.clone()
|
||||
cloneStyle.setImage(new Icon({
|
||||
anchor: data[i].image.anchor,
|
||||
crossOrigin: 'Anonymous',
|
||||
src: data[i].image.src,
|
||||
}))
|
||||
feature.setStyle(cloneStyle)
|
||||
features.push(feature);
|
||||
}
|
||||
let source = new VectorSource();
|
||||
source.addFeatures(features);
|
||||
let vectorLayer = new VectorLayer({
|
||||
source:source,
|
||||
style:style,
|
||||
renderMode:"image",
|
||||
declutter: false
|
||||
})
|
||||
olMap.addLayer(vectorLayer)
|
||||
if (typeof clickEvent == "function") {
|
||||
olMap.on("click", (event)=>{
|
||||
vectorLayer.getFeatures(event.pixel).then((features)=>{
|
||||
if (features.length > 0) {
|
||||
let items = []
|
||||
for (let i = 0; i < features.length; i++) {
|
||||
items.push(features[i].customData)
|
||||
}
|
||||
clickEvent(items)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
return vectorLayer;
|
||||
}
|
||||
},
|
||||
removeLayer(layer){
|
||||
olMap.removeLayer(layer)
|
||||
},
|
||||
|
||||
addLineLayer(positions) {
|
||||
if (positions.length > 0) {
|
||||
let points = [];
|
||||
for (let i = 0; i < positions.length; i++) {
|
||||
points.push(fromLonLat(positions[i]));
|
||||
}
|
||||
let line = new LineString(points)
|
||||
let lineFeature = new Feature(line);
|
||||
lineFeature.setStyle(new Style({
|
||||
stroke: new Stroke({
|
||||
width: 4 ,
|
||||
color: "#0c6d6a",
|
||||
})
|
||||
}))
|
||||
let source = new VectorSource();
|
||||
source.addFeature(lineFeature);
|
||||
let vectorLayer = new VectorLayer({
|
||||
source: source,
|
||||
})
|
||||
olMap.addLayer(vectorLayer)
|
||||
return vectorLayer;
|
||||
}
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
// if (this.jessibuca) {
|
||||
// this.jessibuca.destroy();
|
||||
// }
|
||||
// this.playing = false;
|
||||
// this.loaded = false;
|
||||
// this.performance = "";
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@ -1,386 +0,0 @@
|
||||
<template>
|
||||
<div id="DeviceTree">
|
||||
<div class="page-header" style="margin-bottom: 1rem;" v-if="showHeader">
|
||||
<div class="page-title">行政区划</div>
|
||||
<div class="page-header-btn">
|
||||
<div style="display: inline;">
|
||||
<el-input @input="search" style="visibility:hidden; margin-right: 1rem; width: 12rem;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
|
||||
<el-checkbox v-model="showCode">显示编号</el-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showHeader" style="height: 2rem; background-color: #FFFFFF" ></div>
|
||||
<div>
|
||||
<el-alert v-if="showAlert && edit" title="操作提示" description="你可以使用右键菜单管理节点" type="info" style="text-align: left"></el-alert>
|
||||
<vue-easy-tree
|
||||
class="flow-tree"
|
||||
ref="veTree"
|
||||
node-key="treeId"
|
||||
:height="treeHeight?treeHeight:'78vh'"
|
||||
lazy
|
||||
style="padding: 0 0 2rem 0.5rem"
|
||||
:load="loadNode"
|
||||
:data="treeData"
|
||||
:props="props"
|
||||
:default-expanded-keys="['']"
|
||||
@node-contextmenu="contextmenuEventHandler"
|
||||
@node-click="nodeClickHandler"
|
||||
>
|
||||
<template class="custom-tree-node" v-slot:default="{ node, data }">
|
||||
<span class="custom-tree-node" >
|
||||
<span v-if="node.data.type === 0 && chooseId !== node.data.deviceId" style="color: #409EFF" class="iconfont icon-bianzubeifen3"></span>
|
||||
<span v-if="node.data.type === 0 && chooseId === node.data.deviceId" style="color: #c60135;" class="iconfont icon-bianzubeifen3"></span>
|
||||
<span v-if="node.data.type === 1 && node.data.status === 'ON'" style="color: #409EFF" class="iconfont icon-shexiangtou2"></span>
|
||||
<span v-if="node.data.type === 1 && node.data.status !== 'ON'" style="color: #808181" class="iconfont icon-shexiangtou2"></span>
|
||||
<span style=" padding-left: 1px" v-if="node.data.deviceId !=='' && showCode" :title="node.data.deviceId">{{ node.label }}(编号:{{ node.data.deviceId }})</span>
|
||||
<span style=" padding-left: 1px" v-if="node.data.deviceId ==='' || !showCode" :title="node.data.deviceId">{{ node.label }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</vue-easy-tree>
|
||||
</div>
|
||||
<regionEdit ref="regionEdit"></regionEdit>
|
||||
<gbDeviceSelect ref="gbDeviceSelect"></gbDeviceSelect>
|
||||
<GbChannelSelect ref="gbChannelSelect" dataType="civilCode" ></GbChannelSelect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueEasyTree from "@wchbrad/vue-easy-tree";
|
||||
import regionEdit from './../dialog/regionEdit'
|
||||
import gbDeviceSelect from './../dialog/GbDeviceSelect'
|
||||
import GbChannelSelect from "../dialog/GbChannelSelect.vue";
|
||||
|
||||
export default {
|
||||
name: 'DeviceTree',
|
||||
components: {
|
||||
GbChannelSelect,
|
||||
VueEasyTree, regionEdit, gbDeviceSelect
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
props: {
|
||||
label: "name",
|
||||
},
|
||||
showCode: false,
|
||||
showAlert: true,
|
||||
searchSrt: "",
|
||||
chooseId: "",
|
||||
treeData: [],
|
||||
}
|
||||
},
|
||||
props: ['edit', 'enableAddChannel', 'clickEvent', 'onChannelChange', 'showHeader', 'hasChannel', 'addChannelToCivilCode', 'treeHeight'],
|
||||
created() {
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
|
||||
},
|
||||
loadNode: function (node, resolve) {
|
||||
if (node.level === 0) {
|
||||
resolve([{
|
||||
treeId: "",
|
||||
deviceId: "",
|
||||
name: "根资源组",
|
||||
isLeaf: false,
|
||||
type: 0
|
||||
}]);
|
||||
} else if (node.data.deviceId.length <= 8) {
|
||||
if (node.data.leaf) {
|
||||
resolve([]);
|
||||
return
|
||||
}
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/region/tree/list`,
|
||||
params: {
|
||||
query: this.searchSrt,
|
||||
parent: node.data.id,
|
||||
hasChannel: this.hasChannel
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
if (res.data.data.length > 0) {
|
||||
this.showAlert = false
|
||||
}
|
||||
resolve(res.data.data);
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
},
|
||||
reset: function () {
|
||||
this.$forceUpdate();
|
||||
},
|
||||
contextmenuEventHandler: function (event, data, node, element) {
|
||||
if (!this.edit) {
|
||||
return
|
||||
}
|
||||
console.log(node.level)
|
||||
if (node.data.type === 0) {
|
||||
let menuItem = [
|
||||
{
|
||||
label: "刷新节点",
|
||||
icon: "el-icon-refresh",
|
||||
disabled: false,
|
||||
onClick: () => {
|
||||
this.refreshNode(node);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "新建节点",
|
||||
icon: "el-icon-plus",
|
||||
disabled: false,
|
||||
onClick: () => {
|
||||
this.addRegion(data.id, node);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "编辑节点",
|
||||
icon: "el-icon-edit",
|
||||
disabled: node.level === 1,
|
||||
onClick: () => {
|
||||
this.editCatalog(data, node);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "删除节点",
|
||||
icon: "el-icon-delete",
|
||||
disabled: node.level === 1,
|
||||
divided: true,
|
||||
onClick: () => {
|
||||
this.$confirm('确定删除?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.removeRegion(data.id, node)
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
]
|
||||
if (this.enableAddChannel) {
|
||||
menuItem.push(
|
||||
{
|
||||
label: "添加设备",
|
||||
icon: "el-icon-plus",
|
||||
disabled: node.level === 1,
|
||||
onClick: () => {
|
||||
this.addChannelFormDevice(data.id, node)
|
||||
}
|
||||
}
|
||||
)
|
||||
menuItem.push(
|
||||
{
|
||||
label: "移除设备",
|
||||
icon: "el-icon-delete",
|
||||
disabled: node.level === 1,
|
||||
divided: true,
|
||||
onClick: () => {
|
||||
this.removeChannelFormDevice(data.id, node)
|
||||
}
|
||||
}
|
||||
)
|
||||
menuItem.push(
|
||||
{
|
||||
label: "添加通道",
|
||||
icon: "el-icon-plus",
|
||||
disabled: node.level === 1,
|
||||
onClick: () => {
|
||||
this.addChannel(data.id, node)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
this.$contextmenu({
|
||||
items: menuItem,
|
||||
event, // 鼠标事件信息
|
||||
customClass: "custom-class", // 自定义菜单 class
|
||||
zIndex: 3000, // 菜单样式 z-index
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
removeRegion: function (id, node) {
|
||||
this.$axios({
|
||||
method: "delete",
|
||||
url: `/api/region/delete`,
|
||||
params: {
|
||||
id: node.data.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
console.log("移除成功")
|
||||
node.parent.loaded = false
|
||||
node.parent.expand();
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
addChannelFormDevice: function (id, node) {
|
||||
this.$refs.gbDeviceSelect.openDialog((rows)=>{
|
||||
let deviceIds = []
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
deviceIds.push(rows[i].id)
|
||||
}
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/add`,
|
||||
data: {
|
||||
civilCode: node.data.deviceId,
|
||||
deviceIds: deviceIds,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
})
|
||||
if (this.onChannelChange) {
|
||||
this.onChannelChange()
|
||||
}
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
}).catch((error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
this.loading = false
|
||||
});
|
||||
})
|
||||
},
|
||||
removeChannelFormDevice: function (id, node) {
|
||||
this.$refs.gbDeviceSelect.openDialog((rows)=>{
|
||||
let deviceIds = []
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
deviceIds.push(rows[i].id)
|
||||
}
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/region/device/delete`,
|
||||
data: {
|
||||
deviceIds: deviceIds,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
})
|
||||
if (this.onChannelChange) {
|
||||
this.onChannelChange(node.data.deviceId)
|
||||
}
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
}).catch((error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
this.loading = false
|
||||
});
|
||||
})
|
||||
},
|
||||
addChannel: function (id, node) {
|
||||
this.$refs.gbChannelSelect.openDialog((data) => {
|
||||
console.log("选择的数据")
|
||||
console.log(data)
|
||||
this.addChannelToCivilCode(node.data.deviceId, data)
|
||||
})
|
||||
},
|
||||
refreshNode: function (node) {
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
},
|
||||
refresh: function (id) {
|
||||
// 查询node
|
||||
let node = this.$refs.veTree.getNode(id)
|
||||
if (node) {
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
}
|
||||
|
||||
},
|
||||
addRegion: function (id, node) {
|
||||
|
||||
console.log(node)
|
||||
|
||||
this.$refs.regionEdit.openDialog(form => {
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
}, {
|
||||
deviceId: "",
|
||||
name: "",
|
||||
parentId: node.data.id,
|
||||
parentDeviceId: node.data.deviceId,
|
||||
});
|
||||
},
|
||||
editCatalog: function (data, node){
|
||||
// 打开添加弹窗
|
||||
this.$refs.regionEdit.openDialog(form => {
|
||||
node.loaded = false
|
||||
node.expand();
|
||||
}, node.data);
|
||||
},
|
||||
nodeClickHandler: function (data, node, tree) {
|
||||
|
||||
this.chooseId = data.deviceId;
|
||||
if (this.clickEvent) {
|
||||
this.clickEvent(data)
|
||||
}
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
// if (this.jessibuca) {
|
||||
// this.jessibuca.destroy();
|
||||
// }
|
||||
// this.playing = false;
|
||||
// this.loaded = false;
|
||||
// this.performance = "";
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.device-tree-main-box {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.device-online {
|
||||
color: #252525;
|
||||
}
|
||||
|
||||
.device-offline {
|
||||
color: #727272;
|
||||
}
|
||||
.custom-tree-node .el-radio__label {
|
||||
padding-left: 4px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<div id="easyplayer" ></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'player',
|
||||
data() {
|
||||
return {
|
||||
easyPlayer: null
|
||||
};
|
||||
},
|
||||
props: ['videoUrl', 'error', 'hasaudio', 'height'],
|
||||
mounted () {
|
||||
let paramUrl = decodeURIComponent(this.$route.params.url)
|
||||
this.$nextTick(() =>{
|
||||
if (typeof (this.videoUrl) == "undefined") {
|
||||
this.videoUrl = paramUrl;
|
||||
}
|
||||
console.log("初始化时的地址为: " + this.videoUrl)
|
||||
this.play(this.videoUrl)
|
||||
})
|
||||
},
|
||||
watch:{
|
||||
videoUrl(newData, oldData){
|
||||
this.play(newData)
|
||||
},
|
||||
immediate:true
|
||||
},
|
||||
methods: {
|
||||
play: function (url) {
|
||||
console.log(this.height)
|
||||
if (this.easyPlayer != null) {
|
||||
this.easyPlayer.destroy();
|
||||
}
|
||||
if (typeof (this.height) == "undefined") {
|
||||
this.height = false
|
||||
}
|
||||
this.easyPlayer = new WasmPlayer(null, 'easyplayer', this.eventcallbacK, {Height: this.height})
|
||||
this.easyPlayer.play(url, 1)
|
||||
},
|
||||
pause: function () {
|
||||
this.easyPlayer.destroy();
|
||||
this.easyPlayer = null
|
||||
},
|
||||
eventcallbacK: function(type, message) {
|
||||
// console.log("player 事件回调")
|
||||
// console.log(type)
|
||||
// console.log(message)
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.easyPlayer.destroy();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.LodingTitle {
|
||||
min-width: 70px;
|
||||
}
|
||||
/* 隐藏logo */
|
||||
.iconqingxiLOGO {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,246 +0,0 @@
|
||||
<template>
|
||||
<div ref="container" @dblclick="fullscreenSwich" style="width:100%;height:100%;background-color: #000000;margin:0 auto;">
|
||||
<div id="glplayer" style="width: 100%; height: 100%; display: flex"></div>
|
||||
<div class="buttons-box" id="buttonsBox">
|
||||
<div class="buttons-box-left">
|
||||
<i v-if="!playing" class="iconfont icon-play h265web-btn" @click="unPause"></i>
|
||||
<i v-if="playing" class="iconfont icon-pause h265web-btn" @click="pause"></i>
|
||||
<i class="iconfont icon-stop h265web-btn" @click="destroy"></i>
|
||||
<i v-if="isNotMute" class="iconfont icon-audio-high h265web-btn" @click="mute()"></i>
|
||||
<i v-if="!isNotMute" class="iconfont icon-audio-mute h265web-btn" @click="cancelMute()"></i>
|
||||
</div>
|
||||
<div class="buttons-box-right">
|
||||
<!-- <i class="iconfont icon-file-record1 h265web-btn"></i>-->
|
||||
<!-- <i class="iconfont icon-xiangqing2 h265web-btn" ></i>-->
|
||||
<i class="iconfont icon-camera1196054easyiconnet h265web-btn" @click="screenshot"
|
||||
style="font-size: 1rem !important"></i>
|
||||
<i class="iconfont icon-shuaxin11 h265web-btn" @click="playBtnClick"></i>
|
||||
<i v-if="!fullscreen" class="iconfont icon-weibiaoti10 h265web-btn" @click="fullscreenSwich"></i>
|
||||
<i v-if="fullscreen" class="iconfont icon-weibiaoti11 h265web-btn" @click="fullscreenSwich"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let h265webPlayer = {};
|
||||
/**
|
||||
* 从github上复制的
|
||||
* @see https://github.com/numberwolf/h265web.js/blob/master/example_normal/index.js
|
||||
*/
|
||||
const token = "base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1";
|
||||
export default {
|
||||
name: 'h265web',
|
||||
data() {
|
||||
return {
|
||||
playing: false,
|
||||
isNotMute: false,
|
||||
quieting: false,
|
||||
fullscreen: false,
|
||||
loaded: false, // mute
|
||||
speed: 0,
|
||||
kBps: 0,
|
||||
btnDom: null,
|
||||
videoInfo: null,
|
||||
volume: 1,
|
||||
rotate: 0,
|
||||
vod: true, // 点播
|
||||
forceNoOffscreen: false,
|
||||
};
|
||||
},
|
||||
props: ['videoUrl', 'error', 'hasAudio', 'height'],
|
||||
mounted() {
|
||||
window.onerror = (msg) => {
|
||||
// console.error(msg)
|
||||
};
|
||||
console.log(this._uid)
|
||||
let paramUrl = decodeURIComponent(this.$route.params.url)
|
||||
this.$nextTick(() => {
|
||||
this.updatePlayerDomSize()
|
||||
window.onresize = () => {
|
||||
this.updatePlayerDomSize()
|
||||
}
|
||||
if (typeof (this.videoUrl) == "undefined") {
|
||||
this.videoUrl = paramUrl;
|
||||
}
|
||||
this.btnDom = document.getElementById("buttonsBox");
|
||||
console.log("初始化时的地址为: " + this.videoUrl)
|
||||
this.play(this.videoUrl)
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
videoUrl(newData, oldData) {
|
||||
this.play(newData)
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
methods: {
|
||||
updatePlayerDomSize() {
|
||||
let dom = this.$refs.container;
|
||||
let width = dom.parentNode.clientWidth
|
||||
let height = (9 / 16) * width
|
||||
|
||||
const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
|
||||
if (height > clientHeight) {
|
||||
height = clientHeight
|
||||
width = (16 / 9) * height
|
||||
}
|
||||
|
||||
dom.style.width = width + 'px';
|
||||
dom.style.height = height + "px";
|
||||
},
|
||||
create() {
|
||||
let options = {};
|
||||
console.log("hasAudio " + this.hasAudio)
|
||||
h265webPlayer[this._uid] = new window.new265webjs(this.videoUrl, Object.assign(
|
||||
{
|
||||
player: "glplayer", // 播放器容器id
|
||||
width: 960,
|
||||
height: 540,
|
||||
token : token,
|
||||
extInfo : {
|
||||
coreProbePart : 0.4,
|
||||
probeSize : 8192,
|
||||
ignoreAudio : 0
|
||||
}
|
||||
},
|
||||
options
|
||||
));
|
||||
let h265web = h265webPlayer[this._uid];
|
||||
h265web.onOpenFullScreen = () => {
|
||||
this.fullscreen = true
|
||||
}
|
||||
h265web.onCloseFullScreen = () => {
|
||||
this.fullscreen = false
|
||||
}
|
||||
h265web.onReadyShowDone = () => {
|
||||
// 准备好显示了,尝试自动播放
|
||||
const result = h265web.play()
|
||||
this.playing = result;
|
||||
}
|
||||
h265web.onLoadFinish = () => {
|
||||
this.loaded = true;
|
||||
// 可以获取mediaInfo
|
||||
// @see https://github.com/numberwolf/h265web.js/blob/8b26a31ffa419bd0a0f99fbd5111590e144e36a8/example_normal/index.js#L252C9-L263C11
|
||||
// mediaInfo = playerObj.mediaInfo();
|
||||
}
|
||||
h265web.onPlayTime = (...args) => {
|
||||
console.log(args)
|
||||
}
|
||||
h265web.do()
|
||||
},
|
||||
screenshot: function () {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].screenshot();
|
||||
}
|
||||
},
|
||||
playBtnClick: function (event) {
|
||||
this.play(this.videoUrl)
|
||||
},
|
||||
play: function (url) {
|
||||
console.log(url)
|
||||
if (h265webPlayer[this._uid]) {
|
||||
this.destroy();
|
||||
}
|
||||
this.create();
|
||||
},
|
||||
unPause: function () {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].play();
|
||||
}
|
||||
this.playing = h265webPlayer[this._uid].isPlaying();
|
||||
this.err = "";
|
||||
},
|
||||
pause: function () {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].pause();
|
||||
}
|
||||
this.playing = h265webPlayer[this._uid].isPlaying();
|
||||
this.err = "";
|
||||
},
|
||||
mute: function () {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].setVoice(0.0);
|
||||
this.isNotMute = false;
|
||||
}
|
||||
},
|
||||
cancelMute: function () {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].setVoice(1.0);
|
||||
this.isNotMute = true;
|
||||
}
|
||||
},
|
||||
destroy: function () {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].release();
|
||||
}
|
||||
if (document.getElementById("buttonsBox") == null) {
|
||||
this.$refs.container.appendChild(this.btnDom)
|
||||
}
|
||||
h265webPlayer[this._uid] = null;
|
||||
this.playing = false;
|
||||
this.err = "";
|
||||
|
||||
},
|
||||
eventcallbacK: function (type, message) {
|
||||
// console.log("player 事件回调")
|
||||
// console.log(type)
|
||||
// console.log(message)
|
||||
},
|
||||
fullscreenSwich: function () {
|
||||
let isFull = this.isFullscreen()
|
||||
if (isFull) {
|
||||
h265webPlayer[this._uid].closeFullScreen()
|
||||
} else {
|
||||
h265webPlayer[this._uid].fullScreen()
|
||||
}
|
||||
this.fullscreen = !isFull;
|
||||
},
|
||||
isFullscreen: function () {
|
||||
return document.fullscreenElement ||
|
||||
document.msFullscreenElement ||
|
||||
document.mozFullScreenElement ||
|
||||
document.webkitFullscreenElement || false;
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
if (h265webPlayer[this._uid]) {
|
||||
h265webPlayer[this._uid].destroy();
|
||||
}
|
||||
this.playing = false;
|
||||
this.loaded = false;
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.buttons-box {
|
||||
width: 100%;
|
||||
height: 28px;
|
||||
background-color: rgba(43, 51, 63, 0.7);
|
||||
position: absolute;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
user-select: none;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.h265web-btn {
|
||||
width: 20px;
|
||||
color: rgb(255, 255, 255);
|
||||
line-height: 27px;
|
||||
margin: 0px 10px;
|
||||
padding: 0px 2px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
font-size: 0.8rem !important;
|
||||
}
|
||||
|
||||
.buttons-box-right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
@ -1,309 +0,0 @@
|
||||
<template>
|
||||
<div ref="container" @dblclick="fullscreenSwich"
|
||||
style="width:100%; height: 100%; background-color: #000000;margin:0 auto;position: relative;">
|
||||
<div style="width:100%; padding-top: 56.25%; position: relative;"></div>
|
||||
<div class="buttons-box" id="buttonsBox">
|
||||
<div class="buttons-box-left">
|
||||
<i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i>
|
||||
<i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause"></i>
|
||||
<i class="iconfont icon-stop jessibuca-btn" @click="destroy"></i>
|
||||
<i v-if="isNotMute" class="iconfont icon-audio-high jessibuca-btn" @click="mute()"></i>
|
||||
<i v-if="!isNotMute" class="iconfont icon-audio-mute jessibuca-btn" @click="cancelMute()"></i>
|
||||
</div>
|
||||
<div class="buttons-box-right">
|
||||
<span class="jessibuca-btn">{{ kBps }} kb/s</span>
|
||||
<!-- <i class="iconfont icon-file-record1 jessibuca-btn"></i>-->
|
||||
<!-- <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>-->
|
||||
<i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="screenshot"
|
||||
style="font-size: 1rem !important"></i>
|
||||
<i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i>
|
||||
<i v-if="!fullscreen" class="iconfont icon-weibiaoti10 jessibuca-btn" @click="fullscreenSwich"></i>
|
||||
<i v-if="fullscreen" class="iconfont icon-weibiaoti11 jessibuca-btn" @click="fullscreenSwich"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let jessibucaPlayer = {};
|
||||
export default {
|
||||
name: 'jessibuca',
|
||||
data() {
|
||||
return {
|
||||
playing: false,
|
||||
isNotMute: false,
|
||||
quieting: false,
|
||||
fullscreen: false,
|
||||
loaded: false, // mute
|
||||
speed: 0,
|
||||
performance: "", // 工作情况
|
||||
kBps: 0,
|
||||
btnDom: null,
|
||||
videoInfo: null,
|
||||
volume: 1,
|
||||
rotate: 0,
|
||||
vod: true, // 点播
|
||||
forceNoOffscreen: false,
|
||||
};
|
||||
},
|
||||
props: ['videoUrl', 'error', 'hasAudio', 'height'],
|
||||
created() {
|
||||
let paramUrl = decodeURIComponent(this.$route.params.url)
|
||||
this.$nextTick(() => {
|
||||
console.log(2222)
|
||||
this.updatePlayerDomSize()
|
||||
window.onresize = this.updatePlayerDomSize
|
||||
if (typeof (this.videoUrl) == "undefined") {
|
||||
this.videoUrl = paramUrl;
|
||||
}
|
||||
this.btnDom = document.getElementById("buttonsBox");
|
||||
})
|
||||
},
|
||||
// mounted() {
|
||||
// const ro = new ResizeObserver(entries => {
|
||||
// entries.forEach(entry => {
|
||||
// this.updatePlayerDomSize()
|
||||
// });
|
||||
// });
|
||||
// ro.observe(this.$refs.container);
|
||||
// },
|
||||
mounted(){
|
||||
this.updatePlayerDomSize();
|
||||
},
|
||||
watch: {
|
||||
videoUrl: {
|
||||
handler(val, _) {
|
||||
this.$nextTick(() => {
|
||||
this.play(val);
|
||||
})
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updatePlayerDomSize() {
|
||||
let dom = this.$refs.container;
|
||||
let width = dom.parentNode.clientWidth
|
||||
let height = (9 / 16) * width
|
||||
console.log(height)
|
||||
|
||||
console.log(dom.clientHeight)
|
||||
if (height > dom.clientHeight) {
|
||||
height = dom.clientHeight
|
||||
width = (16 / 9) * height
|
||||
}
|
||||
if (width > 0 && height > 0) {
|
||||
dom.style.width = width + 'px';
|
||||
dom.style.height = height + "px";
|
||||
dom.style.paddingTop = 0;
|
||||
console.log(width)
|
||||
console.log(height)
|
||||
}
|
||||
},
|
||||
create() {
|
||||
let options = {
|
||||
container: this.$refs.container,
|
||||
autoWasm: true,
|
||||
background: "",
|
||||
controlAutoHide: false,
|
||||
debug: false,
|
||||
decoder: "static/js/jessibuca/decoder.js",
|
||||
forceNoOffscreen: false,
|
||||
hasAudio: typeof (this.hasAudio) == "undefined" ? true : this.hasAudio,
|
||||
heartTimeout: 5,
|
||||
heartTimeoutReplay: true,
|
||||
heartTimeoutReplayTimes: 3,
|
||||
hiddenAutoPause: false,
|
||||
hotKey: true,
|
||||
isFlv: false,
|
||||
isFullResize: false,
|
||||
isNotMute: this.isNotMute,
|
||||
isResize: false,
|
||||
keepScreenOn: true,
|
||||
loadingText: "请稍等, 视频加载中......",
|
||||
loadingTimeout: 10,
|
||||
loadingTimeoutReplay: true,
|
||||
loadingTimeoutReplayTimes: 3,
|
||||
openWebglAlignment: false,
|
||||
operateBtns: {
|
||||
fullscreen: false,
|
||||
screenshot: false,
|
||||
play: false,
|
||||
audio: false,
|
||||
record: false
|
||||
},
|
||||
recordType: "mp4",
|
||||
rotate: 0,
|
||||
showBandwidth: false,
|
||||
supportDblclickFullscreen: false,
|
||||
timeout: 10,
|
||||
useMSE: true,
|
||||
useWCS: false,
|
||||
useWebFullScreen: true,
|
||||
videoBuffer: 0.1,
|
||||
wasmDecodeErrorReplay: true,
|
||||
wcsUseVideoRender: true
|
||||
};
|
||||
console.log("Jessibuca -> options: ", options);
|
||||
jessibucaPlayer[this._uid] = new window.Jessibuca({...options});
|
||||
|
||||
let jessibuca = jessibucaPlayer[this._uid];
|
||||
let _this = this;
|
||||
jessibuca.on("pause", function () {
|
||||
_this.playing = false;
|
||||
});
|
||||
jessibuca.on("play", function () {
|
||||
_this.playing = true;
|
||||
});
|
||||
jessibuca.on("fullscreen", function (msg) {
|
||||
_this.fullscreen = msg
|
||||
});
|
||||
jessibuca.on("mute", function (msg) {
|
||||
_this.isNotMute = !msg;
|
||||
});
|
||||
jessibuca.on("performance", function (performance) {
|
||||
let show = "卡顿";
|
||||
if (performance === 2) {
|
||||
show = "非常流畅";
|
||||
} else if (performance === 1) {
|
||||
show = "流畅";
|
||||
}
|
||||
_this.performance = show;
|
||||
});
|
||||
jessibuca.on('kBps', function (kBps) {
|
||||
_this.kBps = Math.round(kBps);
|
||||
});
|
||||
jessibuca.on("videoInfo", function (msg) {
|
||||
console.log("Jessibuca -> videoInfo: ", msg);
|
||||
});
|
||||
jessibuca.on("audioInfo", function (msg) {
|
||||
console.log("Jessibuca -> audioInfo: ", msg);
|
||||
});
|
||||
jessibuca.on("error", function (msg) {
|
||||
console.log("Jessibuca -> error: ", msg);
|
||||
});
|
||||
jessibuca.on("timeout", function (msg) {
|
||||
console.log("Jessibuca -> timeout: ", msg);
|
||||
});
|
||||
jessibuca.on("loadingTimeout", function (msg) {
|
||||
console.log("Jessibuca -> timeout: ", msg);
|
||||
});
|
||||
jessibuca.on("delayTimeout", function (msg) {
|
||||
console.log("Jessibuca -> timeout: ", msg);
|
||||
});
|
||||
jessibuca.on("playToRenderTimes", function (msg) {
|
||||
console.log("Jessibuca -> playToRenderTimes: ", msg);
|
||||
});
|
||||
},
|
||||
playBtnClick: function (event) {
|
||||
this.play(this.videoUrl)
|
||||
},
|
||||
play: function (url) {
|
||||
console.log("Jessibuca -> url: ", url);
|
||||
if (jessibucaPlayer[this._uid]) {
|
||||
this.destroy();
|
||||
}
|
||||
this.create();
|
||||
jessibucaPlayer[this._uid].on("play", () => {
|
||||
this.playing = true;
|
||||
this.loaded = true;
|
||||
this.quieting = jessibuca.quieting;
|
||||
});
|
||||
if (jessibucaPlayer[this._uid].hasLoaded()) {
|
||||
jessibucaPlayer[this._uid].play(url);
|
||||
} else {
|
||||
jessibucaPlayer[this._uid].on("load", () => {
|
||||
jessibucaPlayer[this._uid].play(url);
|
||||
});
|
||||
}
|
||||
},
|
||||
pause: function () {
|
||||
if (jessibucaPlayer[this._uid]) {
|
||||
jessibucaPlayer[this._uid].pause();
|
||||
}
|
||||
this.playing = false;
|
||||
this.err = "";
|
||||
this.performance = "";
|
||||
},
|
||||
screenshot: function () {
|
||||
if (jessibucaPlayer[this._uid]) {
|
||||
jessibucaPlayer[this._uid].screenshot();
|
||||
}
|
||||
},
|
||||
mute: function () {
|
||||
if (jessibucaPlayer[this._uid]) {
|
||||
jessibucaPlayer[this._uid].mute();
|
||||
}
|
||||
},
|
||||
cancelMute: function () {
|
||||
if (jessibucaPlayer[this._uid]) {
|
||||
jessibucaPlayer[this._uid].cancelMute();
|
||||
}
|
||||
},
|
||||
destroy: function () {
|
||||
if (jessibucaPlayer[this._uid]) {
|
||||
jessibucaPlayer[this._uid].destroy();
|
||||
}
|
||||
if (document.getElementById("buttonsBox") == null) {
|
||||
this.$refs.container.appendChild(this.btnDom)
|
||||
}
|
||||
jessibucaPlayer[this._uid] = null;
|
||||
this.playing = false;
|
||||
this.err = "";
|
||||
this.performance = "";
|
||||
|
||||
},
|
||||
fullscreenSwich: function () {
|
||||
let isFull = this.isFullscreen()
|
||||
jessibucaPlayer[this._uid].setFullscreen(!isFull)
|
||||
this.fullscreen = !isFull;
|
||||
},
|
||||
isFullscreen: function () {
|
||||
return document.fullscreenElement ||
|
||||
document.msFullscreenElement ||
|
||||
document.mozFullScreenElement ||
|
||||
document.webkitFullscreenElement || false;
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
if (jessibucaPlayer[this._uid]) {
|
||||
jessibucaPlayer[this._uid].destroy();
|
||||
}
|
||||
this.playing = false;
|
||||
this.loaded = false;
|
||||
this.performance = "";
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.buttons-box {
|
||||
width: 100%;
|
||||
height: 28px;
|
||||
background-color: rgba(43, 51, 63, 0.7);
|
||||
position: absolute;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
user-select: none;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.jessibuca-btn {
|
||||
width: 20px;
|
||||
color: rgb(255, 255, 255);
|
||||
line-height: 27px;
|
||||
margin: 0px 10px;
|
||||
padding: 0px 2px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
font-size: 0.8rem !important;
|
||||
}
|
||||
|
||||
.buttons-box-right {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
</style>
|
||||
@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<div id="mediaInfo" >
|
||||
<el-button style="position: absolute; right: 1rem;" icon="el-icon-refresh-right" circle size="mini" @click="getMediaInfo"></el-button>
|
||||
<el-descriptions size="mini" :column="3" title="概况">
|
||||
<el-descriptions-item label="观看人数">{{ info.readerCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="网络">{{ formatByteSpeed() }}</el-descriptions-item>
|
||||
<el-descriptions-item label="持续时间">{{info.aliveSecond}}秒</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr">
|
||||
<el-descriptions size="mini" v-if="info.videoCodec" :column="2" title="视频信息">
|
||||
<el-descriptions-item label="编码">{{ info.videoCodec }}</el-descriptions-item>
|
||||
<el-descriptions-item label="分辨率"
|
||||
>{{ info.width }}x{{ info.height }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="FPS">{{ info.fps }}</el-descriptions-item>
|
||||
<el-descriptions-item label="丢包率">{{ info.loss }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions size="mini" v-if="info.audioCodec" :column="2" title="音频信息">
|
||||
<el-descriptions-item label="编码">
|
||||
{{ info.audioCodec }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="采样率">{{ info.audioSampleRate }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "mediaInfo",
|
||||
props: [ 'app', 'stream', 'mediaServerId'],
|
||||
components: {},
|
||||
created() {
|
||||
this.getMediaInfo();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
task: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getMediaInfo: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/media_info`,
|
||||
params: {
|
||||
app: this.app,
|
||||
stream: this.stream,
|
||||
mediaServerId: this.mediaServerId,
|
||||
}
|
||||
}).then((res)=> {
|
||||
console.log(res.data.data);
|
||||
if (res.data.code === 0) {
|
||||
this.info = res.data.data
|
||||
}
|
||||
|
||||
}).catch((error)=> {
|
||||
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
startTask: function () {
|
||||
this.task = setInterval(this.getMediaInfo, 1000)
|
||||
},
|
||||
stopTask: function () {
|
||||
if (this.task) {
|
||||
window.clearInterval(this.task);
|
||||
this.task = null;
|
||||
}
|
||||
|
||||
},
|
||||
formatByteSpeed: function (){
|
||||
let bytesSpeed = this.info.bytesSpeed
|
||||
let num = 1024.0 //byte
|
||||
if (bytesSpeed < num) return bytesSpeed + ' B/S'
|
||||
if (bytesSpeed < Math.pow(num, 2)) return (bytesSpeed / num).toFixed(2) + ' KB/S' //kb
|
||||
if (bytesSpeed < Math.pow(num, 3))
|
||||
return (bytesSpeed / Math.pow(num, 2)).toFixed(2) + ' MB/S' //M
|
||||
if (bytesSpeed < Math.pow(num, 4))
|
||||
return (bytesSpeed / Math.pow(num, 3)).toFixed(2) + ' G/S' //G
|
||||
return (bytesSpeed / Math.pow(num, 4)).toFixed(2) + ' T/S' //T
|
||||
},
|
||||
formatAliveSecond: function (){
|
||||
let aliveSecond = this.info.aliveSecond
|
||||
const h = parseInt(aliveSecond.value / 3600)
|
||||
const minute = parseInt((aliveSecond.value / 60) % 60)
|
||||
const second = Math.ceil(aliveSecond.value % 60)
|
||||
|
||||
const hours = h < 10 ? '0' + h : h
|
||||
const formatSecond = second > 59 ? 59 : second
|
||||
return `${hours > 0 ? `${hours}小时` : ''}${minute < 10 ? '0' + minute : minute}分${
|
||||
formatSecond < 10 ? '0' + formatSecond : formatSecond
|
||||
}秒`
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,426 +0,0 @@
|
||||
<template>
|
||||
<div id="ptzCruising">
|
||||
<div style="display: grid; grid-template-columns: 80px auto; line-height: 28px">
|
||||
<span>巡航组号: </span>
|
||||
<el-input
|
||||
min="1"
|
||||
max="255"
|
||||
placeholder="巡航组号"
|
||||
addonBefore="巡航组号"
|
||||
addonAfter="(1-255)"
|
||||
v-model="cruiseId"
|
||||
size="mini"
|
||||
>
|
||||
</el-input>
|
||||
</div>
|
||||
<p>
|
||||
<el-tag v-for="(item, index) in presetList"
|
||||
key="item.presetId"
|
||||
closable
|
||||
@close="delPreset(item, index)"
|
||||
style="margin-right: 1rem; cursor: pointer"
|
||||
>
|
||||
{{item.presetName?item.presetName:item.presetId}}
|
||||
</el-tag>
|
||||
</p>
|
||||
|
||||
<el-form size="mini" :inline="true" v-if="selectPresetVisible">
|
||||
<el-form-item >
|
||||
<el-select v-model="selectPreset" placeholder="请选择预置点">
|
||||
<el-option
|
||||
v-for="item in allPresetList"
|
||||
:key="item.presetId"
|
||||
:label="item.presetName"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="addCruisePoint">保存</el-button>
|
||||
<el-button type="primary" @click="cancelAddCruisePoint">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button size="mini" v-else @click="selectPresetVisible=true">添加巡航点</el-button>
|
||||
|
||||
<el-form size="mini" :inline="true" v-if="setSpeedVisible">
|
||||
<el-form-item >
|
||||
<el-input
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="巡航速度"
|
||||
addonBefore="巡航速度"
|
||||
addonAfter="(1-4095)"
|
||||
v-if="setSpeedVisible"
|
||||
v-model="cruiseSpeed"
|
||||
size="mini"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="setCruiseSpeed">保存</el-button>
|
||||
<el-button @click="cancelSetCruiseSpeed">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="mini" @click="setSpeedVisible = true">设置巡航速度</el-button>
|
||||
|
||||
|
||||
|
||||
<el-form size="mini" :inline="true" v-if="setTimeVisible">
|
||||
<el-form-item >
|
||||
<el-input
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="巡航停留时间(秒)"
|
||||
addonBefore="巡航停留时间(秒)"
|
||||
addonAfter="(1-4095)"
|
||||
style="width: 100%;"
|
||||
v-model="cruiseTime"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="setCruiseTime">保存</el-button>
|
||||
<el-button @click="cancelSetCruiseTime">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="mini" @click="setTimeVisible = true">设置巡航时间</el-button>
|
||||
<el-button size="mini" @click="startCruise">开始巡航</el-button>
|
||||
<el-button size="mini" @click="stopCruise">停止巡航</el-button>
|
||||
<el-button size="mini" type="danger" @click="deleteCruise">删除巡航</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ptzCruising",
|
||||
props: [ 'channelDeviceId', 'deviceId'],
|
||||
components: {},
|
||||
created() {
|
||||
this.getPresetList()
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cruiseId: 1,
|
||||
presetList: [],
|
||||
allPresetList: [],
|
||||
selectPreset: "",
|
||||
inputVisible: false,
|
||||
selectPresetVisible: false,
|
||||
setSpeedVisible: false,
|
||||
setTimeVisible: false,
|
||||
cruiseSpeed: '',
|
||||
cruiseTime: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getPresetList: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/query/${this.deviceId}/${this.channelDeviceId}`,
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.allPresetList = res.data.data;
|
||||
}
|
||||
|
||||
}).catch((error)=> {
|
||||
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
addCruisePoint: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/point/add/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: this.cruiseId,
|
||||
presetId: this.selectPreset.presetId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.presetList.push(this.selectPreset)
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
this.selectPreset = ""
|
||||
this.selectPresetVisible = false;
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelAddCruisePoint: function () {
|
||||
this.selectPreset = ""
|
||||
this.selectPresetVisible = false;
|
||||
},
|
||||
delPreset: function (preset, index){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/point/delete/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: this.cruiseId,
|
||||
presetId: preset.presetId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.presetList.splice(index, 1)
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
deleteCruise: function (preset, index){
|
||||
this.$confirm("确定删除此巡航组", '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/point/delete/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: this.cruiseId,
|
||||
presetId: 0
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.presetList = []
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
})
|
||||
},
|
||||
setCruiseSpeed: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/speed/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: this.cruiseId,
|
||||
speed: this.cruiseSpeed
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
this.cruiseSpeed = ""
|
||||
this.setSpeedVisible = false
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelSetCruiseSpeed: function (){
|
||||
this.cruiseSpeed = ""
|
||||
this.setSpeedVisible = false
|
||||
},
|
||||
setCruiseTime: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/time/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: this.cruiseId,
|
||||
time: this.cruiseTime
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
this.setTimeVisible = false;
|
||||
this.cruiseTime = "";
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelSetCruiseTime: function (){
|
||||
this.setTimeVisible = false;
|
||||
this.cruiseTime = "";
|
||||
},
|
||||
startCruise: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/start/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: this.cruiseId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "发送成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
stopCruise: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/cruise/stop/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
cruiseId: this.cruiseId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "发送成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,212 +0,0 @@
|
||||
<template>
|
||||
<div id="ptzPreset" style="width: 100%">
|
||||
<el-tag v-for="item in presetList"
|
||||
key="item.presetId"
|
||||
closable
|
||||
@close="delPreset(item)"
|
||||
@click="gotoPreset(item)"
|
||||
size="mini"
|
||||
style="margin-right: 1rem; cursor: pointer; margin-bottom: 0.6rem"
|
||||
>
|
||||
{{item.presetName?item.presetName:item.presetId}}
|
||||
</el-tag>
|
||||
<el-input
|
||||
min="1"
|
||||
max="255"
|
||||
placeholder="预置位编号"
|
||||
addonBefore="预置位编号"
|
||||
addonAfter="(1-255)"
|
||||
style="width: 300px; vertical-align: bottom;"
|
||||
v-if="inputVisible"
|
||||
v-model="ptzPresetId"
|
||||
ref="saveTagInput"
|
||||
size="small"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<el-button @click="addPreset()">保存</el-button>
|
||||
<el-button @click="cancel()">取消</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button v-else size="small" @click="showInput">+ 添加</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ptzPreset",
|
||||
props: [ 'channelDeviceId', 'deviceId'],
|
||||
components: {},
|
||||
created() {
|
||||
this.getPresetList()
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
presetList: [],
|
||||
inputVisible: false,
|
||||
ptzPresetId: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getPresetList: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/query/${this.deviceId}/${this.channelDeviceId}`,
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.presetList = res.data.data;
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.channelListTable.doLayout();
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error)=> {
|
||||
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
showInput() {
|
||||
this.inputVisible = true;
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.saveTagInput.$refs.input.focus();
|
||||
});
|
||||
},
|
||||
addPreset: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/add/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
presetId: this.ptzPresetId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
setTimeout(()=>{
|
||||
loading.close()
|
||||
this.inputVisible = false;
|
||||
this.ptzPresetId = ""
|
||||
this.getPresetList()
|
||||
}, 1000)
|
||||
}else {
|
||||
loading.close()
|
||||
this.inputVisible = false;
|
||||
this.ptzPresetId = ""
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
loading.close()
|
||||
this.inputVisible = false;
|
||||
this.ptzPresetId = ""
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
},
|
||||
cancel: function () {
|
||||
this.inputVisible = false;
|
||||
this.ptzPresetId = ""
|
||||
},
|
||||
gotoPreset: function (preset){
|
||||
console.log(preset)
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/call/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
presetId: preset.presetId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '调用成功',
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
},
|
||||
delPreset: function (preset){
|
||||
this.$confirm("确定删除此预置位", '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/preset/delete/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
presetId: preset.presetId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
setTimeout(()=>{
|
||||
loading.close()
|
||||
this.getPresetList()
|
||||
}, 1000)
|
||||
}else {
|
||||
loading.close()
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
|
||||
}).catch((error)=> {
|
||||
loading.close()
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,273 +0,0 @@
|
||||
<template>
|
||||
<div id="ptzScan">
|
||||
<div style="display: grid; grid-template-columns: 80px auto; line-height: 28px">
|
||||
<span>扫描组号: </span>
|
||||
<el-input
|
||||
min="1"
|
||||
max="255"
|
||||
placeholder="扫描组号"
|
||||
addonBefore="扫描组号"
|
||||
addonAfter="(1-255)"
|
||||
v-model="scanId"
|
||||
size="mini"
|
||||
>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<el-button size="mini" @click="setScanLeft">设置左边界</el-button>
|
||||
<el-button size="mini" @click="setScanRight">设置右边界</el-button>
|
||||
|
||||
<el-form size="mini" :inline="true" v-if="setSpeedVisible">
|
||||
<el-form-item >
|
||||
<el-input
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="巡航速度"
|
||||
addonBefore="巡航速度"
|
||||
addonAfter="(1-4095)"
|
||||
v-if="setSpeedVisible"
|
||||
v-model="speed"
|
||||
size="mini"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="setSpeed">保存</el-button>
|
||||
<el-button @click="cancelSetSpeed">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button v-else size="mini" @click="setSpeedVisible = true">设置扫描速度</el-button>
|
||||
|
||||
<el-button size="mini" @click="startScan">开始自动扫描</el-button>
|
||||
<el-button size="mini" @click="stopScan">停止自动扫描</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ptzScan",
|
||||
props: [ 'channelDeviceId', 'deviceId'],
|
||||
components: {},
|
||||
created() {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
scanId: 1,
|
||||
setSpeedVisible: false,
|
||||
speed: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setSpeed: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/set/speed/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
scanId: this.scanId,
|
||||
speed: this.speed
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
this.speed = ""
|
||||
this.setSpeedVisible = false
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
cancelSetSpeed: function (){
|
||||
this.speed = ""
|
||||
this.setSpeedVisible = false
|
||||
},
|
||||
setScanLeft: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/set/left/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
scanId: this.scanId,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
setScanRight: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/set/right/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
scanId: this.scanId,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
this.setSpeedVisible = false;
|
||||
this.speed = "";
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
startScan: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/start/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
scanId: this.scanId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "发送成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
stopScan: function (){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/scan/stop/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
scanId: this.scanId
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "发送成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,90 +0,0 @@
|
||||
<template>
|
||||
<div id="ptzScan">
|
||||
<el-form size="mini" :inline="true" >
|
||||
<el-form-item >
|
||||
<el-input
|
||||
min="1"
|
||||
max="4095"
|
||||
placeholder="开关编号"
|
||||
addonBefore="开关编号"
|
||||
addonAfter="(2-255)"
|
||||
v-model="switchId"
|
||||
size="mini"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button size="mini" @click="open('on')">开启</el-button>
|
||||
<el-button size="mini" @click="open('off')">关闭</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ptzScan",
|
||||
props: [ 'channelDeviceId', 'deviceId'],
|
||||
components: {},
|
||||
created() {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
switchId: 1,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open: function (command){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/auxiliary/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
command: command,
|
||||
switchId: this.switchId,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,70 +0,0 @@
|
||||
<template>
|
||||
<div id="ptzWiper">
|
||||
<el-button size="mini" @click="open('on')">开启</el-button>
|
||||
<el-button size="mini" @click="open('off')">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "ptzWiper",
|
||||
props: [ 'channelDeviceId', 'deviceId'],
|
||||
components: {},
|
||||
created() {
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
open: function (command){
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
fullscreen: true,
|
||||
text: '正在发送指令',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/front-end/wiper/${this.deviceId}/${this.channelDeviceId}`,
|
||||
params: {
|
||||
command: command,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: 'success'
|
||||
});
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: 'error'
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.channel-form {
|
||||
display: grid;
|
||||
background-color: #FFFFFF;
|
||||
padding: 1rem 2rem 0 2rem;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,158 +0,0 @@
|
||||
<template>
|
||||
<div id="app" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">控制台</div>
|
||||
</div>
|
||||
<el-row style="width: 100%">
|
||||
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
|
||||
<div class="control-cell" id="ThreadsLoad" >
|
||||
<div style="width:100%; height:100%; ">
|
||||
<consoleCPU ref="consoleCPU"></consoleCPU>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
|
||||
<div class="control-cell" id="WorkThreadsLoad" >
|
||||
<div style="width:100%; height:100%; ">
|
||||
<consoleResource ref="consoleResource"></consoleResource>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
|
||||
<div class="control-cell" id="WorkThreadsLoad" >
|
||||
<div style="width:100%; height:100%; ">
|
||||
<consoleNet ref="consoleNet"></consoleNet>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
|
||||
<div class="control-cell" id="WorkThreadsLoad" >
|
||||
<div style="width:100%; height:100%; ">
|
||||
|
||||
<consoleMem ref="consoleMem"></consoleMem>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
|
||||
<div class="control-cell" id="WorkThreadsLoad" >
|
||||
<div style="width:100%; height:100%; ">
|
||||
<consoleNodeLoad ref="consoleNodeLoad"></consoleNodeLoad>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
|
||||
<div class="control-cell" id="WorkThreadsLoad" >
|
||||
<div style="width:100%; height:100%; ">
|
||||
<consoleDisk ref="consoleDisk"></consoleDisk>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import consoleCPU from './console/ConsoleCPU.vue'
|
||||
import consoleMem from './console/ConsoleMEM.vue'
|
||||
import consoleNet from './console/ConsoleNet.vue'
|
||||
import consoleNodeLoad from './console/ConsoleNodeLoad.vue'
|
||||
import consoleDisk from './console/ConsoleDisk.vue'
|
||||
import consoleResource from './console/ConsoleResource.vue'
|
||||
|
||||
import echarts from 'echarts';
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
echarts,
|
||||
uiHeader,
|
||||
consoleCPU,
|
||||
consoleMem,
|
||||
consoleNet,
|
||||
consoleNodeLoad,
|
||||
consoleDisk,
|
||||
consoleResource,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timer: null,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getSystemInfo();
|
||||
this.getLoad();
|
||||
this.getResourceInfo();
|
||||
this.loopForSystemInfo();
|
||||
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
loopForSystemInfo: function (){
|
||||
if (this.timer != null) {
|
||||
window.clearTimeout(this.timer);
|
||||
}
|
||||
this.timer = setTimeout(()=>{
|
||||
if (this.$route.path === "/console") {
|
||||
this.getSystemInfo();
|
||||
this.getLoad();
|
||||
this.timer = null;
|
||||
this.loopForSystemInfo()
|
||||
this.getResourceInfo()
|
||||
}
|
||||
|
||||
}, 2000)
|
||||
},
|
||||
getSystemInfo: function (){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/server/system/info`,
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$refs.consoleCPU.setData(res.data.data.cpu)
|
||||
this.$refs.consoleMem.setData(res.data.data.mem)
|
||||
this.$refs.consoleNet.setData(res.data.data.net, res.data.data.netTotal)
|
||||
this.$refs.consoleDisk.setData(res.data.data.disk)
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
});
|
||||
},
|
||||
getLoad: function (){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/server/media_server/load`,
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$refs.consoleNodeLoad.setData(res.data.data)
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
});
|
||||
},
|
||||
getResourceInfo: function (){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/server/resource/info`,
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$refs.consoleResource.setData(res.data.data)
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
});
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
.control-cell {
|
||||
padding-top: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 10px;
|
||||
height: 360px;
|
||||
}
|
||||
</style>
|
||||
@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<div id="consoleCPU" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<ve-line ref="consoleCPU" :data="chartData" :extend="extend" width="100%" height="100%" :legend-visible="false"></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import moment from "moment/moment";
|
||||
|
||||
export default {
|
||||
name: 'consoleCPU',
|
||||
data() {
|
||||
return {
|
||||
chartData: {
|
||||
columns: ['time', 'data'],
|
||||
rows: []
|
||||
},
|
||||
|
||||
extend: {
|
||||
title: {
|
||||
show: true,
|
||||
text: "CPU",
|
||||
left: "center",
|
||||
top: 20,
|
||||
|
||||
},
|
||||
grid: {
|
||||
show: true,
|
||||
right: "30px",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
time: "time",
|
||||
max: 'dataMax',
|
||||
boundaryGap: ['20%', '20%'],
|
||||
axisLabel: {
|
||||
formatter:(v)=>{
|
||||
return moment(v).format("HH:mm:ss");
|
||||
},
|
||||
showMaxLabel: true,
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 1,
|
||||
splitNumber: 6,
|
||||
position: "left",
|
||||
silent: true,
|
||||
axisLabel: {
|
||||
formatter: (v)=>{
|
||||
return v*100 + "%";
|
||||
},
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (data)=>{
|
||||
console.log(data)
|
||||
return moment(data[0].data[0]).format("HH:mm:ss") + "</br> "
|
||||
+ data[0].marker + "使用:" + (data[0].data[1]*100).toFixed(2) + "%";
|
||||
}
|
||||
},
|
||||
series: {
|
||||
itemStyle: {
|
||||
color: "#409EFF"
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [{
|
||||
offset: 0, color: '#50a3f8' // 0% 处的颜色
|
||||
}, {
|
||||
offset: 1, color: '#69b0fa' // 100% 处的颜色
|
||||
}],
|
||||
global: false // 缺省为 false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(_ => {
|
||||
setTimeout(()=>{
|
||||
this.$refs.consoleCPU.echarts.resize()
|
||||
}, 100)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data) {
|
||||
this.chartData .rows = data;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<div id="ConsoleNet" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<ve-bar ref="ConsoleNet" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" ></ve-bar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import moment from "moment/moment";
|
||||
|
||||
export default {
|
||||
name: 'ConsoleNet',
|
||||
data() {
|
||||
return {
|
||||
chartData: {
|
||||
columns: ['path','free','use'],
|
||||
rows: []
|
||||
},
|
||||
chartSettings: {
|
||||
stack: {
|
||||
'xxx': ['free', 'use']
|
||||
},
|
||||
labelMap: {
|
||||
'free': '剩余',
|
||||
'use': '已使用'
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
title: {
|
||||
show: true,
|
||||
text: "磁盘",
|
||||
left: "center",
|
||||
top: 20,
|
||||
},
|
||||
grid: {
|
||||
show: true,
|
||||
right: "30px",
|
||||
containLabel: true,
|
||||
},
|
||||
series: {
|
||||
barWidth: 30
|
||||
},
|
||||
legend: {
|
||||
left: "center",
|
||||
bottom: "15px",
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (data)=>{
|
||||
console.log(data)
|
||||
let relVal = "";
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
relVal += data[i].marker + data[i].seriesName + ":" + data[i].value.toFixed(2) + "GB"
|
||||
if (i < data.length - 1) {
|
||||
relVal += "</br>";
|
||||
}
|
||||
}
|
||||
return relVal;
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(_ => {
|
||||
setTimeout(()=>{
|
||||
this.$refs.ConsoleNet.echarts.resize()
|
||||
}, 100)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data) {
|
||||
this.chartData.rows = data;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,103 +0,0 @@
|
||||
<template>
|
||||
<div id="ConsoleMEM" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<ve-line ref="ConsoleMEM" :data="chartData" :extend="extend" width="100%" height="100%" :legend-visible="false"></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import moment from "moment/moment";
|
||||
|
||||
export default {
|
||||
name: 'ConsoleMEM',
|
||||
data() {
|
||||
return {
|
||||
chartData: {
|
||||
columns: ['time', 'data'],
|
||||
rows: []
|
||||
},
|
||||
|
||||
extend: {
|
||||
title: {
|
||||
show: true,
|
||||
text: "内存",
|
||||
left: "center",
|
||||
top: 20,
|
||||
|
||||
},
|
||||
grid: {
|
||||
show: true,
|
||||
right: "30px",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
time: "time",
|
||||
max: 'dataMax',
|
||||
boundaryGap: ['20%', '20%'],
|
||||
axisLabel: {
|
||||
formatter:(v)=>{
|
||||
return moment(v).format("HH:mm:ss");
|
||||
},
|
||||
showMaxLabel: true,
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 1,
|
||||
splitNumber: 6,
|
||||
position: "left",
|
||||
silent: true,
|
||||
axisLabel: {
|
||||
formatter: (v)=>{
|
||||
return v*100 + "%";
|
||||
},
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (data)=>{
|
||||
console.log(data)
|
||||
return moment(data[0].data[0]).format("HH:mm:ss") + "</br>"+ data[0].marker +" 使用:" + (data[0].data[1]*100).toFixed(2) + "%";
|
||||
}
|
||||
},
|
||||
series: {
|
||||
itemStyle: {
|
||||
color: "#409EFF"
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [{
|
||||
offset: 0, color: '#50a3f8' // 0% 处的颜色
|
||||
}, {
|
||||
offset: 1, color: '#69b0fa' // 100% 处的颜色
|
||||
}],
|
||||
global: false // 缺省为 false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(_ => {
|
||||
setTimeout(()=>{
|
||||
this.$refs.ConsoleMEM.echarts.resize()
|
||||
}, 100)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data) {
|
||||
this.chartData .rows = data;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,85 +0,0 @@
|
||||
<template>
|
||||
<div id="ConsoleMediaServer" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<ve-histogram ref="ConsoleMEM" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" ></ve-histogram>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import moment from "moment/moment";
|
||||
|
||||
export default {
|
||||
name: 'ConsoleMediaServer',
|
||||
data() {
|
||||
return {
|
||||
chartData: {
|
||||
columns: ['time', 'in', 'out'],
|
||||
rows: [
|
||||
]
|
||||
},
|
||||
chartSettings: {
|
||||
area: true,
|
||||
labelMap: {
|
||||
'in': '下载',
|
||||
'out': '上传'
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
title: {
|
||||
show: true,
|
||||
text: "网络",
|
||||
left: "center",
|
||||
top: 20,
|
||||
|
||||
},
|
||||
grid: {
|
||||
show: true,
|
||||
right: "30px",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
time: "time",
|
||||
max: 'dataMax',
|
||||
boundaryGap: ['20%', '20%'],
|
||||
axisLabel: {
|
||||
formatter:(v)=>{
|
||||
return moment(v).format("HH:mm:ss");
|
||||
},
|
||||
showMaxLabel: true,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (data)=>{
|
||||
console.log(parseFloat(data[0].data[1]).toFixed(2))
|
||||
console.log(parseFloat(data[1].data[1]).toFixed(2))
|
||||
console.log("############")
|
||||
return "下载:" + parseFloat(data[0].data[1]).toFixed(2) + "Mbps" + "</br> 上传:" + parseFloat(data[1].data[1]).toFixed(2) + "Mbps";
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
left: "center",
|
||||
bottom: "15px",
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(_ => {
|
||||
setTimeout(()=>{
|
||||
this.$refs.ConsoleMEM.echarts.resize()
|
||||
}, 100)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data) {
|
||||
console.log(data)
|
||||
this.chartData .rows = data;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,131 +0,0 @@
|
||||
<template>
|
||||
<div id="ConsoleNet" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<ve-line ref="ConsoleNet" :data="chartData" :extend="extend" :settings="chartSettings" :events="chartEvents" width="100%" height="100%" ></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import moment from "moment/moment";
|
||||
|
||||
export default {
|
||||
name: 'ConsoleNet',
|
||||
data() {
|
||||
return {
|
||||
chartData: {
|
||||
columns: ['time','out','in'],
|
||||
rows: []
|
||||
},
|
||||
chartSettings: {
|
||||
area: true,
|
||||
labelMap: {
|
||||
'in': '下载',
|
||||
'out': '上传'
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
title: {
|
||||
show: true,
|
||||
text: "网络",
|
||||
left: "center",
|
||||
top: 20,
|
||||
|
||||
},
|
||||
grid: {
|
||||
show: true,
|
||||
right: "30px",
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
time: "time",
|
||||
max: 'dataMax',
|
||||
boundaryGap: ['20%', '20%'],
|
||||
axisLabel: {
|
||||
formatter:(v)=>{
|
||||
return moment(v).format("HH:mm:ss");
|
||||
},
|
||||
showMaxLabel: true,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 1000,
|
||||
splitNumber: 6,
|
||||
position: "left",
|
||||
silent: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: (data)=>{
|
||||
let in_sel = true;
|
||||
let out_sel = true;
|
||||
for (let key in this.extend.legend.selected) {
|
||||
if (key == "上传") {
|
||||
out_sel = this.extend.legend.selected[key];
|
||||
}
|
||||
if (key == "下载") {
|
||||
in_sel = this.extend.legend.selected[key];
|
||||
}
|
||||
}
|
||||
if (out_sel && in_sel) {
|
||||
return (
|
||||
data[1].marker +
|
||||
"下载:" +
|
||||
parseFloat(data[1].data[1]).toFixed(2) +
|
||||
"Mbps" +
|
||||
"</br> " +
|
||||
data[0].marker +
|
||||
"上传:" +
|
||||
parseFloat(data[0].data[1]).toFixed(2) +
|
||||
"Mbps"
|
||||
);
|
||||
} else if (out_sel)
|
||||
return (
|
||||
data[0].marker +
|
||||
"上传:" +
|
||||
parseFloat(data[0].data[1]).toFixed(2) +
|
||||
"Mbps"
|
||||
);
|
||||
else if (in_sel)
|
||||
return (
|
||||
data[0].marker +
|
||||
"下载:" +
|
||||
parseFloat(data[0].data[1]).toFixed(2) +
|
||||
"Mbps"
|
||||
);
|
||||
return "";
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
left: "center",
|
||||
bottom: "15px",
|
||||
selected: {},
|
||||
}
|
||||
},
|
||||
chartEvents: {
|
||||
legendselectchanged: (item) => {
|
||||
this.extend.legend.selected = item.selected;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(_ => {
|
||||
setTimeout(()=>{
|
||||
this.$refs.ConsoleNet.echarts.resize()
|
||||
}, 100)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data, total) {
|
||||
this.chartData .rows = data;
|
||||
this.extend.yAxis.max= total;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<div id="ConsoleNodeLoad" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<ve-histogram ref="consoleNodeLoad" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" :legend-visible="true"></ve-histogram>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
import moment from "moment/moment";
|
||||
|
||||
export default {
|
||||
name: 'ConsoleNodeLoad',
|
||||
data() {
|
||||
return {
|
||||
chartData: {
|
||||
columns: ['id', 'push', 'proxy', 'gbReceive', 'gbSend'],
|
||||
rows: []
|
||||
},
|
||||
chartSettings: {
|
||||
labelMap: {
|
||||
'push': '直播推流',
|
||||
'proxy': '拉流代理',
|
||||
'gbReceive': '国标收流',
|
||||
'gbSend': '国标推流',
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
title: {
|
||||
show: true,
|
||||
text: "节点负载",
|
||||
left: "center",
|
||||
top: 20,
|
||||
|
||||
},
|
||||
legend: {
|
||||
left: "center",
|
||||
bottom: "15px",
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: "top"
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(_ => {
|
||||
setTimeout(()=>{
|
||||
this.$refs.consoleNodeLoad.echarts.resize()
|
||||
}, 100)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data) {
|
||||
this.chartData .rows = data;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,90 +0,0 @@
|
||||
<template >
|
||||
<div id="consoleResource" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
|
||||
<div style="width: 50%;height: 50%; float:left; ">
|
||||
<el-progress v-if="deviceInfo.total > 0" :width="100" :stroke-width="8" type="circle" :percentage="Math.floor(deviceInfo.online/deviceInfo.total*100)" style="margin-top: 20px; font-size: 18px"></el-progress>
|
||||
<el-progress v-if="deviceInfo.total === 0" :width="100" :stroke-width="8" type="circle" :percentage="0" style="margin-top: 20px; font-size: 18px"></el-progress>
|
||||
<div class="resourceInfo">
|
||||
设备总数:{{deviceInfo.total}}<br/>
|
||||
在线数:{{deviceInfo.online}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 50%;height: 50%; float:left; ">
|
||||
<el-progress v-if="channelInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(channelInfo.online/channelInfo.total*100)" style="margin-top: 20px"></el-progress>
|
||||
<el-progress v-if="channelInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
|
||||
<div class="resourceInfo">
|
||||
通道总数:{{channelInfo.total}}<br/>
|
||||
在线数:{{channelInfo.online}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 50%;height: 50%; float:left; ">
|
||||
<el-progress v-if="pushInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(pushInfo.online/pushInfo.total*100)" style="margin-top: 20px"></el-progress>
|
||||
<el-progress v-if="pushInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
|
||||
<div class="resourceInfo">
|
||||
推流总数:{{pushInfo.total}}<br/>
|
||||
在线数:{{pushInfo.online}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 50%;height: 50%; float:left; ">
|
||||
<el-progress v-if="proxyInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(proxyInfo.online/proxyInfo.total*100)" style="margin-top: 20px"></el-progress>
|
||||
<el-progress v-if="proxyInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
|
||||
<div class="resourceInfo">
|
||||
拉流代理总数:{{proxyInfo.total}}<br/>
|
||||
在线数:{{proxyInfo.online}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'consoleResource',
|
||||
data() {
|
||||
return {
|
||||
deviceInfo: {
|
||||
total: 0,
|
||||
online: 0
|
||||
},
|
||||
channelInfo: {
|
||||
total: 0,
|
||||
online: 0
|
||||
},
|
||||
pushInfo: {
|
||||
total: 0,
|
||||
online: 0
|
||||
},
|
||||
proxyInfo: {
|
||||
total: 0,
|
||||
online: 0
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
|
||||
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
setData: function(data) {
|
||||
this.deviceInfo = data.device;
|
||||
this.channelInfo = data.channel;
|
||||
this.pushInfo = data.push;
|
||||
this.proxyInfo = data.proxy;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.resourceInfo{
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 12px
|
||||
}
|
||||
.el-progress__text {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,188 +0,0 @@
|
||||
<template>
|
||||
<div id="gbChannelSelect" v-loading="getChannelListLoading">
|
||||
<el-dialog
|
||||
title="添加国标通道"
|
||||
width="60%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
append-to-body
|
||||
@close="close()"
|
||||
>
|
||||
<div class="page-header" style="width: 100%">
|
||||
<div class="page-header-btn" style="width: 100%; text-align: left">
|
||||
搜索:
|
||||
<el-input @input="getChannelList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
在线状态:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getChannelList" v-model="online" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="在线" value="true"></el-option>
|
||||
<el-option label="离线" value="false"></el-option>
|
||||
</el-select>
|
||||
类型:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getChannelList" v-model="channelType" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option v-for="item in Object.values($channelTypeList)" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
<el-button size="mini" :loading="getChannelListLoading"
|
||||
@click="getChannelList()">刷新</el-button>
|
||||
<el-button type="primary" size="mini" style="float: right" @click="onSubmit">确 定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--通道列表-->
|
||||
<el-table size="small" ref="channelListTable" :data="channelList" :height="winHeight" style="width: 100%;"
|
||||
header-row-class-name="table-header" @selection-change="handleSelectionChange" >
|
||||
<el-table-column type="selection" width="55" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbName" label="名称" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbDeviceId" label="编号" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbManufacturer" label="厂家" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" effect="plain" type="success" :style="$channelTypeList[scope.row.dataType].style" >{{$channelTypeList[scope.row.dataType].name}}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.gbStatus === 'ON'">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="scope.row.gbStatus !== 'ON'">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr">
|
||||
<div style="text-align: left; line-height: 32px">
|
||||
<i class="el-icon-info"></i> 未找到通道,可在国标设备/通道中选择编辑按钮, 选择{{dataType === 'civilCode'?'行政区划':'父节点编码'}}
|
||||
</div>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[10, 25, 35, 50, 200, 1000, 50000]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
name: "gbChannelSelect",
|
||||
props: ['dataType', "selected"],
|
||||
computed: {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
channelList: [], //设备列表
|
||||
currentDevice: {}, //当前操作设备对象
|
||||
searchSrt: "",
|
||||
online: null,
|
||||
channelType: "",
|
||||
videoComponentList: [],
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
currentDeviceChannelsLenth: 0,
|
||||
winHeight: 580,
|
||||
currentPage: 1,
|
||||
count: 10,
|
||||
total: 0,
|
||||
getChannelListLoading: false,
|
||||
multipleSelection: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.getChannelList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getChannelList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getChannelList();
|
||||
},
|
||||
handleSelectionChange: function (val){
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
getChannelList: function () {
|
||||
this.getChannelListLoading = true;
|
||||
if (this.dataType === "civilCode") {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilcode/list`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
channelType: this.channelType,
|
||||
query: this.searchSrt,
|
||||
online: this.online,
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.channelList = res.data.data.list;
|
||||
}
|
||||
this.getChannelListLoading = false;
|
||||
}).catch( (error)=> {
|
||||
console.error(error);
|
||||
this.getChannelListLoading = false;
|
||||
});
|
||||
}else {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/list`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
channelType: this.channelType,
|
||||
online: this.online,
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.channelList = res.data.data.list;
|
||||
}
|
||||
this.getChannelListLoading = false;
|
||||
}).catch( (error)=> {
|
||||
console.error(error);
|
||||
this.getChannelListLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
openDialog: function (callback) {
|
||||
this.listChangeCallback = callback;
|
||||
this.showDialog = true;
|
||||
this.initData();
|
||||
},
|
||||
onSubmit: function () {
|
||||
if (this.listChangeCallback ) {
|
||||
this.listChangeCallback(this.multipleSelection)
|
||||
}
|
||||
this.showDialog = false;
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,153 +0,0 @@
|
||||
<template>
|
||||
<div id="addUser" v-loading="getDeviceListLoading">
|
||||
<el-dialog
|
||||
title="添加国标设备通道"
|
||||
width="60%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
append-to-body
|
||||
@close="close()"
|
||||
>
|
||||
<div class="page-header" style="width: 100%">
|
||||
<div class="page-header-btn" style="width: 100%; text-align: left">
|
||||
搜索:
|
||||
<el-input @input="getDeviceList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
在线状态:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getDeviceList" v-model="online" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="在线" value="true"></el-option>
|
||||
<el-option label="离线" value="false"></el-option>
|
||||
</el-select>
|
||||
<el-button size="mini" :loading="getDeviceListLoading"
|
||||
@click="getDeviceList()">刷新</el-button>
|
||||
<el-button type="primary" size="mini" style="float: right" @click="onSubmit">确 定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--设备列表-->
|
||||
<el-table size="medium" :data="deviceList" style="width: 100%;font-size: 12px;" :height="winHeight" header-row-class-name="table-header" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" label="名称" min-width="160">
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceId" label="设备编号" min-width="200" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="channelCount" label="通道数" min-width="120" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="manufacturer" label="厂家" min-width="120" >
|
||||
</el-table-column>
|
||||
<el-table-column label="地址" min-width="160" >
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag v-if="scope.row.hostAddress" size="medium">{{ scope.row.hostAddress }}</el-tag>
|
||||
<el-tag v-if="!scope.row.hostAddress" size="medium">未知</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="120">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.onLine">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="!scope.row.onLine">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[10, 25, 35, 50, 200, 1000, 50000]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "gbDeviceSelect",
|
||||
props: {},
|
||||
computed: {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
deviceList: [], //设备列表
|
||||
currentDevice: {}, //当前操作设备对象
|
||||
searchSrt: "",
|
||||
online: null,
|
||||
videoComponentList: [],
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
currentDeviceChannelsLenth: 0,
|
||||
winHeight: 580,
|
||||
currentPage: 1,
|
||||
count: 10,
|
||||
total: 0,
|
||||
getDeviceListLoading: false,
|
||||
multipleSelection: [],
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.getDeviceList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getDeviceList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getDeviceList();
|
||||
},
|
||||
handleSelectionChange: function (val){
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
getDeviceList: function () {
|
||||
this.getDeviceListLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/device/query/devices`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
status: this.online,
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.deviceList = res.data.data.list;
|
||||
}
|
||||
this.getDeviceListLoading = false;
|
||||
}).catch( (error)=> {
|
||||
console.error(error);
|
||||
this.getDeviceListLoading = false;
|
||||
});
|
||||
},
|
||||
openDialog: function (callback) {
|
||||
this.listChangeCallback = callback;
|
||||
this.showDialog = true;
|
||||
},
|
||||
onSubmit: function () {
|
||||
if (this.listChangeCallback ) {
|
||||
this.listChangeCallback(this.multipleSelection)
|
||||
}
|
||||
this.showDialog = false;
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,386 +0,0 @@
|
||||
<template>
|
||||
<div id="mediaServerEdit" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="媒体节点"
|
||||
:width="dialogWidth"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="formStep" style="margin-top: 1rem; margin-right: 20px;">
|
||||
<el-form v-if="currentStep == 1" ref="mediaServerForm" :rules="rules" :model="mediaServerForm" label-width="140px" >
|
||||
<el-form-item label="IP" prop="ip">
|
||||
<el-input v-model="mediaServerForm.ip" placeholder="媒体服务IP" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="HTTP端口" prop="httpPort">
|
||||
<el-input v-model="mediaServerForm.httpPort" placeholder="媒体服务HTTP端口" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SECRET" prop="secret">
|
||||
<el-input v-model="mediaServerForm.secret" placeholder="媒体服务SECRET" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="mediaServerForm.type" style="float: left; width: 100%" >
|
||||
<el-option key="zlm" label="ZLMediaKit" value="zlm"></el-option>
|
||||
<el-option key="abl" label="ABLMediaServer" value="abl"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" v-if="currentStep === 1 && serverCheck === 1" @click="next" >下一步</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
<el-button type="primary" @click="checkServer" >测试</el-button>
|
||||
<i v-if="serverCheck === 1" class="el-icon-success" style="color: #3caf36"></i>
|
||||
<i v-if="serverCheck === -1" class="el-icon-error" style="color: #c80000"></i>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form v-if="currentStep === 2 || currentStep === 3" ref="mediaServerForm1" :rules="rules" :model="mediaServerForm" label-width="140px" >
|
||||
<el-form-item label="IP" prop="ip">
|
||||
<el-input v-if="currentStep === 2" v-model="mediaServerForm.ip" disabled :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
<el-input v-if="currentStep === 3" v-model="mediaServerForm.ip" :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="HTTP端口" prop="httpPort">
|
||||
<el-input v-if="currentStep === 2" v-model="mediaServerForm.httpPort" disabled :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
<el-input v-if="currentStep === 3" v-model="mediaServerForm.httpPort" :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="HOOK IP" prop="ip">
|
||||
<el-input v-model="mediaServerForm.hookIp" placeholder="媒体服务HOOK_IP" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SDP IP" prop="ip">
|
||||
<el-input v-model="mediaServerForm.sdpIp" placeholder="媒体服务SDP_IP" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流IP" prop="ip">
|
||||
<el-input v-model="mediaServerForm.streamIp" placeholder="媒体服务流IP" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="HTTPS PORT" prop="httpSSlPort">
|
||||
<el-input v-model="mediaServerForm.httpSSlPort" placeholder="媒体服务HTTPS_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="RTSP PORT" prop="rtspPort">
|
||||
<el-input v-model="mediaServerForm.rtspPort" placeholder="媒体服务RTSP_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="RTSPS PORT" prop="rtspSSLPort">
|
||||
<el-input v-model="mediaServerForm.rtspSSLPort" placeholder="媒体服务RTSPS_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form v-if="currentStep === 2 || currentStep === 3" ref="mediaServerForm2" :rules="rules" :model="mediaServerForm" label-width="180px" >
|
||||
<el-form-item label="RTMP PORT" prop="rtmpPort">
|
||||
<el-input v-model="mediaServerForm.rtmpPort" placeholder="媒体服务RTMP_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="RTMPS PORT" prop="rtmpSSlPort">
|
||||
<el-input v-model="mediaServerForm.rtmpSSlPort" placeholder="媒体服务RTMPS_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="SECRET" prop="secret">
|
||||
<el-input v-if="currentStep === 2" v-model="mediaServerForm.secret" disabled :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
<el-input v-if="currentStep === 3" v-model="mediaServerForm.secret" :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="自动配置媒体服务" >
|
||||
<el-switch v-model="mediaServerForm.autoConfig" :disabled="mediaServerForm.defaultServer"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item label="收流端口模式" >
|
||||
<el-switch active-text="多端口" inactive-text="单端口" @change="portRangeChange" v-model="mediaServerForm.rtpEnable" :disabled="mediaServerForm.defaultServer"></el-switch>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item v-if="!mediaServerForm.rtpEnable" label="收流端口" prop="rtpProxyPort">
|
||||
<el-input v-model.number="mediaServerForm.rtpProxyPort" clearable :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="mediaServerForm.rtpEnable" label="收流端口" >
|
||||
<el-input v-model="rtpPortRange1" placeholder="起始" @change="portRangeChange" clearable style="width: 100px" prop="rtpPortRange1" :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
-
|
||||
<el-input v-model="rtpPortRange2" placeholder="终止" @change="portRangeChange" clearable style="width: 100px" prop="rtpPortRange2" :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="mediaServerForm.sendRtpEnable" label="发流端口" >
|
||||
<el-input v-model="sendRtpPortRange1" placeholder="起始" @change="portRangeChange" clearable style="width: 100px" prop="rtpPortRange1" :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
-
|
||||
<el-input v-model="sendRtpPortRange2" placeholder="终止" @change="portRangeChange" clearable style="width: 100px" prop="rtpPortRange2" :disabled="mediaServerForm.defaultServer"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="录像管理服务端口" prop="recordAssistPort">
|
||||
<el-input v-model.number="mediaServerForm.recordAssistPort" :disabled="mediaServerForm.defaultServer">
|
||||
<!-- <el-button v-if="mediaServerForm.recordAssistPort > 0" slot="append" type="primary" @click="checkRecordServer">测试</el-button>-->
|
||||
<el-button v-if="mediaServerForm.recordAssistPort > 0" class="el-icon-check" slot="append" type="primary" @click="checkRecordServer"></el-button>
|
||||
</el-input>
|
||||
<i v-if="recordServerCheck == 1" class="el-icon-success" style="color: #3caf36; position: absolute;top: 14px;"></i>
|
||||
<i v-if="recordServerCheck == 2" class="el-icon-loading" style="color: #3caf36; position: absolute;top: 14px;"></i>
|
||||
<i v-if="recordServerCheck === -1" class="el-icon-error" style="color: #c80000; position: absolute;top: 14px;"></i>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button v-if="!mediaServerForm.defaultServer" type="primary" @click="onSubmit" >提交</el-button>
|
||||
<el-button v-if="!mediaServerForm.defaultServer" @click="close">取消</el-button>
|
||||
<el-button v-if="mediaServerForm.defaultServer" @click="close">关闭</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MediaServer from './../service/MediaServer'
|
||||
|
||||
export default {
|
||||
name: "streamProxyEdit",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {
|
||||
this.setDialogWidth()
|
||||
},
|
||||
data() {
|
||||
const isValidIp = (rule, value, callback) => { // 校验IP是否符合规则
|
||||
var reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
|
||||
console.log(this.mediaServerForm.ip)
|
||||
if (!reg.test(this.mediaServerForm.ip)) {
|
||||
return callback(new Error('请输入有效的IP地址'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
return true
|
||||
}
|
||||
const isValidPort = (rule, value, callback) => { // 校验IP是否符合规则
|
||||
var reg = /^(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5]))$/
|
||||
if (!reg.test(this.mediaServerForm.httpPort)) {
|
||||
return callback(new Error('请输入有效的端口号'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
return true
|
||||
}
|
||||
return {
|
||||
dialogWidth: 0,
|
||||
defaultWidth: 1000,
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
dialogLoading: false,
|
||||
|
||||
currentStep: 1,
|
||||
platformList: [],
|
||||
mediaServer: new MediaServer(),
|
||||
serverCheck: 0,
|
||||
recordServerCheck: 0,
|
||||
mediaServerForm: {
|
||||
id: "",
|
||||
ip: "",
|
||||
autoConfig: true,
|
||||
hookIp: "",
|
||||
sdpIp: "",
|
||||
streamIp: "",
|
||||
secret: "",
|
||||
httpPort: "",
|
||||
httpSSlPort: "",
|
||||
recordAssistPort: "",
|
||||
rtmpPort: "",
|
||||
rtmpSSlPort: "",
|
||||
rtpEnable: false,
|
||||
rtpPortRange: "",
|
||||
sendRtpPortRange: "",
|
||||
rtpProxyPort: "",
|
||||
rtspPort: "",
|
||||
rtspSSLPort: "",
|
||||
type: "zlm",
|
||||
},
|
||||
rtpPortRange1:30000,
|
||||
rtpPortRange2:30500,
|
||||
|
||||
sendRtpPortRange1:50000,
|
||||
sendRtpPortRange2:60000,
|
||||
|
||||
rules: {
|
||||
ip: [{ required: true, validator: isValidIp, message: '请输入有效的IP地址', trigger: 'blur' }],
|
||||
httpPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
httpSSlPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
recordAssistPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
rtmpPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
rtmpSSlPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
rtpPortRange1: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
rtpPortRange2: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
rtpProxyPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
rtspPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
rtspSSLPort: [{ required: true, validator: isValidPort, message: '请输入有效的端口号', trigger: 'blur' }],
|
||||
secret: [{ required: true, message: "请输入secret", trigger: "blur" }],
|
||||
timeout_ms: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }],
|
||||
ffmpeg_cmd_key: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setDialogWidth() {
|
||||
let val = document.body.clientWidth
|
||||
if (val < this.defaultWidth) {
|
||||
this.dialogWidth = '100%'
|
||||
} else {
|
||||
this.dialogWidth = this.defaultWidth + 'px'
|
||||
}
|
||||
},
|
||||
openDialog: function (param, callback) {
|
||||
this.showDialog = true;
|
||||
this.listChangeCallback = callback;
|
||||
if (param != null) {
|
||||
this.mediaServerForm = param;
|
||||
this.currentStep = 3;
|
||||
if (param.rtpPortRange) {
|
||||
let rtpPortRange = this.mediaServerForm.rtpPortRange.split(",");
|
||||
let sendRtpPortRange = this.mediaServerForm.sendRtpPortRange.split(",");
|
||||
if (rtpPortRange.length > 0) {
|
||||
this.rtpPortRange1 = rtpPortRange[0]
|
||||
this.rtpPortRange2 = rtpPortRange[1]
|
||||
}
|
||||
if (sendRtpPortRange.length > 0) {
|
||||
this.sendRtpPortRange1 = sendRtpPortRange[0]
|
||||
this.sendRtpPortRange2 = sendRtpPortRange[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
checkServer: function() {
|
||||
let that = this;
|
||||
that.serverCheck = 0;
|
||||
that.mediaServer.checkServer(that.mediaServerForm, data =>{
|
||||
if (data.code === 0) {
|
||||
if (parseInt(that.mediaServerForm.httpPort) !== parseInt(data.data.httpPort)) {
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: '如果你正在使用docker部署你的媒体服务,请注意的端口映射。',
|
||||
type: 'warning',
|
||||
duration: 0
|
||||
});
|
||||
}
|
||||
let httpPort = that.mediaServerForm.httpPort;
|
||||
that.mediaServerForm = data.data;
|
||||
that.mediaServerForm.httpPort = httpPort;
|
||||
that.mediaServerForm.autoConfig = true;
|
||||
that.rtpPortRange1 = 30000
|
||||
that.rtpPortRange2 = 30500
|
||||
that.sendRtpPortRange1 = 50000
|
||||
that.sendRtpPortRange2 = 60000
|
||||
that.serverCheck = 1;
|
||||
}else {
|
||||
that.serverCheck = -1;
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
next: function (){
|
||||
this.currentStep = 2;
|
||||
this.defaultWidth = 900;
|
||||
this.setDialogWidth();
|
||||
},
|
||||
checkRecordServer: function (){
|
||||
let that = this;
|
||||
that.recordServerCheck = 2;
|
||||
if (that.mediaServerForm.recordAssistPort <= 0 || that.mediaServerForm.recordAssistPort > 65535 ) {
|
||||
that.recordServerCheck = -1;
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: "端口号应该在-65535之间",
|
||||
type: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
that.mediaServer.checkRecordServer(that.mediaServerForm, data =>{
|
||||
if (data.code === 0) {
|
||||
that.recordServerCheck = 1;
|
||||
}else {
|
||||
that.recordServerCheck = -1;
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
onSubmit: function () {
|
||||
this.dialogLoading = true;
|
||||
let that = this;
|
||||
that.mediaServer.addServer(this.mediaServerForm, data => {
|
||||
if (data.code === 0) {
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: "success",
|
||||
});
|
||||
if (this.listChangeCallback) this.listChangeCallback();
|
||||
that.close()
|
||||
}else {
|
||||
that.$message({
|
||||
showClose: true,
|
||||
message: data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.dialogLoading = false;
|
||||
this.mediaServerForm = {
|
||||
id: "",
|
||||
ip: "",
|
||||
autoConfig: true,
|
||||
hookIp: "",
|
||||
sdpIp: "",
|
||||
streamIp: "",
|
||||
secret: "",
|
||||
httpPort: "",
|
||||
httpSSlPort: "",
|
||||
recordAssistPort: "",
|
||||
rtmpPort: "",
|
||||
rtmpSSlPort: "",
|
||||
rtpEnable: false,
|
||||
rtpPortRange: "",
|
||||
sendRtpPortRange: "",
|
||||
rtpProxyPort: "",
|
||||
rtspPort: "",
|
||||
rtspSSLPort: "",
|
||||
};
|
||||
this.rtpPortRange1 = 30500;
|
||||
this.rtpPortRange2 = 30500;
|
||||
this.sendRtpPortRange1 = 50000;
|
||||
this.sendRtpPortRange2 = 60000;
|
||||
this.listChangeCallback = null
|
||||
this.currentStep = 1;
|
||||
},
|
||||
deviceGBIdExit: async function (deviceGbId) {
|
||||
var result = false;
|
||||
var that = this;
|
||||
await that.$axios({
|
||||
method: 'get',
|
||||
url:`/api/platform/exit/${deviceGbId}`
|
||||
}).then(function (res) {
|
||||
result = res.data;
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
checkExpires: function() {
|
||||
if (this.platform.enable && this.platform.expires == "0") {
|
||||
this.platform.expires = "300";
|
||||
}
|
||||
},
|
||||
portRangeChange: function() {
|
||||
if (this.mediaServerForm.rtpEnable) {
|
||||
this.mediaServerForm.rtpPortRange = this.rtpPortRange1 + "," + this.rtpPortRange2
|
||||
this.mediaServerForm.sendRtpPortRange = this.sendRtpPortRange1 + "," + this.sendRtpPortRange2
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,294 +0,0 @@
|
||||
<template>
|
||||
<div id="addStreamProxy" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="添加代理"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
|
||||
<el-form ref="streamProxy" :rules="rules" :model="proxyParam" label-width="140px" >
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select
|
||||
v-model="proxyParam.type"
|
||||
style="width: 100%"
|
||||
placeholder="请选择代理类型"
|
||||
>
|
||||
<el-option label="默认" value="default"></el-option>
|
||||
<el-option label="FFmpeg" value="ffmpeg"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="proxyParam.name" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流应用名" prop="app">
|
||||
<el-input v-model="proxyParam.app" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流ID" prop="stream">
|
||||
<el-input v-model="proxyParam.stream" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="拉流地址" prop="url" v-if="proxyParam.type=='default'">
|
||||
<el-input v-model="proxyParam.url" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="拉流地址" prop="srcUrl" v-if="proxyParam.type=='ffmpeg'">
|
||||
<el-input v-model="proxyParam.srcUrl" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="超时时间:毫秒" prop="timeoutMs" v-if="proxyParam.type=='ffmpeg'">
|
||||
<el-input v-model="proxyParam.timeoutMs" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="节点选择" prop="rtpType">
|
||||
<el-select
|
||||
v-model="proxyParam.mediaServerId"
|
||||
@change="mediaServerIdChange"
|
||||
style="width: 100%"
|
||||
placeholder="请选择拉流节点"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="FFmpeg命令模板" prop="ffmpegCmdKey" v-if="proxyParam.type=='ffmpeg'">
|
||||
<el-select
|
||||
v-model="proxyParam.ffmpegCmdKey"
|
||||
style="width: 100%"
|
||||
placeholder="请选择FFmpeg命令模板"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in Object.keys(ffmpegCmdList)"
|
||||
:key="item"
|
||||
:label="ffmpegCmdList[item]"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="国标编码" prop="gbId">
|
||||
<el-input v-model="proxyParam.gbId" placeholder="设置国标编码可推送到国标" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="拉流方式" prop="rtpType" v-if="proxyParam.type=='default'">
|
||||
<el-select
|
||||
v-model="proxyParam.rtpType"
|
||||
style="width: 100%"
|
||||
placeholder="请选择拉流方式"
|
||||
>
|
||||
<el-option label="TCP" value="0"></el-option>
|
||||
<el-option label="UDP" value="1"></el-option>
|
||||
<el-option label="组播" value="2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="无人观看" prop="rtpType" >
|
||||
<el-radio v-model="proxyParam.noneReader" label="0">不做处理</el-radio>
|
||||
<el-radio v-model="proxyParam.noneReader" label="1">停用</el-radio>
|
||||
<el-radio v-model="proxyParam.noneReader" label="2">移除</el-radio>
|
||||
<!-- <el-select-->
|
||||
<!-- @change="noneReaderHandler"-->
|
||||
<!-- v-model="proxyParam.noneReader"-->
|
||||
<!-- style="width: 100%"-->
|
||||
<!-- placeholder="请选择无人观看的处理方式"-->
|
||||
<!-- >-->
|
||||
<!-- <el-option label="不做处理" value="0"></el-option>-->
|
||||
<!-- <el-option label="停用" value="1"></el-option>-->
|
||||
<!-- <el-option label="移除" value="2"></el-option>-->
|
||||
<!-- </el-select>-->
|
||||
</el-form-item>
|
||||
<el-form-item label="其他选项">
|
||||
<div style="float: left;">
|
||||
<el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox>
|
||||
<el-checkbox label="开启音频" v-model="proxyParam.enableAudio" ></el-checkbox>
|
||||
<el-checkbox label="录制" v-model="proxyParam.enableMp4" ></el-checkbox>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit" :loading="dialogLoading" >{{onSubmit_text}}</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MediaServer from './../service/MediaServer'
|
||||
|
||||
export default {
|
||||
name: "streamProxyEdit",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
// var deviceGBIdRules = async (rule, value, callback) => {
|
||||
// console.log(value);
|
||||
// if (value === "") {
|
||||
// callback(new Error("请输入设备国标编号"));
|
||||
// } else {
|
||||
// var exit = await this.deviceGBIdExit(value);
|
||||
// console.log(exit);
|
||||
// console.log(exit == "true");
|
||||
// console.log(exit === "true");
|
||||
// if (exit) {
|
||||
// callback(new Error("设备国标编号已存在"));
|
||||
// } else {
|
||||
// callback();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
return {
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
dialogLoading: false,
|
||||
onSubmit_text: "保存",
|
||||
platformList: [],
|
||||
mediaServer: new MediaServer(),
|
||||
proxyParam: {
|
||||
name: null,
|
||||
type: "default",
|
||||
app: null,
|
||||
stream: null,
|
||||
url: "",
|
||||
srcUrl: null,
|
||||
timeoutMs: null,
|
||||
ffmpegCmdKey: null,
|
||||
gbId: null,
|
||||
rtpType: null,
|
||||
enable: true,
|
||||
enableAudio: true,
|
||||
enableMp4: false,
|
||||
noneReader: null,
|
||||
enableRemoveNoneReader: false,
|
||||
enableDisableNoneReader: false,
|
||||
platformGbId: null,
|
||||
mediaServerId: null,
|
||||
},
|
||||
mediaServerList:{},
|
||||
ffmpegCmdList:{},
|
||||
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
||||
app: [{ required: true, message: "请输入应用名", trigger: "blur" }],
|
||||
stream: [{ required: true, message: "请输入流ID", trigger: "blur" }],
|
||||
url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }],
|
||||
srcUrl: [{ required: true, message: "请输入要代理的流", trigger: "blur" }],
|
||||
timeoutMs: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }],
|
||||
ffmpegCmdKey: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (proxyParam, callback) {
|
||||
this.showDialog = true;
|
||||
this.listChangeCallback = callback;
|
||||
if (proxyParam != null) {
|
||||
this.proxyParam = proxyParam;
|
||||
this.proxyParam.noneReader = null;
|
||||
}
|
||||
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/platform/query/10000/1`
|
||||
}).then(function (res) {
|
||||
that.platformList = res.data.data.list;
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
this.mediaServer.getOnlineMediaServerList((data)=>{
|
||||
this.mediaServerList = data.data;
|
||||
this.proxyParam.mediaServerId = this.mediaServerList[0].id
|
||||
this.mediaServerIdChange()
|
||||
})
|
||||
},
|
||||
mediaServerIdChange:function (){
|
||||
let that = this;
|
||||
if (that.proxyParam.mediaServerId !== "auto"){
|
||||
that.$axios({
|
||||
method: 'get',
|
||||
url:`/api/proxy/ffmpeg_cmd/list`,
|
||||
params: {
|
||||
mediaServerId: that.proxyParam.mediaServerId
|
||||
}
|
||||
}).then(function (res) {
|
||||
that.ffmpegCmdList = res.data.data;
|
||||
that.proxyParam.ffmpegCmdKey = Object.keys(res.data.data)[0];
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
onSubmit: function () {
|
||||
this.dialogLoading = true;
|
||||
this.noneReaderHandler();
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url:`/api/proxy/save`,
|
||||
data: this.proxyParam
|
||||
}).then((res)=> {
|
||||
this.dialogLoading = false;
|
||||
if (typeof (res.data.code) != "undefined" && res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "success",
|
||||
});
|
||||
this.showDialog = false;
|
||||
if (this.listChangeCallback != null) {
|
||||
this.listChangeCallback();
|
||||
this.dialogLoading = false;
|
||||
}
|
||||
}
|
||||
}).catch((error) =>{
|
||||
console.log(error);
|
||||
this.dialogLoading = false;
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.dialogLoading = false;
|
||||
this.$refs.streamProxy.resetFields();
|
||||
},
|
||||
deviceGBIdExit: async function (deviceGbId) {
|
||||
var result = false;
|
||||
var that = this;
|
||||
await that.$axios({
|
||||
method: 'get',
|
||||
url:`/api/platform/exit/${deviceGbId}`
|
||||
}).then(function (res) {
|
||||
result = res.data;
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
checkExpires: function() {
|
||||
if (this.platform.enable && this.platform.expires == "0") {
|
||||
this.platform.expires = "300";
|
||||
}
|
||||
},
|
||||
noneReaderHandler: function() {
|
||||
if (this.proxyParam.noneReader === null || this.proxyParam.noneReader === "0") {
|
||||
this.proxyParam.enableDisableNoneReader = false;
|
||||
this.proxyParam.enableRemoveNoneReader = false;
|
||||
}else if (this.proxyParam.noneReader === "1"){
|
||||
this.proxyParam.enableDisableNoneReader = true;
|
||||
this.proxyParam.enableRemoveNoneReader = false;
|
||||
}else if (this.proxyParam.noneReader ==="2"){
|
||||
this.proxyParam.enableDisableNoneReader = false;
|
||||
this.proxyParam.enableRemoveNoneReader = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,118 +0,0 @@
|
||||
<template>
|
||||
<div id="SyncChannelProgress" v-loading="isLoging">
|
||||
<el-dialog
|
||||
width="240px"
|
||||
top="13%"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
:show-close="true"
|
||||
@close="close()"
|
||||
style="text-align: center">
|
||||
<el-progress type="circle" :percentage="percentage" :status="syncStatus"></el-progress>
|
||||
<div style="text-align: center">
|
||||
{{msg}}
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "SyncChannelProgress",
|
||||
computed: {},
|
||||
props: ['platformId'],
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
endCallBack: null,
|
||||
syncStatus: null,
|
||||
percentage: 0,
|
||||
total: 0,
|
||||
current: 0,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
syncFlag: false,
|
||||
deviceId: null,
|
||||
timmer: null,
|
||||
msg: "正在同步",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (deviceId, endCallBack) {
|
||||
console.log("deviceId: " + deviceId)
|
||||
this.deviceId = deviceId;
|
||||
this.showDialog = true;
|
||||
this.msg = "";
|
||||
this.percentage= 0;
|
||||
this.total= 0;
|
||||
this.current= 0;
|
||||
this.syncFlag= false;
|
||||
this.syncStatus = null;
|
||||
this.endCallBack = endCallBack;
|
||||
this.getProgress()
|
||||
},
|
||||
getProgress(){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/device/query/${this.deviceId}/sync_status/`,
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
|
||||
if (res.data.data != null) {
|
||||
if (res.data.data.syncIng) {
|
||||
if (res.data.data.total === 0) {
|
||||
this.msg = `等待同步中`;
|
||||
this.timmer = setTimeout(this.getProgress, 300)
|
||||
}else {
|
||||
this.syncFlag = true;
|
||||
this.total = res.data.data.total;
|
||||
this.current = res.data.data.current;
|
||||
this.percentage = Math.floor(Number(res.data.data.current)/Number(res.data.data.total)* 10000)/100;
|
||||
this.msg = `同步中...[${res.data.data.current}/${res.data.data.total}]`;
|
||||
this.timmer = setTimeout(this.getProgress, 300)
|
||||
}
|
||||
}else {
|
||||
if (res.data.data.errorMsg){
|
||||
this.msg = res.data.data.errorMsg;
|
||||
this.syncStatus = "exception"
|
||||
}else {
|
||||
this.syncStatus = "success"
|
||||
this.percentage = 100;
|
||||
this.msg = '同步成功';
|
||||
setTimeout(()=>{
|
||||
this.showDialog = false;
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
}else {
|
||||
this.msg = res.data.msg;
|
||||
this.timmer = setTimeout(this.getProgress, 300)
|
||||
}
|
||||
}else {
|
||||
if (this.syncFlag) {
|
||||
this.syncStatus = "success"
|
||||
this.percentage = 100;
|
||||
this.msg = '同步成功';
|
||||
}else {
|
||||
this.syncStatus = "error"
|
||||
this.msg = res.data.msg;
|
||||
}
|
||||
}
|
||||
}).catch((error) =>{
|
||||
console.log(error);
|
||||
this.syncStatus = "error"
|
||||
this.msg = error.response.data.msg;
|
||||
});
|
||||
},
|
||||
close: function (){
|
||||
if (this.endCallBack) {
|
||||
this.endCallBack()
|
||||
}
|
||||
window.clearTimeout(this.timmer)
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,257 +0,0 @@
|
||||
<template>
|
||||
<div id="gbChannelSelect" v-loading="getChannelListLoading">
|
||||
<el-dialog
|
||||
title="异常挂载通道"
|
||||
width="60%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
append-to-body
|
||||
@close="close()"
|
||||
>
|
||||
<div class="page-header" style="width: 100%">
|
||||
<div class="page-header-btn" style="width: 100%; text-align: left">
|
||||
搜索:
|
||||
<el-input @input="getChannelList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
在线状态:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getChannelList" v-model="online" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="在线" value="true"></el-option>
|
||||
<el-option label="离线" value="false"></el-option>
|
||||
</el-select>
|
||||
类型:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getChannelList" v-model="channelType" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option v-for="item in Object.values($channelTypeList)" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
<el-button size="mini" type="primary" :loading="getChannelListLoading" :disabled="multipleSelection.length ===0"
|
||||
@click="clearUnusualRegion()">清除</el-button>
|
||||
<el-button size="mini" :loading="getChannelListLoading"
|
||||
@click="clearUnusualRegion(true)">全部清除</el-button>
|
||||
<el-button size="mini" :loading="getChannelListLoading"
|
||||
@click="getChannelList()">刷新</el-button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--通道列表-->
|
||||
<el-table size="small" ref="channelListTable" :data="channelList" :height="winHeight" style="width: 100%;"
|
||||
header-row-class-name="table-header" @selection-change="handleSelectionChange" >
|
||||
<el-table-column type="selection" width="55" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbName" label="名称" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbDeviceId" label="编号" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbManufacturer" label="厂家" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbCivilCode" label="行政区划" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" effect="plain" type="success" :style="$channelTypeList[scope.row.dataType].style">{{$channelTypeList[scope.row.dataType].name}}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.gbStatus === 'ON'">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="scope.row.gbStatus !== 'ON'">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr">
|
||||
<div style="text-align: left; line-height: 32px">
|
||||
<i class="el-icon-info"></i> 清除后通道可正常添加到分组节点。
|
||||
</div>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[10, 25, 35, 50, 200, 1000, 50000]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
name: "UnusualGroupChannelSelect",
|
||||
props: [],
|
||||
computed: {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
channelList: [], //设备列表
|
||||
searchSrt: "",
|
||||
online: null,
|
||||
channelType: "",
|
||||
winHeight: 580,
|
||||
currentPage: 1,
|
||||
count: 10,
|
||||
total: 0,
|
||||
getChannelListLoading: false,
|
||||
multipleSelection: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.getChannelList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getChannelList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getChannelList();
|
||||
},
|
||||
handleSelectionChange: function (val){
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
getChannelList: function () {
|
||||
this.getChannelListLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/parent/unusual/list`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
channelType: this.channelType,
|
||||
query: this.searchSrt,
|
||||
online: this.online,
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
for (let i = 0; i < res.data.data.list.length; i++) {
|
||||
res.data.data.list[i]["addRegionLoading"] = false
|
||||
}
|
||||
this.channelList = res.data.data.list;
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
console.error(error);
|
||||
}).finally(()=>{
|
||||
this.getChannelListLoading = false;
|
||||
})
|
||||
|
||||
},
|
||||
openDialog: function () {
|
||||
this.showDialog = true;
|
||||
this.initData();
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
clearUnusualRegion: function (all) {
|
||||
let channels = null
|
||||
if (all || this.multipleSelection.length > 0 ) {
|
||||
channels = []
|
||||
for (let i = 0; i < this.multipleSelection.length; i++) {
|
||||
channels.push(this.multipleSelection[i].gbId)
|
||||
}
|
||||
}
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/parent/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channels
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "清除成功"
|
||||
})
|
||||
this.getChannelList()
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
}).finally(()=>{
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
},
|
||||
addRegion: function (row) {
|
||||
row.addRegionLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/region/description`,
|
||||
params: {
|
||||
civilCode: row.gbCivilCode,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$confirm(`确定添加: ${res.data.data}`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/region/addByCivilCode`,
|
||||
params: {
|
||||
civilCode: row.gbCivilCode,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "添加成功"
|
||||
})
|
||||
this.initData()
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
}).finally(()=>{
|
||||
row.addRegionLoading = false;
|
||||
})
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,270 +0,0 @@
|
||||
<template>
|
||||
<div id="gbChannelSelect" v-loading="getChannelListLoading">
|
||||
<el-dialog
|
||||
title="异常挂载通道"
|
||||
width="60%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
append-to-body
|
||||
@close="close()"
|
||||
>
|
||||
<div class="page-header" style="width: 100%">
|
||||
<div class="page-header-btn" style="width: 100%; text-align: left">
|
||||
搜索:
|
||||
<el-input @input="getChannelList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
在线状态:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getChannelList" v-model="online" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="在线" value="true"></el-option>
|
||||
<el-option label="离线" value="false"></el-option>
|
||||
</el-select>
|
||||
类型:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="getChannelList" v-model="channelType" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option v-for="item in Object.values($channelTypeList)" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
<el-button size="mini" type="primary" :loading="getChannelListLoading" :disabled="multipleSelection.length ===0"
|
||||
@click="clearUnusualRegion()">清除</el-button>
|
||||
<el-button size="mini" :loading="getChannelListLoading"
|
||||
@click="clearUnusualRegion(true)">全部清除</el-button>
|
||||
<el-button size="mini" :loading="getChannelListLoading"
|
||||
@click="getChannelList()">刷新</el-button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!--通道列表-->
|
||||
<el-table size="small" ref="channelListTable" :data="channelList" :height="winHeight" style="width: 100%;"
|
||||
header-row-class-name="table-header" @selection-change="handleSelectionChange" >
|
||||
<el-table-column type="selection" width="55" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbName" label="名称" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbDeviceId" label="编号" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbManufacturer" label="厂家" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbCivilCode" label="行政区划" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" effect="plain" type="success" :style="$channelTypeList[scope.row.dataType].style">{{$channelTypeList[scope.row.dataType].name}}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.gbStatus === 'ON'">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="scope.row.gbStatus !== 'ON'">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="140" fixed="right">
|
||||
<template v-slot:default="scope">
|
||||
<el-button
|
||||
size="medium"
|
||||
type="text"
|
||||
icon="el-icon-plus"
|
||||
:loading="scope.row.addRegionLoading"
|
||||
@click="addRegion(scope.row)"
|
||||
>
|
||||
添加
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr">
|
||||
<div style="text-align: left; line-height: 32px">
|
||||
<i class="el-icon-info"></i> 清除后通道可正常添加到行政区划,添加可以自动添加对应的行政区划节点。
|
||||
</div>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[10, 25, 35, 50, 200, 1000, 50000]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
export default {
|
||||
name: "UnusualRegionChannelSelect",
|
||||
props: [],
|
||||
computed: {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
channelList: [], //设备列表
|
||||
searchSrt: "",
|
||||
online: null,
|
||||
channelType: "",
|
||||
winHeight: 580,
|
||||
currentPage: 1,
|
||||
count: 10,
|
||||
total: 0,
|
||||
getChannelListLoading: false,
|
||||
multipleSelection: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.getChannelList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getChannelList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getChannelList();
|
||||
},
|
||||
handleSelectionChange: function (val){
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
getChannelList: function () {
|
||||
this.getChannelListLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/common/channel/civilCode/unusual/list`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
channelType: this.channelType,
|
||||
query: this.searchSrt,
|
||||
online: this.online,
|
||||
}
|
||||
}).then( (res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
for (let i = 0; i < res.data.data.list.length; i++) {
|
||||
res.data.data.list[i]["addRegionLoading"] = false
|
||||
}
|
||||
this.channelList = res.data.data.list;
|
||||
}
|
||||
}).catch( (error)=> {
|
||||
console.error(error);
|
||||
}).finally(()=>{
|
||||
this.getChannelListLoading = false;
|
||||
})
|
||||
|
||||
},
|
||||
openDialog: function () {
|
||||
this.showDialog = true;
|
||||
this.initData();
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
clearUnusualRegion: function (all) {
|
||||
let channels = null
|
||||
if (all || this.multipleSelection.length > 0 ) {
|
||||
channels = []
|
||||
for (let i = 0; i < this.multipleSelection.length; i++) {
|
||||
channels.push(this.multipleSelection[i].gbId)
|
||||
}
|
||||
}
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/common/channel/civilCode/unusual/clear`,
|
||||
data: {
|
||||
all: all,
|
||||
channelIds: channels
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "清除成功"
|
||||
})
|
||||
this.getChannelList()
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
}).finally(()=>{
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
},
|
||||
addRegion: function (row) {
|
||||
row.addRegionLoading = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/region/description`,
|
||||
params: {
|
||||
civilCode: row.gbCivilCode,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$confirm(`确定添加: ${res.data.data}`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/region/addByCivilCode`,
|
||||
params: {
|
||||
civilCode: row.gbCivilCode,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "添加成功"
|
||||
})
|
||||
this.initData()
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}).catch(() => {
|
||||
|
||||
});
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
}).finally(()=>{
|
||||
row.addRegionLoading = false;
|
||||
})
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@ -1,154 +0,0 @@
|
||||
<template>
|
||||
<div id="addUser" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="添加用户"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-right: 20px;">
|
||||
<el-form ref="passwordForm" :rules="rules" status-icon label-width="80px">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="username" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户类型" prop="roleId" >
|
||||
<el-select v-model="roleId" placeholder="请选择" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="password" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<el-input v-model="confirmPassword" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "addUser",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getAllRole();
|
||||
},
|
||||
data() {
|
||||
let validatePass1 = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入新密码'));
|
||||
} else {
|
||||
if (this.confirmPassword !== '') {
|
||||
this.$refs.passwordForm.validateField('confirmPassword');
|
||||
}
|
||||
callback();
|
||||
}
|
||||
};
|
||||
let validatePass2 = (rule, value, callback) => {
|
||||
if (this.confirmPassword === '') {
|
||||
callback(new Error('请再次输入密码'));
|
||||
} else if (this.confirmPassword !== this.password) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
value:"",
|
||||
options: [],
|
||||
loading: false,
|
||||
username: null,
|
||||
password: null,
|
||||
roleId: null,
|
||||
confirmPassword: null,
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
rules: {
|
||||
newPassword: [{required: true, validator: validatePass1, trigger: "blur"}, {
|
||||
pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/,
|
||||
message: "密码长度在8-20位之间,由字母+数字+特殊字符组成",
|
||||
},],
|
||||
confirmPassword: [{required: true, validator: validatePass2, trigger: "blur"}],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (callback) {
|
||||
this.listChangeCallback = callback;
|
||||
this.showDialog = true;
|
||||
},
|
||||
onSubmit: function () {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/user/add",
|
||||
params: {
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
roleId: this.roleId
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '添加成功',
|
||||
type: 'success',
|
||||
|
||||
});
|
||||
this.showDialog = false;
|
||||
this.listChangeCallback()
|
||||
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.password = null;
|
||||
this.confirmPassword = null;
|
||||
this.username = null;
|
||||
this.roleId = null;
|
||||
},
|
||||
getAllRole:function () {
|
||||
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/role/all"
|
||||
}).then((res) => {
|
||||
this.loading = true;
|
||||
if (res.data.code === 0) {
|
||||
this.options=res.data.data
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,139 +0,0 @@
|
||||
<template>
|
||||
<div id="addUserApiKey" v-loading="isLoading">
|
||||
<el-dialog
|
||||
title="添加ApiKey"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-right: 20px;">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" status-icon label-width="80px">
|
||||
<el-form-item label="应用名" prop="app">
|
||||
<el-input
|
||||
v-model="form.app"
|
||||
property="app"
|
||||
autocomplete="off"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="启用状态" prop="enable" style="text-align: left">
|
||||
<el-switch
|
||||
v-model="form.enable"
|
||||
property="enable"
|
||||
active-text="启用"
|
||||
inactive-text="停用"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="过期时间" prop="expiresAt" style="text-align: left">
|
||||
<el-date-picker v-model="form.expiresAt"
|
||||
style="width: 100%"
|
||||
property="expiresAt"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="选择过期时间"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注信息" prop="remark">
|
||||
<el-input v-model="form.remark"
|
||||
type="textarea"
|
||||
property="remark"
|
||||
autocomplete="off"
|
||||
:autosize="{ minRows: 5}"
|
||||
maxlength="255"
|
||||
show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'addUserApiKey',
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userId: null,
|
||||
form: {
|
||||
app: null,
|
||||
enable: true,
|
||||
expiresAt: null,
|
||||
remark: null
|
||||
},
|
||||
rules: {
|
||||
app: [{required: true, trigger: 'blur', message: '应用名不能为空'}]
|
||||
},
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
resetForm() {
|
||||
this.form = {
|
||||
app: null,
|
||||
enable: true,
|
||||
expiresAt: null,
|
||||
remark: null
|
||||
}
|
||||
},
|
||||
openDialog(userId, callback) {
|
||||
this.resetForm()
|
||||
this.userId = userId
|
||||
this.listChangeCallback = callback
|
||||
this.showDialog = true
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: '/api/userApiKey/add',
|
||||
params: {
|
||||
userId: this.userId,
|
||||
app: this.form.app,
|
||||
enable: this.form.enable,
|
||||
expiresAt: this.form.expiresAt,
|
||||
remark: this.form.remark,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '添加成功',
|
||||
type: 'success'
|
||||
});
|
||||
this.showDialog = false
|
||||
if (this.listChangeCallback) {
|
||||
this.listChangeCallback()
|
||||
}
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
close() {
|
||||
this.showDialog = false
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,158 +0,0 @@
|
||||
<template>
|
||||
<div id="catalogEdit" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="通道共享"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
|
||||
<el-form ref="form" :rules="rules" :model="form" label-width="140px" >
|
||||
<el-form-item label="节点编号" prop="id" >
|
||||
<el-input v-model="form.id" :disabled="isEdit" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="节点名称" prop="name">
|
||||
<el-input v-model="form.name" clearable></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit" >确认</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "catalogEdit",
|
||||
computed: {},
|
||||
props: ['platformId', 'platformDeviceId'],
|
||||
created() {},
|
||||
data() {
|
||||
let checkId = (rule, value, callback) => {
|
||||
console.log("checkId")
|
||||
console.log(rule)
|
||||
console.log(value)
|
||||
console.log(value.length)
|
||||
console.log(this.level)
|
||||
if (!value) {
|
||||
return callback(new Error('编号不能为空'));
|
||||
}
|
||||
if (value.trim().length <= 8) {
|
||||
if (value.trim().length%2 !== 0) {
|
||||
return callback(new Error('行政区划编号必须为2/4/6/8位'));
|
||||
}
|
||||
if (this.form.parentId !== this.platformDeviceId && this.form.parentId.length >= value.trim().length) {
|
||||
if (this.form.parentId.length === 20) {
|
||||
return callback(new Error('业务分组/虚拟组织下不可创建行政区划'));
|
||||
}else {
|
||||
return callback(new Error('行政区划编号长度应该每次两位递增'));
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if (value.trim().length !== 20) {
|
||||
return callback(new Error('编号必须为2/4/6/8位的行政区划或20位的虚拟组织/业务分组'));
|
||||
}
|
||||
let catalogType = value.substring(10, 13);
|
||||
console.log(catalogType)
|
||||
if (catalogType !== "215" && catalogType !== "216") {
|
||||
return callback(new Error('编号错误,业务分组11-13位为215,虚拟组织11-13位为216'));
|
||||
}
|
||||
if (catalogType === "216") {
|
||||
|
||||
if (this.form.parentId !== this.platformDeviceId){
|
||||
if (this.form.parentId.length <= 8) {
|
||||
return callback(new Error('编号错误,建立虚拟组织前必须先建立业务分组(11-13位为215)'));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (catalogType === "215") {
|
||||
if (this.form.parentId.length === "215") {
|
||||
return callback(new Error('编号错误,业务分组下只能建立虚拟组织(11-13位为216)'));
|
||||
}
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
return {
|
||||
submitCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
isEdit: false,
|
||||
level: 0,
|
||||
form: {
|
||||
id: null,
|
||||
name: null,
|
||||
platformId: null,
|
||||
parentId: null,
|
||||
},
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
||||
id: [{ required: true, trigger: "blur",validator: checkId }]
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (isEdit, id, name, parentId, level, callback) {
|
||||
console.log("parentId: " + parentId)
|
||||
console.log(this.form)
|
||||
this.isEdit = isEdit;
|
||||
this.form.id = id;
|
||||
this.form.name = name;
|
||||
this.form.platformId = this.platformId;
|
||||
this.form.parentId = parentId;
|
||||
this.showDialog = true;
|
||||
this.submitCallback = callback;
|
||||
this.level = level;
|
||||
},
|
||||
onSubmit: function () {
|
||||
this.$refs["form"].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$axios({
|
||||
method:"post",
|
||||
url:`/api/platform/catalog/${!this.isEdit? "add":"edit"}`,
|
||||
data: this.form
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
if (this.submitCallback)this.submitCallback(this.form)
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
this.close();
|
||||
})
|
||||
.catch((error)=> {
|
||||
console.log(error);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.isEdit = false;
|
||||
this.form.id = null;
|
||||
this.form.name = null;
|
||||
this.form.platformId = null;
|
||||
this.form.parentId = null;
|
||||
this.callback = null;
|
||||
this.showDialog = false;
|
||||
console.log(this.form)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,132 +0,0 @@
|
||||
<template>
|
||||
<div id="changePassword" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="修改密码"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-right: 20px;">
|
||||
<el-form ref="passwordForm" :rules="rules" status-icon label-width="80px">
|
||||
<el-form-item label="旧密码" prop="oldPassword" >
|
||||
<el-input v-model="oldPassword" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="newPassword" >
|
||||
<el-input v-model="newPassword" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<el-input v-model="confirmPassword" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import crypto from 'crypto'
|
||||
import userService from "../service/UserService";
|
||||
export default {
|
||||
name: "changePassword",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
let validatePass0 = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入旧密码'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
let validatePass1 = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入新密码'));
|
||||
} else {
|
||||
if (this.confirmPassword !== '') {
|
||||
this.$refs.passwordForm.validateField('confirmPassword');
|
||||
}
|
||||
callback();
|
||||
}
|
||||
};
|
||||
let validatePass2 = (rule, value, callback) => {
|
||||
if (this.confirmPassword === '') {
|
||||
callback(new Error('请再次输入密码'));
|
||||
} else if (this.confirmPassword !== this.newPassword) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
oldPassword: null,
|
||||
newPassword: null,
|
||||
confirmPassword: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
rules: {
|
||||
oldPassword: [{ required: true, validator: validatePass0, trigger: "blur" }],
|
||||
newPassword: [{ required: true, validator: validatePass1, trigger: "blur" }, {
|
||||
pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/,
|
||||
message: "密码长度在8-20位之间,由字母+数字+特殊字符组成",
|
||||
},],
|
||||
confirmPassword: [{ required: true, validator: validatePass2, trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function () {
|
||||
this.showDialog = true;
|
||||
},
|
||||
onSubmit: function () {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url:"/api/user/changePassword",
|
||||
params: {
|
||||
oldPassword: crypto.createHash('md5').update(this.oldPassword, "utf8").digest('hex'),
|
||||
password: this.newPassword
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '修改成功,请重新登录',
|
||||
type: 'success'
|
||||
});
|
||||
this.showDialog = false;
|
||||
setTimeout(()=>{
|
||||
// 删除cookie,回到登录页面
|
||||
userService.clearUserInfo();
|
||||
this.$router.push('/login');
|
||||
this.sseSource.close();
|
||||
},800)
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '修改密码失败,是否已登录(接口鉴权关闭无法修改密码)',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
console.error(error)
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.oldPassword = null;
|
||||
this.newPassword = null;
|
||||
this.confirmPassword = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,121 +0,0 @@
|
||||
<template>
|
||||
<div id="changePassword" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="修改密码"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-right: 20px;">
|
||||
<el-form ref="passwordForm" :rules="rules" status-icon label-width="80px">
|
||||
<el-form-item label="新密码" prop="newPassword" >
|
||||
<el-input v-model="newPassword" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<el-input v-model="confirmPassword" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "changePasswordForAdmin",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
let validatePass1 = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入新密码'));
|
||||
} else {
|
||||
if (this.confirmPassword !== '') {
|
||||
this.$refs.passwordForm.validateField('confirmPassword');
|
||||
}
|
||||
callback();
|
||||
}
|
||||
};
|
||||
let validatePass2 = (rule, value, callback) => {
|
||||
if (this.confirmPassword === '') {
|
||||
callback(new Error('请再次输入密码'));
|
||||
} else if (this.confirmPassword !== this.newPassword) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
newPassword: null,
|
||||
confirmPassword: null,
|
||||
userId: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
listChangeCallback: null,
|
||||
form: {},
|
||||
rules: {
|
||||
newPassword: [{ required: true, validator: validatePass1, trigger: "blur" }, {
|
||||
pattern: /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[~!@#$%^&*()_+`\-={}:";'<>?,.\/]).{8,20}$/,
|
||||
message: "密码长度在8-20位之间,由字母+数字+特殊字符组成",
|
||||
},],
|
||||
confirmPassword: [{ required: true, validator: validatePass2, trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (row, callback) {
|
||||
console.log(row)
|
||||
this.showDialog = true;
|
||||
this.listChangeCallback = callback;
|
||||
if (row != null) {
|
||||
this.form = row;
|
||||
}
|
||||
},
|
||||
onSubmit: function () {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url:"/api/user/changePasswordForAdmin",
|
||||
params: {
|
||||
password: this.newPassword,
|
||||
userId: this.form.id,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '修改成功',
|
||||
type: 'success'
|
||||
});
|
||||
this.showDialog = false;
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '修改密码失败,是否已登录(接口鉴权关闭无法修改密码)',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
console.error(error)
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.newPassword = null;
|
||||
this.confirmPassword = null;
|
||||
this.userId=null;
|
||||
this.adminId=null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,101 +0,0 @@
|
||||
<template>
|
||||
<div id="changepushKey" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="修改pushKey"
|
||||
width="42%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-right: 18px;">
|
||||
<el-form ref="pushKeyForm" :rules="rules" status-icon label-width="86px">
|
||||
<el-form-item label="新pushKey" prop="newPushKey" >
|
||||
<el-input v-model="newPushKey" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "changePushKey",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
let validatePass1 = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入新pushKey'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
newPushKey: null,
|
||||
confirmpushKey: null,
|
||||
userId: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
listChangeCallback: null,
|
||||
form: {},
|
||||
rules: {
|
||||
newpushKey: [{ required: true, validator: validatePass1, trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (row, callback) {
|
||||
console.log(row)
|
||||
this.showDialog = true;
|
||||
this.listChangeCallback = callback;
|
||||
if (row != null) {
|
||||
this.form = row;
|
||||
}
|
||||
},
|
||||
onSubmit: function () {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url:"/api/user/changePushKey",
|
||||
params: {
|
||||
pushKey: this.newPushKey,
|
||||
userId: this.form.id,
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '修改成功',
|
||||
type: 'success'
|
||||
});
|
||||
this.showDialog = false;
|
||||
this.listChangeCallback();
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '修改pushKey失败,是否已登录(接口鉴权关闭无法修改pushKey)',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error)=> {
|
||||
console.error(error)
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.newpushKey = null;
|
||||
this.userId=null;
|
||||
this.adminId=null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,364 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="生成国标编码"
|
||||
width="65rem"
|
||||
top="2rem"
|
||||
center
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showVideoDialog"
|
||||
:destroy-on-close="false"
|
||||
>
|
||||
<el-tabs v-model="activeKey" style="padding: 0 1rem; margin: auto 0" @tab-click="getRegionList">
|
||||
<el-tab-pane name="0" >
|
||||
<div slot="label" >
|
||||
<div class="show-code-item">{{ allVal[0].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[0].meaning }}</div>
|
||||
</div>
|
||||
<el-radio-group v-model="allVal[0].val" >
|
||||
<el-radio v-for="item in regionList" :key="item.deviceId" :label="item.deviceId" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.deviceId }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="1">
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[1].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[1].meaning }}</div>
|
||||
</div>
|
||||
<el-radio-group v-model="allVal[1].val" :disabled="allVal[1].lock">
|
||||
<el-radio v-for="item in regionList" :key="item.deviceId" :label="item.deviceId.substring(2)" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.deviceId.substring(2) }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2">
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[2].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[2].meaning }}</div>
|
||||
</div>
|
||||
<el-radio-group v-model="allVal[2].val" :disabled="allVal[2].lock">
|
||||
<el-radio v-for="item in regionList" :key="item.deviceId" :label="item.deviceId.substring(4)" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.deviceId.substring(4) }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="3">
|
||||
请手动输入基层接入单位编码,两位数字
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[3].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[3].meaning }}</div>
|
||||
</div>
|
||||
<el-input
|
||||
type="text"
|
||||
placeholder="请输入内容"
|
||||
v-model="allVal[3].val"
|
||||
maxlength="2"
|
||||
:disabled="allVal[3].lock"
|
||||
show-word-limit
|
||||
>
|
||||
</el-input>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="4">
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[4].val }}</div>
|
||||
<div style="text-align: center; ">{{ allVal[4].meaning }}</div>
|
||||
</div>
|
||||
<el-radio-group v-model="allVal[4].val" :disabled="allVal[4].lock">
|
||||
<el-radio v-for="item in industryCodeTypeList" :key="item.code" :label="item.code" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.code }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="5">
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[5].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[5].meaning }}</div>
|
||||
</div>
|
||||
<el-radio-group v-model="allVal[5].val" :disabled="allVal[5].lock" >
|
||||
<el-radio v-for="item in deviceTypeList" :label="item.code" :key="item.code" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.code }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="6">
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[6].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[6].meaning }}</div>
|
||||
</div>
|
||||
<el-radio-group v-model="allVal[6].val" :disabled="allVal[6].lock">
|
||||
<el-radio v-for="item in networkIdentificationTypeList" :label="item.code" :key="item.code" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.code }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="7">
|
||||
请手动输入设备/用户序号, 六位数字
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[7].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[7].meaning }}</div>
|
||||
</div>
|
||||
<el-input
|
||||
type="text"
|
||||
placeholder="请输入内容"
|
||||
v-model="allVal[7].val"
|
||||
maxlength="6"
|
||||
:disabled="allVal[7].lock"
|
||||
show-word-limit
|
||||
>
|
||||
</el-input>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form style="">
|
||||
|
||||
<el-form-item style="margin-top: 22px; margin-bottom: 0;">
|
||||
<div style="float:right;">
|
||||
<el-button type="primary" @click="handleOk">保存</el-button>
|
||||
<el-button @click="closeModel">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {},
|
||||
computed: {},
|
||||
data() {
|
||||
return {
|
||||
showVideoDialog: false,
|
||||
activeKey: '0',
|
||||
allVal: [
|
||||
{
|
||||
id: [1, 2],
|
||||
meaning: '省级编码',
|
||||
val: '11',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [3, 4],
|
||||
meaning: '市级编码',
|
||||
val: '01',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [5, 6],
|
||||
meaning: '区级编码',
|
||||
val: '01',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [7, 8],
|
||||
meaning: '基层接入单位编码',
|
||||
val: '01',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [9, 10],
|
||||
meaning: '行业编码',
|
||||
val: '00',
|
||||
type: '行业编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [11, 13],
|
||||
meaning: '类型编码',
|
||||
val: '132',
|
||||
type: '类型编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [14],
|
||||
meaning: '网络标识编码',
|
||||
val: '7',
|
||||
type: '网络标识',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [15, 20],
|
||||
meaning: '设备/用户序号',
|
||||
val: '000001',
|
||||
type: '序号',
|
||||
lock: false,
|
||||
}
|
||||
],
|
||||
regionList: [],
|
||||
deviceTypeList: [],
|
||||
industryCodeTypeList: [],
|
||||
networkIdentificationTypeList: [],
|
||||
endCallBck: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (endCallBck, code, lockIndex, lockContent) {
|
||||
console.log(code)
|
||||
this.showVideoDialog = true
|
||||
this.activeKey= '0';
|
||||
this.regionList = []
|
||||
|
||||
this.getRegionList()
|
||||
if (typeof code != 'undefined' && code.length === 20) {
|
||||
this.allVal[0].val = code.substring(0, 2)
|
||||
this.allVal[1].val = code.substring(2, 4)
|
||||
this.allVal[2].val = code.substring(4, 6)
|
||||
this.allVal[3].val = code.substring(6, 8)
|
||||
this.allVal[4].val = code.substring(8, 10)
|
||||
this.allVal[5].val = code.substring(10, 13)
|
||||
this.allVal[6].val = code.substring(13, 14)
|
||||
this.allVal[7].val = code.substring(14)
|
||||
}
|
||||
console.log(this.allVal)
|
||||
if (typeof lockIndex != 'undefined') {
|
||||
this.allVal[lockIndex].lock = true
|
||||
this.allVal[lockIndex].val = lockContent
|
||||
}
|
||||
this.endCallBck = endCallBck;
|
||||
},
|
||||
getRegionList: function() {
|
||||
if (this.activeKey === '0' || this.activeKey === '1' || this.activeKey === '2') {
|
||||
let parent = ''
|
||||
if (this.activeKey === '1') {
|
||||
parent = this.allVal[0].val
|
||||
}
|
||||
if (this.activeKey === '2') {
|
||||
parent = this.allVal[0].val + this.allVal[1].val
|
||||
}
|
||||
if (this.activeKey !== '0' && parent === '') {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: '请先选择上级行政区划'
|
||||
})
|
||||
|
||||
}
|
||||
this.queryChildList(parent);
|
||||
} else if (this.activeKey === '4') {
|
||||
console.log(222)
|
||||
this.queryIndustryCodeList();
|
||||
} else if (this.activeKey === '5') {
|
||||
this.queryDeviceTypeList();
|
||||
} else if (this.activeKey === '6') {
|
||||
this.queryNetworkIdentificationTypeList();
|
||||
}
|
||||
},
|
||||
queryChildList: function(parent){
|
||||
this.regionList = []
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/region/base/child/list",
|
||||
params: {
|
||||
parent: parent,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.regionList = res.data.data
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
});
|
||||
},
|
||||
queryIndustryCodeList: function(){
|
||||
this.industryCodeTypeList = []
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/common/channel/industry/list",
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.industryCodeTypeList = res.data.data
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
});
|
||||
},
|
||||
queryDeviceTypeList: function(){
|
||||
this.deviceTypeList = []
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/common/channel/type/list",
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.deviceTypeList = res.data.data
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
});
|
||||
},
|
||||
queryNetworkIdentificationTypeList: function(){
|
||||
this.networkIdentificationTypeList = []
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/common/channel/network/identification/list",
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.networkIdentificationTypeList = res.data.data
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
});
|
||||
},
|
||||
closeModel: function (){
|
||||
this.showVideoDialog = false
|
||||
},
|
||||
handleOk: function() {
|
||||
const code =
|
||||
this.allVal[0].val +
|
||||
this.allVal[1].val +
|
||||
this.allVal[2].val +
|
||||
this.allVal[3].val +
|
||||
this.allVal[4].val +
|
||||
this.allVal[5].val +
|
||||
this.allVal[6].val +
|
||||
this.allVal[7].val
|
||||
console.log(code)
|
||||
if (this.endCallBck) {
|
||||
this.endCallBck(code)
|
||||
}
|
||||
this.showVideoDialog = false
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.show-code-item {
|
||||
text-align: center;
|
||||
font-size: 3rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,65 +0,0 @@
|
||||
<template>
|
||||
<div id="channelMapInfobox" style="display: none">
|
||||
<div >
|
||||
<el-descriptions class="margin-top" title="channel.name" :column="4" direction="vertical">
|
||||
<el-descriptions-item label="生产厂商">{{channel.manufacture}}</el-descriptions-item>
|
||||
<el-descriptions-item label="型号">{{channel.model}}</el-descriptions-item>
|
||||
<el-descriptions-item label="设备归属" >{{channel.owner}}</el-descriptions-item>
|
||||
<el-descriptions-item label="行政区域" >{{channel.civilCode}}</el-descriptions-item>
|
||||
<el-descriptions-item label="安装地址" >{{channel.address}}</el-descriptions-item>
|
||||
<el-descriptions-item label="云台类型" >{{channel.ptzTypeText}}</el-descriptions-item>
|
||||
<el-descriptions-item label="经纬度" >{{channel.longitude}},{{channel.latitude}}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag size="small" v-if="channel.status === 1">在线</el-tag>
|
||||
<el-tag size="small" v-if="channel.status === 0">离线</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<devicePlayer ref="devicePlayer" v-loading="isLoging"></devicePlayer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import devicePlayer from '../dialog/devicePlayer.vue'
|
||||
|
||||
export default {
|
||||
name: "channelMapInfobox",
|
||||
props: ['channel'],
|
||||
computed: {devicePlayer},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
isLoging: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
||||
play: function (){
|
||||
let deviceId = this.channel.deviceId;
|
||||
this.isLoging = true;
|
||||
let channelId = this.channel.channelId;
|
||||
console.log("通知设备推流1:" + deviceId + " : " + channelId);
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/play/start/' + deviceId + '/' + channelId
|
||||
}).then(function (res) {
|
||||
that.isLoging = false;
|
||||
if (res.data.code === 0) {
|
||||
that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
|
||||
streamInfo: res.data.data,
|
||||
hasAudio: this.channel.hasAudio
|
||||
});
|
||||
} else {
|
||||
that.$message.error(res.data.msg);
|
||||
}
|
||||
}).catch(function (e) {
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,65 +0,0 @@
|
||||
<template>
|
||||
<div id="chooseCivilCode" >
|
||||
<el-dialog
|
||||
title="选择行政区划"
|
||||
width="30%"
|
||||
top="5rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<RegionTree ref="regionTree" :showHeader=true :edit="true" :enableAddChannel="false" :clickEvent="treeNodeClickEvent"
|
||||
:onChannelChange="onChannelChange" :treeHeight="'45vh'"></RegionTree>
|
||||
<el-form>
|
||||
<el-form-item>
|
||||
<div style="text-align: right">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import RegionTree from "../common/RegionTree.vue";
|
||||
|
||||
export default {
|
||||
name: "chooseCivilCode",
|
||||
components: {RegionTree},
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
endCallback: false,
|
||||
regionDeviceId: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (callback) {
|
||||
this.showDialog = true;
|
||||
this.endCallback = callback;
|
||||
},
|
||||
onSubmit: function () {
|
||||
if (this.endCallback) {
|
||||
this.endCallback(this.regionDeviceId)
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
treeNodeClickEvent: function (region) {
|
||||
this.regionDeviceId = region.deviceId;
|
||||
},
|
||||
onChannelChange: function (deviceId) {
|
||||
//
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<div id="chooseGroup" >
|
||||
<el-dialog
|
||||
title="选择虚拟组织"
|
||||
width="30%"
|
||||
top="5rem"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<GroupTree ref="regionTree" :showHeader=true :edit="true" :enableAddChannel="false" :clickEvent="treeNodeClickEvent"
|
||||
:onChannelChange="onChannelChange" :treeHeight="'45vh'"></GroupTree>
|
||||
<el-form>
|
||||
<el-form-item>
|
||||
<div style="text-align: right">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import GroupTree from "../common/GroupTree.vue";
|
||||
|
||||
export default {
|
||||
name: "chooseCivilCode",
|
||||
components: {GroupTree},
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
endCallback: false,
|
||||
groupDeviceId: "",
|
||||
businessGroup: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (callback) {
|
||||
this.showDialog = true;
|
||||
this.endCallback = callback;
|
||||
},
|
||||
onSubmit: function () {
|
||||
if (this.endCallback) {
|
||||
this.endCallback(this.groupDeviceId, this.businessGroup)
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
treeNodeClickEvent: function (group) {
|
||||
if (group.deviceId === "" || group.deviceId === group.businessGroup) {
|
||||
return
|
||||
}
|
||||
this.groupDeviceId = group.deviceId;
|
||||
this.businessGroup = group.businessGroup;
|
||||
},
|
||||
onChannelChange: function (deviceId) {
|
||||
//
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,59 +0,0 @@
|
||||
<template>
|
||||
<div id="configInfo">
|
||||
<el-dialog
|
||||
title="系统信息"
|
||||
width="=80%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
|
||||
<el-descriptions title="国标服务信息" v-if="configInfoData.sip" :span="2">
|
||||
<el-descriptions-item label="编号" >{{configInfoData.sip.id}}</el-descriptions-item>
|
||||
<el-descriptions-item label="域">{{configInfoData.sip.domain}}</el-descriptions-item>
|
||||
<el-descriptions-item label="IP">{{configInfoData.sip.showIp}}</el-descriptions-item>
|
||||
<el-descriptions-item label="端口">{{configInfoData.sip.port}}</el-descriptions-item>
|
||||
<el-descriptions-item label="密码">
|
||||
<el-tag size="small">{{configInfoData.sip.password}}</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions title="版本信息"v-if="configInfoData.version">
|
||||
<el-descriptions-item label="版本">{{configInfoData.version.version}}</el-descriptions-item>
|
||||
<el-descriptions-item label="编译时间">{{configInfoData.version.build_DATE}}</el-descriptions-item>
|
||||
<el-descriptions-item label="GIT版本">{{configInfoData.version.git_Revision_SHORT}}</el-descriptions-item>
|
||||
<el-descriptions-item label="GIT最后提交时间">{{configInfoData.version.git_DATE}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "configInfo",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
configInfoData: {
|
||||
sip:{},
|
||||
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (data) {
|
||||
console.log(data)
|
||||
this.showDialog = true;
|
||||
this.configInfoData = data;
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,135 +0,0 @@
|
||||
<template>
|
||||
<div id="deviceEdit" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="设备编辑"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
|
||||
<el-form ref="form" :rules="rules" :model="form" label-width="200px" >
|
||||
<el-form-item label="设备编号" prop="deviceId">
|
||||
<el-input v-if="isEdit" v-model="form.deviceId" disabled></el-input>
|
||||
<el-input v-if="!isEdit" v-model="form.deviceId" clearable></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="设备名称" prop="name">
|
||||
<el-input v-model="form.name" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="form.password" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="收流IP" prop="sdpIp">
|
||||
<el-input type="sdpIp" v-model="form.sdpIp" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流媒体ID" prop="mediaServerId">
|
||||
<el-select v-model="form.mediaServerId" style="float: left; width: 100%" >
|
||||
<el-option key="auto" label="自动负载最小" value="auto"></el-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="字符集" prop="charset" >
|
||||
<el-select v-model="form.charset" style="float: left; width: 100%" >
|
||||
<el-option key="GB2312" label="GB2312" value="gb2312"></el-option>
|
||||
<el-option key="UTF-8" label="UTF-8" value="utf-8"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他选项">
|
||||
<el-checkbox label="SSRC校验" v-model="form.ssrcCheck" style="float: left"></el-checkbox>
|
||||
<el-checkbox label="作为消息通道" v-model="form.asMessageChannel" style="float: left"></el-checkbox>
|
||||
<el-checkbox label="收到ACK后发流" v-model="form.broadcastPushAfterAck" style="float: left"></el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit" >确认</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MediaServer from '../service/MediaServer'
|
||||
export default {
|
||||
name: "deviceEdit",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
hostNames:[],
|
||||
mediaServerList: [], // 滅体节点列表
|
||||
mediaServerObj : new MediaServer(),
|
||||
form: {},
|
||||
isEdit: false,
|
||||
rules: {
|
||||
deviceId: [{ required: true, message: "请输入设备编号", trigger: "blur" }]
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (row, callback) {
|
||||
console.log(row)
|
||||
this.showDialog = true;
|
||||
this.isEdit = false;
|
||||
if (row) {
|
||||
this.isEdit = true;
|
||||
}
|
||||
this.form = {};
|
||||
this.listChangeCallback = callback;
|
||||
if (row != null) {
|
||||
this.form = row;
|
||||
}
|
||||
this.getMediaServerList();
|
||||
},
|
||||
getMediaServerList: function (){
|
||||
let that = this;
|
||||
that.mediaServerObj.getOnlineMediaServerList((data)=>{
|
||||
that.mediaServerList = data.data;
|
||||
})
|
||||
},
|
||||
onSubmit: function () {
|
||||
console.log("onSubmit");
|
||||
console.log(this.form);
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url:`/api/device/query/device/${this.isEdit?'update':'add'}`,
|
||||
data: this.form
|
||||
}).then((res) => {
|
||||
console.log(res.data)
|
||||
if (res.data.code === 0) {
|
||||
this.listChangeCallback()
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.$refs.form.resetFields();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,866 +0,0 @@
|
||||
<template>
|
||||
<div id="devicePlayer" v-loading="isLoging">
|
||||
|
||||
<el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" @close="close()" v-if="showVideoDialog">
|
||||
<div style="width: 100%; height: 100%">
|
||||
<el-tabs type="card" :stretch="true" v-model="activePlayer" @tab-click="changePlayer"
|
||||
v-if="Object.keys(this.player).length > 1">
|
||||
<el-tab-pane label="Jessibuca" name="jessibuca">
|
||||
<jessibucaPlayer v-if="activePlayer === 'jessibuca'" ref="jessibuca" :visible.sync="showVideoDialog"
|
||||
:videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
:hasAudio="hasAudio" fluent autoplay live></jessibucaPlayer>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="WebRTC" name="webRTC">
|
||||
<rtc-player v-if="activePlayer === 'webRTC'" ref="webRTC" :visible.sync="showVideoDialog"
|
||||
:videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px"
|
||||
:hasAudio="hasAudio" fluent autoplay live></rtc-player>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="h265web" name="h265web">
|
||||
<h265web v-if="activePlayer === 'h265web'" ref="h265web"
|
||||
:videoUrl="videoUrl" :error="videoError" :message="videoError" height="100px"
|
||||
:hasAudio="hasAudio" fluent autoplay live></h265web>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<jessibucaPlayer v-if="Object.keys(this.player).length == 1 && this.player.jessibuca" ref="jessibuca"
|
||||
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
:hasAudio="hasAudio" fluent autoplay live></jessibucaPlayer>
|
||||
<rtc-player v-if="Object.keys(this.player).length == 1 && this.player.webRTC" ref="jessibuca"
|
||||
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
height="100px" :hasAudio="hasAudio" fluent autoplay live></rtc-player>
|
||||
<h265web v-if="Object.keys(this.player).length == 1 && this.player.h265web" ref="jessibuca"
|
||||
:visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
|
||||
height="100px" :hasAudio="hasAudio" fluent autoplay live></h265web>
|
||||
</div>
|
||||
<div id="shared" style="text-align: right; margin-top: 1rem;">
|
||||
|
||||
<el-tabs v-model="tabActiveName" @tab-click="tabHandleClick">
|
||||
<el-tab-pane label="实时视频" name="media">
|
||||
<div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;">
|
||||
<span style="width: 5rem; line-height: 2.5rem; text-align: right;">播放地址:</span>
|
||||
<el-input v-model="getPlayerShared.sharedUrl" :disabled="true">
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="getPlayerShared.sharedUrl"
|
||||
@success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;">
|
||||
<span style="width: 5rem; line-height: 2.5rem; text-align: right;">iframe:</span>
|
||||
<el-input v-model="getPlayerShared.sharedIframe" :disabled="true">
|
||||
<template slot="append">
|
||||
<i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="getPlayerShared.sharedIframe"
|
||||
@success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;">
|
||||
<span style="width: 5rem; line-height: 2.5rem; text-align: right;">资源地址:</span>
|
||||
<el-input v-model="getPlayerShared.sharedRtmp" :disabled="true">
|
||||
<el-button slot="append" icon="el-icon-document-copy" title="点击拷贝"
|
||||
v-clipboard="getPlayerShared.sharedRtmp"
|
||||
@success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
|
||||
<el-dropdown slot="prepend" v-if="streamInfo" trigger="click" @command="copyUrl">
|
||||
<el-button>
|
||||
更多地址<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</el-button>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv">
|
||||
<el-tag>FLV:</el-tag>
|
||||
<span>{{ streamInfo.flv }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_flv" :command="streamInfo.https_flv">
|
||||
<el-tag>FLV(https):</el-tag>
|
||||
<span>{{ streamInfo.https_flv }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_flv" :command="streamInfo.ws_flv">
|
||||
<el-tag>FLV(ws):</el-tag>
|
||||
<span>{{ streamInfo.ws_flv }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_flv" :command="streamInfo.wss_flv">
|
||||
<el-tag>FLV(wss):</el-tag>
|
||||
<span>{{ streamInfo.wss_flv }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.fmp4" :command="streamInfo.fmp4">
|
||||
<el-tag>FMP4:</el-tag>
|
||||
<span>{{ streamInfo.fmp4 }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_fmp4" :command="streamInfo.https_fmp4">
|
||||
<el-tag>FMP4(https):</el-tag>
|
||||
<span>{{ streamInfo.https_fmp4 }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_fmp4" :command="streamInfo.ws_fmp4">
|
||||
<el-tag>FMP4(ws):</el-tag>
|
||||
<span>{{ streamInfo.ws_fmp4 }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_fmp4" :command="streamInfo.wss_fmp4">
|
||||
<el-tag>FMP4(wss):</el-tag>
|
||||
<span>{{ streamInfo.wss_fmp4 }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.hls" :command="streamInfo.hls">
|
||||
<el-tag>HLS:</el-tag>
|
||||
<span>{{ streamInfo.hls }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_hls" :command="streamInfo.https_hls">
|
||||
<el-tag>HLS(https):</el-tag>
|
||||
<span>{{ streamInfo.https_hls }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_hls" :command="streamInfo.ws_hls">
|
||||
<el-tag>HLS(ws):</el-tag>
|
||||
<span>{{ streamInfo.ws_hls }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_hls" :command="streamInfo.wss_hls">
|
||||
<el-tag>HLS(wss):</el-tag>
|
||||
<span>{{ streamInfo.wss_hls }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ts" :command="streamInfo.ts">
|
||||
<el-tag>TS:</el-tag>
|
||||
<span>{{ streamInfo.ts }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.https_ts" :command="streamInfo.https_ts">
|
||||
<el-tag>TS(https):</el-tag>
|
||||
<span>{{ streamInfo.https_ts }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.ws_ts" :command="streamInfo.ws_ts">
|
||||
<el-tag>TS(ws):</el-tag>
|
||||
<span>{{ streamInfo.ws_ts }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.wss_ts" :command="streamInfo.wss_ts">
|
||||
<el-tag>TS(wss):</el-tag>
|
||||
<span>{{ streamInfo.wss_ts }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtc" :command="streamInfo.rtc">
|
||||
<el-tag>RTC:</el-tag>
|
||||
<span>{{ streamInfo.rtc }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtcs" :command="streamInfo.rtcs">
|
||||
<el-tag>RTCS:</el-tag>
|
||||
<span>{{ streamInfo.rtcs }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtmp" :command="streamInfo.rtmp">
|
||||
<el-tag>RTMP:</el-tag>
|
||||
<span>{{ streamInfo.rtmp }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtmps" :command="streamInfo.rtmps">
|
||||
<el-tag>RTMPS:</el-tag>
|
||||
<span>{{ streamInfo.rtmps }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtsp" :command="streamInfo.rtsp">
|
||||
<el-tag>RTSP:</el-tag>
|
||||
<span>{{ streamInfo.rtsp }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="streamInfo.rtsps" :command="streamInfo.rtsps">
|
||||
<el-tag>RTSPS:</el-tag>
|
||||
<span>{{ streamInfo.rtsps }}</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</el-input>
|
||||
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}-->
|
||||
<!--遥控界面-->
|
||||
<el-tab-pane label="云台控制" name="control" v-if="showPtz">
|
||||
<div style="display: grid; grid-template-columns: 240px auto; height: 180px; overflow: auto">
|
||||
<div style="display: grid; grid-template-columns: 6.25rem auto;">
|
||||
|
||||
<div class="control-wrapper">
|
||||
<div class="control-btn control-top" @mousedown="ptzCamera('up')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-top"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
</div>
|
||||
<div class="control-btn control-left" @mousedown="ptzCamera('left')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-left"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
</div>
|
||||
<div class="control-btn control-bottom" @mousedown="ptzCamera('down')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-bottom"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
</div>
|
||||
<div class="control-btn control-right" @mousedown="ptzCamera('right')" @mouseup="ptzCamera('stop')">
|
||||
<i class="el-icon-caret-right"></i>
|
||||
<div class="control-inner-btn control-inner"></div>
|
||||
</div>
|
||||
<div class="control-round">
|
||||
<div class="control-round-inner"><i class="fa fa-pause-circle"></i></div>
|
||||
</div>
|
||||
<div class="contro-speed" style="position: absolute; left: 4px; top: 7rem; width: 6.25rem;">
|
||||
<el-slider v-model="controSpeed" :max="100"></el-slider>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="ptz-btn-box">
|
||||
<div style="" @mousedown="ptzCamera('zoomin')" @mouseup="ptzCamera('stop')" title="变倍+">
|
||||
<i class="el-icon-zoom-in control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
<div style="" @mousedown="ptzCamera('zoomout')" @mouseup="ptzCamera('stop')" title="变倍-">
|
||||
<i class="el-icon-zoom-out control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ptz-btn-box">
|
||||
<div @mousedown="focusCamera('near')" @mouseup="focusCamera('stop')" title="聚焦+">
|
||||
<i class="iconfont icon-bianjiao-fangda control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
<div @mousedown="focusCamera('far')" @mouseup="focusCamera('stop')" title="聚焦-">
|
||||
<i class="iconfont icon-bianjiao-suoxiao control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ptz-btn-box">
|
||||
<div @mousedown="irisCamera('in')" @mouseup="irisCamera('stop')" title="光圈+">
|
||||
<i class="iconfont icon-guangquan control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
<div @mousedown="pirisCamera('out')" @mouseup="irisCamera('stop')" title="光圈-">
|
||||
<i class="iconfont icon-guangquan- control-zoom-btn" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: left" >
|
||||
<el-select
|
||||
v-model="ptzMethod"
|
||||
style="width: 100%"
|
||||
size="mini"
|
||||
placeholder="请选择云台功能"
|
||||
>
|
||||
<el-option label="预置点" value="preset"></el-option>
|
||||
<el-option label="巡航组" value="cruise"></el-option>
|
||||
<el-option label="自动扫描" value="scan"></el-option>
|
||||
<el-option label="雨刷" value="wiper"></el-option>
|
||||
<el-option label="辅助开关" value="switch"></el-option>
|
||||
</el-select>
|
||||
|
||||
<ptzPreset :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'preset'" style="margin-top: 1rem"></ptzPreset>
|
||||
<ptzCruising :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'cruise'" style="margin-top: 1rem"></ptzCruising>
|
||||
<ptzScan :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'scan'" style="margin-top: 1rem"></ptzScan>
|
||||
<ptzWiper :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'wiper'" style="margin-top: 1rem"></ptzWiper>
|
||||
<ptzSwitch :channelDeviceId="channelId" :deviceId="deviceId" v-if="ptzMethod === 'switch'" style="margin-top: 1rem"></ptzSwitch>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="编码信息" name="codec" >
|
||||
<mediaInfo ref="mediaInfo" :app="app" :stream="streamId" :mediaServerId="mediaServerId"></mediaInfo>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="语音对讲" name="broadcast">
|
||||
<div style="padding: 0 10px">
|
||||
<!-- <el-switch v-model="broadcastMode" :disabled="broadcastStatus !== -1" active-color="#409EFF"-->
|
||||
<!-- active-text="喊话(Broadcast)"-->
|
||||
<!-- inactive-text="对讲(Talk)"></el-switch>-->
|
||||
|
||||
<el-radio-group v-model="broadcastMode" :disabled="broadcastStatus !== -1">
|
||||
<el-radio :label="true" >喊话(Broadcast)</el-radio>
|
||||
<el-radio :label="false" >对讲(Talk)</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="trank" style="text-align: center;">
|
||||
<el-button @click="broadcastStatusClick()" :type="getBroadcastStatus()" :disabled="broadcastStatus === -2"
|
||||
circle icon="el-icon-microphone" style="font-size: 32px; padding: 24px;margin-top: 24px;"/>
|
||||
<p>
|
||||
<span v-if="broadcastStatus === -2">正在释放资源</span>
|
||||
<span v-if="broadcastStatus === -1">点击开始对讲</span>
|
||||
<span v-if="broadcastStatus === 0">等待接通中...</span>
|
||||
<span v-if="broadcastStatus === 1">请说话</span>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import rtcPlayer from '../dialog/rtcPlayer.vue'
|
||||
import LivePlayer from '@liveqing/liveplayer'
|
||||
import crypto from 'crypto'
|
||||
import jessibucaPlayer from '../common/jessibuca.vue'
|
||||
import PtzPreset from "../common/ptzPreset.vue";
|
||||
import PtzCruising from "../common/ptzCruising.vue";
|
||||
import ptzScan from "../common/ptzScan.vue";
|
||||
import ptzWiper from "../common/ptzWiper.vue";
|
||||
import ptzSwitch from "../common/ptzSwitch.vue";
|
||||
import mediaInfo from "../common/mediaInfo.vue";
|
||||
import H265web from "../common/h265web.vue";
|
||||
|
||||
export default {
|
||||
name: 'devicePlayer',
|
||||
props: {},
|
||||
components: {
|
||||
H265web,
|
||||
PtzPreset,PtzCruising,ptzScan,ptzWiper,ptzSwitch,mediaInfo,
|
||||
LivePlayer, jessibucaPlayer, rtcPlayer,
|
||||
},
|
||||
computed: {
|
||||
getPlayerShared: function () {
|
||||
return {
|
||||
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
|
||||
sharedIframe: '<iframe src="' + window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl) + '"></iframe>',
|
||||
sharedRtmp: this.videoUrl
|
||||
};
|
||||
}
|
||||
},
|
||||
created() {
|
||||
console.log("created")
|
||||
console.log(this.player)
|
||||
this.broadcastStatus = -1;
|
||||
if (Object.keys(this.player).length === 1) {
|
||||
this.activePlayer = Object.keys(this.player)[0]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
video: 'http://lndxyj.iqilu.com/public/upload/2019/10/14/8c001ea0c09cdc59a57829dabc8010fa.mp4',
|
||||
videoUrl: '',
|
||||
activePlayer: "jessibuca",
|
||||
// 如何你只是用一种播放器,直接注释掉不用的部分即可
|
||||
player: {
|
||||
jessibuca: ["ws_flv", "wss_flv"],
|
||||
webRTC: ["rtc", "rtcs"],
|
||||
h265web: ["ws_flv", "wss_flv"],
|
||||
},
|
||||
showVideoDialog: false,
|
||||
streamId: '',
|
||||
ptzMethod: 'preset',
|
||||
ptzPresetId: '',
|
||||
app: '',
|
||||
mediaServerId: '',
|
||||
deviceId: '',
|
||||
channelId: '',
|
||||
tabActiveName: 'media',
|
||||
hasAudio: false,
|
||||
loadingRecords: false,
|
||||
recordsLoading: false,
|
||||
isLoging: false,
|
||||
controSpeed: 30,
|
||||
timeVal: 0,
|
||||
timeMin: 0,
|
||||
timeMax: 1440,
|
||||
presetPos: 1,
|
||||
cruisingSpeed: 100,
|
||||
cruisingTime: 5,
|
||||
cruisingGroup: 0,
|
||||
scanSpeed: 100,
|
||||
scanGroup: 0,
|
||||
tracks: [],
|
||||
showPtz: true,
|
||||
showRrecord: true,
|
||||
sliderTime: 0,
|
||||
seekTime: 0,
|
||||
recordStartTime: 0,
|
||||
showTimeText: "00:00:00",
|
||||
streamInfo: null,
|
||||
broadcastMode: true,
|
||||
broadcastRtc: null,
|
||||
broadcastStatus: -1, // -2 正在释放资源 -1 默认状态 0 等待接通 1 接通成功
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
tabHandleClick: function (tab, event) {
|
||||
console.log(tab)
|
||||
this.tracks = [];
|
||||
if (tab.name === "codec") {
|
||||
this.$refs.mediaInfo.startTask()
|
||||
}else {
|
||||
this.$refs.mediaInfo.stopTask()
|
||||
}
|
||||
},
|
||||
changePlayer: function (tab) {
|
||||
console.log(this.player[tab.name][0])
|
||||
this.activePlayer = tab.name;
|
||||
this.videoUrl = this.getUrlByStreamInfo()
|
||||
console.log(this.videoUrl)
|
||||
},
|
||||
openDialog: function (tab, deviceId, channelId, param) {
|
||||
if (this.showVideoDialog) {
|
||||
return;
|
||||
}
|
||||
this.tabActiveName = tab;
|
||||
this.channelId = channelId;
|
||||
this.deviceId = deviceId;
|
||||
this.streamId = "";
|
||||
this.mediaServerId = "";
|
||||
this.app = "";
|
||||
this.videoUrl = ""
|
||||
if (!!this.$refs[this.activePlayer]) {
|
||||
this.$refs[this.activePlayer].pause();
|
||||
}
|
||||
switch (tab) {
|
||||
case "media":
|
||||
this.play(param.streamInfo, param.hasAudio)
|
||||
break;
|
||||
case "streamPlay":
|
||||
this.tabActiveName = "media";
|
||||
this.showRrecord = false;
|
||||
this.showPtz = false;
|
||||
this.play(param.streamInfo, param.hasAudio)
|
||||
break;
|
||||
case "control":
|
||||
break;
|
||||
}
|
||||
},
|
||||
play: function (streamInfo, hasAudio) {
|
||||
this.streamInfo = streamInfo;
|
||||
this.hasAudio = hasAudio;
|
||||
this.isLoging = false;
|
||||
// this.videoUrl = streamInfo.rtc;
|
||||
this.videoUrl = this.getUrlByStreamInfo();
|
||||
this.streamId = streamInfo.stream;
|
||||
this.app = streamInfo.app;
|
||||
this.mediaServerId = streamInfo.mediaServerId;
|
||||
this.playFromStreamInfo(false, streamInfo)
|
||||
},
|
||||
getUrlByStreamInfo() {
|
||||
console.log(this.streamInfo)
|
||||
let streamInfo = this.streamInfo
|
||||
if (this.streamInfo.transcodeStream) {
|
||||
streamInfo = this.streamInfo.transcodeStream;
|
||||
}
|
||||
if (location.protocol === "https:") {
|
||||
this.videoUrl = streamInfo[this.player[this.activePlayer][1]]
|
||||
} else {
|
||||
this.videoUrl = streamInfo[this.player[this.activePlayer][0]]
|
||||
}
|
||||
return this.videoUrl;
|
||||
|
||||
},
|
||||
|
||||
playFromStreamInfo: function (realHasAudio, streamInfo) {
|
||||
this.showVideoDialog = true;
|
||||
this.hasaudio = realHasAudio && this.hasaudio;
|
||||
if (this.$refs[this.activePlayer]) {
|
||||
this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo))
|
||||
}else {
|
||||
this.$nextTick(() => {
|
||||
this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo))
|
||||
});
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
console.log('关闭视频');
|
||||
if (!!this.$refs[this.activePlayer]){
|
||||
this.$refs[this.activePlayer].pause();
|
||||
}
|
||||
this.videoUrl = '';
|
||||
this.coverPlaying = false;
|
||||
this.showVideoDialog = false;
|
||||
this.stopBroadcast()
|
||||
},
|
||||
|
||||
copySharedInfo: function (data) {
|
||||
console.log('复制内容:' + data);
|
||||
this.coverPlaying = false;
|
||||
this.tracks = []
|
||||
let _this = this;
|
||||
this.$copyText(data).then(
|
||||
function (e) {
|
||||
_this.$message({
|
||||
showClose: true,
|
||||
message: '复制成功',
|
||||
type: 'success'
|
||||
});
|
||||
},
|
||||
function (e) {
|
||||
_this.$message({
|
||||
showClose: true,
|
||||
message: '复制失败,请手动复制',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
ptzCamera: function (command) {
|
||||
console.log('云台控制:' + command);
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/front-end/ptz/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&horizonSpeed=' + parseInt(this.controSpeed * 255/100) + '&verticalSpeed=' + parseInt(this.controSpeed * 255/100) + '&zoomSpeed=' + parseInt(this.controSpeed * 16/100)
|
||||
}).then(function (res) {
|
||||
});
|
||||
},
|
||||
irisCamera: function (command) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/front-end/fi/iris/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&speed=' + parseInt(this.controSpeed * 255/100)
|
||||
}).then(function (res) {
|
||||
});
|
||||
},
|
||||
focusCamera: function (command) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/front-end/fi/focus/' + this.deviceId + '/' + this.channelId + '?command=' + command + '&speed=' + parseInt(this.controSpeed * 255/100)
|
||||
}).then(function (res) {
|
||||
});
|
||||
},
|
||||
//////////////////////播放器事件处理//////////////////////////
|
||||
videoError: function (e) {
|
||||
console.log("播放器错误:" + JSON.stringify(e));
|
||||
},
|
||||
copyUrl: function (dropdownItem) {
|
||||
console.log(dropdownItem)
|
||||
this.$copyText(dropdownItem).then((e) => {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "成功拷贝到粘贴板"
|
||||
})
|
||||
}, (e) => {
|
||||
|
||||
})
|
||||
},
|
||||
getBroadcastStatus() {
|
||||
if (this.broadcastStatus == -2) {
|
||||
return "primary"
|
||||
}
|
||||
if (this.broadcastStatus == -1) {
|
||||
return "primary"
|
||||
}
|
||||
if (this.broadcastStatus == 0) {
|
||||
return "warning"
|
||||
}
|
||||
if (this.broadcastStatus == 1) {
|
||||
return "danger"
|
||||
}
|
||||
|
||||
},
|
||||
broadcastStatusClick() {
|
||||
if (this.broadcastStatus == -1) {
|
||||
// 默认状态, 开始
|
||||
this.broadcastStatus = 0
|
||||
// 发起语音对讲
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/play/broadcast/' + this.deviceId + '/' + this.channelId + "?timeout=30&broadcastMode=" + this.broadcastMode
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
let streamInfo = res.data.data.streamInfo;
|
||||
if (document.location.protocol.includes("https")) {
|
||||
this.startBroadcast(streamInfo.rtcs)
|
||||
} else {
|
||||
this.startBroadcast(streamInfo.rtc)
|
||||
}
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (this.broadcastStatus === 1) {
|
||||
this.broadcastStatus = -1;
|
||||
this.broadcastRtc.close()
|
||||
}
|
||||
},
|
||||
startBroadcast(url) {
|
||||
// 获取推流鉴权Key
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: '/api/user/userInfo',
|
||||
}).then((res) => {
|
||||
if (res.data.code !== 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "获取推流鉴权Key失败",
|
||||
type: "error",
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
} else {
|
||||
let pushKey = res.data.data.pushKey;
|
||||
// 获取推流鉴权KEY
|
||||
url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex')
|
||||
console.log("开始语音喊话: " + url)
|
||||
this.broadcastRtc = new ZLMRTCClient.Endpoint({
|
||||
debug: true, // 是否打印日志
|
||||
zlmsdpUrl: url, //流地址
|
||||
simulecast: false,
|
||||
useCamera: false,
|
||||
audioEnable: true,
|
||||
videoEnable: false,
|
||||
recvOnly: false,
|
||||
})
|
||||
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT, (e) => {// 获取到了本地流
|
||||
console.error('不支持webrtc', e)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '不支持webrtc, 无法进行语音喊话',
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, (e) => {// ICE 协商出错
|
||||
console.error('ICE 协商出错')
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'ICE 协商出错',
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e) => {// offer anwser 交换失败
|
||||
console.error('offer anwser 交换失败', e)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'offer anwser 交换失败' + e,
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, (e) => {// offer anwser 交换失败
|
||||
console.log('状态改变', e)
|
||||
if (e === "connecting") {
|
||||
this.broadcastStatus = 0;
|
||||
} else if (e === "connected") {
|
||||
this.broadcastStatus = 1;
|
||||
} else if (e === "disconnected") {
|
||||
this.broadcastStatus = -1;
|
||||
}
|
||||
});
|
||||
this.broadcastRtc.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, (e) => {// offer anwser 交换失败
|
||||
console.log('捕获流失败', e)
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '捕获流失败' + e,
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
}
|
||||
}).catch((e) => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: e,
|
||||
type: 'error'
|
||||
});
|
||||
this.broadcastStatus = -1;
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
stopBroadcast() {
|
||||
this.broadcastRtc.close();
|
||||
this.broadcastStatus = -1;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/play/broadcast/stop/' + this.deviceId + '/' + this.channelId
|
||||
}).then((res) => {
|
||||
if (res.data.code == 0) {
|
||||
// this.broadcastStatus = -1;
|
||||
// this.broadcastRtc.close()
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.control-wrapper {
|
||||
position: relative;
|
||||
width: 6.25rem;
|
||||
height: 6.25rem;
|
||||
max-width: 6.25rem;
|
||||
max-height: 6.25rem;
|
||||
border-radius: 100%;
|
||||
margin-top: 1.5rem;
|
||||
margin-left: 0.5rem;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 5rem;
|
||||
height: 11rem;
|
||||
max-height: 11rem;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
width: 44%;
|
||||
height: 44%;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #78aee4;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
.control-btn:hover {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.control-btn i {
|
||||
font-size: 20px;
|
||||
color: #78aee4;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.control-btn i:hover {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.control-zoom-btn:hover {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.control-round {
|
||||
position: absolute;
|
||||
top: 21%;
|
||||
left: 21%;
|
||||
width: 58%;
|
||||
height: 58%;
|
||||
background: #fff;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.control-round-inner {
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
top: 13%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 70%;
|
||||
height: 70%;
|
||||
font-size: 40px;
|
||||
color: #78aee4;
|
||||
border: 1px solid #78aee4;
|
||||
border-radius: 100%;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
|
||||
.control-inner-btn {
|
||||
position: absolute;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.control-top {
|
||||
top: -8%;
|
||||
left: 27%;
|
||||
transform: rotate(-45deg);
|
||||
border-radius: 5px 100% 5px 0;
|
||||
}
|
||||
|
||||
.control-top i {
|
||||
transform: rotate(45deg);
|
||||
border-radius: 5px 100% 5px 0;
|
||||
}
|
||||
|
||||
.control-top .control-inner {
|
||||
left: -1px;
|
||||
bottom: 0;
|
||||
border-top: 1px solid #78aee4;
|
||||
border-right: 1px solid #78aee4;
|
||||
border-radius: 0 100% 0 0;
|
||||
}
|
||||
|
||||
.control-top .fa {
|
||||
transform: rotate(45deg) translateY(-7px);
|
||||
}
|
||||
|
||||
.control-left {
|
||||
top: 27%;
|
||||
left: -8%;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 5px 0 5px 100%;
|
||||
}
|
||||
|
||||
.control-left i {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.control-left .control-inner {
|
||||
right: -1px;
|
||||
top: -1px;
|
||||
border-bottom: 1px solid #78aee4;
|
||||
border-left: 1px solid #78aee4;
|
||||
border-radius: 0 0 0 100%;
|
||||
}
|
||||
|
||||
.control-left .fa {
|
||||
transform: rotate(-45deg) translateX(-7px);
|
||||
}
|
||||
|
||||
.control-right {
|
||||
top: 27%;
|
||||
right: -8%;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 5px 100% 5px 0;
|
||||
}
|
||||
|
||||
.control-right i {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.control-right .control-inner {
|
||||
left: -1px;
|
||||
bottom: -1px;
|
||||
border-top: 1px solid #78aee4;
|
||||
border-right: 1px solid #78aee4;
|
||||
border-radius: 0 100% 0 0;
|
||||
}
|
||||
|
||||
.control-right .fa {
|
||||
transform: rotate(-45deg) translateX(7px);
|
||||
}
|
||||
|
||||
.control-bottom {
|
||||
left: 27%;
|
||||
bottom: -8%;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 0 5px 100% 5px;
|
||||
}
|
||||
|
||||
.control-bottom i {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.control-bottom .control-inner {
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
border-bottom: 1px solid #78aee4;
|
||||
border-right: 1px solid #78aee4;
|
||||
border-radius: 0 0 100% 0;
|
||||
}
|
||||
|
||||
.control-bottom .fa {
|
||||
transform: rotate(-45deg) translateY(7px);
|
||||
}
|
||||
|
||||
.trank {
|
||||
width: 80%;
|
||||
height: 180px;
|
||||
text-align: left;
|
||||
padding: 0 10%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.trankInfo {
|
||||
width: 80%;
|
||||
padding: 0 10%;
|
||||
}
|
||||
.el-dialog__body{
|
||||
padding: 10px 20px;
|
||||
}
|
||||
.ptz-btn-box {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding: 0 2rem;
|
||||
height: 3rem;
|
||||
line-height: 4rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,228 +0,0 @@
|
||||
<template>
|
||||
<div id="editRecordPlan" v-loading="loading" style="text-align: left;">
|
||||
<el-dialog
|
||||
title="录制计划"
|
||||
width="700px"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-right: 20px;">
|
||||
<el-form >
|
||||
<el-form-item label="名称">
|
||||
<el-input type="text" v-model="planName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<ByteWeektimePicker v-model="byteTime" name="name"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right; margin-top: 20px">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ByteWeektimePicker } from 'byte-weektime-picker'
|
||||
|
||||
|
||||
export default {
|
||||
name: "editRecordPlan",
|
||||
props: {},
|
||||
components: {ByteWeektimePicker},
|
||||
created() {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [],
|
||||
loading: false,
|
||||
edit: false,
|
||||
planName: null,
|
||||
id: null,
|
||||
showDialog: false,
|
||||
endCallback: "",
|
||||
byteTime: "",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (recordPlan, endCallback) {
|
||||
this.endCallback = endCallback;
|
||||
this.showDialog = true;
|
||||
this.byteTime= "";
|
||||
if (recordPlan) {
|
||||
this.edit = true
|
||||
this.planName = recordPlan.name
|
||||
this.id = recordPlan.id
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/record/plan/get",
|
||||
params: {
|
||||
planId: recordPlan.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0 && res.data.data.planItemList) {
|
||||
this.byteTime = this.plan2Byte(res.data.data.planItemList)
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
onSubmit: function () {
|
||||
let planList = this.byteTime2PlanList();
|
||||
if (!this.edit) {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/record/plan/add",
|
||||
data: {
|
||||
name: this.planName,
|
||||
planItemList: planList
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '添加成功',
|
||||
type: 'success',
|
||||
});
|
||||
this.showDialog = false;
|
||||
this.endCallback()
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
});
|
||||
}else {
|
||||
this.$axios({
|
||||
method: 'post',
|
||||
url: "/api/record/plan/update",
|
||||
data: {
|
||||
id: this.id,
|
||||
name: this.planName,
|
||||
planItemList: planList
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '更新成功',
|
||||
type: 'success',
|
||||
});
|
||||
this.showDialog = false;
|
||||
this.endCallback()
|
||||
} else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.id = null
|
||||
this.planName = null
|
||||
this.byteTime = ""
|
||||
this.endCallback = ""
|
||||
if(this.endCallback) {
|
||||
this.endCallback();
|
||||
}
|
||||
},
|
||||
byteTime2PlanList() {
|
||||
if (this.byteTime.length === 0) {
|
||||
return;
|
||||
}
|
||||
const DayTimes = 24 * 2;
|
||||
let planList = []
|
||||
let week = 1;
|
||||
// 把 336长度的 list 分成 7 组,每组 48 个
|
||||
for (let i = 0; i < this.byteTime.length; i += DayTimes) {
|
||||
let planArray = this.byteTime2Plan(this.byteTime.slice(i, i + DayTimes));
|
||||
if(!planArray || planArray.length === 0) {
|
||||
week ++;
|
||||
continue
|
||||
}
|
||||
for (let j = 0; j < planArray.length; j++) {
|
||||
planList.push({
|
||||
planId: this.id,
|
||||
start: planArray[j].start,
|
||||
stop: planArray[j].stop,
|
||||
weekDay: week
|
||||
})
|
||||
}
|
||||
week ++;
|
||||
}
|
||||
return planList
|
||||
},
|
||||
byteTime2Plan(weekItem){
|
||||
let start = null;
|
||||
let stop = null;
|
||||
let result = []
|
||||
for (let i = 0; i < weekItem.length; i++) {
|
||||
let item = weekItem[i]
|
||||
if (item === '1') { // 表示选中
|
||||
stop = i
|
||||
if (start === null ) {
|
||||
start = i
|
||||
}
|
||||
if (i === weekItem.length - 1 && start != null && stop != null) {
|
||||
result.push({
|
||||
start: start,
|
||||
stop: stop,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (stop !== null){
|
||||
result.push({
|
||||
start: start,
|
||||
stop: stop,
|
||||
})
|
||||
start = null
|
||||
stop = null
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
plan2Byte(planList) {
|
||||
let byte = ""
|
||||
let indexArray = {}
|
||||
for (let i = 0; i < planList.length; i++) {
|
||||
|
||||
let weekDay = planList[i].weekDay
|
||||
let index = planList[i].start
|
||||
let endIndex = planList[i].stop
|
||||
for (let j = index; j <= endIndex; j++) {
|
||||
indexArray["key_" + (j + (weekDay - 1 )*48)] = 1
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 336; i++) {
|
||||
if (indexArray["key_" + i]){
|
||||
byte += "1"
|
||||
}else {
|
||||
byte += "0"
|
||||
}
|
||||
}
|
||||
return byte
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,129 +0,0 @@
|
||||
<template>
|
||||
<div id="groupEdit" v-loading="loading">
|
||||
<el-dialog
|
||||
title="分组编辑"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
|
||||
<el-form ref="form" :model="group" label-width="140px" >
|
||||
<el-form-item label="节点编号" prop="id" >
|
||||
<el-input v-model="group.deviceId" placeholder="请输入编码">
|
||||
<el-button slot="append" @click="buildDeviceIdCode(group.deviceId)">生成</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="节点名称" prop="name">
|
||||
<el-input v-model="group.name" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="行政区划" prop="name">
|
||||
<el-input v-model="group.civilCode" >
|
||||
<el-button slot="append" @click="buildCivilCode(group.civilCode)">选择</el-button>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit" >确认</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<channelCode ref="channelCode"></channelCode>
|
||||
<chooseCivilCode ref="chooseCivilCode"></chooseCivilCode>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import channelCode from "./channelCode.vue";
|
||||
import ChooseCivilCode from "./chooseCivilCode.vue";
|
||||
|
||||
export default {
|
||||
name: "groupEdit",
|
||||
components: {ChooseCivilCode, channelCode},
|
||||
computed: {},
|
||||
props: [],
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
submitCallback: null,
|
||||
showDialog: false,
|
||||
loading: false,
|
||||
level: 0,
|
||||
group: {
|
||||
id: 0,
|
||||
deviceId: "",
|
||||
name: "",
|
||||
parentDeviceId: "",
|
||||
businessGroup: "",
|
||||
civilCode: "",
|
||||
platformId: "",
|
||||
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (group, callback) {
|
||||
console.log(group)
|
||||
if (group) {
|
||||
this.group = group;
|
||||
}
|
||||
this.showDialog = true;
|
||||
this.submitCallback = callback;
|
||||
},
|
||||
onSubmit: function () {
|
||||
|
||||
this.$axios({
|
||||
method:"post",
|
||||
url: this.group.id ? '/api/group/update':'/api/group/add',
|
||||
data: this.group
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
})
|
||||
if (this.submitCallback)this.submitCallback(this.group)
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
this.close();
|
||||
})
|
||||
.catch((error)=> {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: error,
|
||||
type: "error",
|
||||
});
|
||||
});
|
||||
},
|
||||
buildDeviceIdCode: function (deviceId){
|
||||
console.log(this.group)
|
||||
let lockContent = this.group.businessGroup ? "216":"215"
|
||||
this.$refs.channelCode.openDialog(code=>{
|
||||
this.group.deviceId = code;
|
||||
}, deviceId, 5 , lockContent);
|
||||
},
|
||||
buildCivilCode: function (deviceId){
|
||||
this.$refs.chooseCivilCode.openDialog(code=>{
|
||||
this.group.civilCode = code;
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
console.log(this.group)
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,131 +0,0 @@
|
||||
<template>
|
||||
<div id="importChannel" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="导入通道数据"
|
||||
width="30rem"
|
||||
top="2rem"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div>
|
||||
<el-upload
|
||||
class="upload-box"
|
||||
drag
|
||||
:action="uploadUrl"
|
||||
name="file"
|
||||
:headers="headers"
|
||||
:on-success="successHook"
|
||||
:on-error="errorHook"
|
||||
>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div class="el-upload__tip" slot="tip">只能上传 csv / xls / xlsx 文件</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<ShowErrorData ref="showErrorData" :gbIds="errorGBIds" :streams="errorStreams" ></ShowErrorData>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ShowErrorData from './importChannelShowErrorData.vue'
|
||||
|
||||
import userService from "../service/UserService";
|
||||
|
||||
export default {
|
||||
name: "importChannel",
|
||||
components: {
|
||||
ShowErrorData,
|
||||
},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
submitCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
isEdit: false,
|
||||
errorStreams: [],
|
||||
errorGBIds: [],
|
||||
headers: {
|
||||
"access-token": userService.getToken()
|
||||
},
|
||||
uploadUrl: process.env.NODE_ENV === 'development'? `http://127.0.0.1:8080/debug/api/push/upload`: (window.baseUrl ? window.baseUrl : "") + `/api/push/upload`,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (callback) {
|
||||
this.showDialog = true;
|
||||
this.submitCallback = callback;
|
||||
},
|
||||
onSubmit: function () {
|
||||
console.log("onSubmit");
|
||||
console.log(this.form);
|
||||
this.$axios({
|
||||
method:"post",
|
||||
url:`/api/platform/catalog/${!this.isEdit? "add":"edit"}`,
|
||||
data: this.form
|
||||
})
|
||||
.then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
console.log("添加/修改成功")
|
||||
if (this.submitCallback)this.submitCallback()
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
this.close();
|
||||
})
|
||||
.catch((error)=> {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
successHook: function(response, file, fileList){
|
||||
if (response.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: response.msg,
|
||||
type: "success",
|
||||
});
|
||||
}else if (response.code === 1) {
|
||||
this.errorGBIds = response.data.gbId
|
||||
this.errorStreams = response.data.stream
|
||||
console.log(this.$refs)
|
||||
console.log(this.$refs.showErrorData)
|
||||
this.$refs.showErrorData.openDialog()
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: response.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
},
|
||||
errorHook: function (err, file, fileList) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: err,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.upload-box{
|
||||
text-align: center;
|
||||
}
|
||||
.errDataBox{
|
||||
max-height: 15rem;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
@ -1,64 +0,0 @@
|
||||
<template>
|
||||
<div id="importChannelShowErrorData" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="导入通道数据成功,但数据存在重复"
|
||||
width="30rem"
|
||||
top="2rem"
|
||||
:append-to-body="true"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div >
|
||||
重复国标ID:
|
||||
<el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="gbIds.join(',')" @success="$message({type:'success', message:'成功拷贝到粘贴板'})">复制</el-button>
|
||||
<ul class="errDataBox">
|
||||
<li v-for="id in gbIds" >
|
||||
{{ id }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div >
|
||||
重复App/stream:
|
||||
<el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="streams.join(',')" @success="$message({type:'success', message:'成功拷贝到粘贴板'})">复制</el-button>
|
||||
<ul class="errDataBox">
|
||||
<li v-for="id in streams" >
|
||||
{{ id }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: "importChannelShowErrorData",
|
||||
computed: {},
|
||||
created() {},
|
||||
props: ['gbIds', 'streams'],
|
||||
data() {
|
||||
return {
|
||||
isLoging: false,
|
||||
showDialog: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function () {
|
||||
this.showDialog = true;
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.errDataBox{
|
||||
max-height: 15rem;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
@ -1,351 +0,0 @@
|
||||
<template>
|
||||
<div id="linkChannelRecord" style="width: 100%; background-color: #FFFFFF; display: grid; grid-template-columns: 200px auto;">
|
||||
<el-dialog title="通道关联" v-loading="dialogLoading" v-if="showDialog" top="2rem" width="80%" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()">
|
||||
<div style="display: grid; grid-template-columns: 100px auto;">
|
||||
<el-tabs tab-position="left" style="" v-model="hasLink" @tab-click="search">
|
||||
<el-tab-pane label="未关联" name="false"></el-tab-pane>
|
||||
<el-tab-pane label="已关联" name="true"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<div>
|
||||
<div class="page-header">
|
||||
<div class="page-header-btn" >
|
||||
<div style="display: inline;">
|
||||
搜索:
|
||||
<el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
|
||||
|
||||
在线状态:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="在线" value="true"></el-option>
|
||||
<el-option label="离线" value="false"></el-option>
|
||||
</el-select>
|
||||
类型:
|
||||
<el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="search" v-model="channelType" placeholder="请选择"
|
||||
default-first-option>
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option v-for="item in Object.values($channelTypeList)" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
<el-button v-if="hasLink !=='true'" size="mini" type="primary" @click="add()">
|
||||
添加
|
||||
</el-button>
|
||||
<el-button v-if="hasLink ==='true'" size="mini" type="danger" @click="remove()">
|
||||
移除
|
||||
</el-button>
|
||||
<el-button size="mini" v-if="hasLink !=='true'" @click="addByDevice()">按设备添加</el-button>
|
||||
<el-button size="mini" v-if="hasLink ==='true'" @click="removeByDevice()">按设备移除</el-button>
|
||||
<el-button size="mini" v-if="hasLink !=='true'" @click="addAll()">添加所有通道</el-button>
|
||||
<el-button size="mini" v-if="hasLink ==='true'" @click="removeAll()">移除所有通道</el-button>
|
||||
<el-button size="mini" @click="getChannelList()">刷新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-table size="small" ref="channelListTable" :data="channelList" :height="winHeight"
|
||||
header-row-class-name="table-header" @selection-change="handleSelectionChange" >
|
||||
<el-table-column type="selection" width="55" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbName" label="名称" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbDeviceId" label="编号" min-width="180">
|
||||
</el-table-column>
|
||||
<el-table-column prop="gbManufacturer" label="厂家" min-width="100">
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" effect="plain" type="success" :style="$channelTypeList[scope.row.dataType].style">{{$channelTypeList[scope.row.dataType].name}}</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" min-width="100">
|
||||
<template v-slot:default="scope">
|
||||
<div slot="reference" class="name-wrapper">
|
||||
<el-tag size="medium" v-if="scope.row.gbStatus === 'ON'">在线</el-tag>
|
||||
<el-tag size="medium" type="info" v-if="scope.row.gbStatus !== 'ON'">离线</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="text-align: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
<gbDeviceSelect ref="gbDeviceSelect"></gbDeviceSelect>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import gbDeviceSelect from "./GbDeviceSelect.vue";
|
||||
|
||||
export default {
|
||||
name: 'linkChannelRecord',
|
||||
components: {gbDeviceSelect},
|
||||
data() {
|
||||
return {
|
||||
dialogLoading: false,
|
||||
showDialog: false,
|
||||
chooseData: {},
|
||||
channelList: [],
|
||||
searchSrt: "",
|
||||
channelType: "",
|
||||
online: "",
|
||||
hasLink: "false",
|
||||
winHeight: window.innerHeight - 250,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
loading: false,
|
||||
planId: null,
|
||||
loadSnap: {},
|
||||
multipleSelection: []
|
||||
};
|
||||
},
|
||||
|
||||
created() {},
|
||||
destroyed() {},
|
||||
methods: {
|
||||
openDialog(planId, closeCallback) {
|
||||
this.planId = planId
|
||||
this.showDialog = true
|
||||
this.closeCallback = closeCallback
|
||||
this.initData()
|
||||
},
|
||||
initData: function () {
|
||||
this.currentPage= 1;
|
||||
this.count= 15;
|
||||
this.total= 0;
|
||||
this.getChannelList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.initData();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getChannelList();
|
||||
},
|
||||
getChannelList: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/record/plan/channel/list`,
|
||||
params: {
|
||||
page: this.currentPage,
|
||||
count: this.count,
|
||||
query: this.searchSrt,
|
||||
online: this.online,
|
||||
channelType: this.channelType,
|
||||
planId: this.planId,
|
||||
hasLink: this.hasLink
|
||||
}
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.channelList = res.data.data.list;
|
||||
// 防止出现表格错位
|
||||
this.$nextTick(() => {
|
||||
this.$refs.channelListTable.doLayout();
|
||||
})
|
||||
}
|
||||
|
||||
}).catch((error)=> {
|
||||
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
handleSelectionChange: function (val){
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
|
||||
linkPlan: function (data){
|
||||
this.loading = true
|
||||
return this.$axios({
|
||||
method: 'post',
|
||||
url: `/api/record/plan/link`,
|
||||
data: data
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success({
|
||||
showClose: true,
|
||||
message: "保存成功"
|
||||
})
|
||||
this.getChannelList()
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
this.loading = false
|
||||
}).catch((error)=> {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
})
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
add: function (row) {
|
||||
let channels = []
|
||||
for (let i = 0; i < this.multipleSelection.length; i++) {
|
||||
channels.push(this.multipleSelection[i].gbId)
|
||||
}
|
||||
if (channels.length === 0) {
|
||||
this.$message.info({
|
||||
showClose: true,
|
||||
message: "请选择通道"
|
||||
})
|
||||
return;
|
||||
}
|
||||
this.linkPlan({
|
||||
planId: this.planId,
|
||||
channelIds: channels
|
||||
})
|
||||
},
|
||||
addAll: function (row) {
|
||||
this.$confirm("添加所有通道将包括已经添加到其他计划的通道,确定添加所有通道?", '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.linkPlan({
|
||||
planId: this.planId,
|
||||
allLink: true
|
||||
})
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
|
||||
addByDevice: function (row) {
|
||||
this.$refs.gbDeviceSelect.openDialog((rows)=>{
|
||||
let deviceIds = []
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
deviceIds.push(rows[i].id)
|
||||
}
|
||||
this.linkPlan({
|
||||
planId: this.planId,
|
||||
deviceDbIds: deviceIds
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
removeByDevice: function (row) {
|
||||
this.$refs.gbDeviceSelect.openDialog((rows)=>{
|
||||
let deviceIds = []
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
deviceIds.push(rows[i].id)
|
||||
}
|
||||
this.linkPlan({
|
||||
deviceDbIds: deviceIds
|
||||
})
|
||||
})
|
||||
},
|
||||
remove: function (row) {
|
||||
let channels = []
|
||||
for (let i = 0; i < this.multipleSelection.length; i++) {
|
||||
channels.push(this.multipleSelection[i].gbId)
|
||||
}
|
||||
if (channels.length === 0) {
|
||||
this.$message.info({
|
||||
showClose: true,
|
||||
message: "请选择通道"
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
this.linkPlan({
|
||||
channelIds: channels
|
||||
})
|
||||
},
|
||||
removeAll: function (row) {
|
||||
|
||||
this.$confirm("确定移除所有通道?", '提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.linkPlan({
|
||||
planId: this.planId,
|
||||
allLink: false
|
||||
})
|
||||
}).catch(() => {
|
||||
});
|
||||
},
|
||||
search: function () {
|
||||
this.currentPage = 1;
|
||||
this.total = 0;
|
||||
this.initData();
|
||||
},
|
||||
refresh: function () {
|
||||
this.initData();
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.videoList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 10rem;
|
||||
margin-right: 1rem;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-item-img:after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
background-image: url("../../assets/loading.png");
|
||||
background-size: cover;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.video-item-title {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
color: #000000;
|
||||
background-color: #ffffff;
|
||||
line-height: 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: 14.4rem;
|
||||
}
|
||||
</style>
|
||||
@ -1,121 +0,0 @@
|
||||
<template>
|
||||
<div id="onvif搜索" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title="onvif搜索"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
|
||||
<el-form ref="form" :rules="rules" :model="form" label-width="140px" >
|
||||
<el-form-item label="地址" prop="hostName" >
|
||||
<el-select v-model="form.hostName" style="float: left; width: 100%" >
|
||||
<el-option
|
||||
v-for="item in hostNames"
|
||||
:key="item"
|
||||
:label="item.replace('http://', '')"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="form.username" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="form.password" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit" >确认</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "onvifEdit",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
hostNames:[],
|
||||
form: {
|
||||
hostName: null,
|
||||
username: "admin",
|
||||
password: "admin123",
|
||||
},
|
||||
|
||||
rules: {
|
||||
hostName: [{ required: true, message: "请选择", trigger: "blur" }],
|
||||
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
||||
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (hostNamesParam, callback) {
|
||||
console.log(hostNamesParam)
|
||||
this.showDialog = true;
|
||||
this.listChangeCallback = callback;
|
||||
if (hostNamesParam != null) {
|
||||
this.hostNames = hostNamesParam;
|
||||
}
|
||||
|
||||
},
|
||||
onSubmit: function () {
|
||||
console.log("onSubmit");
|
||||
console.log(this.form);
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/api/onvif/rtsp`,
|
||||
params: {
|
||||
hostname: this.form.hostName,
|
||||
timeout: 3000,
|
||||
username: this.form.username,
|
||||
password: this.form.password,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res.data)
|
||||
if (res.data.code === 0) {
|
||||
if (res.data.data != null) {
|
||||
this.listChangeCallback(res.data.data)
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.$refs.form.resetFields();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,181 +0,0 @@
|
||||
<template>
|
||||
<div id="log" style="width: 100%;height: 100%;">
|
||||
<div style="width: 100%; height: 40px; display: grid; grid-template-columns: 1fr 1fr">
|
||||
<div style="text-align: left; line-height: 40px;">
|
||||
<span style="width: 5vw">过滤: </span>
|
||||
<el-input size="mini" v-model="filter" placeholder="请输入过滤关键字" style="width: 20vw"></el-input>
|
||||
</div>
|
||||
<div style="text-align: right; line-height: 40px;">
|
||||
<el-button size="mini" icon="el-icon-download" @click="downloadFile()">下载
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<log-viewer :log="logData" :auto-scroll="true" :height="winHeight"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import userService from "./../service/UserService";
|
||||
import moment from "moment/moment";
|
||||
import stripAnsi from "strip-ansi";
|
||||
|
||||
export default {
|
||||
name: 'log',
|
||||
props: [ 'fileUrl', 'remoteUrl', 'loadEnd'],
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
winHeight: window.innerHeight - 300,
|
||||
data: [],
|
||||
filter: "",
|
||||
logData: "",
|
||||
websocket: null,
|
||||
destroyedCallback: null
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
remoteUrl(newValue) {
|
||||
console.log(newValue);
|
||||
this.remoteUrl = newValue;
|
||||
this.initData();
|
||||
},
|
||||
fileUrl(newValue) {
|
||||
this.fileUrl = newValue;
|
||||
this.initData();
|
||||
},
|
||||
filter(newValue) {
|
||||
this.filter = newValue;
|
||||
this.logData = this.getLogData();
|
||||
},
|
||||
data(newValue) {
|
||||
this.data = newValue;
|
||||
this.logData = this.getLogData();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.data = []
|
||||
if (this.fileUrl || this.remoteUrl) {
|
||||
this.initData();
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
console.log('destroyed');
|
||||
if (this.destroyedCallback) {
|
||||
this.destroyedCallback()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
this.loading = true
|
||||
this.data = []
|
||||
console.log(this.loading)
|
||||
if (this.fileUrl) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: this.fileUrl,
|
||||
}).then((res) => {
|
||||
let dataArray = res.data.split("\n");
|
||||
dataArray.forEach(item => {
|
||||
this.data.push(item);
|
||||
})
|
||||
this.loading = false
|
||||
if (this.loadEnd && typeof this.loadEnd === "function") {
|
||||
this.loadEnd()
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}else if (this.remoteUrl) {
|
||||
console.log('remoteUrl' + this.remoteUrl);
|
||||
console.log(window.location.host)
|
||||
window.websocket = new WebSocket(this.remoteUrl, userService.getToken());
|
||||
window.websocket.onclose = e => {
|
||||
console.log(`conn closed: code=${e.code}, reason=${e.reason}, wasClean=${e.wasClean}`)
|
||||
}
|
||||
window.websocket.onmessage = e => {
|
||||
this.loading = false
|
||||
this.data.push(e.data);
|
||||
}
|
||||
window.websocket.onerror = e => {
|
||||
console.log(`conn err`)
|
||||
console.error(e)
|
||||
}
|
||||
window.websocket.onopen = e => {
|
||||
console.log(`conn open: ${e}`);
|
||||
this.destroyedCallback = ()=>{
|
||||
window.websocket.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getLogData: function () {
|
||||
this.loading = true;
|
||||
if (this.data.length === 0) {
|
||||
this.loading = false;
|
||||
return "";
|
||||
}else {
|
||||
let result = '';
|
||||
for (let i = 0; i < this.data.length; i++) {
|
||||
if (this.filter.length === 0) {
|
||||
result += this.data[i] + "\r\n"
|
||||
}else {
|
||||
if (this.data[i].indexOf(this.filter) > -1) {
|
||||
result += this.data[i] + "\r\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
this.loading = false;
|
||||
return result;
|
||||
}
|
||||
},
|
||||
getLogDataWithOutAnsi: function () {
|
||||
if (this.data.length === 0) {
|
||||
return "";
|
||||
}else {
|
||||
let result = '';
|
||||
for (let i = 0; i < this.data.length; i++) {
|
||||
if (this.filter.length === 0) {
|
||||
result += stripAnsi(this.data[i]) + "\r\n"
|
||||
}else {
|
||||
if (this.data[i].indexOf(this.filter) > -1) {
|
||||
result += stripAnsi(this.data[i]) + "\r\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
downloadFile() {
|
||||
let blob = new Blob([this.getLogDataWithOutAnsi()], {
|
||||
type: "text/plain;charset=utf-8"
|
||||
});
|
||||
let reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onload = (e)=> {
|
||||
let a = document.createElement('a');
|
||||
a.download = `wvp-${this.filter}-${moment().format('yyyy-MM-DD')}.log`;
|
||||
a.href = e.target.result;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.log-loading{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
background-color: transparent;
|
||||
font-size: 20px;
|
||||
color: rgb(255, 255, 255);
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
||||
@ -1,180 +0,0 @@
|
||||
<template>
|
||||
<div id="addStreamProxy" v-loading="isLoging">
|
||||
<el-dialog
|
||||
title=" 加入"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div id="shared" style="margin-top: 1rem;margin-right: 100px;">
|
||||
<el-form ref="streamProxy" :rules="rules" :model="proxyParam" label-width="140px">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="proxyParam.name" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流应用名" prop="app">
|
||||
<el-input v-model="proxyParam.app" clearable :disabled="edit"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="流ID" prop="stream">
|
||||
<el-input v-model="proxyParam.stream" clearable :disabled="edit"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="国标编码" prop="gbId">
|
||||
<el-input v-model="proxyParam.gbId" placeholder="设置国标编码可推送到国标" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="经度" prop="longitude" v-if="proxyParam.gbId">
|
||||
<el-input v-model="proxyParam.longitude" placeholder="经度" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="纬度" prop="latitude" v-if="proxyParam.gbId">
|
||||
<el-input v-model="proxyParam.latitude" placeholder="经度" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div style="float: right;">
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
<el-button @click="close">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "pushStreamEdit",
|
||||
props: {},
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
// var deviceGBIdRules = async (rule, value, callback) => {
|
||||
// console.log(value);
|
||||
// if (value === "") {
|
||||
// callback(new Error("请输入设备国标编号"));
|
||||
// } else {
|
||||
// var exit = await this.deviceGBIdExit(value);
|
||||
// console.log(exit);
|
||||
// console.log(exit == "true");
|
||||
// console.log(exit === "true");
|
||||
// if (exit) {
|
||||
// callback(new Error("设备国标编号已存在"));
|
||||
// } else {
|
||||
// callback();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
return {
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
edit: false,
|
||||
proxyParam: {
|
||||
name: null,
|
||||
app: null,
|
||||
stream: null,
|
||||
gbId: null,
|
||||
longitude: null,
|
||||
latitude: null,
|
||||
},
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
|
||||
app: [{ required: true, message: "请输入应用名", trigger: "blur" }],
|
||||
stream: [{ required: true, message: "请输入流ID", trigger: "blur" }],
|
||||
gbId: [{ required: true, message: "请输入国标编码", trigger: "blur" }],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (proxyParam, callback) {
|
||||
this.showDialog = true;
|
||||
this.listChangeCallback = callback;
|
||||
if (proxyParam != null) {
|
||||
this.proxyParam = proxyParam;
|
||||
this.edit = true
|
||||
}else{
|
||||
this.proxyParam= {
|
||||
name: null,
|
||||
app: null,
|
||||
stream: null,
|
||||
gbId: null,
|
||||
longitude: null,
|
||||
latitude: null,
|
||||
}
|
||||
this.edit = false
|
||||
}
|
||||
},
|
||||
onSubmit: function () {
|
||||
console.log("onSubmit");
|
||||
if (this.edit) {
|
||||
this.$axios({
|
||||
method:"post",
|
||||
url:`/api/push/save_to_gb`,
|
||||
data: this.proxyParam
|
||||
}).then( (res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: "success",
|
||||
});
|
||||
this.showDialog = false;
|
||||
if (this.listChangeCallback != null) {
|
||||
this.listChangeCallback();
|
||||
}
|
||||
}
|
||||
}).catch((error)=> {
|
||||
console.log(error);
|
||||
});
|
||||
}else {
|
||||
this.$axios({
|
||||
method:"post",
|
||||
url:`/api/push/add`,
|
||||
data: this.proxyParam
|
||||
}).then( (res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: "保存成功",
|
||||
type: "success",
|
||||
});
|
||||
this.showDialog = false;
|
||||
if (this.listChangeCallback != null) {
|
||||
this.listChangeCallback();
|
||||
}
|
||||
}
|
||||
}).catch((error)=> {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
close: function () {
|
||||
console.log("关闭加入GB");
|
||||
this.showDialog = false;
|
||||
this.$refs.streamProxy.resetFields();
|
||||
},
|
||||
deviceGBIdExit: async function (deviceGbId) {
|
||||
var result = false;
|
||||
var that = this;
|
||||
await that.$axios({
|
||||
method:"get",
|
||||
url:`/api/platform/exit/${deviceGbId}`
|
||||
}).then(function (res) {
|
||||
result = res.data;
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
checkExpires: function() {
|
||||
if (this.platform.enable && this.platform.expires == "0") {
|
||||
this.platform.expires = "300";
|
||||
}
|
||||
},
|
||||
handleNodeClick: function (node){
|
||||
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,107 +0,0 @@
|
||||
<template>
|
||||
<div id="queryTrace" >
|
||||
<el-dialog
|
||||
title="查询轨迹"
|
||||
width="40%"
|
||||
top="2rem"
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showDialog"
|
||||
:destroy-on-close="true"
|
||||
@close="close()"
|
||||
>
|
||||
<div v-loading="isLoging">
|
||||
<el-date-picker v-model="searchFrom" type="datetime" placeholder="选择开始日期时间" default-time="00:00:00" value-format="yyyy-MM-dd HH:mm:ss" size="mini" style="width: 11rem;" align="right" :picker-options="pickerOptions"></el-date-picker>
|
||||
<el-date-picker v-model="searchTo" type="datetime" placeholder="选择结束日期时间" default-time="00:00:00" value-format="yyyy-MM-dd HH:mm:ss" size="mini" style="width: 11rem;" align="right" :picker-options="pickerOptions"></el-date-picker>
|
||||
<el-button icon="el-icon-search" size="mini" type="primary" @click="onSubmit">查询</el-button>
|
||||
</div>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DeviceService from '../service/DeviceService'
|
||||
|
||||
export default {
|
||||
name: "deviceEdit",
|
||||
props: [],
|
||||
computed: {},
|
||||
created() {},
|
||||
data() {
|
||||
return {
|
||||
deviceService: new DeviceService(),
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '今天',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', new Date());
|
||||
}
|
||||
}, {
|
||||
text: '昨天',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
picker.$emit('pick', date);
|
||||
}
|
||||
}, {
|
||||
text: '一周前',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', date);
|
||||
}
|
||||
}]
|
||||
},
|
||||
searchFrom: null,
|
||||
searchTo: null,
|
||||
listChangeCallback: null,
|
||||
showDialog: false,
|
||||
isLoging: false,
|
||||
channel: null,
|
||||
callback: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (channel, callback) {
|
||||
console.log(channel)
|
||||
this.showDialog = true;
|
||||
this.callback = callback;
|
||||
this.channel = channel;
|
||||
},
|
||||
|
||||
onSubmit: function () {
|
||||
console.log("onSubmit");
|
||||
this.isLoging = true;
|
||||
let url = `/api/position/history/${this.channel.deviceId}?start=${this.searchFrom}&end=${this.searchTo}`;
|
||||
if (this.channel.channelId) {
|
||||
url+="&channelId=${this.channel.channelId}"
|
||||
}
|
||||
this.$axios.get(url, {
|
||||
}).then((res)=> {
|
||||
this.isLoging = false;
|
||||
if (typeof this.callback == "function") {
|
||||
if (res.data.code == 0) {
|
||||
this.callback(res.data.data)
|
||||
this.close()
|
||||
}else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}).catch(function (error) {
|
||||
this.isLoging = false;
|
||||
console.error(error);
|
||||
})
|
||||
},
|
||||
close: function () {
|
||||
this.showDialog = false;
|
||||
this.isLoging = false;
|
||||
this.callback = null;
|
||||
this.channel = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@ -1,156 +0,0 @@
|
||||
<template>
|
||||
<div id="recordDownload" >
|
||||
<el-dialog :title="title" v-if="showDialog" width="45rem" :append-to-body="true" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()" center>
|
||||
<el-row>
|
||||
<el-col :span="18" style="padding-top: 7px;">
|
||||
<el-progress :percentage="percentage"></el-progress>
|
||||
</el-col>
|
||||
<el-col :span="6" >
|
||||
<el-button icon="el-icon-download" v-if="downloadFile" size="mini" title="点击下载" @click="downloadFileClientEvent()">下载</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
export default {
|
||||
name: 'recordDownload',
|
||||
created() {
|
||||
window.addEventListener('beforeunload', this.stopDownloadRecord)
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: "下载中...",
|
||||
deviceId: "",
|
||||
channelId: "",
|
||||
app: "",
|
||||
stream: "",
|
||||
mediaServerId: "",
|
||||
showDialog: false,
|
||||
scale: 1,
|
||||
percentage: 0.00,
|
||||
streamInfo: null,
|
||||
taskId: null,
|
||||
getProgressRun: false,
|
||||
timer: null,
|
||||
downloadFile: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (deviceId, channelId, app, stream, mediaServerId) {
|
||||
this.deviceId = deviceId;
|
||||
this.channelId = channelId;
|
||||
this.app = app;
|
||||
this.stream = stream;
|
||||
this.mediaServerId = mediaServerId;
|
||||
this.showDialog = true;
|
||||
this.getProgressRun = true;
|
||||
this.percentage = 0.0;
|
||||
this.downloadFile = null;
|
||||
this.getProgressTimer()
|
||||
},
|
||||
getProgressTimer: function (){
|
||||
if (!this.getProgressRun) {
|
||||
return;
|
||||
}
|
||||
if (this.downloadFile) {
|
||||
return;
|
||||
}
|
||||
setTimeout( ()=>{
|
||||
if (!this.showDialog) return;
|
||||
this.getProgress(this.getProgressTimer)
|
||||
}, 5000)
|
||||
},
|
||||
getProgress: function (callback){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/gb_record/download/progress/${this.deviceId}/${this.channelId}/${this.stream}`
|
||||
}).then((res)=> {
|
||||
if (res.data.code === 0) {
|
||||
this.streamInfo = res.data.data;
|
||||
if (parseFloat(res.data.progress) === 1) {
|
||||
this.percentage = 100;
|
||||
}else {
|
||||
this.percentage = (parseFloat(res.data.data.progress)*100).toFixed(1);
|
||||
}
|
||||
if (this.streamInfo.downLoadFilePath) {
|
||||
if (location.protocol === "https:") {
|
||||
this.downloadFile = this.streamInfo.downLoadFilePath.httpsPath;
|
||||
}else {
|
||||
this.downloadFile = this.streamInfo.downLoadFilePath.httpPath;
|
||||
}
|
||||
this.percentage = 100
|
||||
this.getProgressRun = false;
|
||||
this.downloadFileClientEvent()
|
||||
}
|
||||
if (callback)callback();
|
||||
}else {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: res.data.msg,
|
||||
type: "error",
|
||||
});
|
||||
this.close();
|
||||
}
|
||||
|
||||
}).catch((e) =>{
|
||||
console.log(e)
|
||||
});
|
||||
},
|
||||
close: function (){
|
||||
if (this.streamInfo.progress < 1) {
|
||||
this.stopDownloadRecord();
|
||||
}
|
||||
|
||||
if (this.timer !== null) {
|
||||
window.clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
this.showDialog=false;
|
||||
this.getProgressRun = false;
|
||||
},
|
||||
gbScale: function (scale){
|
||||
this.scale = scale;
|
||||
},
|
||||
|
||||
stopDownloadRecord: function (callback) {
|
||||
if (this.deviceId && this.channelId && this.stream) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.stream
|
||||
}).then((res)=> {
|
||||
if (callback) callback(res)
|
||||
});
|
||||
}
|
||||
},
|
||||
downloadFileClientEvent: function (){
|
||||
// window.open(this.downloadFile )
|
||||
|
||||
let x = new XMLHttpRequest();
|
||||
x.open("GET", this.downloadFile, true);
|
||||
x.responseType = 'blob';
|
||||
x.onload=(e)=> {
|
||||
let url = window.URL.createObjectURL(x.response)
|
||||
let a = document.createElement('a');
|
||||
a.href = url
|
||||
a.download = this.deviceId + "-" + this.channelId + ".mp4";
|
||||
a.click()
|
||||
}
|
||||
x.send();
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('beforeunload', this.stopDownloadRecord)
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@ -1,275 +0,0 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="生成行政区划编码"
|
||||
width="65rem"
|
||||
top="2rem"
|
||||
center
|
||||
:close-on-click-modal="false"
|
||||
:visible.sync="showVideoDialog"
|
||||
:destroy-on-close="false"
|
||||
>
|
||||
<el-tabs v-model="activeKey" style="padding: 0 1rem; margin: auto 0" @tab-click="getRegionList">
|
||||
<el-tab-pane name="0" >
|
||||
<div slot="label" >
|
||||
<div class="show-code-item">{{ allVal[0].val }}</div>
|
||||
<div style="text-align: center">{{ allVal[0].meaning }}</div>
|
||||
</div>
|
||||
<el-radio v-for="item in regionList" v-model="allVal[0].val" :key="item.deviceId" :name="item.name" :label="item.deviceId" @input="deviceChange(item)" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.deviceId }}
|
||||
</el-radio>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="1">
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[1].val?allVal[1].val:"--" }}</div>
|
||||
<div style="text-align: center">{{ allVal[1].meaning }}</div>
|
||||
</div>
|
||||
<el-radio :key="-1" v-model="allVal[1].val" @input="deviceChange" label="" style="line-height: 2rem">
|
||||
不添加
|
||||
</el-radio>
|
||||
<el-radio v-for="item in regionList" v-model="allVal[1].val" @input="deviceChange(item)" :key="item.deviceId" :label="item.deviceId.substring(2)" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.deviceId.substring(2) }}
|
||||
</el-radio>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="2">
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[2].val?allVal[2].val:"--" }}</div>
|
||||
<div style="text-align: center">{{ allVal[2].meaning }}</div>
|
||||
</div>
|
||||
<el-radio :key="-1" label="" v-model="allVal[2].val" style="line-height: 2rem" @input="deviceChange">
|
||||
不添加
|
||||
</el-radio>
|
||||
<el-radio v-for="item in regionList" v-model="allVal[2].val" @input="deviceChange(item)" :key="item.deviceId" :label="item.deviceId.substring(4)" style="line-height: 2rem">
|
||||
{{ item.name }} - {{ item.deviceId.substring(4) }}
|
||||
</el-radio>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="3">
|
||||
请手动输入基层接入单位编码,两位数字
|
||||
<div slot="label">
|
||||
<div class="show-code-item">{{ allVal[3].val?allVal[3].val:"--" }}</div>
|
||||
<div style="text-align: center">{{ allVal[3].meaning }}</div>
|
||||
</div>
|
||||
<el-input
|
||||
type="text"
|
||||
placeholder="请输入内容"
|
||||
v-model="allVal[3].val"
|
||||
maxlength="2"
|
||||
:disabled="allVal[3].lock"
|
||||
show-word-limit
|
||||
@input="deviceChange"
|
||||
>
|
||||
</el-input>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form style="">
|
||||
|
||||
<el-form-item style="margin-top: 22px; margin-bottom: 0;">
|
||||
<div style="float:right;">
|
||||
<el-button type="primary" @click="handleOk">保存</el-button>
|
||||
<el-button @click="closeModel">取消</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: {},
|
||||
computed: {},
|
||||
data() {
|
||||
return {
|
||||
showVideoDialog: false,
|
||||
activeKey: '0',
|
||||
allVal: [
|
||||
{
|
||||
id: [1, 2],
|
||||
meaning: '省级编码',
|
||||
val: '11',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [3, 4],
|
||||
meaning: '市级编码',
|
||||
val: '',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [5, 6],
|
||||
meaning: '区级编码',
|
||||
val: '',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [7, 8],
|
||||
meaning: '基层接入单位编码',
|
||||
val: '',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
}
|
||||
],
|
||||
regionList: [],
|
||||
deviceTypeList: [],
|
||||
industryCodeTypeList: [],
|
||||
networkIdentificationTypeList: [],
|
||||
endCallBck: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openDialog: function (endCallBck, code, lockContent) {
|
||||
this.showVideoDialog = true
|
||||
this.activeKey= '0';
|
||||
this.regionList = []
|
||||
this.allVal = [
|
||||
{
|
||||
id: [1, 2],
|
||||
meaning: '省级编码',
|
||||
val: '11',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [3, 4],
|
||||
meaning: '市级编码',
|
||||
val: '',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [5, 6],
|
||||
meaning: '区级编码',
|
||||
val: '',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
},
|
||||
{
|
||||
id: [7, 8],
|
||||
meaning: '基层接入单位编码',
|
||||
val: '',
|
||||
type: '中心编码',
|
||||
lock: false,
|
||||
}
|
||||
]
|
||||
if (code) {
|
||||
if (code.length >= 2) {
|
||||
this.allVal[0].val = code.substring(0, 2)
|
||||
this.activeKey = "0"
|
||||
}
|
||||
if (code.length >= 4) {
|
||||
this.allVal[1].val = code.substring(2, 4)
|
||||
this.activeKey = "1"
|
||||
}
|
||||
if (code.length >= 6) {
|
||||
this.allVal[2].val = code.substring(4, 6)
|
||||
this.activeKey = "2"
|
||||
}
|
||||
if (code.length === 8) {
|
||||
this.allVal[3].val = code.substring(6, 8)
|
||||
this.activeKey = "3"
|
||||
}
|
||||
}
|
||||
|
||||
this.getRegionList()
|
||||
this.endCallBck = endCallBck;
|
||||
},
|
||||
getRegionList: function() {
|
||||
console.log("getRegionList")
|
||||
if (this.activeKey === '0' ) {
|
||||
this.queryChildList();
|
||||
}else if (this.activeKey === '1' || this.activeKey === '2') {
|
||||
let parent = ''
|
||||
if (this.activeKey === '1') {
|
||||
parent = this.allVal[0].val
|
||||
}
|
||||
if (this.activeKey === '2') {
|
||||
if (this.allVal[1].val === ""){
|
||||
parent = ""
|
||||
} else {
|
||||
parent = this.allVal[0].val + this.allVal[1].val
|
||||
}
|
||||
}
|
||||
if (this.activeKey !== '0' && parent === '') {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: "请先选择上级行政区划"
|
||||
})
|
||||
}
|
||||
if (parent !== "") {
|
||||
this.queryChildList(parent);
|
||||
}else {
|
||||
this.regionList = []
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
queryChildList: function(parent){
|
||||
console.log("queryChildList")
|
||||
this.regionList = []
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: "/api/region/base/child/list",
|
||||
params: {
|
||||
parent: parent,
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.data.code === 0) {
|
||||
this.regionList = res.data.data
|
||||
} else {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: res.data.msg
|
||||
})
|
||||
}
|
||||
}).catch((error) => {
|
||||
this.$message.error({
|
||||
showClose: true,
|
||||
message: error
|
||||
});
|
||||
});
|
||||
},
|
||||
handleOk: function (){
|
||||
const code =
|
||||
this.allVal[0].val +
|
||||
this.allVal[1].val +
|
||||
this.allVal[2].val +
|
||||
this.allVal[3].val
|
||||
console.log(code)
|
||||
if (this.endCallBck) {
|
||||
this.endCallBck(code)
|
||||
}
|
||||
this.showVideoDialog = false
|
||||
},
|
||||
closeModel: function (){
|
||||
this.showVideoDialog = false
|
||||
},
|
||||
deviceChange: function (item){
|
||||
console.log(item)
|
||||
let code = this.allVal[0].val
|
||||
if (this.allVal[1].val) {
|
||||
code += this.allVal[1].val
|
||||
if (this.allVal[2].val) {
|
||||
code += this.allVal[2].val
|
||||
if (this.allVal[3].val) {
|
||||
code += this.allVal[3].val
|
||||
}
|
||||
}else {
|
||||
this.allVal[3].val = ""
|
||||
}
|
||||
}else {
|
||||
this.allVal[2].val = ""
|
||||
this.allVal[3].val = ""
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.show-code-item {
|
||||
text-align: center;
|
||||
font-size: 3rem;
|
||||
}
|
||||
</style>
|
||||