mirror of https://github.com/fatedier/frp
fatedier
8 years ago
21 changed files with 1299 additions and 0 deletions
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"presets": [ |
||||||
|
["es2015", { "modules": false }] |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
.DS_Store |
||||||
|
node_modules/ |
||||||
|
dist/ |
||||||
|
npm-debug.log |
||||||
|
.idea |
||||||
|
.vscode/settings.json |
@ -0,0 +1,9 @@ |
|||||||
|
.PHONY: dist build |
||||||
|
install: |
||||||
|
@npm install
|
||||||
|
|
||||||
|
dev: install |
||||||
|
@npm run dev
|
||||||
|
|
||||||
|
build: |
||||||
|
@npm run build
|
@ -0,0 +1,46 @@ |
|||||||
|
{ |
||||||
|
"name": "frps-dashboard", |
||||||
|
"description": "A dashboard for frp server.", |
||||||
|
"author": "fatedier", |
||||||
|
"private": true, |
||||||
|
"scripts": { |
||||||
|
"dev": "webpack-dev-server -d --inline --hot --env.dev", |
||||||
|
"build": "rimraf dist && webpack -p --progress --hide-modules" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"bootstrap": "^3.3.7", |
||||||
|
"echarts": "^3.5.0", |
||||||
|
"element-ui": "^1.2.5", |
||||||
|
"humanize-plus": "^1.8.2", |
||||||
|
"vue": "^2.2.4", |
||||||
|
"vue-resource": "^1.2.1", |
||||||
|
"vue-router": "^2.3.0" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": ">=6" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"autoprefixer": "^6.6.0", |
||||||
|
"babel-core": "^6.21.0", |
||||||
|
"babel-eslint": "^7.1.1", |
||||||
|
"babel-loader": "^6.4.0", |
||||||
|
"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": "^2.7.2", |
||||||
|
"less-loader": "^3.0.0", |
||||||
|
"postcss-loader": "^1.3.3", |
||||||
|
"rimraf": "^2.5.4", |
||||||
|
"style-loader": "^0.13.2", |
||||||
|
"url-loader": "^0.5.8", |
||||||
|
"vue-loader": "^11.1.4", |
||||||
|
"vue-template-compiler": "^2.1.8", |
||||||
|
"webpack": "^2.2.0-rc.4", |
||||||
|
"webpack-dev-server": "beta" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
module.exports = { |
||||||
|
plugins: [ |
||||||
|
require('autoprefixer')() |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
<template> |
||||||
|
<div id="app"> |
||||||
|
<header class="grid-content header-color"> |
||||||
|
<el-row> |
||||||
|
<a class="brand" href="#">frp</a> |
||||||
|
</el-row> |
||||||
|
</header> |
||||||
|
<section> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col id="side-nav" :xs="24" :md="4"> |
||||||
|
<el-menu default-active="1" mode="vertical" theme="light" router="false" @select="handleSelect"> |
||||||
|
<el-menu-item index="/">Overview</el-menu-item> |
||||||
|
<el-submenu index="/proxies"> |
||||||
|
<template slot="title">Proxies</template> |
||||||
|
<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/http">HTTP</el-menu-item> |
||||||
|
<el-menu-item index="/proxies/https">HTTPS</el-menu-item> |
||||||
|
</el-submenu> |
||||||
|
<el-menu-item index="">Help</el-menu-item> |
||||||
|
</el-menu> |
||||||
|
</el-col> |
||||||
|
|
||||||
|
<el-col :xs="24" :md="20"> |
||||||
|
<div id="content"> |
||||||
|
<router-view></router-view> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</section> |
||||||
|
<footer></footer> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
export default { |
||||||
|
methods: { |
||||||
|
handleSelect(key, path) { |
||||||
|
if (key == '') { |
||||||
|
window.open("http://github.com/fatedier/frp") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
body { |
||||||
|
background-color: #fafafa; |
||||||
|
margin: 0px; |
||||||
|
} |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
</style> |
After Width: | Height: | Size: 9.4 KiB |
@ -0,0 +1,140 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-row> |
||||||
|
<el-col :md="12"> |
||||||
|
<div class="source"> |
||||||
|
<el-form label-position="left" class="server_info"> |
||||||
|
<el-form-item label="Http Port"> |
||||||
|
<span>{{ vhost_http_port }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Https Port"> |
||||||
|
<span>{{ vhost_https_port }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Auth Timeout"> |
||||||
|
<span>{{ auth_timeout }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Subdomain Host"> |
||||||
|
<span>{{ subdomain_host }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Max PoolCount"> |
||||||
|
<span>{{ max_pool_count }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="HeartBeat Timeout"> |
||||||
|
<span>{{ heart_beat_timeout }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Client Counts"> |
||||||
|
<span>{{ client_counts }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Current Conns"> |
||||||
|
<span>{{ cur_conns }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Proxy Counts"> |
||||||
|
<span>{{ proxy_counts }}</span> |
||||||
|
</el-form-item> |
||||||
|
</el-form> |
||||||
|
</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> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import {DrawTrafficChart, DrawProxyChart} from "../utils/chart.js" |
||||||
|
|
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
vhost_http_port: "", |
||||||
|
vhost_https_port: "", |
||||||
|
auth_timeout: "", |
||||||
|
subdomain_host: "", |
||||||
|
max_pool_count: "", |
||||||
|
heart_beat_timeout: "", |
||||||
|
client_counts: "", |
||||||
|
cur_conns: "", |
||||||
|
proxy_counts: "" |
||||||
|
} |
||||||
|
}, |
||||||
|
created() { |
||||||
|
this.fetchData() |
||||||
|
}, |
||||||
|
watch: { |
||||||
|
'$route': 'fetchData' |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
fetchData() { |
||||||
|
fetch('/api/serverinfo') |
||||||
|
.then(res => { |
||||||
|
return res.json() |
||||||
|
}).then(json => { |
||||||
|
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.auth_timeout = json.auth_timeout |
||||||
|
this.subdomain_host = json.subdomain_host |
||||||
|
this.max_pool_count = json.max_pool_count |
||||||
|
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 |
||||||
|
} |
||||||
|
} |
||||||
|
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' |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
.source { |
||||||
|
border: 1px solid #eaeefb; |
||||||
|
border-radius: 4px; |
||||||
|
transition: .2s; |
||||||
|
padding: 24px; |
||||||
|
} |
||||||
|
|
||||||
|
.server_info { |
||||||
|
margin-left: 40px; |
||||||
|
font-size: 0px; |
||||||
|
} |
||||||
|
|
||||||
|
.server_info label { |
||||||
|
width: 150px; |
||||||
|
color: #99a9bf; |
||||||
|
} |
||||||
|
|
||||||
|
.server_info .el-form-item { |
||||||
|
margin-right: 0; |
||||||
|
margin-bottom: 0; |
||||||
|
width: 100%; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,142 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%"> |
||||||
|
<el-table-column type="expand"> |
||||||
|
<template 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-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-item label="Name"> |
||||||
|
<span>{{ props.row.name }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Type"> |
||||||
|
<span>{{ props.row.type }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Domains"> |
||||||
|
<span>{{ props.row.custom_domains }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="SubDomain"> |
||||||
|
<span>{{ props.row.subdomain }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="locations"> |
||||||
|
<span>{{ props.row.locations }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="HostRewrite"> |
||||||
|
<span>{{ props.row.host_header_rewrite }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Encryption"> |
||||||
|
<span>{{ props.row.encryption }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Compression"> |
||||||
|
<span>{{ props.row.compression }}</span> |
||||||
|
</el-form-item> |
||||||
|
</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> |
||||||
|
<template 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> |
||||||
|
|
||||||
|
<script> |
||||||
|
import Humanize from "humanize-plus"; |
||||||
|
import Traffic from './Traffic.vue' |
||||||
|
import { |
||||||
|
HttpProxy |
||||||
|
} from "../utils/proxy.js" |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
proxies: null, |
||||||
|
vhost_http_port: "", |
||||||
|
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') |
||||||
|
.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') |
||||||
|
.then(res => { |
||||||
|
return res.json() |
||||||
|
}).then(json => { |
||||||
|
this.proxies = new Array() |
||||||
|
for (let proxyStats of json.proxies) { |
||||||
|
this.proxies.push(new HttpProxy(proxyStats, this.vhost_http_port, this.subdomain_host)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { |
||||||
|
'my-traffic-chart': Traffic |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
</style> |
@ -0,0 +1,137 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%"> |
||||||
|
<el-table-column type="expand"> |
||||||
|
<template 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-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-item label="Name"> |
||||||
|
<span>{{ props.row.name }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Type"> |
||||||
|
<span>{{ props.row.type }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Domains"> |
||||||
|
<span>{{ props.row.custom_domains }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="SubDomain"> |
||||||
|
<span>{{ props.row.subdomain }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Encryption"> |
||||||
|
<span>{{ props.row.encryption }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Compression"> |
||||||
|
<span>{{ props.row.compression }}</span> |
||||||
|
</el-form-item> |
||||||
|
</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> |
||||||
|
<template 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> |
||||||
|
|
||||||
|
<script> |
||||||
|
import Humanize from "humanize-plus"; |
||||||
|
import Traffic from './Traffic.vue' |
||||||
|
import { |
||||||
|
HttpsProxy |
||||||
|
} from "../utils/proxy.js" |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
proxies: null, |
||||||
|
vhost_https_port: "", |
||||||
|
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') |
||||||
|
.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') |
||||||
|
.then(res => { |
||||||
|
return res.json() |
||||||
|
}).then(json => { |
||||||
|
this.proxies = new Array() |
||||||
|
for (let proxyStats of json.proxies) { |
||||||
|
this.proxies.push(new HttpsProxy(proxyStats, this.vhost_https_port, this.subdomain_host)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { |
||||||
|
'my-traffic-chart': Traffic |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
</style> |
@ -0,0 +1,118 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%"> |
||||||
|
<el-table-column type="expand"> |
||||||
|
<template 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-button v-popover:popover4 type="primary" size="small" icon="view" :name="props.row.name" style="margin-bottom:10px" @click="fetchData2">Traffic Statistics</el-button> |
||||||
|
|
||||||
|
<el-form label-position="left" inline class="demo-table-expand"> |
||||||
|
<el-form-item label="Name"> |
||||||
|
<span>{{ props.row.name }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Type"> |
||||||
|
<span>{{ props.row.type }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Addr"> |
||||||
|
<span>{{ props.row.addr }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Encryption"> |
||||||
|
<span>{{ props.row.encryption }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Compression"> |
||||||
|
<span>{{ props.row.compression }}</span> |
||||||
|
</el-form-item> |
||||||
|
</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> |
||||||
|
<template 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> |
||||||
|
|
||||||
|
<script> |
||||||
|
import Humanize from 'humanize-plus' |
||||||
|
import Traffic from './Traffic.vue' |
||||||
|
import { TcpProxy } from '../utils/proxy.js' |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
proxies: null |
||||||
|
} |
||||||
|
}, |
||||||
|
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') |
||||||
|
.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> |
||||||
|
|
||||||
|
<style> |
||||||
|
</style> |
@ -0,0 +1,120 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-table :data="proxies" :default-sort="{prop: 'name', order: 'ascending'}" style="width: 100%"> |
||||||
|
<el-table-column type="expand"> |
||||||
|
<template 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-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-item label="Name"> |
||||||
|
<span>{{ props.row.name }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Type"> |
||||||
|
<span>{{ props.row.type }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Addr"> |
||||||
|
<span>{{ props.row.addr }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Encryption"> |
||||||
|
<span>{{ props.row.encryption }}</span> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="Compression"> |
||||||
|
<span>{{ props.row.compression }}</span> |
||||||
|
</el-form-item> |
||||||
|
</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> |
||||||
|
<template 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> |
||||||
|
|
||||||
|
<script> |
||||||
|
import Humanize from "humanize-plus"; |
||||||
|
import Traffic from './Traffic.vue' |
||||||
|
import { |
||||||
|
UdpProxy |
||||||
|
} from "../utils/proxy.js" |
||||||
|
export default { |
||||||
|
data() { |
||||||
|
return { |
||||||
|
proxies: null |
||||||
|
} |
||||||
|
}, |
||||||
|
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') |
||||||
|
.then(res => { |
||||||
|
return res.json() |
||||||
|
}).then(json => { |
||||||
|
this.proxies = new Array() |
||||||
|
for (let proxyStats of json.proxies) { |
||||||
|
this.proxies.push(new UdpProxy(proxyStats)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
components: { |
||||||
|
'my-traffic-chart': Traffic |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
</style> |
@ -0,0 +1,36 @@ |
|||||||
|
<template> |
||||||
|
<div :id="proxy_name" style="width: 600px;height:400px;"></div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import {DrawProxyTrafficChart} from '../utils/chart.js' |
||||||
|
export default { |
||||||
|
props: ['proxy_name'], |
||||||
|
created() { |
||||||
|
this.fetchData() |
||||||
|
}, |
||||||
|
//watch: { |
||||||
|
//'$route': 'fetchData' |
||||||
|
//}, |
||||||
|
methods: { |
||||||
|
fetchData() { |
||||||
|
let url = '/api/proxy/traffic/' + this.proxy_name |
||||||
|
fetch(url) |
||||||
|
.then(res => { |
||||||
|
return res.json() |
||||||
|
}).then(json => { |
||||||
|
DrawProxyTrafficChart(this.proxy_name, json.traffic_in, json.traffic_out) |
||||||
|
}).catch( err => { |
||||||
|
this.$message({ |
||||||
|
showClose: true, |
||||||
|
message: 'Get server info from frps failed!' + err, |
||||||
|
type: 'warning' |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
</style> |
@ -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> |
@ -0,0 +1,17 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import ElementUI from 'element-ui' |
||||||
|
import 'element-ui/lib/theme-default/index.css' |
||||||
|
import './utils/less/custom.less' |
||||||
|
|
||||||
|
import App from './App.vue' |
||||||
|
import router from './router' |
||||||
|
|
||||||
|
Vue.use(ElementUI) |
||||||
|
Vue.config.productionTip = false |
||||||
|
|
||||||
|
new Vue({ |
||||||
|
el: '#app', |
||||||
|
router, |
||||||
|
template: '<App/>', |
||||||
|
components: { App } |
||||||
|
}) |
@ -0,0 +1,33 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import Router from 'vue-router' |
||||||
|
import Overview from '../components/Overview.vue' |
||||||
|
import ProxiesTcp from '../components/ProxiesTcp.vue' |
||||||
|
import ProxiesUdp from '../components/ProxiesUdp.vue' |
||||||
|
import ProxiesHttp from '../components/ProxiesHttp.vue' |
||||||
|
import ProxiesHttps from '../components/ProxiesHttps.vue' |
||||||
|
|
||||||
|
Vue.use(Router) |
||||||
|
|
||||||
|
export default new Router({ |
||||||
|
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 |
||||||
|
}] |
||||||
|
}) |
@ -0,0 +1,187 @@ |
|||||||
|
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" |
||||||
|
|
||||||
|
function DrawTrafficChart(elementId, trafficIn, trafficOut) { |
||||||
|
let myChart = echarts.init(document.getElementById(elementId), 'macarons'); |
||||||
|
myChart.showLoading() |
||||||
|
|
||||||
|
let option = { |
||||||
|
title: { |
||||||
|
text: 'Network Traffic', |
||||||
|
subtext: 'today', |
||||||
|
x: 'center' |
||||||
|
}, |
||||||
|
tooltip: { |
||||||
|
trigger: 'item', |
||||||
|
formatter: function(v) { |
||||||
|
return Humanize.fileSize(v.data.value) + " (" + v.percent + "%)" |
||||||
|
} |
||||||
|
}, |
||||||
|
series: [{ |
||||||
|
type: 'pie', |
||||||
|
radius: '55%', |
||||||
|
center: ['50%', '60%'], |
||||||
|
data: [{ |
||||||
|
value: trafficIn, |
||||||
|
name: 'Traffic In' |
||||||
|
}, { |
||||||
|
value: trafficOut, |
||||||
|
name: 'Traffic Out' |
||||||
|
}, ], |
||||||
|
itemStyle: { |
||||||
|
emphasis: { |
||||||
|
shadowBlur: 10, |
||||||
|
shadowOffsetX: 0, |
||||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||||
|
} |
||||||
|
} |
||||||
|
}] |
||||||
|
}; |
||||||
|
myChart.setOption(option); |
||||||
|
myChart.hideLoading() |
||||||
|
} |
||||||
|
|
||||||
|
function DrawProxyChart(elementId, serverInfo) { |
||||||
|
if (serverInfo.proxy_type_count.tcp == null) { |
||||||
|
serverInfo.proxy_type_count.tcp = 0 |
||||||
|
} |
||||||
|
if (serverInfo.proxy_type_count.udp == null) { |
||||||
|
serverInfo.proxy_type_count.udp = 0 |
||||||
|
} |
||||||
|
if (serverInfo.proxy_type_count.http == null) { |
||||||
|
serverInfo.proxy_type_count.http = 0 |
||||||
|
} |
||||||
|
if (serverInfo.proxy_type_count.https == null) { |
||||||
|
serverInfo.proxy_type_count.https = 0 |
||||||
|
} |
||||||
|
let myChart = echarts.init(document.getElementById(elementId), 'macarons') |
||||||
|
myChart.showLoading() |
||||||
|
|
||||||
|
let option = { |
||||||
|
title: { |
||||||
|
text: 'Proxies', |
||||||
|
subtext: 'now', |
||||||
|
x: 'center' |
||||||
|
}, |
||||||
|
tooltip: { |
||||||
|
trigger: 'item', |
||||||
|
formatter: function(v) { |
||||||
|
return v.data.value |
||||||
|
} |
||||||
|
}, |
||||||
|
series: [{ |
||||||
|
type: 'pie', |
||||||
|
radius: '55%', |
||||||
|
center: ['50%', '60%'], |
||||||
|
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' |
||||||
|
}], |
||||||
|
itemStyle: { |
||||||
|
emphasis: { |
||||||
|
shadowBlur: 10, |
||||||
|
shadowOffsetX: 0, |
||||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)' |
||||||
|
} |
||||||
|
} |
||||||
|
}] |
||||||
|
}; |
||||||
|
myChart.setOption(option); |
||||||
|
myChart.hideLoading() |
||||||
|
} |
||||||
|
|
||||||
|
// 7 days
|
||||||
|
function DrawProxyTrafficChart(elementId, trafficInArr, trafficOutArr) { |
||||||
|
let params = { |
||||||
|
width: '600px', |
||||||
|
height: '400px' |
||||||
|
} |
||||||
|
|
||||||
|
let myChart = echarts.init(document.getElementById(elementId), 'macarons', params); |
||||||
|
myChart.showLoading() |
||||||
|
|
||||||
|
trafficInArr = trafficInArr.reverse() |
||||||
|
trafficOutArr = trafficOutArr.reverse() |
||||||
|
let now = new Date() |
||||||
|
now = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 6) |
||||||
|
let dates = new Array() |
||||||
|
for (let i = 0; i < 7; i++) { |
||||||
|
dates.push(now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate()) |
||||||
|
now = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1) |
||||||
|
} |
||||||
|
|
||||||
|
let option = { |
||||||
|
tooltip: { |
||||||
|
trigger: 'axis', |
||||||
|
axisPointer: { |
||||||
|
type: 'shadow' |
||||||
|
}, |
||||||
|
formatter: function(data) { |
||||||
|
let html = '' |
||||||
|
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>'; |
||||||
|
html += colorEl + v.seriesName + ': ' + Humanize.fileSize(v.value) + '<br/>' |
||||||
|
} |
||||||
|
return html |
||||||
|
} |
||||||
|
}, |
||||||
|
legend: { |
||||||
|
data: ['Traffic In', 'Traffic Out'] |
||||||
|
}, |
||||||
|
grid: { |
||||||
|
left: '3%', |
||||||
|
right: '4%', |
||||||
|
bottom: '3%', |
||||||
|
containLabel: true |
||||||
|
}, |
||||||
|
xAxis: [{ |
||||||
|
type: 'category', |
||||||
|
data: dates |
||||||
|
}], |
||||||
|
yAxis: [{ |
||||||
|
type: 'value', |
||||||
|
axisLabel: { |
||||||
|
formatter: function(value) { |
||||||
|
return Humanize.fileSize(value) |
||||||
|
} |
||||||
|
} |
||||||
|
}], |
||||||
|
series: [{ |
||||||
|
name: 'Traffic In', |
||||||
|
type: 'bar', |
||||||
|
data: trafficInArr |
||||||
|
}, { |
||||||
|
|
||||||
|
name: 'Traffic Out', |
||||||
|
type: 'bar', |
||||||
|
data: trafficOutArr |
||||||
|
}] |
||||||
|
}; |
||||||
|
myChart.setOption(option); |
||||||
|
myChart.hideLoading() |
||||||
|
} |
||||||
|
|
||||||
|
export { |
||||||
|
DrawTrafficChart, |
||||||
|
DrawProxyChart, |
||||||
|
DrawProxyTrafficChart |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
@color: red; |
||||||
|
|
||||||
|
.el-form-item { |
||||||
|
span { |
||||||
|
margin-left: 15px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.demo-table-expand { |
||||||
|
font-size: 0; |
||||||
|
|
||||||
|
label { |
||||||
|
width: 90px; |
||||||
|
color: #99a9bf; |
||||||
|
} |
||||||
|
|
||||||
|
.el-form-item { |
||||||
|
margin-right: 0; |
||||||
|
margin-bottom: 0; |
||||||
|
width: 50%; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
class BaseProxy { |
||||||
|
constructor(proxyStats) { |
||||||
|
this.name = proxyStats.name |
||||||
|
if (proxyStats.conf != null) { |
||||||
|
this.encryption = proxyStats.conf.use_encryption |
||||||
|
this.compression = proxyStats.conf.use_compression |
||||||
|
} else { |
||||||
|
this.encryption = "" |
||||||
|
this.compression = "" |
||||||
|
} |
||||||
|
this.conns = proxyStats.cur_conns |
||||||
|
this.traffic_in = proxyStats.today_traffic_in |
||||||
|
this.traffic_out = proxyStats.today_traffic_out |
||||||
|
this.status = proxyStats.status |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class TcpProxy extends BaseProxy { |
||||||
|
constructor(proxyStats) { |
||||||
|
super(proxyStats) |
||||||
|
this.type = "tcp" |
||||||
|
if (proxyStats.conf != null) { |
||||||
|
this.addr = proxyStats.conf.bind_addr + ":" + proxyStats.conf.remote_port |
||||||
|
this.port = proxyStats.conf.remote_port |
||||||
|
} else { |
||||||
|
this.addr = "" |
||||||
|
this.port = "" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class UdpProxy extends BaseProxy { |
||||||
|
constructor(proxyStats) { |
||||||
|
super(proxyStats) |
||||||
|
this.type = "udp" |
||||||
|
if (proxyStats.conf != null) { |
||||||
|
this.addr = proxyStats.conf.bind_addr + ":" + proxyStats.conf.remote_port |
||||||
|
this.port = proxyStats.conf.remote_port |
||||||
|
} else { |
||||||
|
this.addr = "" |
||||||
|
this.port = "" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class HttpProxy extends BaseProxy { |
||||||
|
constructor(proxyStats, port, subdomain_host) { |
||||||
|
super(proxyStats) |
||||||
|
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 |
||||||
|
} else { |
||||||
|
this.subdomain = "" |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.custom_domains = "" |
||||||
|
this.host_header_rewrite = "" |
||||||
|
this.subdomain = "" |
||||||
|
this.locations = "" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class HttpsProxy extends BaseProxy { |
||||||
|
constructor(proxyStats, port, subdomain_host) { |
||||||
|
super(proxyStats) |
||||||
|
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 |
||||||
|
} else { |
||||||
|
this.subdomain = "" |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.custom_domains = "" |
||||||
|
this.subdomain = "" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export {BaseProxy, TcpProxy, UdpProxy, HttpProxy, HttpsProxy} |
@ -0,0 +1,2 @@ |
|||||||
|
import Vue from 'vue' |
||||||
|
import ElementUI from 'element-ui' |
@ -0,0 +1,93 @@ |
|||||||
|
const path = require('path') |
||||||
|
var webpack = require('webpack') |
||||||
|
var HtmlWebpackPlugin = require('html-webpack-plugin') |
||||||
|
var url = require('url') |
||||||
|
var publicPath = '' |
||||||
|
|
||||||
|
module.exports = (options = {}) => ({ |
||||||
|
entry: { |
||||||
|
vendor: './src/vendor', |
||||||
|
index: './src/main.js' |
||||||
|
}, |
||||||
|
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$/, |
||||||
|
use: ['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' |
||||||
|
}) |
||||||
|
], |
||||||
|
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'
|
||||||
|
}) |
Loading…
Reference in new issue