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 .DS_Store
node_modules node_modules/
/dist dist/
npm-debug.log
# 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
.idea .idea
.vscode .vscode/settings.json
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.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 .PHONY: dist build
build: install build:
@npm run build @npm run build
dev: install dev: install
@npm run serve @npm run dev
install:
@npm install

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

@ -1,87 +1,80 @@
<template> <template>
<div id="app"> <div id="app">
<header class="grid-content header-color"> <header class="grid-content header-color">
<el-row> <el-row>
<a class="brand" href="#">frp</a> <a class="brand" href="#">frp</a>
</el-row> </el-row>
</header> </header>
<section> <section>
<el-row> <el-row>
<el-col id="side-nav" :xs="24" :md="4"> <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-menu-item index="/">Overview</el-menu-item>
<el-submenu index="/proxies"> <el-submenu index="/proxies">
<template slot="title">Proxies</template> <template slot="title">Proxies</template>
<el-menu-item index="/proxies/tcp">TCP</el-menu-item> <el-menu-item index="/proxies/tcp">TCP</el-menu-item>
<el-menu-item index="/proxies/udp">UDP</el-menu-item> <el-menu-item index="/proxies/udp">UDP</el-menu-item>
<el-menu-item index="/proxies/http">HTTP</el-menu-item> <el-menu-item index="/proxies/http">HTTP</el-menu-item>
<el-menu-item index="/proxies/https">HTTPS</el-menu-item> <el-menu-item index="/proxies/https">HTTPS</el-menu-item>
<el-menu-item index="/proxies/stcp">STCP</el-menu-item> <el-menu-item index="/proxies/stcp">STCP</el-menu-item>
</el-submenu> </el-submenu>
<el-menu-item index="">Help</el-menu-item> <el-menu-item index="">Help</el-menu-item>
</el-menu> </el-menu>
</el-col> </el-col>
<el-col :xs="24" :md="20"> <el-col :xs="24" :md="20">
<div id="content"> <div id="content">
<router-view v-if="serverInfo" /> <router-view></router-view>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
</section> </section>
</div> <footer></footer>
</div>
</template> </template>
<script> <script>
export default { export default {
computed: { methods: {
serverInfo() { handleSelect(key, path) {
return this.$store.state.serverInfo if (key == '') {
window.open("https://github.com/fatedier/frp")
}
}
}
} }
},
async created() {
this.$store.dispatch('fetchServerInfo')
},
methods: {
handleSelect(key, path) {
if (key === '') {
window.open('https://github.com/fatedier/frp')
}
}
}
}
</script> </script>
<style> <style>
body { body {
background-color: #fafafa; background-color: #fafafa;
margin: 0px; margin: 0px;
font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, sans-serif; font-family: -apple-system,BlinkMacSystemFont,Helvetica Neue,sans-serif;
} }
header { header {
width: 100%; width: 100%;
height: 60px; height: 60px;
} }
.header-color { .header-color {
background: #58b7ff; background: #58B7FF;
} }
#content { #content {
margin-top: 20px; margin-top: 20px;
padding-right: 40px; padding-right: 40px;
} }
.brand { .brand {
color: #fff; color: #fff;
background-color: transparent; background-color: transparent;
margin-left: 20px; margin-left: 20px;
float: left; float: left;
line-height: 25px; line-height: 25px;
font-size: 25px; font-size: 25px;
padding: 15px 15px; padding: 15px 15px;
height: 30px; height: 30px;
text-decoration: none; text-decoration: none;
} }
</style> </style>

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -1,160 +1,166 @@
<template> <template>
<div> <div>
<el-row> <el-row>
<el-col :md="12"> <el-col :md="12">
<div class="source"> <div class="source">
<el-form label-position="left" class="server_info"> <el-form label-position="left" class="server_info">
<el-form-item label="Version"> <el-form-item label="Version">
<span>{{ version }}</span> <span>{{ version }}</span>
</el-form-item> </el-form-item>
<el-form-item label="BindPort"> <el-form-item label="BindPort">
<span>{{ bind_port }}</span> <span>{{ bind_port }}</span>
</el-form-item> </el-form-item>
<el-form-item label="BindUdpPort"> <el-form-item label="BindUdpPort">
<span>{{ bind_udp_port }}</span> <span>{{ bind_udp_port }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Http Port"> <el-form-item label="Http Port">
<span>{{ vhost_http_port }}</span> <span>{{ vhost_http_port }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Https Port"> <el-form-item label="Https Port">
<span>{{ vhost_https_port }}</span> <span>{{ vhost_https_port }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Subdomain Host"> <el-form-item label="Subdomain Host">
<span>{{ subdomain_host }}</span> <span>{{ subdomain_host }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Max PoolCount"> <el-form-item label="Max PoolCount">
<span>{{ max_pool_count }}</span> <span>{{ max_pool_count }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Max Ports Per Client"> <el-form-item label="Max Ports Per Client">
<span>{{ max_ports_per_client }}</span> <span>{{ max_ports_per_client }}</span>
</el-form-item> </el-form-item>
<el-form-item label="HeartBeat Timeout"> <el-form-item label="HeartBeat Timeout">
<span>{{ heart_beat_timeout }}</span> <span>{{ heart_beat_timeout }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Client Counts"> <el-form-item label="Client Counts">
<span>{{ client_counts }}</span> <span>{{ client_counts }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Current Connections"> <el-form-item label="Current Connections">
<span>{{ cur_conns }}</span> <span>{{ cur_conns }}</span>
</el-form-item> </el-form-item>
<el-form-item label="Proxy Counts"> <el-form-item label="Proxy Counts">
<span>{{ proxy_counts }}</span> <span>{{ proxy_counts }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div>
</el-col> </el-col>
<el-col :md="12"> <el-col :md="12">
<div id="traffic" style="width: 400px; height: 250px; margin-bottom: 30px" /> <div id="traffic" style="width: 400px;height:250px;margin-bottom: 30px;"></div>
<div id="proxies" style="width: 400px; height: 250px" /> <div id="proxies" style="width: 400px;height:250px;"></div>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script> <script>
import { DrawTrafficChart, DrawProxyChart } from '../utils/chart.js' import {DrawTrafficChart, DrawProxyChart} from '../utils/chart.js'
export default { export default {
data() { data() {
return { return {
version: '', version: '',
bind_port: '', bind_port: '',
bind_udp_port: '', bind_udp_port: '',
vhost_http_port: '', vhost_http_port: '',
vhost_https_port: '', vhost_https_port: '',
subdomain_host: '', subdomain_host: '',
max_pool_count: '', max_pool_count: '',
max_ports_per_client: '', max_ports_per_client: '',
heart_beat_timeout: '', heart_beat_timeout: '',
client_counts: '', client_counts: '',
cur_conns: '', cur_conns: '',
proxy_counts: '' proxy_counts: ''
}
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
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 = json.vhost_http_port
if (this.vhost_http_port == 0) {
this.vhost_http_port = "disable"
}
this.vhost_https_port = json.vhost_https_port
if (this.vhost_https_port == 0) {
this.vhost_https_port = "disable"
}
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 = json.heart_beat_timeout
this.client_counts = json.client_counts
this.cur_conns = json.cur_conns
this.proxy_counts = 0
if (json.proxy_type_count != null) {
if (json.proxy_type_count.tcp != null) {
this.proxy_counts += json.proxy_type_count.tcp
}
if (json.proxy_type_count.udp != null) {
this.proxy_counts += json.proxy_type_count.udp
}
if (json.proxy_type_count.http != null) {
this.proxy_counts += json.proxy_type_count.http
}
if (json.proxy_type_count.https != null) {
this.proxy_counts += json.proxy_type_count.https
}
if (json.proxy_type_count.stcp != null) {
this.proxy_counts += json.proxy_type_count.stcp
}
if (json.proxy_type_count.xtcp != null) {
this.proxy_counts += json.proxy_type_count.xtcp
}
}
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'
})
})
}
}
} }
},
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
},
mounted() {
this.initData()
},
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'
}
this.vhost_http_port = this.serverInfo.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.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.heart_beat_timeout = this.serverInfo.heart_beat_timeout
this.client_counts = this.serverInfo.client_counts
this.cur_conns = this.serverInfo.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 (this.serverInfo.proxy_type_count.udp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.udp
}
if (this.serverInfo.proxy_type_count.http != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.http
}
if (this.serverInfo.proxy_type_count.https != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.https
}
if (this.serverInfo.proxy_type_count.stcp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.stcp
}
if (this.serverInfo.proxy_type_count.xtcp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.xtcp
}
}
DrawTrafficChart('traffic', this.serverInfo.total_traffic_in, this.serverInfo.total_traffic_out)
DrawProxyChart('proxies', this.serverInfo)
}
}
}
</script> </script>
<style> <style>
.source { .source {
border: 1px solid #eaeefb; border: 1px solid #eaeefb;
border-radius: 4px; border-radius: 4px;
transition: 0.2s; transition: .2s;
padding: 24px; padding: 24px;
} }
.server_info { .server_info {
margin-left: 40px; margin-left: 40px;
font-size: 0px; font-size: 0px;
} }
.server_info label { .server_info label {
width: 150px; width: 150px;
color: #99a9bf; color: #99a9bf;
} }
.server_info .el-form-item { .server_info .el-form-item {
margin-right: 0; margin-right: 0;
margin-bottom: 0; margin-bottom: 0;
width: 100%; width: 100%;
} }
</style> </style>

