Merge remote-tracking branch 'origin/feature/1.6.2'
This commit is contained in:
@@ -5,6 +5,7 @@ data.db*
|
||||
.neutrino-proxy.license
|
||||
.neutrino-proxy-client.json*
|
||||
lib/*
|
||||
SensitiveInformation.txt
|
||||
|
||||
|
||||
# Log file
|
||||
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
# 中微子代理客户端启动脚本,基础参数请自行修改
|
||||
|
||||
JAVA_OPS="-server -Xms256m -Xmx512m -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/work/$NAME/heapError/"
|
||||
export JAVA_HOME=/work/programs/jdk/jdk1.8.0_171
|
||||
export PATH=:$PATH:$JAVA_HOME/bin
|
||||
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
|
||||
mkdir -p /work/$NAME/heapError/
|
||||
|
||||
NAME=neutrino-proxy-client
|
||||
WORK=/work/projects
|
||||
OUT=$WORK/$NAME/$NAME.out
|
||||
JAR_PATH=$WORK/$NAME
|
||||
|
||||
function start(){
|
||||
PID=`jps -l | grep $NAME.jar | cut -d' ' -f 1`
|
||||
if [ -n "$PID" ]; then
|
||||
echo "kill pid : $PID"
|
||||
kill $PID
|
||||
fi
|
||||
sleep 3
|
||||
if [ -n "$PID" ]; then
|
||||
echo "kill fail & kill -9 pid : $PID"
|
||||
kill -9 $PID
|
||||
fi
|
||||
if [ -f "$OUT" ]; then
|
||||
time=$(date "+%Y%m%d-%H%M%S")
|
||||
cp $OUT $JAR_PATH/logs/back_$time.out
|
||||
fi
|
||||
rm -f $OUT
|
||||
cd $JAR_PATH
|
||||
nohup java $JAVA_OPS -jar $NAME.jar > $OUT 2>&1 &
|
||||
echo "sleep 15s wating service start"
|
||||
sleep 15
|
||||
tail -200 $OUT
|
||||
echo "start ${JAR_PATH} success ;log path:$OUT"
|
||||
}
|
||||
|
||||
start
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
# 中微子代理服务端启动脚本,基础参数请自行修改
|
||||
|
||||
JAVA_OPS="-server -Xms256m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/work/$NAME/heapError/"
|
||||
export JAVA_HOME=/work/programs/jdk/jdk1.8.0_171
|
||||
export PATH=:$PATH:$JAVA_HOME/bin
|
||||
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
|
||||
mkdir -p /work/$NAME/heapError/
|
||||
|
||||
NAME=neutrino-proxy-server
|
||||
WORK=/work/projects
|
||||
OUT=$WORK/$NAME/$NAME.out
|
||||
JAR_PATH=$WORK/$NAME
|
||||
|
||||
function start(){
|
||||
PID=`jps -l | grep $NAME.jar | cut -d' ' -f 1`
|
||||
if [ -n "$PID" ]; then
|
||||
echo "kill pid : $PID"
|
||||
kill $PID
|
||||
fi
|
||||
sleep 3
|
||||
if [ -n "$PID" ]; then
|
||||
echo "kill fail & kill -9 pid : $PID"
|
||||
kill -9 $PID
|
||||
fi
|
||||
if [ -f "$OUT" ]; then
|
||||
time=$(date "+%Y%m%d-%H%M%S")
|
||||
cp $OUT $JAR_PATH/logs/back_$time.out
|
||||
fi
|
||||
rm -f $OUT
|
||||
cd $JAR_PATH
|
||||
nohup java $JAVA_OPS -jar $NAME.jar > $OUT 2>&1 &
|
||||
echo "sleep 15s wating service start"
|
||||
sleep 15
|
||||
tail -200 $OUT
|
||||
echo "start ${JAR_PATH} success ;log path:$OUT"
|
||||
}
|
||||
|
||||
start
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
- 1.3、服务端通过`CmdChannel`接收到来自客户端的`Auth`指令。若验证`license`有效,则建立`licenseId`与`CmdChannel`的映射缓存、
|
||||
外网端口与`CmdChannel`的映射缓存。并启动服务端代理端口,等待用户连接。
|
||||
## 2、用户连接阶段
|
||||
- 2.1、用户访向服务端代理的外网端口发起请求,服务端建立`VisitorChannel`。
|
||||
- 2.1、用户向服务端代理的外网端口发起请求,服务端建立`VisitorChannel`。
|
||||
- 2.2、根据外网端口查找`CmdChannel`,若不存在有效的`CmdChannel`,则关闭该`VisitorChannel`。否则,
|
||||
设置`VisitorChannel`为不可读,并携带内网映射信息(如:`127.0.0.1:3306`)通过`CmdChannel`向客户端发送`Connect`指令。
|
||||
## 3、实际被代理服务连接阶段
|
||||
|
||||
@@ -171,6 +171,7 @@ public class AsgcCompiler {
|
||||
|
||||
/**
|
||||
* 编译代码
|
||||
* @param pkg 包名
|
||||
* @param className 类名
|
||||
* @param sourceCode 源代码
|
||||
*/
|
||||
|
||||
@@ -145,6 +145,19 @@ public class DateUtil {
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该日期当月第一天
|
||||
*
|
||||
* @param date 日期
|
||||
* @return 结果日期
|
||||
*/
|
||||
public static Date getMonthBegin(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(getDayBegin(date));
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该日期当月最后一天
|
||||
*
|
||||
@@ -153,10 +166,10 @@ public class DateUtil {
|
||||
*/
|
||||
public static Date getMonthEnd(Date date) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(getDayEnd(date));
|
||||
calendar.setTime(getDayBegin(date));
|
||||
calendar.add(Calendar.MONTH, 1);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -1);
|
||||
calendar.add(Calendar.MILLISECOND, -1);
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
'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 HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
const portfinder = require('portfinder')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
const HOST = process.env.HOST
|
||||
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: true,
|
||||
hot: true,
|
||||
compress: true,
|
||||
host: HOST || config.dev.host,
|
||||
port: 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/local.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,
|
||||
favicon: resolve('favicon.ico'),
|
||||
title: 'vue-element-admin',
|
||||
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
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,5 +1,5 @@
|
||||
module.exports = {
|
||||
NODE_ENV: '"development"',
|
||||
ENV_CONFIG: '"dev"',
|
||||
BASE_API: '"http://localhost:8888"'
|
||||
BASE_API: '"http://103.163.47.16:8888"'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
NODE_ENV: '"development"',
|
||||
ENV_CONFIG: '"local"',
|
||||
BASE_API: '"http://localhost:8888"'
|
||||
}
|
||||
@@ -6,7 +6,9 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host=0.0.0.0",
|
||||
"local": "webpack-dev-server --inline --progress --config build/webpack.local.conf.js",
|
||||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||
"build:local": "cross-env NODE_ENV=dev env_config=local node build/build.js",
|
||||
"build:dev": "cross-env NODE_ENV=dev env_config=dev node build/build.js",
|
||||
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
|
||||
"build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function fetchList(query) {
|
||||
return request({
|
||||
url: '/client-connect-record/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -51,3 +51,13 @@ export function deleteLicense(id) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function resetLicense(id) {
|
||||
return request({
|
||||
url: '/license/reset',
|
||||
method: 'post',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -73,3 +73,27 @@ export function hello() {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员修改成员密码
|
||||
* @param params
|
||||
*/
|
||||
export function updatePassword(params) {
|
||||
return request({
|
||||
url: '/user/update/password',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改自己密码
|
||||
* @param params
|
||||
*/
|
||||
export function updateUserPassword(params) {
|
||||
return request({
|
||||
url: '/user/current-user/update/password',
|
||||
method: 'post',
|
||||
data: params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -54,12 +54,14 @@ export default {
|
||||
jobManager: '调度管理',
|
||||
jobLog: '调度日志',
|
||||
log: '日志管理',
|
||||
loginLog: '登录日志'
|
||||
loginLog: '登录日志',
|
||||
clientConnectLog: '客户端连接日志'
|
||||
},
|
||||
navbar: {
|
||||
logOut: '退出登录',
|
||||
dashboard: '首页',
|
||||
github: '项目地址',
|
||||
updatePwd: '修改密码',
|
||||
screenfull: '全屏',
|
||||
theme: '换肤'
|
||||
},
|
||||
@@ -135,11 +137,20 @@ export default {
|
||||
jobParam: '任务参数',
|
||||
alarmEmail: '任务报警邮箱',
|
||||
alarmDing: '任务报警钉钉',
|
||||
jobLogCode: '执行结果',
|
||||
jobLogMsg: '执行日志',
|
||||
jobLogCode: '调度结果',
|
||||
jobLogMsg: '调度日志',
|
||||
jobLogTime: '调度时间',
|
||||
alarmStatus: '报警状态',
|
||||
ip: 'IP',
|
||||
happendTime: '发生时间'
|
||||
happendTime: '发生时间',
|
||||
updatePwd: '修改密码',
|
||||
msg: '消息',
|
||||
outcome: '结果',
|
||||
err: '异常信息',
|
||||
resetKey: '重置Key'
|
||||
},
|
||||
button: {
|
||||
lookOver: '查看'
|
||||
},
|
||||
errorLog: {
|
||||
tips: '请点击右上角bug小图标',
|
||||
|
||||
@@ -90,7 +90,8 @@ export const asyncRouterMap = [
|
||||
},
|
||||
children: [
|
||||
{ path: 'jobLog', component: _import('log/jobLog'), name: 'jobLog', meta: { title: 'jobLog' }},
|
||||
{ path: 'loginLog', component: _import('log/loginLog'), name: 'loginLog', meta: { title: 'loginLog' }}
|
||||
{ path: 'loginLog', component: _import('log/loginLog'), name: 'loginLog', meta: { title: 'loginLog' }},
|
||||
{ path: 'clientConnectLog', component: _import('log/clientConnectLog'), name: 'clientConnectLog', meta: { title: 'clientConnectLog' }}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
.fixed-width{
|
||||
.el-button--mini{
|
||||
padding: 7px 10px;
|
||||
width: 60px;
|
||||
min-width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ service.interceptors.response.use(
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
if (res.code === 4 && !window.location.href.endsWith('#/login')) {
|
||||
if ((res.code === 4 || res.code === 1) && !window.location.href.endsWith('#/login')) {
|
||||
store.dispatch('FedLogOut').then(() => {
|
||||
location.reload() // 为了重新实例化vue-router对象 避免bug
|
||||
})
|
||||
|
||||
@@ -33,12 +33,17 @@
|
||||
{{$t('navbar.github')}}
|
||||
</el-dropdown-item>
|
||||
</a>
|
||||
<el-dropdown-item>
|
||||
<span @click="updatePwdvisible = true">{{$t('navbar.updatePwd')}}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided>
|
||||
<span @click="logout" style="display:block;">{{$t('navbar.logOut')}}</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
||||
<UpdatePwd :visible="updatePwdvisible" @cancel="handleCancel"></UpdatePwd>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
@@ -50,9 +55,11 @@ import ErrorLog from '@/components/ErrorLog'
|
||||
import Screenfull from '@/components/Screenfull'
|
||||
import LangSelect from '@/components/LangSelect'
|
||||
import ThemePicker from '@/components/ThemePicker'
|
||||
import UpdatePwd from '../../system/components/update-pwd'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
UpdatePwd,
|
||||
Breadcrumb,
|
||||
Hamburger,
|
||||
ErrorLog,
|
||||
@@ -68,6 +75,11 @@ export default {
|
||||
'loginName'
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
updatePwdvisible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar() {
|
||||
this.$store.dispatch('toggleSideBar')
|
||||
@@ -76,6 +88,9 @@ export default {
|
||||
this.$store.dispatch('LogOut').then(() => {
|
||||
location.reload()// In order to re-instantiate the vue-router object to avoid bugs
|
||||
})
|
||||
},
|
||||
handleCancel() {
|
||||
this.updatePwdvisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,12 +145,12 @@ export default {
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.el-icon-caret-bottom {
|
||||
/*.el-icon-caret-bottom {
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<div class="filter-container">
|
||||
<el-button type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row style="width: 100%">
|
||||
<el-table-column type="index" width="100" :label="$t('table.id')"></el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.userName')" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.userName}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.licenseName')" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.licenseName}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.ip')" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.ip}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.type')" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.type | statusFilter">{{scope.row.type | statusName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.msg')" min-width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.msg}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.outcome')" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.code | statusFilter">{{scope.row.code | outcomeName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.err')" min-width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.err}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.happendTime')" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.createTime | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="listQuery.currentPage"
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
title="调度日志"
|
||||
:visible.sync="dialogVisible"
|
||||
width="700px"
|
||||
:before-close="() => this.dialogVisible = false">
|
||||
<div class="job-msg-div">{{selectRow.msg}}</div>
|
||||
<div slot="footer" class="dialog-footer"></div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fetchList } from '@/api/clientConnectLog'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'clientConnectLog',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableKey: 0,
|
||||
list: null,
|
||||
total: null,
|
||||
listLoading: false,
|
||||
listQuery: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
jobId: undefined
|
||||
},
|
||||
dialogVisible: false,
|
||||
selectRow: {}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
statusName(status) {
|
||||
const statusMap = {
|
||||
1: '连接',
|
||||
2: '断开'
|
||||
}
|
||||
return statusMap[status]
|
||||
},
|
||||
statusFilter(status) {
|
||||
const statusMap = {
|
||||
1: 'success',
|
||||
2: 'danger'
|
||||
}
|
||||
return statusMap[status]
|
||||
},
|
||||
outcomeName(status) {
|
||||
const statusMap = {
|
||||
1: '成功',
|
||||
2: '失败'
|
||||
}
|
||||
return statusMap[status]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
fetchList(this.listQuery).then(response => {
|
||||
this.list = response.data.data.records
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.currentPage = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.currentPage = 1
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.currentPage = val
|
||||
this.getList()
|
||||
},
|
||||
handleLookOver(row) {
|
||||
this.selectRow = row
|
||||
this.dialogVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.job-msg-div{
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,7 @@
|
||||
<el-select v-model="listQuery.jobId" placeholder="请选择" clearable>
|
||||
<el-option v-for="item in jobList" :key="item.id" :label="item.desc" :value="item.id"/>
|
||||
</el-select>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
|
||||
<el-button type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row style="width: 100%">
|
||||
@@ -24,9 +24,9 @@
|
||||
<el-tag :type="scope.row.code | statusFilter">{{scope.row.code | statusName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.jobLogMsg')" min-width="400">
|
||||
<el-table-column align="center" :label="$t('table.jobLogMsg')" min-width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.msg}}</span>
|
||||
<el-button type="text" @click="handleLookOver(scope.row)">{{$t('button.lookOver')}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.alarmStatus')" min-width="120">
|
||||
@@ -34,7 +34,7 @@
|
||||
<el-tag :type="scope.row.alarmStatus | alarmStatusFilter">{{scope.row.alarmStatus | salarmStatusName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.createTime')" min-width="150">
|
||||
<el-table-column align="center" :label="$t('table.jobLogTime')" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
<span>{{scope.row.createTime | parseTime('{y}-{m}-{d} {h}:{i}')}}</span>
|
||||
</template>
|
||||
@@ -50,6 +50,15 @@
|
||||
:page-sizes="[10,20,30, 50]" :page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
title="调度日志"
|
||||
:visible.sync="dialogVisible"
|
||||
width="700px"
|
||||
:before-close="() => this.dialogVisible = false">
|
||||
<div class="job-msg-div">{{selectRow.msg}}</div>
|
||||
<div slot="footer" class="dialog-footer"></div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -74,7 +83,9 @@ export default {
|
||||
pageSize: 10,
|
||||
jobId: undefined
|
||||
},
|
||||
jobList: []
|
||||
jobList: [],
|
||||
dialogVisible: false,
|
||||
selectRow: {}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
@@ -119,7 +130,6 @@ export default {
|
||||
this.getJobList()
|
||||
if (this.$route.query.jobId) {
|
||||
this.listQuery.jobId = this.$route.query.jobId
|
||||
console.log(this.listQuery.jobId, this.$route.query.jobId)
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
@@ -143,6 +153,7 @@ export default {
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.currentPage = 1
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
@@ -151,7 +162,18 @@ export default {
|
||||
},
|
||||
handleShowClick(row) {
|
||||
console.log(row)
|
||||
},
|
||||
handleLookOver(row) {
|
||||
this.selectRow = row
|
||||
this.dialogVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.job-msg-div{
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -121,6 +121,7 @@ export default {
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.pageSize = val
|
||||
this.listQuery.currentPage = 1
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
|
||||
@@ -47,14 +47,14 @@
|
||||
<el-tag :type="scope.row.isOnline | statusFilter">{{scope.row.isOnline | isOnlineName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="230" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="330" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">{{$t('table.edit')}}</el-button>
|
||||
<el-button size="mini" type="primary" @click="handleReset(scope.row)">{{$t('table.resetKey')}}</el-button>
|
||||
<el-button v-if="scope.row.enable =='1'" size="mini" type="danger" @click="handleModifyStatus(scope.row,2)">{{$t('table.disable')}}</el-button>
|
||||
<el-button v-if="scope.row.enable =='2'" size="mini" type="success" @click="handleModifyStatus(scope.row,1)">{{$t('table.enable')}}</el-button>
|
||||
<!-- <el-button size="mini" type="danger" @click="handleDelete(scope.row,'deleted')">{{$t('table.delete')}}</el-button>-->
|
||||
<ButtonPopover @handleCommitClick="handleDelete2(scope.row)" style="margin-left: 10px"/>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -98,7 +98,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fetchList, createLicense, updateLicense, updateEnableStatus, deleteLicense } from '@/api/license'
|
||||
import { fetchList, createLicense, updateLicense, updateEnableStatus, deleteLicense, resetLicense } from '@/api/license'
|
||||
import { userList } from '@/api/user'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { parseTime } from '@/utils'
|
||||
@@ -277,6 +277,25 @@
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
handleReset(row) {
|
||||
this.$confirm('确定重置吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
}).then(() => {
|
||||
resetLicense(row.id).then(response => {
|
||||
if (response.data.code === 0) {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '重置成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
updateData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog title="修改密码"
|
||||
:visible.sync="visible"
|
||||
:close-on-click-modal="false"
|
||||
:before-close="onCancel"
|
||||
:width="width"
|
||||
>
|
||||
<el-form :rules="rules" ref='form' :model="formData" label-position="left" label-width="80px" style='padding:0 20px'>
|
||||
<el-form-item label="登录名" prop="loginName" v-if="row">
|
||||
<el-input v-model="formData.loginName" disabled/>
|
||||
</el-form-item>
|
||||
<el-form-item label="旧密码" prop="oldLoginPassword" v-if="!row">
|
||||
<el-input v-model="formData.oldLoginPassword" type="password" placeholder="请输入旧密码"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="loginPassword">
|
||||
<el-input v-model="formData.loginPassword" type="password" placeholder="请输入新密码"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword" v-if="!row">
|
||||
<el-input v-model="formData.confirmPassword" type="password" placeholder="请输入确认密码"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="updatePwd">确定</el-button>
|
||||
<el-button @click="onCancel">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { updatePassword, updateUserPassword } from '@/api/user'
|
||||
|
||||
export default {
|
||||
name: 'updatePwd',
|
||||
props: {
|
||||
row: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
visible: Boolean,
|
||||
width: {
|
||||
type: String,
|
||||
default: '500px'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const validatorValue = (rule, value, callback) => {
|
||||
if (value === '' || !value) {
|
||||
callback(new Error('确认密码必填'))
|
||||
} else if (this.formData.loginPassword !== value) {
|
||||
callback(new Error('与新密码不一致'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
formData: {
|
||||
id: undefined,
|
||||
loginName: undefined,
|
||||
loginPassword: undefined,
|
||||
oldLoginPassword: undefined,
|
||||
confirmPassword: undefined
|
||||
},
|
||||
rules: {
|
||||
loginName: [
|
||||
{ required: true, message: '用户名', trigger: 'blur' }
|
||||
],
|
||||
loginPassword: [
|
||||
{ required: true, message: '新密码必填', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '密码长度为 6 到 10 位之间', trigger: 'blur' }
|
||||
],
|
||||
oldLoginPassword: [
|
||||
{ required: true, message: '旧密码必填', trigger: 'blur' }
|
||||
],
|
||||
confirmPassword: [
|
||||
{ required: true, validator: validatorValue, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.row && this.getRow()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getRow() {
|
||||
this.formData.id = this.row.id
|
||||
this.formData.loginName = this.row.loginName
|
||||
this.formData.loginPassword = ''
|
||||
},
|
||||
updatePwd() {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.row) {
|
||||
updatePassword(this.formData).then(res => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success('修改成功')
|
||||
this.onCancel()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
updateUserPassword(this.formData).then(res => {
|
||||
if (res.data.code === 0) {
|
||||
this.$message.success('修改成功')
|
||||
this.onCancel()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
onCancel() {
|
||||
this.$emit('cancel')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="app-container calendar-list-container">
|
||||
<div class="filter-container">
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">{{$t('table.search')}}</el-button>
|
||||
<el-button class="filter-item" style="margin-left: 10px;" @click="handleCreate" type="primary" icon="el-icon-edit">{{$t('table.add')}}</el-button>
|
||||
<el-button class="filter-item" style="margin-left: 10px" @click="handleCreate" type="primary" icon="el-icon-edit">{{$t('table.add')}}</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :key='tableKey' :data="list" v-loading="listLoading" element-loading-text="给我一点时间" border fit highlight-current-row
|
||||
@@ -37,14 +37,14 @@
|
||||
<el-tag :type="scope.row.enable | statusFilter">{{scope.row.enable | statusName}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="230" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" :label="$t('table.actions')" :width="loginName === 'admin' ? 320 : 230" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">{{$t('table.edit')}}</el-button>
|
||||
<el-button v-if="scope.row.enable =='1'" size="mini" type="danger" @click="handleModifyStatus(scope.row,2)">{{$t('table.disable')}}</el-button>
|
||||
<el-button v-if="scope.row.enable =='2'" size="mini" type="success" @click="handleModifyStatus(scope.row,1)">{{$t('table.enable')}}</el-button>
|
||||
<el-button v-if="scope.row.enable === 1" size="mini" type="danger" @click="handleModifyStatus(scope.row,2)">{{$t('table.disable')}}</el-button>
|
||||
<el-button v-if="scope.row.enable === 2" size="mini" type="success" @click="handleModifyStatus(scope.row,1)">{{$t('table.enable')}}</el-button>
|
||||
<el-button v-if="loginName === 'admin'" type="warning" size="mini" @click="handleUpdatePassword(scope.row)">{{$t('table.updatePwd')}}</el-button>
|
||||
<!-- <el-button size="mini" type="danger" @click="handleDelete(scope.row,'deleted')">{{$t('table.delete')}}</el-button>-->
|
||||
<ButtonPopover @handleCommitClick="handleDelete2(scope.row)" style="margin-left: 10px"/>
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -56,7 +56,7 @@
|
||||
</div>
|
||||
|
||||
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
|
||||
<el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="70px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form :rules="rules" ref="dataForm" :model="temp" label-position="left" label-width="70px" style='width: 400px; margin-left:50px'>
|
||||
<el-form-item :label="$t('用户名')" prop="name">
|
||||
<el-input v-model="temp.name"></el-input>
|
||||
</el-form-item>
|
||||
@@ -81,6 +81,8 @@
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<UpdatePwd :row="selectRow" :visible="updatePwdvisible" @cancel="handleCancel"></UpdatePwd>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -89,6 +91,8 @@
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { parseTime } from '@/utils'
|
||||
import ButtonPopover from '../../components/Button/buttonPopover'
|
||||
import UpdatePwd from './components/update-pwd'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
const calendarTypeOptions = [
|
||||
{ key: 'CN', display_name: 'China' },
|
||||
@@ -108,8 +112,14 @@
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'loginName'
|
||||
])
|
||||
},
|
||||
components: {
|
||||
ButtonPopover
|
||||
ButtonPopover,
|
||||
UpdatePwd
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -150,7 +160,9 @@
|
||||
name: [{ required: true, message: '用户名必填', trigger: 'blur' }],
|
||||
loginName: [{ required: true, message: '登录名必填', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
downloadLoading: false,
|
||||
updatePwdvisible: false,
|
||||
selectRow: null
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
@@ -327,6 +339,14 @@
|
||||
return v[j]
|
||||
}
|
||||
}))
|
||||
},
|
||||
handleUpdatePassword(row) {
|
||||
this.selectRow = row
|
||||
this.updatePwdvisible = true
|
||||
},
|
||||
handleCancel() {
|
||||
this.updatePwdvisible = false
|
||||
this.selectRow = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
<artifactId>druid</artifactId>
|
||||
<version>1.1.24</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.29</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- <build>-->
|
||||
|
||||
+39
-14
@@ -26,8 +26,11 @@ import com.google.common.collect.Lists;
|
||||
import fun.asgc.neutrino.core.annotation.PreLoad;
|
||||
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
|
||||
import fun.asgc.neutrino.core.util.*;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.config.SqliteConfig;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.config.DbConfig;
|
||||
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.sqlite.SQLiteConfig;
|
||||
import org.sqlite.SQLiteDataSource;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
import java.util.List;
|
||||
@@ -41,11 +44,18 @@ import java.util.List;
|
||||
@PreLoad("init")
|
||||
public class DBInitialize {
|
||||
private static List<String> initDataTableNameList = Lists.newArrayList("user", "license", "port_pool", "port_mapping", "job_info");
|
||||
private static SqliteConfig sqliteConfig;
|
||||
private static DbConfig dbConfig;
|
||||
private static JdbcTemplate jdbcTemplate;
|
||||
|
||||
private static DbTypeEnum dbTypeEnum;
|
||||
|
||||
public static void init() throws Exception {
|
||||
sqliteConfig = ConfigUtil.getYmlConfig(SqliteConfig.class);
|
||||
dbConfig = ConfigUtil.getYmlConfig(DbConfig.class);
|
||||
Assert.notNull(dbConfig.getType(), "neutrino.data.db.type不能为空!");
|
||||
dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
|
||||
Assert.notNull(dbTypeEnum, "neutrino.data.db.type取值异常!");
|
||||
|
||||
log.info("{}数据库初始化...", dbConfig.getType());
|
||||
jdbcTemplate = getJdbcTemplate();
|
||||
initDBStructure();
|
||||
initDBData();
|
||||
@@ -55,7 +65,7 @@ public class DBInitialize {
|
||||
* 初始化数据库结构
|
||||
*/
|
||||
private static void initDBStructure() throws Exception {
|
||||
List<String> lines = FileUtil.readContentAsStringList("classpath:/sql/init-structure.sql");
|
||||
List<String> lines = FileUtil.readContentAsStringList(String.format("classpath:/sql/%s/init-structure.sql", dbConfig.getType()));
|
||||
if (CollectionUtil.isEmpty(lines)) {
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +97,7 @@ public class DBInitialize {
|
||||
if (count > 0) {
|
||||
continue;
|
||||
}
|
||||
List<String> lines = FileUtil.readContentAsStringList(String.format("classpath:/sql/%s.data.sql", tableName));
|
||||
List<String> lines = FileUtil.readContentAsStringList(String.format("classpath:/sql/%s/%s.data.sql", dbConfig.getType(), tableName));
|
||||
if (CollectionUtil.isEmpty(lines)) {
|
||||
return;
|
||||
}
|
||||
@@ -116,15 +126,30 @@ public class DBInitialize {
|
||||
() -> null == jdbcTemplate,
|
||||
DBInitialize.class,
|
||||
() -> {
|
||||
Class.forName(sqliteConfig.getDriverClass());
|
||||
//建立一个数据库名data.db的连接,如果不存在就在当前目录下创建之
|
||||
DriverManager.getConnection(sqliteConfig.getUrl());
|
||||
// 创建数据源
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setUrl(sqliteConfig.getUrl());
|
||||
dataSource.setDriverClassName(sqliteConfig.getDriverClass());
|
||||
// 创建jdbcTemplate
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
if (DbTypeEnum.SQLITE == dbTypeEnum) {
|
||||
//建立一个数据库名data.db的连接,如果不存在就在当前目录下创建之
|
||||
DriverManager.getConnection(dbConfig.getUrl());
|
||||
// 创建数据源
|
||||
SQLiteDataSource dataSource = new SQLiteDataSource();
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
|
||||
// 创建jdbcTemplate
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setDriverClassName(dbConfig.getDriverClass());
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setInitialSize(5);
|
||||
dataSource.setMinIdle(5);
|
||||
dataSource.setMaxActive(20);
|
||||
dataSource.setMaxWait(60000);
|
||||
dataSource.setPoolPreparedStatements(true);
|
||||
dataSource.setUsername(dbConfig.getUsername());
|
||||
dataSource.setPassword(dbConfig.getPassword());
|
||||
|
||||
// 创建jdbcTemplate
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
},
|
||||
() -> jdbcTemplate
|
||||
);
|
||||
|
||||
+21
-2
@@ -24,6 +24,7 @@ package fun.asgc.neutrino.proxy.server.base.rest.config;
|
||||
import fun.asgc.neutrino.core.annotation.Configuration;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.annotation.Value;
|
||||
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -33,8 +34,14 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@NonIntercept
|
||||
@Configuration(prefix = "neutrino.data.sqlite")
|
||||
public class SqliteConfig {
|
||||
@Configuration(prefix = "neutrino.data.db")
|
||||
public class DbConfig {
|
||||
/**
|
||||
* 数据库类型
|
||||
* {@link DbTypeEnum}
|
||||
*/
|
||||
@Value("type")
|
||||
private String type;
|
||||
/**
|
||||
* 连接url
|
||||
*/
|
||||
@@ -45,4 +52,16 @@ public class SqliteConfig {
|
||||
*/
|
||||
@Value("driver-class")
|
||||
private String driverClass;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@Value("username")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@Value("password")
|
||||
private String password;
|
||||
}
|
||||
+25
-5
@@ -21,9 +21,12 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.base.rest.config;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import fun.asgc.neutrino.core.annotation.*;
|
||||
import fun.asgc.neutrino.core.base.Ordered;
|
||||
import fun.asgc.neutrino.core.db.template.JdbcTemplate;
|
||||
import fun.asgc.neutrino.proxy.server.constant.DbTypeEnum;
|
||||
import org.sqlite.SQLiteConfig;
|
||||
import org.sqlite.SQLiteDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@@ -37,14 +40,31 @@ import javax.sql.DataSource;
|
||||
@Component
|
||||
public class RestConfiguration {
|
||||
@Autowired
|
||||
private SqliteConfig sqliteConfig;
|
||||
private DbConfig dbConfig;
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
SQLiteDataSource dataSource = new SQLiteDataSource();
|
||||
dataSource.setUrl(sqliteConfig.getUrl());
|
||||
dataSource.setJournalMode("WAL");
|
||||
return dataSource;
|
||||
DbTypeEnum dbTypeEnum = DbTypeEnum.of(dbConfig.getType());
|
||||
if (DbTypeEnum.SQLITE == dbTypeEnum) {
|
||||
SQLiteDataSource dataSource = new SQLiteDataSource();
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setJournalMode(SQLiteConfig.JournalMode.WAL.getValue());
|
||||
return dataSource;
|
||||
} else if (DbTypeEnum.MYSQL == dbTypeEnum) {
|
||||
DruidDataSource dataSource = new DruidDataSource();
|
||||
dataSource.setDriverClassName(dbConfig.getDriverClass());
|
||||
dataSource.setUrl(dbConfig.getUrl());
|
||||
dataSource.setInitialSize(5);
|
||||
dataSource.setMinIdle(5);
|
||||
dataSource.setMaxActive(20);
|
||||
dataSource.setMaxWait(60000);
|
||||
dataSource.setPoolPreparedStatements(true);
|
||||
dataSource.setUsername(dbConfig.getUsername());
|
||||
dataSource.setPassword(dbConfig.getPassword());
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.constant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 数据库类型美剧
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/25
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DbTypeEnum {
|
||||
SQLITE("sqlite"),
|
||||
MYSQL("mysql");
|
||||
|
||||
private String type;
|
||||
|
||||
private static final Map<String, DbTypeEnum> cache = Stream.of(DbTypeEnum.values()).collect(Collectors.toMap(DbTypeEnum::getType, Function.identity()));
|
||||
|
||||
public static DbTypeEnum of(String type) {
|
||||
return cache.get(type);
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.GetMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RestController;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.ClientConnectRecordService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/26
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@RequestMapping("client-connect-record")
|
||||
@RestController
|
||||
public class ClientConnectRecordController {
|
||||
@Autowired
|
||||
private ClientConnectRecordService clientConnectRecordService;
|
||||
|
||||
@GetMapping("page")
|
||||
public Page<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
return clientConnectRecordService.page(pageQuery, req);
|
||||
}
|
||||
}
|
||||
+38
@@ -21,11 +21,20 @@
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.web.annotation.GetMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RequestMapping;
|
||||
import fun.asgc.neutrino.core.web.annotation.RestController;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.LicenseFlowReportRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.ReportDataViewRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
|
||||
import fun.asgc.neutrino.proxy.server.service.ReportService;
|
||||
import fun.asgc.neutrino.proxy.server.util.ParamCheckUtil;
|
||||
|
||||
/**
|
||||
* 报表管理
|
||||
@@ -37,6 +46,9 @@ import fun.asgc.neutrino.proxy.server.controller.res.ReportDataViewRes;
|
||||
@RestController
|
||||
public class ReportController {
|
||||
|
||||
@Autowired
|
||||
private ReportService reportService;
|
||||
|
||||
/**
|
||||
* 数据一览:
|
||||
* 在线用户数 查询token有效的用户ID数
|
||||
@@ -59,4 +71,30 @@ public class ReportController {
|
||||
.setTotalUpstreamFlow("23K").setTotalDownwardFlow("47M")
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户流量报表分页
|
||||
* @param pageQuery
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("user/flow-report/page")
|
||||
public Page<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return reportService.userFlowReportPage(pageQuery, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* license流量报表分页
|
||||
* @param pageQuery
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("license/flow-report/page")
|
||||
public Page<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
|
||||
ParamCheckUtil.checkNotNull(pageQuery, "pageQuery");
|
||||
|
||||
return reportService.licenseFlowReportPage(pageQuery, req);
|
||||
}
|
||||
}
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/26
|
||||
*/
|
||||
@Data
|
||||
public class ClientConnectRecordListReq {
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/12/21
|
||||
*/
|
||||
@Data
|
||||
public class LicenseFlowReportReq {
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/12/21
|
||||
*/
|
||||
@Data
|
||||
public class UserFlowReportReq {
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.res;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/26
|
||||
*/
|
||||
@Data
|
||||
public class ClientConnectRecordListRes {
|
||||
private Integer id;
|
||||
private String ip;
|
||||
private Integer licenseId;
|
||||
private Integer type;
|
||||
private Integer userId;
|
||||
private String userName;
|
||||
private String licenseName;
|
||||
private String msg;
|
||||
/**
|
||||
* 1、成功
|
||||
* 2、失败
|
||||
*/
|
||||
private Integer code;
|
||||
private String err;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.res;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/12/21
|
||||
*/
|
||||
@Data
|
||||
public class LicenseFlowReportRes {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String userName;
|
||||
/**
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
/**
|
||||
* license名称
|
||||
*/
|
||||
private String licenseName;
|
||||
/**
|
||||
* 写入字节数
|
||||
*/
|
||||
private Long writeBytes;
|
||||
/**
|
||||
* 读取字节数
|
||||
*/
|
||||
private Long readBytes;
|
||||
/**
|
||||
* 写入流量描述
|
||||
*/
|
||||
private String writeFlowStr;
|
||||
/**
|
||||
* 读取流量描述
|
||||
*/
|
||||
private String readFlowStr;
|
||||
/**
|
||||
* 流量描述
|
||||
*/
|
||||
private String flowStr;
|
||||
/**
|
||||
* 报表时间
|
||||
*/
|
||||
private Date date;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.controller.res;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/12/21
|
||||
*/
|
||||
@Data
|
||||
public class UserFlowReportRes {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String userName;
|
||||
/**
|
||||
* 历史写入字节数
|
||||
*/
|
||||
private Long historyWriteBytes;
|
||||
/**
|
||||
* 历史读取字节数
|
||||
*/
|
||||
private Long historyReadBytes;
|
||||
/**
|
||||
* 写入字节数
|
||||
*/
|
||||
private Long writeBytes;
|
||||
/**
|
||||
* 读取字节数
|
||||
*/
|
||||
private Long readBytes;
|
||||
/**
|
||||
* 写入流量描述
|
||||
*/
|
||||
private String writeFlowStr;
|
||||
/**
|
||||
* 读取流量描述
|
||||
*/
|
||||
private String readFlowStr;
|
||||
/**
|
||||
* 流量描述
|
||||
*/
|
||||
private String flowStr;
|
||||
/**
|
||||
* 报表时间
|
||||
*/
|
||||
private Date date;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
}
|
||||
+9
@@ -2,7 +2,12 @@ package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.ResultType;
|
||||
import fun.asgc.neutrino.core.db.annotation.Select;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
|
||||
/**
|
||||
@@ -14,4 +19,8 @@ import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
public interface ClientConnectRecordMapper extends SqlMapper {
|
||||
|
||||
void add(ClientConnectRecordDO clientConnectRecordDO);
|
||||
|
||||
@ResultType(ClientConnectRecordListRes.class)
|
||||
@Select("select * from client_connect_record order by id desc")
|
||||
void page(Page page, ClientConnectRecordListReq req);
|
||||
}
|
||||
|
||||
+8
-6
@@ -26,6 +26,8 @@ import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.annotation.Delete;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/9/17
|
||||
@@ -35,21 +37,21 @@ import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
public interface DataCleanMapper extends SqlMapper {
|
||||
|
||||
@Delete("delete from `job_log` where create_time < ?")
|
||||
void cleanJobLog(long date);
|
||||
void cleanJobLog(Date date);
|
||||
|
||||
@Delete("delete from `user_login_record` where create_time < ?")
|
||||
void cleanUserLoginRecord(long date);
|
||||
void cleanUserLoginRecord(Date date);
|
||||
|
||||
@Delete("delete from `client_connect_record` where create_time < ?")
|
||||
void cleanClientConnectRecord(long date);
|
||||
void cleanClientConnectRecord(Date date);
|
||||
|
||||
@Delete("delete from `flow_report_minute` where create_time < ?")
|
||||
void cleanFlowMinuteReport(long date);
|
||||
void cleanFlowMinuteReport(Date date);
|
||||
|
||||
@Delete("delete from `flow_report_hour` where create_time < ?")
|
||||
void cleanFlowHourReport(long date);
|
||||
void cleanFlowHourReport(Date date);
|
||||
|
||||
@Delete("delete from `flow_report_day` where create_time < ?")
|
||||
void cleanFlowDayReport(long date);
|
||||
void cleanFlowDayReport(Date date);
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -77,7 +77,7 @@ public interface LicenseMapper extends SqlMapper {
|
||||
@Update("update `license` set is_online = :isOnline, update_time = :updateTime")
|
||||
void updateOnlineStatus(@Param("isOnline") Integer isOnline, @Param("updateTime") Date updateTime);
|
||||
|
||||
@Update("update `license` set key = :key,update_time = :updateTime where id = :id")
|
||||
@Update("update `license` set `key` = :key,update_time = :updateTime where id = :id")
|
||||
void reset(@Param("id") Integer id, @Param("key") String key, @Param("updateTime") Date updateTime);
|
||||
|
||||
@Delete("delete from `license` where id = ?")
|
||||
@@ -101,6 +101,6 @@ public interface LicenseMapper extends SqlMapper {
|
||||
@Select("select * from `license` where user_id = :userId and name =:name and id not in (:excludeIds) limit 0,1")
|
||||
LicenseDO checkRepeat(@Param("userId") Integer userId, @Param("name") String name, @Param("excludeIds") Set<Integer> excludeIds);
|
||||
|
||||
@Select("select * from `license` where key = ?")
|
||||
@Select("select * from `license` where `key` = ?")
|
||||
LicenseDO findByKey(String licenseKey);
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package fun.asgc.neutrino.proxy.server.dal;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.Param;
|
||||
import fun.asgc.neutrino.core.aop.Intercept;
|
||||
import fun.asgc.neutrino.core.db.mapper.SqlMapper;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2023/1/18
|
||||
*/
|
||||
@Intercept(ignoreGlobal = true)
|
||||
@Component
|
||||
public interface UserReportMapper extends SqlMapper {
|
||||
|
||||
void userFlowReportPage(Page<UserFlowReportRes> page, @Param("todayBegin") Date todayBegin, @Param("todayEnd") Date todayEnd);
|
||||
|
||||
}
|
||||
+1
-1
@@ -56,7 +56,7 @@ public interface UserTokenMapper extends SqlMapper {
|
||||
* @return
|
||||
*/
|
||||
// @Select("select * from user_token where token = ? and expiration_time > ?")
|
||||
UserTokenDO findByAvailableToken(String token, Long time);
|
||||
UserTokenDO findByAvailableToken(String token, Date date);
|
||||
|
||||
/**
|
||||
* 根据token删除记录
|
||||
|
||||
+6
-6
@@ -84,37 +84,37 @@ public class DataCleanJob implements IJobHandler {
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getJobLogKeepDays());
|
||||
log.info("清理调度管理日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanJobLog(date.getTime());
|
||||
dataCleanMapper.cleanJobLog(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getUserLoginRecordKeepDays());
|
||||
log.info("清理用户登录日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanUserLoginRecord(date.getTime());
|
||||
dataCleanMapper.cleanUserLoginRecord(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getClientConnectRecordKeepDays());
|
||||
log.info("清理客户端连接日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanClientConnectRecord(date.getTime());
|
||||
dataCleanMapper.cleanClientConnectRecord(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowMinuteReportKeepDays());
|
||||
log.info("清理流通统计分钟报表日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanFlowMinuteReport(date.getTime());
|
||||
dataCleanMapper.cleanFlowMinuteReport(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowHourReportKeepDays());
|
||||
log.info("清理流通统计小时报表日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanFlowHourReport(date.getTime());
|
||||
dataCleanMapper.cleanFlowHourReport(date);
|
||||
}
|
||||
|
||||
{
|
||||
Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowDayReportKeepDays());
|
||||
log.info("清理流通统计日报表日志 date:{}", sdf.format(date));
|
||||
dataCleanMapper.cleanFlowDayReport(date.getTime());
|
||||
dataCleanMapper.cleanFlowDayReport(date);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -63,11 +63,11 @@ public class FlowReportForMonthJob implements IJobHandler {
|
||||
Date now = new Date();
|
||||
String dateStr = DateUtil.format(DateUtil.addDate(now, Calendar.MONTH, -1), "yyyy-MM");
|
||||
Date date = DateUtil.parse(dateStr, "yyyy-MM");
|
||||
Date startDayDate = DateUtil.getDayBegin(date);
|
||||
Date endEndDate = DateUtil.getDayEnd(date);
|
||||
Date startDayDate = DateUtil.getMonthBegin(date);
|
||||
Date endEndDate = DateUtil.getMonthEnd(date);
|
||||
|
||||
// 删除原来的记录
|
||||
flowReportDayMapper.deleteByDateStr(dateStr);
|
||||
flowReportMonthMapper.deleteByDateStr(dateStr);
|
||||
|
||||
// 查询上个月的天级别统计数据
|
||||
List<FlowReportDayDO> flowReportDayList = flowReportDayMapper.findListByDateRange(startDayDate, endEndDate);
|
||||
|
||||
+59
@@ -24,10 +24,26 @@ package fun.asgc.neutrino.proxy.server.service;
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.core.util.CollectionUtil;
|
||||
import fun.asgc.neutrino.proxy.server.base.rest.SystemContextHolder;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.ClientConnectRecordListReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.ClientConnectRecordListRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.ClientConnectRecordMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.LicenseMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.UserMapper;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.ClientConnectRecordDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
|
||||
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/11/23
|
||||
@@ -38,8 +54,51 @@ import lombok.extern.slf4j.Slf4j;
|
||||
public class ClientConnectRecordService {
|
||||
@Autowired
|
||||
private ClientConnectRecordMapper clientConnectRecordMapper;
|
||||
@Autowired
|
||||
private LicenseMapper licenseMapper;
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
|
||||
public void add(ClientConnectRecordDO clientConnectRecordDO) {
|
||||
clientConnectRecordMapper.add(clientConnectRecordDO);
|
||||
}
|
||||
|
||||
public Page<ClientConnectRecordListRes> page(PageQuery pageQuery, ClientConnectRecordListReq req) {
|
||||
Page<ClientConnectRecordListRes> page = Page.create(pageQuery);
|
||||
clientConnectRecordMapper.page(page, req);
|
||||
if (CollectionUtil.isEmpty(page.getRecords())) {
|
||||
return page;
|
||||
}
|
||||
Set<Integer> licenseIds = page.getRecords().stream().map(ClientConnectRecordListRes::getLicenseId).collect(Collectors.toSet());
|
||||
if (CollectionUtil.isEmpty(licenseIds)) {
|
||||
return page;
|
||||
}
|
||||
List<LicenseDO> licenseList = licenseMapper.findByIds(licenseIds);
|
||||
if (CollectionUtil.isEmpty(licenseList)) {
|
||||
return page;
|
||||
}
|
||||
Set<Integer> userIds = licenseList.stream().map(LicenseDO::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, LicenseDO> licenseMap = licenseList.stream().collect(Collectors.toMap(LicenseDO::getId, Function.identity()));
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
boolean isAdmin = SystemContextHolder.isAdmin();
|
||||
page.getRecords().forEach(item -> {
|
||||
LicenseDO license = licenseMap.get(item.getLicenseId());
|
||||
if (null == license) {
|
||||
return;
|
||||
}
|
||||
item.setLicenseName(license.getName());
|
||||
item.setUserId(license.getUserId());
|
||||
UserDO user = userMap.get(license.getUserId());
|
||||
if (null == user) {
|
||||
return;
|
||||
}
|
||||
item.setUserName(user.getName());
|
||||
if (!isAdmin) {
|
||||
// msg可能带有license等敏感信息,若登录者为游客,则不展示
|
||||
item.setMsg("******");
|
||||
}
|
||||
});
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2022 aoshiguchen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package fun.asgc.neutrino.proxy.server.service;
|
||||
|
||||
import fun.asgc.neutrino.core.annotation.Autowired;
|
||||
import fun.asgc.neutrino.core.annotation.Component;
|
||||
import fun.asgc.neutrino.core.annotation.NonIntercept;
|
||||
import fun.asgc.neutrino.core.db.page.Page;
|
||||
import fun.asgc.neutrino.core.db.page.PageQuery;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.LicenseFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.req.UserFlowReportReq;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.LicenseFlowReportRes;
|
||||
import fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes;
|
||||
import fun.asgc.neutrino.proxy.server.dal.UserReportMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/12/23
|
||||
*/
|
||||
@Slf4j
|
||||
@NonIntercept
|
||||
@Component
|
||||
public class ReportService {
|
||||
|
||||
@Autowired
|
||||
private UserReportMapper userReportMapper;
|
||||
|
||||
/**
|
||||
* 用户流量报表分页
|
||||
* @param pageQuery
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public Page<UserFlowReportRes> userFlowReportPage(PageQuery pageQuery, UserFlowReportReq req) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* license流量报表分页
|
||||
* @param pageQuery
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public Page<LicenseFlowReportRes> licenseFlowReportPage(PageQuery pageQuery, LicenseFlowReportReq req) {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -115,7 +115,7 @@ public class UserService {
|
||||
|
||||
public UserDO findByToken(String token) {
|
||||
Date now = new Date();
|
||||
UserTokenDO userTokenDO = userTokenMapper.findByAvailableToken(token, now.getTime());
|
||||
UserTokenDO userTokenDO = userTokenMapper.findByAvailableToken(token, now);
|
||||
if (null == userTokenDO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,12 @@ neutrino:
|
||||
key-manager-password: 123456
|
||||
jks-path: classpath:/test.jks
|
||||
data:
|
||||
sqlite:
|
||||
db:
|
||||
type: sqlite
|
||||
url: jdbc:sqlite:data.db
|
||||
driver-class: org.sqlite.JDBC
|
||||
# type: mysql
|
||||
# url: jdbc:mysql://103.163.47.16:3306/neutrino-proxy?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useAffectedRows=true&useSSL=false
|
||||
# driver-class: com.mysql.jdbc.Driver
|
||||
# username: "******"
|
||||
# password: "******"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<mapper namespace = "fun.asgc.neutrino.proxy.server.dal.UserReportMapper">
|
||||
|
||||
<select id="userFlowReportPage" resultType="fun.asgc.neutrino.proxy.server.controller.res.UserFlowReportRes">
|
||||
SELECT
|
||||
u.id AS userId,
|
||||
u.NAME AS userName,
|
||||
IFNULL( SUM( frm.write_bytes ), 0 ) AS historyWriteBytes,
|
||||
IFNULL( SUM( frm.read_bytes ), 0 ) AS historyReadBytes
|
||||
FROM `user` u
|
||||
LEFT JOIN flow_report_month frm ON u.id = frm.user_id
|
||||
GROUP BY u.id
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,192 @@
|
||||
#############################系统管理相关表#############################
|
||||
#用户表
|
||||
CREATE TABLE IF NOT EXISTS `user` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`name` varchar(50) NOT NULL COMMENT '用户名',
|
||||
`login_name` varchar(50) NOT NULL COMMENT '登录名',
|
||||
`login_password` varchar(255) NOT NULL COMMENT '登录密码',
|
||||
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_user_login_name` (`login_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#用户token表
|
||||
CREATE TABLE IF NOT EXISTS `user_token` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`token` varchar(50) NOT NULL COMMENT 'token',
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`expiration_time` datetime(3) NOT NULL COMMENT '过期时间',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_user_token_user_id` (`user_id`),
|
||||
KEY `I_user_token_token` (`token`),
|
||||
KEY `I_user_token_expiration_time` (`expiration_time`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#端口池
|
||||
CREATE TABLE IF NOT EXISTS `port_pool` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`port` int NOT NULL COMMENT '端口',
|
||||
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_port_pool_port` (`port`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#############################代理配置相关表#############################
|
||||
#license表
|
||||
CREATE TABLE IF NOT EXISTS `license` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`name` varchar(50) NOT NULL COMMENT 'license名称',
|
||||
`key` varchar(100) NOT NULL COMMENT 'license key',
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)',
|
||||
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `I_license_key` (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#端口映射表
|
||||
CREATE TABLE IF NOT EXISTS `port_mapping` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`license_id` int NOT NULL COMMENT 'licenseID',
|
||||
`server_port` int NOT NULL COMMENT '服务端端口',
|
||||
`client_ip` varchar(20) NOT NULL COMMENT '客户端IP',
|
||||
`client_port` int NOT NULL COMMENT '客户端端口',
|
||||
`is_online` int NOT NULL COMMENT '是否在线(1、在线 2、离线)',
|
||||
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_port_mapping_server_port` (`server_port`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#############################日志管理相关表#############################
|
||||
#用户登录记录表
|
||||
CREATE TABLE IF NOT EXISTS `user_login_record` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`ip` varchar(50) NOT NULL COMMENT 'IP',
|
||||
`token` varchar(100) NOT NULL COMMENT 'token',
|
||||
`type` int NOT NULL COMMENT '类型(1、登录 2、登出)',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
#客户端连接记录表
|
||||
CREATE TABLE IF NOT EXISTS `client_connect_record` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'IP',
|
||||
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||
`type` int NOT NULL COMMENT '类型(1、连接 2、断开连接)',
|
||||
`msg` varchar(512) DEFAULT NULL COMMENT '消息',
|
||||
`code` int NOT NULL COMMENT '结果 (1、成功 2、失败)',
|
||||
`err` text DEFAULT NULL COMMENT '异常信息',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
#############################调度管理相关表#############################
|
||||
#触发器信息表
|
||||
CREATE TABLE IF NOT EXISTS `job_info` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`desc` varchar(255) NOT NULL COMMENT '描述',
|
||||
`handler` varchar(255) NOT NULL COMMENT '处理器',
|
||||
`cron` varchar(128) NOT NULL COMMENT 'cron',
|
||||
`param` varchar(512) DEFAULT NULL COMMENT '参数',
|
||||
`alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮箱',
|
||||
`alarm_ding` varchar(255) DEFAULT NULL COMMENT '报警钉钉配置',
|
||||
`enable` int NOT NULL COMMENT '是否启用(1、启用 2、禁用)',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
`update_time` datetime(3) NOT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_job_info_handler` (`handler`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#触发器日志表
|
||||
CREATE TABLE IF NOT EXISTS `job_log` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`job_id` int NOT NULL COMMENT 'JobId',
|
||||
`handler` varchar(255) NOT NULL COMMENT '处理器',
|
||||
`param` varchar(512) DEFAULT NULL COMMENT '参数',
|
||||
`code` int NOT NULL COMMENT '结果(1、成功 2、失败)',
|
||||
`msg` text COMMENT '消息',
|
||||
`alarm_status` int NOT NULL COMMENT '报警状态(1、未报警 2、已报警)',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `I_job_log_create_time` (`create_time`) USING BTREE,
|
||||
KEY `I_job_log_code` (`code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#############################报表管理相关表#############################
|
||||
#流量统计报表-分钟(保留24小时)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_minute` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||
`date_str` varchar(20) NOT NULL COMMENT '时间 yyyy-MM-dd HH:mm',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_flow_report_minute_create_time` (`create_time`) USING BTREE,
|
||||
KEY `I_flow_report_minute_date` (`date`) USING BTREE,
|
||||
KEY `I_flow_report_minute_user_id` (`user_id`),
|
||||
KEY `I_flow_report_minute_license_id` (`license_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#流量统计报表-小时(保留60天)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_hour` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||
`date_str` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '时间 yyyy-MM-dd HH',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_flow_report_hour_create_time` (`create_time`) USING BTREE,
|
||||
KEY `I_flow_report_hour_date` (`date`) USING BTREE,
|
||||
KEY `I_flow_report_hour_user_id` (`user_id`),
|
||||
KEY `I_flow_report_hour_license_id` (`license_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#流量统计报表-天(保留1年)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_day` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||
`date_str` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '时间 yyyy-MM-dd',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_flow_report_day_create_time` (`create_time`) USING BTREE,
|
||||
KEY `I_flow_report_day_date` (`date`) USING BTREE,
|
||||
KEY `I_flow_report_day_user_id` (`user_id`),
|
||||
KEY `I_flow_report_day_license_id` (`license_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
#流量统计报表-月(全量保留)
|
||||
CREATE TABLE IF NOT EXISTS `flow_report_month` (
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`license_id` int NOT NULL COMMENT 'licenseId',
|
||||
`write_bytes` int NOT NULL COMMENT '写入流量',
|
||||
`read_bytes` int NOT NULL COMMENT '读取流量',
|
||||
`date` datetime(3) NOT NULL COMMENT '时间',
|
||||
`date_str` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '时间 yyyy-MM',
|
||||
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `I_flow_report_month_create_time` (`create_time`) USING BTREE,
|
||||
KEY `I_flow_report_month_date` (`date`) USING BTREE,
|
||||
KEY `I_flow_report_month_user_id` (`user_id`),
|
||||
KEY `I_flow_report_month_license_id` (`license_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
@@ -0,0 +1,13 @@
|
||||
#job_qrtz_trigger_info
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, '示例Job', 'DemoJob', '0/10 * * * * ?', '{"a":101}', 1, now(), now());
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(2, '数据清理任务', 'DataCleanJob', '0 0 1 * * ?', '', 1, now(), now());
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(3, '流量统计报表-分钟', 'FlowReportForMinuteJob', '0 */1 * * * ?', '', 1, now(), now());
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(4, '流量统计报表-小时', 'FlowReportForHourJob', '0 0 */1 * * ?', '', 1, now(), now());
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(5, '流量统计报表-天', 'FlowReportForDayJob', '0 0 1 * * ?', '', 1, now(), now());
|
||||
INSERT INTO job_info(`id`, `desc`, `handler`, `cron`, `param`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(6, '流量统计报表-月', 'FlowReportForMonthJob', '0 30 1 1 * ?', '', 1, now(), now());
|
||||
@@ -0,0 +1,3 @@
|
||||
#license
|
||||
INSERT INTO license(`id`, `name`, `key`, `user_id`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, '我的mac', 'b0a907332b474b25897c4dcb31fc7eb6', 1, 2, 1, now(), now());
|
||||
@@ -0,0 +1,5 @@
|
||||
#port_mapping
|
||||
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, 1, 9101, '127.0.0.1', 8080, 2, 1, now(), now());
|
||||
INSERT INTO port_mapping(`id`, `license_id`, `server_port`, `client_ip`, `client_port`, `is_online`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(2, 1, 9102, '127.0.0.1', 3306, 2, 1, now(), now());
|
||||
@@ -0,0 +1,41 @@
|
||||
#端口池
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(1, 9101, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(2, 9102, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(3, 9103, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(4, 9104, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(5, 9105, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(6, 9106, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(7, 9107, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(8, 9108, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(9, 9109, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(10, 9110, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(11, 9111, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(12, 9112, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(13, 9113, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(14, 9114, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(15, 9115, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(16, 9116, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(17, 9117, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(18, 9118, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(19, 9119, 1, now(), now());
|
||||
INSERT INTO port_pool(`id`, `port`, `enable`, `create_time`, `update_time`) VALUES
|
||||
(20, 9120, 1, now(), now());
|
||||
@@ -0,0 +1,5 @@
|
||||
#用户表 6613b92b77056faeb72068f184ed4c4f
|
||||
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
|
||||
(1, '管理员', 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now());
|
||||
INSERT INTO `user`(`id`, `name`,`login_name`,`login_password`,`enable`,`create_time`, `update_time`) VALUES
|
||||
(2, '游客', 'visitor', 'e10adc3949ba59abbe56e057f20f883e', 1, now(), now());
|
||||
+12
-6
@@ -1,7 +1,13 @@
|
||||
# BUG
|
||||
- neutrino-proxy-admin 打包后启动,token失效不会跳回登录页面
|
||||
# 功能点
|
||||
- 用户流量报表
|
||||
- 弹框展示月度明细
|
||||
- 弹框展示今日流量明细
|
||||
- License流量报表
|
||||
- 弹框展示月度明细
|
||||
- 弹框展示今日流量明细
|
||||
- 首页图表📈
|
||||
|
||||
# 优化
|
||||
- 调度管理,增加查看按钮,解决异常情况下,列表展示堆栈异常信息不全,不方便查看的问题
|
||||
- 用户列表增加修改密码入口,管理员可以修改指定用户密码,无需验证原密码(仅管理员操作
|
||||
- 增加当前登录用户修改自己密码的功能,需要验证原密码
|
||||
# Bug
|
||||
- windows环境下直接运行发布版的jar包,日志输出乱码
|
||||
- 部份用户windows环境下启动客户端,扫描类个数为0个
|
||||
- 代理mysql时,使用未开启远程访问的账号走代理访问mysql,代理客户端出现断开现象
|
||||
Reference in New Issue
Block a user