mirror of
https://github.com/fatedier/frp.git
synced 2024-11-27 20:49:10 +08:00
web/frpc: upgrade vue and element-plus (#3322)
This commit is contained in:
parent
24f0b3afa5
commit
fe8374e99b
Binary file not shown.
Binary file not shown.
1
assets/frpc/static/index-26827c97.css
Normal file
1
assets/frpc/static/index-26827c97.css
Normal file
File diff suppressed because one or more lines are too long
32
assets/frpc/static/index-fec891f3.js
Normal file
32
assets/frpc/static/index-fec891f3.js
Normal file
File diff suppressed because one or more lines are too long
@ -1 +1,16 @@
|
||||
<!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?5d5774096cf5c1b4d5af"></script><script type="text/javascript" src="vendor.js?dc42700731a508d39009"></script></body> </html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>frp client admin UI</title>
|
||||
<script type="module" crossorigin src="./index-fec891f3.js"></script>
|
||||
<link rel="stylesheet" href="./index-26827c97.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -1 +0,0 @@
|
||||
!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:"dc42700731a508d39009"}[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
@ -1,14 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
["es2015", { "modules": false }]
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"component",
|
||||
{
|
||||
"libraryName": "element-ui",
|
||||
"styleLibraryName": "theme-chalk"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
30
web/frpc/.eslintrc.cjs
Normal file
30
web/frpc/.eslintrc.cjs
Normal file
@ -0,0 +1,30 @@
|
||||
/* eslint-env node */
|
||||
require("@rushstack/eslint-patch/modern-module-resolution");
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/eslint-config-typescript",
|
||||
"@vue/eslint-config-prettier",
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"vue/multi-word-component-names": [
|
||||
"error",
|
||||
{
|
||||
ignores: ["Overview"],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
30
web/frpc/.gitignore
vendored
30
web/frpc/.gitignore
vendored
@ -1,6 +1,28 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
node_modules/
|
||||
dist/
|
||||
npm-debug.log
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.vscode/settings.json
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
1
web/frpc/.prettierrc.json
Normal file
1
web/frpc/.prettierrc.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -1,6 +1,13 @@
|
||||
.PHONY: dist build
|
||||
.PHONY: dist build preview lint
|
||||
|
||||
build:
|
||||
@npm run build
|
||||
|
||||
dev:
|
||||
dev:
|
||||
@npm run dev
|
||||
|
||||
preview:
|
||||
@npm run preview
|
||||
|
||||
lint:
|
||||
@npm run lint
|
||||
|
25
web/frpc/README.md
Normal file
25
web/frpc/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
# frpc-dashboard
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
make dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
make build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
make lint
|
||||
```
|
8
web/frpc/auto-imports.d.ts
vendored
Normal file
8
web/frpc/auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
|
||||
}
|
25
web/frpc/components.d.ts
vendored
Normal file
25
web/frpc/components.d.ts
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import '@vue/runtime-core'
|
||||
|
||||
export {}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
ClientConfigure: typeof import('./src/components/ClientConfigure.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
Overview: typeof import('./src/components/Overview.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
}
|
1
web/frpc/env.d.ts
vendored
Normal file
1
web/frpc/env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
@ -8,8 +8,7 @@
|
||||
|
||||
<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>-->
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,46 +1,35 @@
|
||||
{
|
||||
"name": "frpc-web",
|
||||
"description": "An admin web ui for frp client.",
|
||||
"author": "fatedier",
|
||||
"name": "-frpc-dashboard",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server -d --inline --hot --env.dev",
|
||||
"build": "rimraf dist && webpack -p --progress --hide-modules"
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check build-only",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"element-ui": "^2.5.3",
|
||||
"vue": "^2.5.22",
|
||||
"vue-resource": "^1.5.1",
|
||||
"vue-router": "^3.0.2",
|
||||
"whatwg-fetch": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
"element-plus": "^2.2.28",
|
||||
"vue": "^3.2.45",
|
||||
"vue-router": "^4.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^9.4.7",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-plugin-component": "^1.1.1",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"css-loader": "^2.1.0",
|
||||
"eslint": "^5.12.1",
|
||||
"eslint-config-enough": "^0.3.4",
|
||||
"eslint-loader": "^2.1.1",
|
||||
"file-loader": "^3.0.1",
|
||||
"html-loader": "^0.5.5",
|
||||
"html-webpack-plugin": "^2.24.1",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^4.1.0",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"rimraf": "^2.6.3",
|
||||
"style-loader": "^0.23.1",
|
||||
"url-loader": "^1.1.2",
|
||||
"vue-loader": "^15.6.2",
|
||||
"vue-template-compiler": "^2.5.22",
|
||||
"webpack": "^2.7.0",
|
||||
"webpack-cli": "^3.2.1",
|
||||
"webpack-dev-server": "^3.1.14"
|
||||
"@rushstack/eslint-patch": "^1.1.4",
|
||||
"@types/node": "^18.11.12",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.0",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-plugin-vue": "^9.3.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "~4.7.4",
|
||||
"unplugin-auto-import": "^0.14.3",
|
||||
"unplugin-vue-components": "^0.24.0",
|
||||
"vite": "^4.0.0",
|
||||
"vue-tsc": "^1.0.12"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('autoprefixer')()
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
@ -1,73 +1,75 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<header class="grid-content header-color">
|
||||
<el-row>
|
||||
<a class="brand" href="#">frp client</a>
|
||||
</el-row>
|
||||
</header>
|
||||
<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-item index="/">Overview</el-menu-item>
|
||||
<el-menu-item index="/configure">Configure</el-menu-item>
|
||||
<el-menu-item index="">Help</el-menu-item>
|
||||
</el-menu>
|
||||
</el-col>
|
||||
<div id="app">
|
||||
<header class="grid-content header-color">
|
||||
<el-row>
|
||||
<a class="brand" href="#">frp client</a>
|
||||
</el-row>
|
||||
</header>
|
||||
<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-item index="/">Overview</el-menu-item>
|
||||
<el-menu-item index="/configure">Configure</el-menu-item>
|
||||
<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>
|
||||
<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("https://github.com/fatedier/frp")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<script setup lang="ts">
|
||||
const handleSelect = (key: string) => {
|
||||
if (key == "") {
|
||||
window.open("https://github.com/fatedier/frp");
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #fafafa;
|
||||
margin: 0px;
|
||||
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;
|
||||
}
|
||||
body {
|
||||
background-color: #fafafa;
|
||||
margin: 0px;
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
|
102
web/frpc/src/components/ClientConfigure.vue
Normal file
102
web/frpc/src/components/ClientConfigure.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row id="head">
|
||||
<el-button type="primary" @click="fetchData">Refresh</el-button>
|
||||
<el-button type="primary" @click="uploadConfig">Upload</el-button>
|
||||
</el-row>
|
||||
<el-input
|
||||
type="textarea"
|
||||
autosize
|
||||
v-model="textarea"
|
||||
placeholder="frpc configrue file, can not be empty..."
|
||||
></el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
|
||||
let textarea = ref("");
|
||||
|
||||
const fetchData = () => {
|
||||
fetch("/api/config", { credentials: "include" })
|
||||
.then((res) => {
|
||||
return res.text();
|
||||
})
|
||||
.then((text) => {
|
||||
textarea.value = text;
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
showClose: true,
|
||||
message: "Get configure content from frpc failed!",
|
||||
type: "warning",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const uploadConfig = () => {
|
||||
ElMessageBox.confirm(
|
||||
"This operation will upload your frpc configure file content and hot reload it, do you want to continue?",
|
||||
"Notice",
|
||||
{
|
||||
confirmButtonText: "Yes",
|
||||
cancelButtonText: "No",
|
||||
type: "warning",
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
if (textarea.value == "") {
|
||||
ElMessage({
|
||||
message: "Configure content can not be empty!",
|
||||
type: "warning",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fetch("/api/config", {
|
||||
credentials: "include",
|
||||
method: "PUT",
|
||||
body: textarea.value,
|
||||
})
|
||||
.then(() => {
|
||||
fetch("/api/reload", { credentials: "include" })
|
||||
.then(() => {
|
||||
ElMessage({
|
||||
type: "success",
|
||||
message: "Success",
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage({
|
||||
showClose: true,
|
||||
message: "Reload frpc configure file error, " + err,
|
||||
type: "warning",
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
showClose: true,
|
||||
message: "Put config to frpc and hot reload failed!",
|
||||
type: "warning",
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
message: "Canceled",
|
||||
type: "info",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
fetchData();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#head {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
</style>
|
@ -1,93 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row id="head">
|
||||
<el-button type="primary" @click="fetchData">Refresh</el-button>
|
||||
<el-button type="primary" @click="uploadConfig">Upload</el-button>
|
||||
</el-row>
|
||||
<el-input type="textarea" autosize v-model="textarea" placeholder="frpc configrue file, can not be empty..."></el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
textarea: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
'$route': 'fetchData'
|
||||
},
|
||||
methods: {
|
||||
fetchData() {
|
||||
fetch('/api/config', {credentials: 'include'})
|
||||
.then(res => {
|
||||
return res.text()
|
||||
}).then(text => {
|
||||
this.textarea= text
|
||||
}).catch( err => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'Get configure content from frpc failed!',
|
||||
type: 'warning'
|
||||
})
|
||||
})
|
||||
},
|
||||
uploadConfig() {
|
||||
this.$confirm('This operation will upload your frpc configure file content and hot reload it, do you want to continue?', 'Notice', {
|
||||
confirmButtonText: 'Yes',
|
||||
cancelButtonText: 'No',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (this.textarea == "") {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: 'Configure content can not be empty!'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
fetch('/api/config', {
|
||||
credentials: 'include',
|
||||
method: 'PUT',
|
||||
body: this.textarea,
|
||||
}).then(() => {
|
||||
fetch('/api/reload', {credentials: 'include'})
|
||||
.then(() => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: 'Success'
|
||||
})
|
||||
}).catch(err => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'Reload frpc configure file error, ' + err,
|
||||
type: 'warning'
|
||||
})
|
||||
})
|
||||
}).catch(err => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'Put config to frpc and hot reload failed!',
|
||||
type: 'warning'
|
||||
})
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: 'Canceled'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#head {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
</style>
|
@ -1,75 +1,91 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :md="24">
|
||||
<div>
|
||||
<el-table :data="status" stripe style="width: 100%" :default-sort="{prop: 'type', order: 'ascending'}">
|
||||
<el-table-column prop="name" label="name"></el-table-column>
|
||||
<el-table-column prop="type" label="type" width="150"></el-table-column>
|
||||
<el-table-column prop="local_addr" label="local address" width="200"></el-table-column>
|
||||
<el-table-column prop="plugin" label="plugin" width="200"></el-table-column>
|
||||
<el-table-column prop="remote_addr" label="remote address"></el-table-column>
|
||||
<el-table-column prop="status" label="status" width="150"></el-table-column>
|
||||
<el-table-column prop="err" label="info"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :md="24">
|
||||
<div>
|
||||
<el-table
|
||||
:data="status"
|
||||
stripe
|
||||
style="width: 100%"
|
||||
:default-sort="{ prop: 'type', order: 'ascending' }"
|
||||
>
|
||||
<el-table-column prop="name" label="name"></el-table-column>
|
||||
<el-table-column
|
||||
prop="type"
|
||||
label="type"
|
||||
width="150"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="local_addr"
|
||||
label="local address"
|
||||
width="200"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="plugin"
|
||||
label="plugin"
|
||||
width="200"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="remote_addr"
|
||||
label="remote address"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="status"
|
||||
label="status"
|
||||
width="150"
|
||||
></el-table-column>
|
||||
<el-table-column prop="err" label="info"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
status: new Array(),
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
'$route': 'fetchData'
|
||||
},
|
||||
methods: {
|
||||
fetchData() {
|
||||
fetch('/api/status', {credentials: 'include'})
|
||||
.then(res => {
|
||||
return res.json()
|
||||
}).then(json => {
|
||||
this.status = new Array()
|
||||
for (let s of json.tcp) {
|
||||
this.status.push(s)
|
||||
}
|
||||
for (let s of json.udp) {
|
||||
this.status.push(s)
|
||||
}
|
||||
for (let s of json.http) {
|
||||
this.status.push(s)
|
||||
}
|
||||
for (let s of json.https) {
|
||||
this.status.push(s)
|
||||
}
|
||||
for (let s of json.stcp) {
|
||||
this.status.push(s)
|
||||
}
|
||||
for (let s of json.sudp) {
|
||||
this.status.push(s)
|
||||
}
|
||||
for (let s of json.xtcp) {
|
||||
this.status.push(s)
|
||||
}
|
||||
}).catch( err => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: 'Get status info from frpc failed!',
|
||||
type: 'warning'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
let status = ref<any[]>([]);
|
||||
|
||||
const fetchData = () => {
|
||||
fetch("/api/status", { credentials: "include" })
|
||||
.then((res) => {
|
||||
return res.json();
|
||||
})
|
||||
.then((json) => {
|
||||
status.value = new Array();
|
||||
for (let s of json.tcp) {
|
||||
status.value.push(s);
|
||||
}
|
||||
for (let s of json.udp) {
|
||||
status.value.push(s);
|
||||
}
|
||||
for (let s of json.http) {
|
||||
status.value.push(s);
|
||||
}
|
||||
for (let s of json.https) {
|
||||
status.value.push(s);
|
||||
}
|
||||
for (let s of json.stcp) {
|
||||
status.value.push(s);
|
||||
}
|
||||
for (let s of json.sudp) {
|
||||
status.value.push(s);
|
||||
}
|
||||
for (let s of json.xtcp) {
|
||||
status.value.push(s);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
showClose: true,
|
||||
message: "Get status info from frpc failed!",
|
||||
type: "warning",
|
||||
});
|
||||
});
|
||||
};
|
||||
fetchData();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
<style></style>
|
||||
|
@ -1,52 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
// import ElementUI from 'element-ui'
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
FormItem,
|
||||
Row,
|
||||
Col,
|
||||
Table,
|
||||
TableColumn,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MessageBox,
|
||||
Message,
|
||||
Input
|
||||
} 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'
|
||||
import './utils/less/custom.less'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import 'whatwg-fetch'
|
||||
|
||||
locale.use(lang)
|
||||
|
||||
Vue.use(Button)
|
||||
Vue.use(Form)
|
||||
Vue.use(FormItem)
|
||||
Vue.use(Row)
|
||||
Vue.use(Col)
|
||||
Vue.use(Table)
|
||||
Vue.use(TableColumn)
|
||||
Vue.use(Menu)
|
||||
Vue.use(MenuItem)
|
||||
Vue.use(Input)
|
||||
|
||||
Vue.prototype.$msgbox = MessageBox;
|
||||
Vue.prototype.$confirm = MessageBox.confirm
|
||||
Vue.prototype.$message = Message
|
||||
|
||||
//Vue.use(ElementUI)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
template: '<App/>',
|
||||
components: { App }
|
||||
})
|
12
web/frpc/src/main.ts
Normal file
12
web/frpc/src/main.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { createApp } from "vue";
|
||||
import "element-plus/dist/index.css";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
|
||||
// import './assets/custom.css'
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
app.use(router);
|
||||
|
||||
app.mount("#app");
|
@ -1,18 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import Overview from '../components/Overview.vue'
|
||||
import Configure from '../components/Configure.vue'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export default new Router({
|
||||
routes: [{
|
||||
path: '/',
|
||||
name: 'Overview',
|
||||
component: Overview
|
||||
},{
|
||||
path: '/configure',
|
||||
name: 'Configure',
|
||||
component: Configure,
|
||||
}]
|
||||
})
|
21
web/frpc/src/router/index.ts
Normal file
21
web/frpc/src/router/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { createRouter, createWebHashHistory } from "vue-router";
|
||||
import Overview from "../components/Overview.vue";
|
||||
import ClientConfigure from "../components/ClientConfigure.vue";
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
name: "Overview",
|
||||
component: Overview,
|
||||
},
|
||||
{
|
||||
path: "/configure",
|
||||
name: "ClientConfigure",
|
||||
component: ClientConfigure,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export default router;
|
@ -1,22 +0,0 @@
|
||||
@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%;
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
class ProxyStatus {
|
||||
constructor(status) {
|
||||
this.name = status.name
|
||||
this.type = status.type
|
||||
this.status = status.status
|
||||
this.err = status.err
|
||||
this.local_addr = status.local_addr
|
||||
this.plugin = status.plugin
|
||||
this.remote_addr = status.remote_addr
|
||||
}
|
||||
}
|
||||
|
||||
export {ProxyStatus}
|
8
web/frpc/tsconfig.config.json
Normal file
8
web/frpc/tsconfig.config.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.node.json",
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
16
web/frpc/tsconfig.json
Normal file
16
web/frpc/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.web.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.config.json"
|
||||
}
|
||||
]
|
||||
}
|
29
web/frpc/vite.config.ts
Normal file
29
web/frpc/vite.config.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import AutoImport from "unplugin-auto-import/vite";
|
||||
import Components from "unplugin-vue-components/vite";
|
||||
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: "",
|
||||
plugins: [
|
||||
vue(),
|
||||
AutoImport({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
}),
|
||||
Components({
|
||||
resolvers: [ElementPlusResolver()],
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
assetsDir: "",
|
||||
},
|
||||
});
|
@ -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'
|
||||
})
|
7633
web/frpc/yarn.lock
7633
web/frpc/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -1,46 +1,25 @@
|
||||
# frps-dashboard
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||
|
||||
1. Disable the built-in TypeScript Extension
|
||||
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
make dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
make build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
make lint
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user