Browse Source

web/frpc: upgrade vue and element-plus (#3322)

fatedier 2 years ago
parent
commit
fe8374e99b

BIN
assets/frpc/static/535877f50039c0cb49a6196a5b7517cd.woff


BIN
assets/frpc/static/732389ded34cb9c52dd88271f1345af9.ttf


File diff suppressed because it is too large
+ 0 - 0
assets/frpc/static/index-26827c97.css


File diff suppressed because it is too large
+ 0 - 0
assets/frpc/static/index-fec891f3.js


+ 16 - 1
assets/frpc/static/index.html

@@ -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>

+ 0 - 1
assets/frpc/static/manifest.js

@@ -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 it is too large
+ 0 - 0
assets/frpc/static/vendor.js


+ 0 - 14
web/frpc/.babelrc

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

+ 30 - 0
web/frpc/.eslintrc.cjs

@@ -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"],
+      },
+    ],
+  },
+};

+ 26 - 4
web/frpc/.gitignore

@@ -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 - 0
web/frpc/.prettierrc.json

@@ -0,0 +1 @@
+{}

+ 9 - 2
web/frpc/Makefile

@@ -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 - 0
web/frpc/README.md

@@ -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 - 0
web/frpc/auto-imports.d.ts

@@ -0,0 +1,8 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// Generated by unplugin-auto-import
+export {}
+declare global {
+
+}

+ 25 - 0
web/frpc/components.d.ts

@@ -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 - 0
web/frpc/env.d.ts

@@ -0,0 +1 @@
+/// <reference types="vite/client" />

+ 1 - 2
web/frpc/src/index.html → web/frpc/index.html

@@ -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>

+ 26 - 37
web/frpc/package.json

@@ -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"
   }
 }

+ 0 - 5
web/frpc/postcss.config.js

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

+ 0 - 0
web/frpc/src/assets/favicon.ico → web/frpc/public/favicon.ico


+ 67 - 65
web/frpc/src/App.vue

@@ -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 - 0
web/frpc/src/components/ClientConfigure.vue

@@ -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>

+ 0 - 93
web/frpc/src/components/Configure.vue

@@ -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>

+ 86 - 70
web/frpc/src/components/Overview.vue

@@ -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>

+ 0 - 52
web/frpc/src/main.js

@@ -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 - 0
web/frpc/src/main.ts

@@ -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");

+ 0 - 18
web/frpc/src/router/index.js

@@ -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 - 0
web/frpc/src/router/index.ts

@@ -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;

+ 0 - 22
web/frpc/src/utils/less/custom.less

@@ -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%;
-    }
-}

+ 0 - 13
web/frpc/src/utils/status.js

@@ -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 - 0
web/frpc/tsconfig.config.json

@@ -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 - 0
web/frpc/tsconfig.json

@@ -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 - 0
web/frpc/vite.config.ts

@@ -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: "",
+  },
+});

+ 0 - 107
web/frpc/webpack.config.js

@@ -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'
-})

File diff suppressed because it is too large
+ 2183 - 4645
web/frpc/yarn.lock


+ 4 - 25
web/frps/README.md

@@ -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
 ```

Some files were not shown because too many files changed in this diff