some dashboard refactor (#2101)

This commit is contained in:
hubery 2020-12-03 20:20:48 +08:00 committed by GitHub
parent 0ab055e946
commit 1e846df870
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 10494 additions and 10531 deletions

View File

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

5
web/frps/.editorconfig Normal file
View File

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

View File

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

2
web/frps/.env.production Normal file
View File

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

267
web/frps/.eslintrc.js Normal file
View File

@ -0,0 +1,267 @@
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,6 +1,25 @@
.DS_Store
node_modules/
dist/
npm-debug.log
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
.idea
.vscode/settings.json
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.json

8
web/frps/.prettierrc Normal file
View File

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

View File

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

25
web/frps/README.md Normal file
View File

@ -0,0 +1,25 @@
# 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
```

3
web/frps/babel.config.js Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

@ -4,45 +4,43 @@
"author": "fatedier",
"private": true,
"scripts": {
"dev": "webpack-dev-server -d --inline --hot --env.dev",
"build": "rimraf dist && webpack -p --progress --hide-modules"
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"bootstrap": "^3.3.7",
"echarts": "^3.5.0",
"element-ui": "^2.3.8",
"echarts": "^4.9.0",
"element-ui": "^2.14.1",
"humanize-plus": "^1.8.2",
"vue": "^2.5.16",
"vue-resource": "^1.2.1",
"vue-router": "^2.3.0",
"whatwg-fetch": "^2.0.3"
},
"engines": {
"node": ">=6"
"core-js": "^3.7.0",
"vue": "^2.6.12",
"vue-router": "^3.4.9",
"whatwg-fetch": "^3.5.0",
"vuex": "^3.5.1"
},
"devDependencies": {
"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"
}
"@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",
"node-sass": "^5.0.0",
"sass-loader": "^10.1.0",
"less": "^3.12.2",
"less-loader": "^7.1.0",
"vue-template-compiler": "^2.6.12"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

View File

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

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,17 @@
<!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="false" @select="handleSelect">
<el-menu default-active="1" mode="vertical" theme="light" router @select="handleSelect">
<el-menu-item index="/">Overview</el-menu-item>
<el-submenu index="/proxies">
<template slot="title">Proxies</template>
@ -24,21 +24,28 @@
<el-col :xs="24" :md="20">
<div id="content">
<router-view></router-view>
<router-view v-if="serverInfo" />
</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')
}
}
}
@ -58,7 +65,7 @@
}
.header-color {
background: #58B7FF;
background: #58b7ff;
}
#content {

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>
<div id="proxies" style="width: 400px;height:250px;"></div>
<div id="traffic" style="width: 400px; height: 250px; margin-bottom: 30px" />
<div id="proxies" style="width: 400px; height: 250px" />
</el-col>
</el-row>
</div>
@ -70,71 +70,65 @@
proxy_counts: ''
}
},
created() {
this.fetchData()
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
},
watch: {
'$route': 'fetchData'
mounted() {
this.initData()
},
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"
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 = json.vhost_http_port
if (this.vhost_http_port == 0) {
this.vhost_http_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 = json.vhost_https_port
if (this.vhost_https_port == 0) {
this.vhost_https_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 = 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.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 = json.heart_beat_timeout
this.client_counts = json.client_counts
this.cur_conns = json.cur_conns
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 (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 != null) {
if (this.serverInfo.proxy_type_count.tcp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.tcp
}
if (json.proxy_type_count.udp != null) {
this.proxy_counts += json.proxy_type_count.udp
if (this.serverInfo.proxy_type_count.udp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.udp
}
if (json.proxy_type_count.http != null) {
this.proxy_counts += json.proxy_type_count.http
if (this.serverInfo.proxy_type_count.http != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.http
}
if (json.proxy_type_count.https != null) {
this.proxy_counts += json.proxy_type_count.https
if (this.serverInfo.proxy_type_count.https != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.https
}
if (json.proxy_type_count.stcp != null) {
this.proxy_counts += json.proxy_type_count.stcp
if (this.serverInfo.proxy_type_count.stcp != null) {
this.proxy_counts += this.serverInfo.proxy_type_count.stcp
}
if (json.proxy_type_count.xtcp != null) {
this.proxy_counts += json.proxy_type_count.xtcp
if (this.serverInfo.proxy_type_count.xtcp != null) {
this.proxy_counts += this.serverInfo.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'
})
})
DrawTrafficChart('traffic', this.serverInfo.total_traffic_in, this.serverInfo.total_traffic_out)
DrawProxyChart('proxies', this.serverInfo)
}
}
}
@ -144,7 +138,7 @@
.source {
border: 1px solid #eaeefb;
border-radius: 4px;
transition: .2s;
transition: 0.2s;
padding: 24px;
}

View File

@ -3,13 +3,8 @@
<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"></my-traffic-chart>
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom: 10px">Traffic Statistics</el-button>
@ -48,40 +43,15 @@
</el-form>
</template>
</el-table-column>
<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>
<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>
<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>
<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>
</template>
</el-table-column>
</el-table>
@ -89,24 +59,27 @@
</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: null,
vhost_http_port: "",
subdomain_host: ""
proxies: [],
vhost_http_port: '',
subdomain_host: ''
}
},
created() {
this.fetchData()
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
},
watch: {
'$route': 'fetchData'
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
@ -115,34 +88,20 @@
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) {
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))
}
})
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>
<style>
</style>

View File

@ -3,13 +3,8 @@
<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"></my-traffic-chart>
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom: 10px">Traffic Statistics</el-button>
@ -42,66 +37,43 @@
</el-form>
</template>
</el-table-column>
<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>
<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>
<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>
<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>
</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: null,
proxies: [],
vhost_https_port: '',
subdomain_host: ''
}
},
created() {
this.fetchData()
computed: {
serverInfo() {
return this.$store.state.serverInfo
}
},
watch: {
'$route': 'fetchData'
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
@ -110,34 +82,21 @@
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) {
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))
}
})
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>
<style>
</style>

View File

@ -3,16 +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"></my-traffic-chart>
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
</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">
@ -36,35 +33,14 @@
</el-form>
</template>
</el-table-column>
<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>
<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>
<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>
<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>
</template>
</el-table-column>
</el-table>
@ -76,16 +52,16 @@
import Traffic from './Traffic.vue'
import { StcpProxy } from '../utils/proxy.js'
export default {
components: {
'my-traffic-chart': Traffic
},
data() {
return {
proxies: null
proxies: []
}
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
@ -94,20 +70,15 @@
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) {
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))
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>

View File

@ -3,16 +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"></my-traffic-chart>
</el-popover>
<el-popover placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
<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 slot="reference" type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom: 10px">
Traffic Statistics
</el-button>
</el-popover>
<el-form label-position="left" inline class="demo-table-expand">
<el-form-item label="Name">
@ -39,40 +36,15 @@
</el-form>
</template>
</el-table-column>
<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>
<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>
<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>
<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>
</template>
</el-table-column>
</el-table>
@ -84,16 +56,16 @@
import Traffic from './Traffic.vue'
import { TcpProxy } from '../utils/proxy.js'
export default {
components: {
'my-traffic-chart': Traffic
},
data() {
return {
proxies: null
proxies: []
}
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
@ -102,20 +74,15 @@
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) {
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))
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>

View File

@ -3,13 +3,8 @@
<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"></my-traffic-chart>
<el-popover ref="popover4" placement="right" width="600" style="margin-left: 0px" trigger="click">
<my-traffic-chart :proxy-name="props.row.name" />
</el-popover>
<el-button v-popover:popover4 type="primary" size="small" icon="view" style="margin-bottom: 10px">Traffic Statistics</el-button>
@ -39,40 +34,15 @@
</el-form>
</template>
</el-table-column>
<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>
<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>
<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>
<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>
</template>
</el-table-column>
</el-table>
@ -80,22 +50,20 @@
</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: null
proxies: []
}
},
created() {
this.fetchData()
},
watch: {
'$route': 'fetchData'
mounted() {
this.initData()
},
methods: {
formatTrafficIn(row, column) {
@ -104,23 +72,16 @@
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) {
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))
}
})
}
},
components: {
'my-traffic-chart': Traffic
}
}
</script>
<style>
</style>

View File

@ -1,36 +1,26 @@
<template>
<div :id="proxy_name" style="width: 600px;height:400px;"></div>
<div :id="proxyName" style="width: 600px; height: 400px" />
</template>
<script>
import { DrawProxyTrafficChart } from '../utils/chart.js'
export default {
props: ['proxy_name'],
created() {
this.fetchData()
props: {
proxyName: {
type: String,
required: true
}
},
mounted() {
this.initData()
},
//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'
})
})
async initData() {
const json = await this.$fetch(`traffic/${this.proxyName}`)
if (!json) return
DrawProxyTrafficChart(this.proxyName, json.traffic_in, json.traffic_out)
}
}
}
</script>
<style>
</style>

View File

@ -1,15 +0,0 @@
<!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,19 +1,6 @@
import Vue from 'vue'
// import ElementUI from 'element-ui'
import {
Button,
Form,
FormItem,
Row,
Col,
Table,
TableColumn,
Popover,
Menu,
Submenu,
MenuItem,
Tag
} from 'element-ui'
import { Button, Form, FormItem, Row, Col, Table, TableColumn, Popover, Menu, Submenu, MenuItem, Tag, Message } 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'
@ -21,6 +8,7 @@ import './utils/less/custom.less'
import App from './App.vue'
import router from './router'
import store from '@/store'
import 'whatwg-fetch'
locale.use(lang)
@ -37,12 +25,15 @@ 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,
template: '<App/>',
components: { App }
})
store,
render: h => h(App)
}).$mount('#app')

View File

@ -10,29 +10,36 @@ 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

@ -0,0 +1,24 @@
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) {
let myChart = echarts.init(document.getElementById(elementId), 'macarons');
const myChart = echarts.init(document.getElementById(elementId), 'macarons')
myChart.showLoading()
let option = {
const option = {
title: {
text: 'Network Traffic',
subtext: 'today',
@ -20,20 +20,24 @@ 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,
@ -41,9 +45,10 @@ function DrawTrafficChart(elementId, trafficIn, trafficOut) {
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
myChart.setOption(option);
}
]
}
myChart.setOption(option)
myChart.hideLoading()
}
@ -66,10 +71,10 @@ function DrawProxyChart(elementId, serverInfo) {
if (serverInfo.proxy_type_count.xtcp == null) {
serverInfo.proxy_type_count.xtcp = 0
}
let myChart = echarts.init(document.getElementById(elementId), 'macarons')
const myChart = echarts.init(document.getElementById(elementId), 'macarons')
myChart.showLoading()
let option = {
const option = {
title: {
text: 'Proxies',
subtext: 'now',
@ -81,29 +86,37 @@ 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,
@ -111,33 +124,34 @@ 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) {
let params = {
const params = {
width: '600px',
height: '400px'
}
let myChart = echarts.init(document.getElementById(elementId), 'macarons', params);
const 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)
let dates = new Array()
const dates = []
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)
}
let option = {
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
@ -148,9 +162,9 @@ function DrawProxyTrafficChart(elementId, trafficInArr, trafficOutArr) {
if (data.length > 0) {
html += data[0].name + '<br/>'
}
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>';
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>'
html += colorEl + v.seriesName + ': ' + Humanize.fileSize(v.value) + '<br/>'
}
return html
@ -165,35 +179,37 @@ 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

@ -0,0 +1,20 @@
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'
}
}

16
web/frps/vue.config.js Normal file
View File

@ -0,0 +1,16 @@
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': ''
}
}
}
}
}

View File

@ -1,107 +0,0 @@
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'
})

9207
web/frps/yarn.lock Normal file

File diff suppressed because it is too large Load Diff