View File

@ -1,13 +1,18 @@
<template> <template>
<div> <div>
<el-table :data="proxies" :default-sort="{ prop: 'name', order: 'ascending' }" style="width: 100%"> <el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand"> <el-table-column type="expand">
<template slot-scope="props"> <template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click"> <el-popover
<my-traffic-chart :proxy-name="props.row.name" /> 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-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom: 10px">Traffic Statistics</el-button> <el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom:10px">Traffic Statistics</el-button>
<el-form label-position="left" inline class="demo-table-expand"> <el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="Name"> <el-form-item label="Name">
@ -40,68 +45,104 @@
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ props.row.last_close_time }}</span> <span>{{ props.row.last_close_time }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="Name" prop="name" sortable /> <el-table-column
<el-table-column label="Port" prop="port" sortable /> label="Name"
<el-table-column label="Connections" prop="conns" sortable /> prop="name"
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable /> sortable>
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable /> </el-table-column>
<el-table-column label="status" prop="status" sortable> <el-table-column
<template slot-scope="scope"> label="Port"
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag> prop="port"
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag> sortable>
</template> </el-table-column>
</el-table-column> <el-table-column
</el-table> label="Connections"
</div> 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 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> </template>
<script> <script>
import Humanize from 'humanize-plus' import Humanize from 'humanize-plus';
import Traffic from './Traffic.vue' import Traffic from './Traffic.vue'
import { HttpProxy } from '../utils/proxy.js' import {
export default { HttpProxy
components: { } from '../utils/proxy.js'
'my-traffic-chart': Traffic export default {
}, data() {
data() { return {
return { proxies: null,
proxies: [], vhost_http_port: "",
vhost_http_port: '', subdomain_host: ""
subdomain_host: ''
}
},
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
},
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
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) {
this.proxies.push(new HttpProxy(proxyStats, this.vhost_http_port, this.subdomain_host))
} }
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
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> </script>
<style>
</style>

View File

@ -1,13 +1,18 @@
<template> <template>
<div> <div>
<el-table :data="proxies" :default-sort="{ prop: 'name', order: 'ascending' }" style="width: 100%"> <el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand"> <el-table-column type="expand">
<template slot-scope="props"> <template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click"> <el-popover
<my-traffic-chart :proxy-name="props.row.name" /> 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-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom: 10px">Traffic Statistics</el-button> <el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom:10px">Traffic Statistics</el-button>
<el-form label-position="left" inline class="demo-table-expand"> <el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="Name"> <el-form-item label="Name">
@ -34,69 +39,105 @@
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ props.row.last_close_time }}</span> <span>{{ props.row.last_close_time }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="Name" prop="name" sortable /> <el-table-column
<el-table-column label="Port" prop="port" sortable /> label="Name"
<el-table-column label="Connections" prop="conns" sortable /> prop="name"
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable /> sortable>
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable /> </el-table-column>
<el-table-column label="status" prop="status" sortable> <el-table-column
<template slot-scope="scope"> label="Port"
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag> prop="port"
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag> sortable>
</template> </el-table-column>
</el-table-column> <el-table-column
</el-table> label="Connections"
</div> 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 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> </template>
<script> <script>
import Humanize from 'humanize-plus' import Humanize from 'humanize-plus';
import Traffic from './Traffic.vue' import Traffic from './Traffic.vue'
import { HttpsProxy } from '../utils/proxy.js' import {
export default { HttpsProxy
components: { } from '../utils/proxy.js'
'my-traffic-chart': Traffic export default {
}, data() {
data() { return {
return { proxies: null,
proxies: [], vhost_https_port: '',
vhost_https_port: '', subdomain_host: ''
subdomain_host: ''
}
},
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
},
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
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) {
this.proxies.push(new HttpsProxy(proxyStats, this.vhost_https_port, this.subdomain_host))
} }
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
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> </script>
<style>
</style>

View File

@ -1,15 +1,18 @@
<template> <template>
<div> <div>
<el-table :data="proxies" :default-sort="{ prop: 'name', order: 'ascending' }" style="width: 100%"> <el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand"> <el-table-column type="expand">
<template slot-scope="props"> <template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click"> <el-popover
<my-traffic-chart :proxy-name="props.row.name" /> 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-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom: 10px" @click="fetchData2"> <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>
Traffic Statistics
</el-button>
<el-form label-position="left" inline class="demo-table-expand"> <el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="Name"> <el-form-item label="Name">
@ -30,57 +33,83 @@
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ props.row.last_close_time }}</span> <span>{{ props.row.last_close_time }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="Name" prop="name" sortable /> <el-table-column
<el-table-column label="Connections" prop="conns" sortable /> label="Name"
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable /> prop="name"
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable /> sortable>
<el-table-column label="status" prop="status" sortable> </el-table-column>
<template slot-scope="scope"> <el-table-column
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag> label="Connections"
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag> prop="conns"
</template> sortable>
</el-table-column> </el-table-column>
</el-table> <el-table-column
</div> 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 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> </template>
<script> <script>
import Humanize from 'humanize-plus' import Humanize from 'humanize-plus'
import Traffic from './Traffic.vue' import Traffic from './Traffic.vue'
import { StcpProxy } from '../utils/proxy.js' import { StcpProxy } from '../utils/proxy.js'
export default { export default {
components: { data() {
'my-traffic-chart': Traffic return {
}, proxies: null
data() {
return {
proxies: []
}
},
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
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) {
this.proxies.push(new StcpProxy(proxyStats))
} }
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
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> </script>
<style> <style>

View File

@ -1,16 +1,19 @@
<template> <template>
<div> <div>
<el-table :data="proxies" :default-sort="{ prop: 'name', order: 'ascending' }" style="width: 100%"> <el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand"> <el-table-column type="expand">
<template slot-scope="props"> <template slot-scope="props">
<el-popover placement="right" width="600" style="margin-left: 0px" trigger="click"> <el-popover
<my-traffic-chart :proxy-name="props.row.name" /> ref="popover4"
placement="right"
<el-button slot="reference" type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom: 10px"> width="600"
Traffic Statistics style="margin-left:0px"
</el-button> trigger="click">
<my-traffic-chart :proxy_name="props.row.name"></my-traffic-chart>
</el-popover> </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 label-position="left" inline class="demo-table-expand">
<el-form-item label="Name"> <el-form-item label="Name">
<span>{{ props.row.name }}</span> <span>{{ props.row.name }}</span>
@ -33,58 +36,88 @@
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ props.row.last_close_time }}</span> <span>{{ props.row.last_close_time }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="Name" prop="name" sortable /> <el-table-column
<el-table-column label="Port" prop="port" sortable /> label="Name"
<el-table-column label="Connections" prop="conns" sortable /> prop="name"
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable /> sortable>
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable /> </el-table-column>
<el-table-column label="status" prop="status" sortable> <el-table-column
<template slot-scope="scope"> label="Port"
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag> prop="port"
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag> sortable>
</template> </el-table-column>
</el-table-column> <el-table-column
</el-table> label="Connections"
</div> 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 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> </template>
<script> <script>
import Humanize from 'humanize-plus' import Humanize from 'humanize-plus'
import Traffic from './Traffic.vue' import Traffic from './Traffic.vue'
import { TcpProxy } from '../utils/proxy.js' import { TcpProxy } from '../utils/proxy.js'
export default { export default {
components: { data() {
'my-traffic-chart': Traffic return {
}, proxies: null
data() {
return {
proxies: []
}
},
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
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) {
this.proxies.push(new TcpProxy(proxyStats))
} }
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
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> </script>
<style> <style>

View File

@ -1,13 +1,18 @@
<template> <template>
<div> <div>
<el-table :data="proxies" :default-sort="{ prop: 'name', order: 'ascending' }" style="width: 100%"> <el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%">
<el-table-column type="expand"> <el-table-column type="expand">
<template slot-scope="props"> <template slot-scope="props">
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click"> <el-popover
<my-traffic-chart :proxy-name="props.row.name" /> 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-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom: 10px">Traffic Statistics</el-button> <el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom:10px">Traffic Statistics</el-button>
<el-form label-position="left" inline class="demo-table-expand"> <el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="Name"> <el-form-item label="Name">
@ -31,57 +36,91 @@
<el-form-item label="Last Close"> <el-form-item label="Last Close">
<span>{{ props.row.last_close_time }}</span> <span>{{ props.row.last_close_time }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="Name" prop="name" sortable /> <el-table-column
<el-table-column label="Port" prop="port" sortable /> label="Name"
<el-table-column label="Connections" prop="conns" sortable /> prop="name"
<el-table-column label="Traffic In" prop="traffic_in" :formatter="formatTrafficIn" sortable /> sortable>
<el-table-column label="Traffic Out" prop="traffic_out" :formatter="formatTrafficOut" sortable /> </el-table-column>
<el-table-column label="status" prop="status" sortable> <el-table-column
<template slot-scope="scope"> label="Port"
<el-tag v-if="scope.row.status === 'online'" type="success">{{ scope.row.status }}</el-tag> prop="port"
<el-tag v-else type="danger">{{ scope.row.status }}</el-tag> sortable>
</template> </el-table-column>
</el-table-column> <el-table-column
</el-table> label="Connections"
</div> 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 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> </template>
<script> <script>
import Humanize from 'humanize-plus' import Humanize from 'humanize-plus';
import Traffic from './Traffic.vue' import Traffic from './Traffic.vue'
import { UdpProxy } from '../utils/proxy.js' import {
export default { UdpProxy
components: { } from '../utils/proxy.js'
'my-traffic-chart': Traffic export default {
}, data() {
data() { return {
return { proxies: null
proxies: []
}
},
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
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) {
this.proxies.push(new UdpProxy(proxyStats))
} }
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
formatTrafficIn(row, column) {
return Humanize.fileSize(row.traffic_in)
},
formatTrafficOut(row, column) {
return Humanize.fileSize(row.traffic_out)
},
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> </script>
<style>
</style>

View File

@ -1,26 +1,36 @@
<template> <template>
<div :id="proxyName" style="width: 600px; height: 400px" /> <div :id="proxy_name" style="width: 600px;height:400px;"></div>
</template> </template>
<script> <script>
import { DrawProxyTrafficChart } from '../utils/chart.js' import {DrawProxyTrafficChart} from '../utils/chart.js'
export default { export default {
props: { props: ['proxy_name'],
proxyName: { created() {
type: String, this.fetchData()
required: true },
//watch: {
//'$route': 'fetchData'
//},
methods: {
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'
})
})
}
} }
},
mounted() {
this.initData()
},
methods: {
async initData() {
const json = await this.$fetch(`traffic/${this.proxyName}`)
if (!json) return
DrawProxyTrafficChart(this.proxyName, json.traffic_in, json.traffic_out)
}
}
} }
</script> </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 Vue from 'vue'
// import ElementUI from 'element-ui' //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 lang from 'element-ui/lib/locale/lang/en'
import locale from 'element-ui/lib/locale' import locale from 'element-ui/lib/locale'
import 'element-ui/lib/theme-chalk/index.css' import 'element-ui/lib/theme-chalk/index.css'
@ -8,7 +21,6 @@ import './utils/less/custom.less'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import store from '@/store'
import 'whatwg-fetch' import 'whatwg-fetch'
locale.use(lang) locale.use(lang)
@ -25,15 +37,12 @@ Vue.use(Menu)
Vue.use(Submenu) Vue.use(Submenu)
Vue.use(MenuItem) Vue.use(MenuItem)
Vue.use(Tag) Vue.use(Tag)
Vue.prototype.$message = Message
import fetch from '@/utils/fetch'
Vue.prototype.$fetch = fetch
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({
router, el: '#app',
store, router,
render: h => h(App) template: '<App/>',
}).$mount('#app') components: { App }
})

