revert web code (#2215)

This commit is contained in:
fatedier 2021-01-25 16:04:33 +08:00 committed by GitHub
parent b26080589b
commit ecb6ed9258
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 9003 additions and 21790 deletions

View File

@ -1 +1 @@
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frp client admin UI</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?d2cd6337d30c7b22e836"></script><script type="text/javascript" src="vendor.js?edb271e1d9c81f857840"></script></body> </html>
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frp client admin UI</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?f30e0e5ff7dbde4611e0"></script><script type="text/javascript" src="vendor.js?a82aed5fb0b844cbdb29"></script></body> </html>

View File

@ -1 +1 @@
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"edb271e1d9c81f857840"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in c)Object.prototype.hasOwnProperty.call(c,i)&&(e[i]=c[i]);for(r&&r(t,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=n(n.s=u[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var u=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"a82aed5fb0b844cbdb29"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,u.appendChild(i),c},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.el-form-item span{margin-left:15px}.demo-table-expand{font-size:0}.demo-table-expand label{width:90px;color:#99a9bf}.demo-table-expand .el-form-item{margin-right:0;margin-bottom:0;width:50%}body{background-color:#fafafa;margin:0;font-family:-apple-system,BlinkMacSystemFont,Helvetica Neue,sans-serif}header{width:100%;height:60px}.header-color{background:#58b7ff}#content{margin-top:20px;padding-right:40px}.brand{color:#fff;background-color:transparent;margin-left:20px;float:left;line-height:25px;font-size:25px;padding:15px 15px;height:30px;text-decoration:none}.source{border:1px solid #eaeefb;border-radius:4px;transition:.2s;padding:24px}.server_info{margin-left:40px;font-size:0}.server_info label{width:150px;color:#99a9bf}.server_info .el-form-item{margin-right:0;margin-bottom:0;width:100%}

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>frps-dashboard</title><link href="css/app.808290ae.css" rel="preload" as="style"><link href="css/chunk-vendors.84bb20f7.css" rel="preload" as="style"><link href="js/app.bb942a48.js" rel="preload" as="script"><link href="js/chunk-vendors.4421b07d.js" rel="preload" as="script"><link href="css/chunk-vendors.84bb20f7.css" rel="stylesheet"><link href="css/app.808290ae.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but frps-dashboard doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.4421b07d.js"></script><script src="js/app.bb942a48.js"></script></body></html>
<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?b8b55d8156200869417b"></script><script type="text/javascript" src="vendor.js?3e078a9d741093b909de"></script></body> </html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,u,c){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in u)Object.prototype.hasOwnProperty.call(u,i)&&(e[i]=u[i]);for(r&&r(t,u,c);s.length;)s.shift()();if(c)for(l=0;l<c.length;l++)f=n(n.s=c[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var u=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=u;var c=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"3e078a9d741093b909de"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,c.appendChild(i),u},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

14
web/frps/.babelrc Normal file
View File

@ -0,0 +1,14 @@
{
"presets": [
["es2015", { "modules": false }]
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}

View File

@ -1,5 +0,0 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -1,2 +0,0 @@
# just a flag
ENV = 'development'

View File

@ -1,2 +0,0 @@
# just a flag
ENV = 'production'

View File

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

27
web/frps/.gitignore vendored
View File

@ -1,25 +1,6 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
node_modules/
dist/
npm-debug.log
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.json
.vscode/settings.json

View File

@ -1,8 +0,0 @@
{
"bracketSpacing": true,
"printWidth": 160,
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid"
}

View File

@ -1,10 +1,7 @@
.PHONY: dist build
build: install
build:
@npm run build
dev: install
@npm run serve
install:
@npm install
@npm run dev

View File

@ -1,25 +0,0 @@
# frps
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```

View File

@ -1,3 +0,0 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset']
}

View File

@ -4,43 +4,45 @@
"author": "fatedier",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
"dev": "webpack-dev-server -d --inline --hot --env.dev",
"build": "rimraf dist && webpack -p --progress --hide-modules"
},
"dependencies": {
"core-js": "^3.7.0",
"echarts": "^4.9.0",
"element-ui": "^2.14.1",
"bootstrap": "^3.3.7",
"echarts": "^3.5.0",
"element-ui": "^2.3.8",
"humanize-plus": "^1.8.2",
"vue": "^2.6.12",
"vue-router": "^3.4.9",
"vuex": "^3.5.1",
"whatwg-fetch": "^3.5.0"
"vue": "^2.5.16",
"vue-resource": "^1.2.1",
"vue-router": "^2.3.0",
"whatwg-fetch": "^2.0.3"
},
"engines": {
"node": ">=6"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.9",
"@vue/cli-plugin-eslint": "~4.5.9",
"@vue/cli-plugin-router": "~4.5.9",
"@vue/cli-plugin-vuex": "~4.5.9",
"@vue/cli-service": "~4.5.9",
"@vue/eslint-config-standard": "^5.1.2",
"babel-eslint": "^10.1.0",
"eslint": "^7.14.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^7.1.0",
"less": "^3.12.2",
"less-loader": "^7.1.0",
"node-sass": "^5.0.0",
"sass-loader": "^10.1.0",
"vue-template-compiler": "^2.6.12"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
"autoprefixer": "^6.6.0",
"babel-core": "^6.21.0",
"babel-eslint": "^7.1.1",
"babel-loader": "^6.4.0",
"babel-plugin-component": "^1.1.1",
"babel-preset-es2015": "^6.13.2",
"css-loader": "^0.27.0",
"eslint": "^3.12.2",
"eslint-config-enough": "^0.2.2",
"eslint-loader": "^1.6.3",
"file-loader": "^0.10.1",
"html-loader": "^0.4.5",
"html-webpack-plugin": "^2.24.1",
"less": "^3.0.4",
"less-loader": "^4.1.0",
"postcss-loader": "^1.3.3",
"rimraf": "^2.5.4",
"style-loader": "^0.13.2",
"url-loader": "^1.0.1",
"vue-loader": "^15.0.10",
"vue-template-compiler": "^2.1.8",
"webpack": "^2.2.0-rc.4",
"webpack-dev-server": "^3.1.4"
}
}

View File

@ -0,0 +1,5 @@
module.exports = {
plugins: [
require('autoprefixer')()
]
}

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@ -8,7 +8,7 @@
<section>
<el-row>
<el-col id="side-nav" :xs="24" :md="4">
<el-menu default-active="1" mode="vertical" theme="light" router @select="handleSelect">
<el-menu default-active="1" mode="vertical" theme="light" router="false" @select="handleSelect">
<el-menu-item index="/">Overview</el-menu-item>
<el-submenu index="/proxies">
<template slot="title">Proxies</template>
@ -24,28 +24,21 @@
<el-col :xs="24" :md="20">
<div id="content">
<router-view v-if="serverInfo" />
<router-view></router-view>
</div>
</el-col>
</el-row>
</section>
<footer></footer>
</div>
</template>
<script>
export default {
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
},
async created() {
this.$store.dispatch('fetchServerInfo')
},
methods: {
handleSelect(key, path) {
if (key === '') {
window.open('https://github.com/fatedier/frp')
if (key == '') {
window.open("https://github.com/fatedier/frp")
}
}
}
@ -65,7 +58,7 @@ header {
}
.header-color {
background: #58b7ff;
background: #58B7FF;
}
#content {

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -44,8 +44,8 @@
</div>
</el-col>
<el-col :md="12">
<div id="traffic" style="width: 400px; height: 250px; margin-bottom: 30px" />
<div id="proxies" style="width: 400px; height: 250px" />
<div id="traffic" style="width: 400px;height:250px;margin-bottom: 30px;"></div>
<div id="proxies" style="width: 400px;height:250px;"></div>
</el-col>
</el-row>
</div>
@ -70,65 +70,71 @@ export default {
proxy_counts: ''
}
},
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
created() {
this.fetchData()
},
mounted() {
this.initData()
watch: {
'$route': 'fetchData'
},
methods: {
initData() {
console.log(!!this.serverInfo, this.serverInfo)
if (!this.serverInfo) return
this.version = this.serverInfo.version
this.bind_port = this.serverInfo.bind_port
this.bind_udp_port = this.serverInfo.bind_udp_port
if (this.bind_udp_port === 0) {
this.bind_udp_port = 'disable'
fetchData() {
fetch('/api/serverinfo', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.version = json.version
this.bind_port = json.bind_port
this.bind_udp_port = json.bind_udp_port
if (this.bind_udp_port == 0) {
this.bind_udp_port = "disable"
}
this.vhost_http_port = this.serverInfo.vhost_http_port
if (this.vhost_http_port === 0) {
this.vhost_http_port = 'disable'
this.vhost_http_port = json.vhost_http_port
if (this.vhost_http_port == 0) {
this.vhost_http_port = "disable"
}
this.vhost_https_port = this.serverInfo.vhost_https_port
if (this.vhost_https_port === 0) {
this.vhost_https_port = 'disable'
this.vhost_https_port = json.vhost_https_port
if (this.vhost_https_port == 0) {
this.vhost_https_port = "disable"
}
this.subdomain_host = this.serverInfo.subdomain_host
this.max_pool_count = this.serverInfo.max_pool_count
this.max_ports_per_client = this.serverInfo.max_ports_per_client
if (this.max_ports_per_client === 0) {
this.max_ports_per_client = 'no limit'
this.subdomain_host = json.subdomain_host
this.max_pool_count = json.max_pool_count
this.max_ports_per_client = json.max_ports_per_client
if (this.max_ports_per_client == 0) {
this.max_ports_per_client = "no limit"
}
this.heart_beat_timeout = this.serverInfo.heart_beat_timeout
this.client_counts = this.serverInfo.client_counts
this.cur_conns = this.serverInfo.cur_conns
this.heart_beat_timeout = json.heart_beat_timeout
this.client_counts = json.client_counts
this.cur_conns = json.cur_conns
this.proxy_counts = 0
if (this.serverInfo.proxy_type_count != null) {
if (this.serverInfo.proxy_type_count.tcp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.tcp
if (json.proxy_type_count != null) {
if (json.proxy_type_count.tcp != null) {
this.proxy_counts += json.proxy_type_count.tcp
}
if (this.serverInfo.proxy_type_count.udp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.udp
if (json.proxy_type_count.udp != null) {
this.proxy_counts += json.proxy_type_count.udp
}
if (this.serverInfo.proxy_type_count.http != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.http
if (json.proxy_type_count.http != null) {
this.proxy_counts += json.proxy_type_count.http
}
if (this.serverInfo.proxy_type_count.https != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.https
if (json.proxy_type_count.https != null) {
this.proxy_counts += json.proxy_type_count.https
}
if (this.serverInfo.proxy_type_count.stcp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.stcp
if (json.proxy_type_count.stcp != null) {
this.proxy_counts += json.proxy_type_count.stcp
}
if (this.serverInfo.proxy_type_count.xtcp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.xtcp
if (json.proxy_type_count.xtcp != null) {
this.proxy_counts += json.proxy_type_count.xtcp
}
}
DrawTrafficChart('traffic', this.serverInfo.total_traffic_in, this.serverInfo.total_traffic_out)
DrawProxyChart('proxies', this.serverInfo)
DrawTrafficChart('traffic', json.total_traffic_in, json.total_traffic_out)
DrawProxyChart('proxies', json)
}).catch( err => {
this.$message({
showClose: true,
message: 'Get server info from frps failed!',
type: 'warning'
})
})
}
}
}
@ -138,7 +144,7 @@ export default {
.source {
border: 1px solid #eaeefb;
border-radius: 4px;
transition: 0.2s;
transition: .2s;
padding: 24px;
}

View File

@ -3,8 +3,13 @@
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand">
<template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
<el-popover
ref="popover4"
placement="right"
width="600"
style="margin-left:0px"
trigger="click">
<my-traffic-chart :proxy_name="props.row.name"></my-traffic-chart>
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom:10px">Traffic Statistics</el-button>
@ -43,15 +48,40 @@
</el-form>
</template>
</el-table-column>
<el-table-column label="Name" prop="name" sortable />
<el-table-column label="Port" prop="port" sortable />
<el-table-column label="Connections" prop="conns" sortable />
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable />
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable />
<el-table-column label="status" prop="status" sortable>
<el-table-column
label="Name"
prop="name"
sortable>
</el-table-column>
<el-table-column
label="Port"
prop="port"
sortable>
</el-table-column>
<el-table-column
label="Connections"
prop="conns"
sortable>
</el-table-column>
<el-table-column
label="Traffic In"
prop="traffic_in"
:formatter="formatTrafficIn"
sortable>
</el-table-column>
<el-table-column
label="Traffic Out"
prop="traffic_out"
:formatter="formatTrafficOut"
sortable>
</el-table-column>
<el-table-column
label="status"
prop="status"
sortable>
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag>
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag>
<el-tag type="success" v-if="scope.row.status === 'online'">{{ scope.row.status }}</el-tag>
<el-tag type="danger" v-else>{{ scope.row.status }}</el-tag>
</template>
</el-table-column>
</el-table>
@ -59,27 +89,24 @@
</template>
<script>
import Humanize from 'humanize-plus'
import Humanize from 'humanize-plus';
import Traffic from './Traffic.vue'
import { HttpProxy } from '../utils/proxy.js'
import {
HttpProxy
} from '../utils/proxy.js'
export default {
components: {
'my-traffic-chart': Traffic
},
data() {
return {
proxies: [],
vhost_http_port: '',
subdomain_host: ''
proxies: null,
vhost_http_port: "",
subdomain_host: ""
}
},
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
created() {
this.fetchData()
},
mounted() {
this.initData()
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
@ -88,20 +115,34 @@ export default {
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
async initData() {
if (!this.serverInfo) return
this.vhost_http_port = this.serverInfo.vhost_http_port
this.subdomain_host = this.serverInfo.subdomain_host
if (this.vhost_http_port == null || this.vhost_http_port === 0) return
const json = await this.$fetch('proxy/http')
if (!json) return
this.proxies = []
for (const proxyStats of json.proxies) {
fetchData() {
fetch('/api/serverinfo', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.vhost_http_port = json.vhost_http_port
this.subdomain_host = json.subdomain_host
if (this.vhost_http_port == null || this.vhost_http_port == 0) {
return
} else {
fetch('/api/proxy/http', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.proxies = new Array()
for (let proxyStats of json.proxies) {
this.proxies.push(new HttpProxy(proxyStats, this.vhost_http_port, this.subdomain_host))
}
})
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>
<style>
</style>

View File

@ -3,8 +3,13 @@
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand">
<template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
<el-popover
ref="popover4"
placement="right"
width="600"
style="margin-left:0px"
trigger="click">
<my-traffic-chart :proxy_name="props.row.name"></my-traffic-chart>
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom:10px">Traffic Statistics</el-button>
@ -37,43 +42,66 @@
</el-form>
</template>
</el-table-column>
<el-table-column label="Name" prop="name" sortable />
<el-table-column label="Port" prop="port" sortable />
<el-table-column label="Connections" prop="conns" sortable />
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable />
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable />
<el-table-column label="status" prop="status" sortable>
<el-table-column
label="Name"
prop="name"
sortable>
</el-table-column>
<el-table-column
label="Port"
prop="port"
sortable>
</el-table-column>
<el-table-column
label="Connections"
prop="conns"
sortable>
</el-table-column>
<el-table-column
label="Traffic In"
prop="traffic_in"
:formatter="formatTrafficIn"
sortable>
</el-table-column>
<el-table-column
label="Traffic Out"
prop="traffic_out"
:formatter="formatTrafficOut"
sortable>
</el-table-column>
<el-table-column
label="status"
prop="status"
sortable>
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag>
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag>
<el-tag type="success" v-if="scope.row.status === 'online'">{{ scope.row.status }}</el-tag>
<el-tag type="danger" v-else>{{ scope.row.status }}</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import Humanize from 'humanize-plus'
import Humanize from 'humanize-plus';
import Traffic from './Traffic.vue'
import { HttpsProxy } from '../utils/proxy.js'
import {
HttpsProxy
} from '../utils/proxy.js'
export default {
components: {
'my-traffic-chart': Traffic
},
data() {
return {
proxies: [],
proxies: null,
vhost_https_port: '',
subdomain_host: ''
}
},
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
created() {
this.fetchData()
},
mounted() {
this.initData()
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
@ -82,21 +110,34 @@ export default {
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
async initData() {
if (!this.serverInfo) return
this.vhost_https_port = this.serverInfo.vhost_https_port
this.subdomain_host = this.serverInfo.subdomain_host
if (this.vhost_https_port == null || this.vhost_https_port === 0) return
const json = await this.$fetch('proxy/https')
if (!json) return
this.proxies = []
for (const proxyStats of json.proxies) {
fetchData() {
fetch('/api/serverinfo', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.vhost_https_port = json.vhost_https_port
this.subdomain_host = json.subdomain_host
if (this.vhost_https_port == null || this.vhost_https_port == 0) {
return
} else {
fetch('/api/proxy/https', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.proxies = new Array()
for (let proxyStats of json.proxies) {
this.proxies.push(new HttpsProxy(proxyStats, this.vhost_https_port, this.subdomain_host))
}
})
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>
<style>
</style>

View File

@ -3,13 +3,16 @@
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand">
<template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
<el-popover
ref="popover4"
placement="right"
width="600"
style="margin-left:0px"
trigger="click">
<my-traffic-chart :proxy_name="props.row.name"></my-traffic-chart>
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom: 10px" @click="fetchData2">
Traffic Statistics
</el-button>
<el-button v-popover:popover4 type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom:10px" @click="fetchData2">Traffic Statistics</el-button>
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="Name">
@ -33,14 +36,35 @@
</el-form>
</template>
</el-table-column>
<el-table-column label="Name" prop="name" sortable />
<el-table-column label="Connections" prop="conns" sortable />
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable />
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable />
<el-table-column label="status" prop="status" sortable>
<el-table-column
label="Name"
prop="name"
sortable>
</el-table-column>
<el-table-column
label="Connections"
prop="conns"
sortable>
</el-table-column>
<el-table-column
label="Traffic In"
prop="traffic_in"
:formatter="formatTrafficIn"
sortable>
</el-table-column>
<el-table-column
label="Traffic Out"
prop="traffic_out"
:formatter="formatTrafficOut"
sortable>
</el-table-column>
<el-table-column
label="status"
prop="status"
sortable>
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag>
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag>
<el-tag type="success" v-if="scope.row.status === 'online'">{{ scope.row.status }}</el-tag>
<el-tag type="danger" v-else>{{ scope.row.status }}</el-tag>
</template>
</el-table-column>
</el-table>
@ -52,16 +76,16 @@ import Humanize from 'humanize-plus'
import Traffic from './Traffic.vue'
import { StcpProxy } from '../utils/proxy.js'
export default {
components: {
'my-traffic-chart': Traffic
},
data() {
return {
proxies: []
proxies: null
}
},
mounted() {
this.initData()
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
@ -70,15 +94,20 @@ export default {
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
async initData() {
const json = await this.$fetch('proxy/stcp')
if (!json) return
this.proxies = []
for (const proxyStats of json.proxies) {
fetchData() {
fetch('/api/proxy/stcp', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.proxies = new Array()
for (let proxyStats of json.proxies) {
this.proxies.push(new StcpProxy(proxyStats))
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>

View File

@ -3,14 +3,17 @@
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand">
<template slot-scope="props">
<el-popover placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
<el-button slot="reference" type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom: 10px">
Traffic Statistics
</el-button>
<el-popover
ref="popover4"
placement="right"
width="600"
style="margin-left:0px"
trigger="click">
<my-traffic-chart :proxy_name="props.row.name"></my-traffic-chart>
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom:10px" @click="fetchData2">Traffic Statistics</el-button>
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="Name">
<span>{{ props.row.name }}</span>
@ -36,15 +39,40 @@
</el-form>
</template>
</el-table-column>
<el-table-column label="Name" prop="name" sortable />
<el-table-column label="Port" prop="port" sortable />
<el-table-column label="Connections" prop="conns" sortable />
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable />
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable />
<el-table-column label="status" prop="status" sortable>
<el-table-column
label="Name"
prop="name"
sortable>
</el-table-column>
<el-table-column
label="Port"
prop="port"
sortable>
</el-table-column>
<el-table-column
label="Connections"
prop="conns"
sortable>
</el-table-column>
<el-table-column
label="Traffic In"
prop="traffic_in"
:formatter="formatTrafficIn"
sortable>
</el-table-column>
<el-table-column
label="Traffic Out"
prop="traffic_out"
:formatter="formatTrafficOut"
sortable>
</el-table-column>
<el-table-column
label="status"
prop="status"
sortable>
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag>
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag>
<el-tag type="success" v-if="scope.row.status === 'online'">{{ scope.row.status }}</el-tag>
<el-tag type="danger" v-else>{{ scope.row.status }}</el-tag>
</template>
</el-table-column>
</el-table>
@ -56,16 +84,16 @@ import Humanize from 'humanize-plus'
import Traffic from './Traffic.vue'
import { TcpProxy } from '../utils/proxy.js'
export default {
components: {
'my-traffic-chart': Traffic
},
data() {
return {
proxies: []
proxies: null
}
},
mounted() {
this.initData()
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
@ -74,15 +102,20 @@ export default {
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
async initData() {
const json = await this.$fetch('proxy/tcp')
if (!json) return
this.proxies = []
for (const proxyStats of json.proxies) {
fetchData() {
fetch('/api/proxy/tcp', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.proxies = new Array()
for (let proxyStats of json.proxies) {
this.proxies.push(new TcpProxy(proxyStats))
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>

View File

@ -3,8 +3,13 @@
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand">
<template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
<el-popover
ref="popover4"
placement="right"
width="600"
style="margin-left:0px"
trigger="click">
<my-traffic-chart :proxy_name="props.row.name"></my-traffic-chart>
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom:10px">Traffic Statistics</el-button>
@ -34,15 +39,40 @@
</el-form>
</template>
</el-table-column>
<el-table-column label="Name" prop="name" sortable />
<el-table-column label="Port" prop="port" sortable />
<el-table-column label="Connections" prop="conns" sortable />
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable />
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable />
<el-table-column label="status" prop="status" sortable>
<el-table-column
label="Name"
prop="name"
sortable>
</el-table-column>
<el-table-column
label="Port"
prop="port"
sortable>
</el-table-column>
<el-table-column
label="Connections"
prop="conns"
sortable>
</el-table-column>
<el-table-column
label="Traffic In"
prop="traffic_in"
:formatter="formatTrafficIn"
sortable>
</el-table-column>
<el-table-column
label="Traffic Out"
prop="traffic_out"
:formatter="formatTrafficOut"
sortable>
</el-table-column>
<el-table-column
label="status"
prop="status"
sortable>
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag>
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag>
<el-tag type="success" v-if="scope.row.status === 'online'">{{ scope.row.status }}</el-tag>
<el-tag type="danger" v-else>{{ scope.row.status }}</el-tag>
</template>
</el-table-column>
</el-table>
@ -50,20 +80,22 @@
</template>
<script>
import Humanize from 'humanize-plus'
import Humanize from 'humanize-plus';
import Traffic from './Traffic.vue'
import { UdpProxy } from '../utils/proxy.js'
import {
UdpProxy
} from '../utils/proxy.js'
export default {
components: {
'my-traffic-chart': Traffic
},
data() {
return {
proxies: []
proxies: null
}
},
mounted() {
this.initData()
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
@ -72,16 +104,23 @@ export default {
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
async initData() {
const json = await this.$fetch('proxy/udp')
if (!json) return
this.proxies = []
for (const proxyStats of json.proxies) {
fetchData() {
fetch('/api/proxy/udp', {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
this.proxies = new Array()
for (let proxyStats of json.proxies) {
this.proxies.push(new UdpProxy(proxyStats))
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>
<style>
</style>

View File

@ -1,26 +1,36 @@
<template>
<div :id="proxyName" style="width: 600px; height: 400px" />
<div :id="proxy_name" style="width: 600px;height:400px;"></div>
</template>
<script>
import {DrawProxyTrafficChart} from '../utils/chart.js'
export default {
props: {
proxyName: {
type: String,
required: true
}
},
mounted() {
this.initData()
props: ['proxy_name'],
created() {
this.fetchData()
},
//watch: {
//'$route': 'fetchData'
//},
methods: {
async initData() {
const json = await this.$fetch(`traffic/${this.proxyName}`)
if (!json) return
DrawProxyTrafficChart(this.proxyName, json.traffic_in, json.traffic_out)
fetchData() {
let url = '/api/traffic/' + this.proxy_name
fetch(url, {credentials: 'include'})
.then(res => {
return res.json()
}).then(json => {
DrawProxyTrafficChart(this.proxy_name, json.traffic_in, json.traffic_out)
}).catch( err => {
this.$message({
showClose: true,
message: 'Get server info from frps failed!' + err,
type: 'warning'
})
})
}
}
}
</script>
<style>
</style>

15
web/frps/src/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>frps dashboard</title>
</head>
<body>
<div id="app"></div>
<!--<script src="https://code.jquery.com/jquery-3.2.0.min.js"></script>-->
<!--<script src="//cdn.bootcss.com/echarts/3.4.0/echarts.min.js"></script>-->
</body>
</html>

View File

@ -1,6 +1,19 @@
import Vue from 'vue'
//import ElementUI from 'element-ui'
import { Button, Form, FormItem, Row, Col, Table, TableColumn, Popover, Menu, Submenu, MenuItem, Tag, Message } from 'element-ui'
import {
Button,
Form,
FormItem,
Row,
Col,
Table,
TableColumn,
Popover,
Menu,
Submenu,
MenuItem,
Tag
} from 'element-ui'
import lang from 'element-ui/lib/locale/lang/en'
import locale from 'element-ui/lib/locale'
import 'element-ui/lib/theme-chalk/index.css'
@ -8,7 +21,6 @@ import './utils/less/custom.less'
import App from './App.vue'
import router from './router'
import store from '@/store'
import 'whatwg-fetch'
locale.use(lang)
@ -25,15 +37,12 @@ Vue.use(Menu)
Vue.use(Submenu)
Vue.use(MenuItem)
Vue.use(Tag)
Vue.prototype.$message = Message
import fetch from '@/utils/fetch'
Vue.prototype.$fetch = fetch
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
render: h => h(App)
}).$mount('#app')
template: '<App/>',
components: { App }
})

View File

@ -10,36 +10,29 @@ import ProxiesStcp from '../components/ProxiesStcp.vue'
Vue.use(Router)
export default new Router({
routes: [
{
routes: [{
path: '/',
name: 'Overview',
component: Overview
},
{
}, {
path: '/proxies/tcp',
name: 'ProxiesTcp',
component: ProxiesTcp
},
{
}, {
path: '/proxies/udp',
name: 'ProxiesUdp',
component: ProxiesUdp
},
{
}, {
path: '/proxies/http',
name: 'ProxiesHttp',
component: ProxiesHttp
},
{
}, {
path: '/proxies/https',
name: 'ProxiesHttps',
component: ProxiesHttps
},
{
}, {
path: '/proxies/stcp',
name: 'ProxiesStcp',
component: ProxiesStcp
}
]
}]
})

View File

@ -1,24 +0,0 @@
import Vue from 'vue'
import Vuex from 'vuex'
import fetch from '@/utils/fetch'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
serverInfo: null
},
mutations: {
SET_SERVER_INFO(state, serverInfo) {
state.serverInfo = serverInfo
}
},
actions: {
async fetchServerInfo({ commit }) {
const json = await fetch('serverinfo')
commit('SET_SERVER_INFO', json || null)
return json
}
}
})
export default store

View File

@ -1,17 +1,17 @@
import Humanize from 'humanize-plus'
import echarts from 'echarts/lib/echarts'
import Humanize from "humanize-plus"
import echarts from "echarts/lib/echarts"
import 'echarts/theme/macarons'
import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/pie'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/title'
import "echarts/theme/macarons"
import "echarts/lib/chart/bar"
import "echarts/lib/chart/pie"
import "echarts/lib/component/tooltip"
import "echarts/lib/component/title"
function DrawTrafficChart(elementId, trafficIn, trafficOut) {
const myChart = echarts.init(document.getElementById(elementId), 'macarons')
let myChart = echarts.init(document.getElementById(elementId), 'macarons');
myChart.showLoading()
const option = {
let option = {
title: {
text: 'Network Traffic',
subtext: 'today',
@ -20,24 +20,20 @@ function DrawTrafficChart(elementId, trafficIn, trafficOut) {
tooltip: {
trigger: 'item',
formatter: function(v) {
return Humanize.fileSize(v.data.value) + ' (' + v.percent + '%)'
return Humanize.fileSize(v.data.value) + " (" + v.percent + "%)"
}
},
series: [
{
series: [{
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [
{
data: [{
value: trafficIn,
name: 'Traffic In'
},
{
}, {
value: trafficOut,
name: 'Traffic Out'
}
],
}, ],
itemStyle: {
emphasis: {
shadowBlur: 10,
@ -45,10 +41,9 @@ function DrawTrafficChart(elementId, trafficIn, trafficOut) {
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
myChart.setOption(option)
}]
};
myChart.setOption(option);
myChart.hideLoading()
}
@ -71,10 +66,10 @@ function DrawProxyChart(elementId, serverInfo) {
if (serverInfo.proxy_type_count.xtcp == null) {
serverInfo.proxy_type_count.xtcp = 0
}
const myChart = echarts.init(document.getElementById(elementId), 'macarons')
let myChart = echarts.init(document.getElementById(elementId), 'macarons')
myChart.showLoading()
const option = {
let option = {
title: {
text: 'Proxies',
subtext: 'now',
@ -86,37 +81,29 @@ function DrawProxyChart(elementId, serverInfo) {
return v.data.value
}
},
series: [
{
series: [{
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [
{
data: [{
value: serverInfo.proxy_type_count.tcp,
name: 'TCP'
},
{
}, {
value: serverInfo.proxy_type_count.udp,
name: 'UDP'
},
{
}, {
value: serverInfo.proxy_type_count.http,
name: 'HTTP'
},
{
}, {
value: serverInfo.proxy_type_count.https,
name: 'HTTPS'
},
{
}, {
value: serverInfo.proxy_type_count.stcp,
name: 'STCP'
},
{
}, {
value: serverInfo.proxy_type_count.xtcp,
name: 'XTCP'
}
],
}],
itemStyle: {
emphasis: {
shadowBlur: 10,
@ -124,34 +111,33 @@ function DrawProxyChart(elementId, serverInfo) {
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
myChart.setOption(option)
}]
};
myChart.setOption(option);
myChart.hideLoading()
}
// 7 days
function DrawProxyTrafficChart(elementId, trafficInArr, trafficOutArr) {
const params = {
let params = {
width: '600px',
height: '400px'
}
const myChart = echarts.init(document.getElementById(elementId), 'macarons', params)
let myChart = echarts.init(document.getElementById(elementId), 'macarons', params);
myChart.showLoading()
trafficInArr = trafficInArr.reverse()
trafficOutArr = trafficOutArr.reverse()
let now = new Date()
now = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 6)
const dates = []
let dates = new Array()
for (let i = 0; i < 7; i++) {
dates.push(now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate())
now = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1)
}
const option = {
let option = {
tooltip: {
trigger: 'axis',
axisPointer: {
@ -162,9 +148,9 @@ function DrawProxyTrafficChart(elementId, trafficInArr, trafficOutArr) {
if (data.length > 0) {
html += data[0].name + '<br/>'
}
for (const v of data) {
const colorEl =
'<span style="display:inline-block;margin-right:5px;' + 'border-radius:10px;width:9px;height:9px;background-color:' + v.color + '"></span>'
for (let v of data) {
let colorEl = '<span style="display:inline-block;margin-right:5px;' +
'border-radius:10px;width:9px;height:9px;background-color:' + v.color + '"></span>';
html += colorEl + v.seriesName + ': ' + Humanize.fileSize(v.value) + '<br/>'
}
return html
@ -179,37 +165,35 @@ function DrawProxyTrafficChart(elementId, trafficInArr, trafficOutArr) {
bottom: '3%',
containLabel: true
},
xAxis: [
{
xAxis: [{
type: 'category',
data: dates
}
],
yAxis: [
{
}],
yAxis: [{
type: 'value',
axisLabel: {
formatter: function(value) {
return Humanize.fileSize(value)
}
}
}
],
series: [
{
}],
series: [{
name: 'Traffic In',
type: 'bar',
data: trafficInArr
},
{
}, {
name: 'Traffic Out',
type: 'bar',
data: trafficOutArr
}
]
}
myChart.setOption(option)
}]
};
myChart.setOption(option);
myChart.hideLoading()
}
export { DrawTrafficChart, DrawProxyChart, DrawProxyTrafficChart }
export {
DrawTrafficChart,
DrawProxyChart,
DrawProxyTrafficChart
}

View File

@ -1,20 +0,0 @@
import { Message } from 'element-ui'
export default function(api, init = {}) {
return new Promise(resolve => {
fetch(`/api/${api}`, Object.assign({ credentials: 'include' }, init))
.then(res => {
if (res.status < 200 || res.status >= 300) {
Message.warning('Get server info from frps failed!')
resolve()
return
}
resolve(res ? res.json() : undefined)
})
.catch(err => {
this.$message.error(err.message)
resolve()
})
})
}

View File

@ -5,8 +5,8 @@ class BaseProxy {
this.encryption = proxyStats.conf.use_encryption
this.compression = proxyStats.conf.use_compression
} else {
this.encryption = ''
this.compression = ''
this.encryption = ""
this.compression = ""
}
this.conns = proxyStats.cur_conns
this.traffic_in = proxyStats.today_traffic_in
@ -20,13 +20,13 @@ class BaseProxy {
class TcpProxy extends BaseProxy {
constructor(proxyStats) {
super(proxyStats)
this.type = 'tcp'
this.type = "tcp"
if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port
this.addr = ":" + proxyStats.conf.remote_port
this.port = proxyStats.conf.remote_port
} else {
this.addr = ''
this.port = ''
this.addr = ""
this.port = ""
}
}
}
@ -34,13 +34,13 @@ class TcpProxy extends BaseProxy {
class UdpProxy extends BaseProxy {
constructor(proxyStats) {
super(proxyStats)
this.type = 'udp'
this.type = "udp"
if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port
this.addr = ":" + proxyStats.conf.remote_port
this.port = proxyStats.conf.remote_port
} else {
this.addr = ''
this.port = ''
this.addr = ""
this.port = ""
}
}
}
@ -48,22 +48,22 @@ class UdpProxy extends BaseProxy {
class HttpProxy extends BaseProxy {
constructor(proxyStats, port, subdomain_host) {
super(proxyStats)
this.type = 'http'
this.type = "http"
this.port = port
if (proxyStats.conf != null) {
this.custom_domains = proxyStats.conf.custom_domains
this.host_header_rewrite = proxyStats.conf.host_header_rewrite
this.locations = proxyStats.conf.locations
if (proxyStats.conf.sub_domain !== '') {
this.subdomain = proxyStats.conf.sub_domain + '.' + subdomain_host
if (proxyStats.conf.sub_domain != "") {
this.subdomain = proxyStats.conf.sub_domain + "." + subdomain_host
} else {
this.subdomain = ''
this.subdomain = ""
}
} else {
this.custom_domains = ''
this.host_header_rewrite = ''
this.subdomain = ''
this.locations = ''
this.custom_domains = ""
this.host_header_rewrite = ""
this.subdomain = ""
this.locations = ""
}
}
}
@ -71,18 +71,18 @@ class HttpProxy extends BaseProxy {
class HttpsProxy extends BaseProxy {
constructor(proxyStats, port, subdomain_host) {
super(proxyStats)
this.type = 'https'
this.type = "https"
this.port = port
if (proxyStats.conf != null) {
this.custom_domains = proxyStats.conf.custom_domains
if (proxyStats.conf.sub_domain !== '') {
this.subdomain = proxyStats.conf.sub_domain + '.' + subdomain_host
if (proxyStats.conf.sub_domain != "") {
this.subdomain = proxyStats.conf.sub_domain + "." + subdomain_host
} else {
this.subdomain = ''
this.subdomain = ""
}
} else {
this.custom_domains = ''
this.subdomain = ''
this.custom_domains = ""
this.subdomain = ""
}
}
}
@ -90,7 +90,7 @@ class HttpsProxy extends BaseProxy {
class StcpProxy extends BaseProxy {
constructor(proxyStats) {
super(proxyStats)
this.type = 'stcp'
this.type = "stcp"
}
}

View File

@ -1,16 +0,0 @@
module.exports = {
publicPath: './',
devServer: {
host: '127.0.0.1',
port: 8010,
proxy: {
'/api/': {
target: 'http://127.0.0.1:8080/api',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}

107
web/frps/webpack.config.js Normal file
View File

@ -0,0 +1,107 @@
const path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var VueLoaderPlugin = require('vue-loader/lib/plugin')
var url = require('url')
var publicPath = ''
module.exports = (options = {}) => ({
entry: {
vendor: './src/main'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: options.dev ? '[name].js' : '[name].js?[chunkhash]',
chunkFilename: '[id].js?[chunkhash]',
publicPath: options.dev ? '/assets/' : publicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': path.resolve(__dirname, 'src'),
}
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
}, {
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/
}, {
test: /\.html$/,
use: [{
loader: 'html-loader',
options: {
root: path.resolve(__dirname, 'src'),
attrs: ['img:src', 'link:href']
}
}]
}, {
test: /\.less$/,
loader: 'style-loader!css-loader!postcss-loader!less-loader'
}, {
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}, {
test: /favicon\.png$/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}]
}, {
test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
exclude: /favicon\.png$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000
}
}]
}]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest']
}),
new HtmlWebpackPlugin({
favicon: 'src/assets/favicon.ico',
template: 'src/index.html'
}),
new webpack.NormalModuleReplacementPlugin(/element-ui[\/\\]lib[\/\\]locale[\/\\]lang[\/\\]zh-CN/, 'element-ui/lib/locale/lang/en'),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: false,
comments: false,
compress: {
warnings: false
}
}),
new VueLoaderPlugin()
],
devServer: {
host: '127.0.0.1',
port: 8010,
proxy: {
'/api/': {
target: 'http://127.0.0.1:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
historyApiFallback: {
index: url.parse(options.dev ? '/assets/' : publicPath).pathname
}
}//,
//devtool: options.dev ? '#eval-source-map' : '#source-map'
})

File diff suppressed because it is too large Load Diff