View File

@ -10,36 +10,29 @@ import ProxiesStcp from '../components/ProxiesStcp.vue'
Vue.use(Router) Vue.use(Router)
export default new Router({ export default new Router({
routes: [ routes: [{
{ path: '/',
path: '/', name: 'Overview',
name: 'Overview', component: Overview
component: Overview }, {
}, path: '/proxies/tcp',
{ name: 'ProxiesTcp',
path: '/proxies/tcp', component: ProxiesTcp
name: 'ProxiesTcp', }, {
component: ProxiesTcp path: '/proxies/udp',
}, name: 'ProxiesUdp',
{ component: ProxiesUdp
path: '/proxies/udp', }, {
name: 'ProxiesUdp', path: '/proxies/http',
component: ProxiesUdp name: 'ProxiesHttp',
}, component: ProxiesHttp
{ }, {
path: '/proxies/http', path: '/proxies/https',
name: 'ProxiesHttp', name: 'ProxiesHttps',
component: ProxiesHttp component: ProxiesHttps
}, }, {
{ path: '/proxies/stcp',
path: '/proxies/https', name: 'ProxiesStcp',
name: 'ProxiesHttps', component: ProxiesStcp
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,215 +1,199 @@
import Humanize from 'humanize-plus' import Humanize from "humanize-plus"
import echarts from 'echarts/lib/echarts' import echarts from "echarts/lib/echarts"
import 'echarts/theme/macarons' import "echarts/theme/macarons"
import 'echarts/lib/chart/bar' import "echarts/lib/chart/bar"
import 'echarts/lib/chart/pie' import "echarts/lib/chart/pie"
import 'echarts/lib/component/tooltip' import "echarts/lib/component/tooltip"
import 'echarts/lib/component/title' import "echarts/lib/component/title"
function DrawTrafficChart(elementId, trafficIn, trafficOut) { function DrawTrafficChart(elementId, trafficIn, trafficOut) {
const myChart = echarts.init(document.getElementById(elementId), 'macarons') let myChart = echarts.init(document.getElementById(elementId), 'macarons');
myChart.showLoading() myChart.showLoading()
const option = { let option = {
title: { title: {
text: 'Network Traffic', text: 'Network Traffic',
subtext: 'today', subtext: 'today',
x: 'center' x: 'center'
}, },
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: function(v) { formatter: function(v) {
return Humanize.fileSize(v.data.value) + ' (' + v.percent + '%)' return Humanize.fileSize(v.data.value) + " (" + v.percent + "%)"
} }
}, },
series: [ series: [{
{ type: 'pie',
type: 'pie', radius: '55%',
radius: '55%', center: ['50%', '60%'],
center: ['50%', '60%'], data: [{
data: [ value: trafficIn,
{ name: 'Traffic In'
value: trafficIn, }, {
name: 'Traffic In' value: trafficOut,
}, name: 'Traffic Out'
{ }, ],
value: trafficOut, itemStyle: {
name: 'Traffic Out' emphasis: {
} shadowBlur: 10,
], shadowOffsetX: 0,
itemStyle: { shadowColor: 'rgba(0, 0, 0, 0.5)'
emphasis: { }
shadowBlur: 10, }
shadowOffsetX: 0, }]
shadowColor: 'rgba(0, 0, 0, 0.5)' };
} myChart.setOption(option);
} myChart.hideLoading()
}
]
}
myChart.setOption(option)
myChart.hideLoading()
} }
function DrawProxyChart(elementId, serverInfo) { function DrawProxyChart(elementId, serverInfo) {
if (serverInfo.proxy_type_count.tcp == null) { if (serverInfo.proxy_type_count.tcp == null) {
serverInfo.proxy_type_count.tcp = 0 serverInfo.proxy_type_count.tcp = 0
} }
if (serverInfo.proxy_type_count.udp == null) { if (serverInfo.proxy_type_count.udp == null) {
serverInfo.proxy_type_count.udp = 0 serverInfo.proxy_type_count.udp = 0
} }
if (serverInfo.proxy_type_count.http == null) { if (serverInfo.proxy_type_count.http == null) {
serverInfo.proxy_type_count.http = 0 serverInfo.proxy_type_count.http = 0
} }
if (serverInfo.proxy_type_count.https == null) { if (serverInfo.proxy_type_count.https == null) {
serverInfo.proxy_type_count.https = 0 serverInfo.proxy_type_count.https = 0
} }
if (serverInfo.proxy_type_count.stcp == null) { if (serverInfo.proxy_type_count.stcp == null) {
serverInfo.proxy_type_count.stcp = 0 serverInfo.proxy_type_count.stcp = 0
} }
if (serverInfo.proxy_type_count.xtcp == null) { if (serverInfo.proxy_type_count.xtcp == null) {
serverInfo.proxy_type_count.xtcp = 0 serverInfo.proxy_type_count.xtcp = 0
} }
const myChart = echarts.init(document.getElementById(elementId), 'macarons') let myChart = echarts.init(document.getElementById(elementId), 'macarons')
myChart.showLoading() myChart.showLoading()
const option = { let option = {
title: { title: {
text: 'Proxies', text: 'Proxies',
subtext: 'now', subtext: 'now',
x: 'center' x: 'center'
}, },
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: function(v) { formatter: function(v) {
return v.data.value return v.data.value
} }
}, },
series: [ series: [{
{ type: 'pie',
type: 'pie', radius: '55%',
radius: '55%', center: ['50%', '60%'],
center: ['50%', '60%'], data: [{
data: [ value: serverInfo.proxy_type_count.tcp,
{ name: 'TCP'
value: serverInfo.proxy_type_count.tcp, }, {
name: 'TCP' value: serverInfo.proxy_type_count.udp,
}, name: 'UDP'
{ }, {
value: serverInfo.proxy_type_count.udp, value: serverInfo.proxy_type_count.http,
name: 'UDP' name: 'HTTP'
}, }, {
{ value: serverInfo.proxy_type_count.https,
value: serverInfo.proxy_type_count.http, name: 'HTTPS'
name: 'HTTP' }, {
}, value: serverInfo.proxy_type_count.stcp,
{ name: 'STCP'
value: serverInfo.proxy_type_count.https, }, {
name: 'HTTPS' value: serverInfo.proxy_type_count.xtcp,
}, name: 'XTCP'
{ }],
value: serverInfo.proxy_type_count.stcp, itemStyle: {
name: 'STCP' emphasis: {
}, shadowBlur: 10,
{ shadowOffsetX: 0,
value: serverInfo.proxy_type_count.xtcp, shadowColor: 'rgba(0, 0, 0, 0.5)'
name: 'XTCP' }
} }
], }]
itemStyle: { };
emphasis: { myChart.setOption(option);
shadowBlur: 10, myChart.hideLoading()
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
myChart.setOption(option)
myChart.hideLoading()
} }
// 7 days // 7 days
function DrawProxyTrafficChart(elementId, trafficInArr, trafficOutArr) { function DrawProxyTrafficChart(elementId, trafficInArr, trafficOutArr) {
const params = { let params = {
width: '600px', width: '600px',
height: '400px' height: '400px'
} }
const myChart = echarts.init(document.getElementById(elementId), 'macarons', params) let myChart = echarts.init(document.getElementById(elementId), 'macarons', params);
myChart.showLoading() myChart.showLoading()
trafficInArr = trafficInArr.reverse() trafficInArr = trafficInArr.reverse()
trafficOutArr = trafficOutArr.reverse() trafficOutArr = trafficOutArr.reverse()
let now = new Date() let now = new Date()
now = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 6) now = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 6)
const dates = [] let dates = new Array()
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
dates.push(now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate()) dates.push(now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate())
now = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1) now = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1)
} }
const option = { let option = {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
type: 'shadow' type: 'shadow'
}, },
formatter: function(data) { formatter: function(data) {
let html = '' let html = ''
if (data.length > 0) { if (data.length > 0) {
html += data[0].name + '<br/>' html += data[0].name + '<br/>'
} }
for (const v of data) { for (let v of data) {
const colorEl = let colorEl = '<span style="display:inline-block;margin-right:5px;' +
'<span style="display:inline-block;margin-right:5px;' + 'border-radius:10px;width:9px;height:9px;background-color:' + v.color + '"></span>' 'border-radius:10px;width:9px;height:9px;background-color:' + v.color + '"></span>';
html += colorEl + v.seriesName + ': ' + Humanize.fileSize(v.value) + '<br/>' html += colorEl + v.seriesName + ': ' + Humanize.fileSize(v.value) + '<br/>'
} }
return html return html
} }
}, },
legend: { legend: {
data: ['Traffic In', 'Traffic Out'] data: ['Traffic In', 'Traffic Out']
}, },
grid: { grid: {
left: '3%', left: '3%',
right: '4%', right: '4%',
bottom: '3%', bottom: '3%',
containLabel: true containLabel: true
}, },
xAxis: [ xAxis: [{
{ type: 'category',
type: 'category', data: dates
data: dates }],
} yAxis: [{
], type: 'value',
yAxis: [ axisLabel: {
{ formatter: function(value) {
type: 'value', return Humanize.fileSize(value)
axisLabel: { }
formatter: function(value) { }
return Humanize.fileSize(value) }],
} series: [{
} name: 'Traffic In',
} type: 'bar',
], data: trafficInArr
series: [ }, {
{
name: 'Traffic In', name: 'Traffic Out',
type: 'bar', type: 'bar',
data: trafficInArr data: trafficOutArr
}, }]
{ };
name: 'Traffic Out', myChart.setOption(option);
type: 'bar', myChart.hideLoading()
data: trafficOutArr
}
]
}
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

@ -1,97 +1,97 @@
class BaseProxy { class BaseProxy {
constructor(proxyStats) { constructor(proxyStats) {
this.name = proxyStats.name this.name = proxyStats.name
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.encryption = proxyStats.conf.use_encryption this.encryption = proxyStats.conf.use_encryption
this.compression = proxyStats.conf.use_compression this.compression = proxyStats.conf.use_compression
} else { } else {
this.encryption = '' this.encryption = ""
this.compression = '' this.compression = ""
}
this.conns = proxyStats.cur_conns
this.traffic_in = proxyStats.today_traffic_in
this.traffic_out = proxyStats.today_traffic_out
this.last_start_time = proxyStats.last_start_time
this.last_close_time = proxyStats.last_close_time
this.status = proxyStats.status
} }
this.conns = proxyStats.cur_conns
this.traffic_in = proxyStats.today_traffic_in
this.traffic_out = proxyStats.today_traffic_out
this.last_start_time = proxyStats.last_start_time
this.last_close_time = proxyStats.last_close_time
this.status = proxyStats.status
}
} }
class TcpProxy extends BaseProxy { class TcpProxy extends BaseProxy {
constructor(proxyStats) { constructor(proxyStats) {
super(proxyStats) super(proxyStats)
this.type = 'tcp' this.type = "tcp"
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port this.addr = ":" + proxyStats.conf.remote_port
this.port = proxyStats.conf.remote_port this.port = proxyStats.conf.remote_port
} else { } else {
this.addr = '' this.addr = ""
this.port = '' this.port = ""
}
} }
}
} }
class UdpProxy extends BaseProxy { class UdpProxy extends BaseProxy {
constructor(proxyStats) { constructor(proxyStats) {
super(proxyStats) super(proxyStats)
this.type = 'udp' this.type = "udp"
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.addr = ':' + proxyStats.conf.remote_port this.addr = ":" + proxyStats.conf.remote_port
this.port = proxyStats.conf.remote_port this.port = proxyStats.conf.remote_port
} else { } else {
this.addr = '' this.addr = ""
this.port = '' this.port = ""
}
} }
}
} }
class HttpProxy extends BaseProxy { class HttpProxy extends BaseProxy {
constructor(proxyStats, port, subdomain_host) { constructor(proxyStats, port, subdomain_host) {
super(proxyStats) super(proxyStats)
this.type = 'http' this.type = "http"
this.port = port this.port = port
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.custom_domains = proxyStats.conf.custom_domains this.custom_domains = proxyStats.conf.custom_domains
this.host_header_rewrite = proxyStats.conf.host_header_rewrite this.host_header_rewrite = proxyStats.conf.host_header_rewrite
this.locations = proxyStats.conf.locations this.locations = proxyStats.conf.locations
if (proxyStats.conf.sub_domain !== '') { if (proxyStats.conf.sub_domain != "") {
this.subdomain = proxyStats.conf.sub_domain + '.' + subdomain_host this.subdomain = proxyStats.conf.sub_domain + "." + subdomain_host
} else { } else {
this.subdomain = '' this.subdomain = ""
} }
} else { } else {
this.custom_domains = '' this.custom_domains = ""
this.host_header_rewrite = '' this.host_header_rewrite = ""
this.subdomain = '' this.subdomain = ""
this.locations = '' this.locations = ""
}
} }
}
} }
class HttpsProxy extends BaseProxy { class HttpsProxy extends BaseProxy {
constructor(proxyStats, port, subdomain_host) { constructor(proxyStats, port, subdomain_host) {
super(proxyStats) super(proxyStats)
this.type = 'https' this.type = "https"
this.port = port this.port = port
if (proxyStats.conf != null) { if (proxyStats.conf != null) {
this.custom_domains = proxyStats.conf.custom_domains this.custom_domains = proxyStats.conf.custom_domains
if (proxyStats.conf.sub_domain !== '') { if (proxyStats.conf.sub_domain != "") {
this.subdomain = proxyStats.conf.sub_domain + '.' + subdomain_host this.subdomain = proxyStats.conf.sub_domain + "." + subdomain_host
} else { } else {
this.subdomain = '' this.subdomain = ""
} }
} else { } else {
this.custom_domains = '' this.custom_domains = ""
this.subdomain = '' this.subdomain = ""
}
} }
}
} }
class StcpProxy extends BaseProxy { class StcpProxy extends BaseProxy {
constructor(proxyStats) { constructor(proxyStats) {
super(proxyStats) super(proxyStats)
this.type = 'stcp' this.type = "stcp"
} }
} }
export { BaseProxy, TcpProxy, UdpProxy, HttpProxy, HttpsProxy, StcpProxy } export {BaseProxy, TcpProxy, UdpProxy, HttpProxy, HttpsProxy, StcpProxy}

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