完成vue的切换
parent
4cb6e54aed
commit
633ae92a71
|
@ -12,6 +12,8 @@
|
||||||
"name": "yutent",
|
"name": "yutent",
|
||||||
"email": "yutent.io@gmail.com"
|
"email": "yutent.io@gmail.com"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {
|
||||||
|
"@bytedo/vue-live": "0.0.5"
|
||||||
|
},
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
}
|
}
|
||||||
|
|
15
src/app.vue
15
src/app.vue
|
@ -1,9 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<Sidebar></Sidebar>
|
<Sidebar />
|
||||||
<h1>hello vue-live!</h1>
|
<router-view />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import fetch from '@/lib/fetch'
|
||||||
|
|
||||||
import Sidebar from './components/sidebar.vue'
|
import Sidebar from './components/sidebar.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -13,7 +15,14 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
console.log(this.$store)
|
this.getVersion()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getVersion() {
|
||||||
|
fetch('/version').then(r => {
|
||||||
|
this.$store.version = r.version
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
<nav class="nav-list">
|
<nav class="nav-list">
|
||||||
<a
|
<a
|
||||||
class="item"
|
class="item"
|
||||||
v-for="(it, i) in navs"
|
v-for="it in navs"
|
||||||
:class="{ active: i === tab }"
|
:key="it.path"
|
||||||
@click="changeTab(i)"
|
:class="{ active: it.path === tab }"
|
||||||
:text="it"
|
@click="changeTab(it)"
|
||||||
|
:text="it.title"
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -22,14 +23,21 @@
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
navs: ['代理', '规则', '连接', '订阅', '设置'],
|
navs: [
|
||||||
tab: +localStorage.getItem('tab') || 0
|
{ title: '代理', path: '/proxies' },
|
||||||
|
{ title: '规则', path: '/rules' },
|
||||||
|
{ title: '连接', path: '/connects' },
|
||||||
|
{ title: '订阅', path: '/remote' },
|
||||||
|
{ title: '设置', path: '/config' }
|
||||||
|
],
|
||||||
|
tab: localStorage.getItem('tab') || '/proxies'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
changeTab(idx) {
|
changeTab(it) {
|
||||||
this.tab = idx
|
this.tab = it.path
|
||||||
localStorage.setItem('tab', idx)
|
localStorage.setItem('tab', it.path)
|
||||||
|
this.$router.push(it.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
.tab-content{flex:1;flex-shrink:0;display:flex;flex-direction:column;height:540px;padding:16px}.tab-content .field{display:flex;align-items:center;width:100%;height:36px;margin-top:12px}.tab-content .field .label{width:128px;font-weight:bold;color:var(--color-grey-3)}.tab-content .field .full{flex:1}.tab-content.configs{width:49%;margin-left:1%}.tab-content.remote wc-button,.tab-content.rules wc-button{width:64px;min-width:64px;margin-left:16px}.tab-content.remote .scroll,.tab-content.rules .scroll{overflow:hidden;flex:1;margin-top:24px}.tab-content.remote .card,.tab-content.rules .card{margin:0 auto}.tab-content.remote .list,.tab-content.rules .list{word-break:break-all}.tab-content.remote .list .item,.tab-content.rules .list .item{display:flex;align-items:center;justify-content:space-between;height:36px;padding:0 16px;border-bottom:1px solid var(--color-plain-1);font-family:Menlo,"Courier New",Courier,monospace;transition:background .2s linear}.tab-content.remote .list .item:hover,.tab-content.rules .list .item:hover{background-color:var(--color-plain-1)}.tab-content.remote .list span.type,.tab-content.rules .list span.type{padding:2px 3px;border-radius:2px;background-color:var(--color-blue-1);color:#fff}.card{flex:1;flex-shrink:0;display:flex;flex-direction:column;flex-wrap:wrap;width:100%;max-height:100%;padding:12px;margin:0 auto 24px;border:0;border-radius:4px;background-color:#fff;box-shadow:0 0 8px rgba(0,0,0,.075)}.card legend{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;color:var(--color-blue-1);font-weight:bold}
|
|
|
@ -29,97 +29,9 @@
|
||||||
<span class="version">{{version}}</span>
|
<span class="version">{{version}}</span>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main class="tab-content" :if="tab === 0"></main>
|
|
||||||
|
|
||||||
<main class="tab-content rules" :if="tab === 1">
|
|
||||||
<fieldset class="card">
|
|
||||||
<legend>规则列表</legend>
|
|
||||||
|
|
||||||
<wc-scroll class="scroll">
|
|
||||||
<ul class="list">
|
|
||||||
<li class="item" :for="i it in rules">
|
|
||||||
<span>{{it.type}}</span>
|
|
||||||
<span>{{it.payload}}</span>
|
|
||||||
<span class="type">{{it.proxy}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</wc-scroll>
|
|
||||||
</fieldset>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<main class="tab-content" :if="tab === 2"></main>
|
|
||||||
|
|
||||||
<main class="tab-content remote" :if="tab === 3">
|
|
||||||
<fieldset class="card">
|
|
||||||
<legend>订阅配置</legend>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">订阅地址</span>
|
|
||||||
<wc-input class="full" :duplex="remote.link"></wc-input>
|
|
||||||
<wc-button type="info" :disabled="!remote.link" @click="updateRemote">更新</wc-button>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<wc-scroll class="scroll">
|
|
||||||
<ul class="list">
|
|
||||||
<li class="item" :for="i it in remote.list">
|
|
||||||
{{i + 1}}.
|
|
||||||
<span>{{it[0]}}</span>
|
|
||||||
<span class="type">{{it[1]}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</wc-scroll>
|
|
||||||
</fieldset>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<main class="tab-content configs" :if="tab === 4">
|
|
||||||
<fieldset class="card">
|
|
||||||
<legend>系统设置</legend>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">开机启动Clash</span>
|
|
||||||
<wc-switch disabled></wc-switch>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">设置为系统代理</span>
|
|
||||||
<wc-switch disabled></wc-switch>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">允许局域网的连接</span>
|
|
||||||
<wc-switch :duplex="configs.allowLan"></wc-switch>
|
|
||||||
</section>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset class="card">
|
|
||||||
<legend>Clash设置</legend>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">代理模式</span>
|
|
||||||
<wc-radio-group :duplex="configs.proxy">
|
|
||||||
<wc-radio value="global">全局</wc-radio>
|
|
||||||
<wc-radio value="rule">规则</wc-radio>
|
|
||||||
<wc-radio value="direct">直连</wc-radio>
|
|
||||||
</wc-radio-group>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">Socks5 代理端口</span>
|
|
||||||
<wc-input size="small" :duplex="configs.socks5"></wc-input>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">HTTP 代理端口</span>
|
|
||||||
<wc-input size="small" :duplex="configs.http"></wc-input>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="field">
|
|
||||||
<span class="label">混合代理端口</span>
|
|
||||||
<wc-input size="small" :duplex="configs.mixed"></wc-input>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</fieldset>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
168
src/js/app.js
168
src/js/app.js
|
@ -1,168 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author yutent<yutent.io@gmail.com>
|
|
||||||
* @date 2022/05/16 00:38:48
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Anot from '//unpkg.yutent.top/anot/dist/anot.js'
|
|
||||||
import fetch from '//unpkg.yutent.top/@bytedo/fetch/dist/index.js'
|
|
||||||
import '//unpkg.yutent.top/@bytedo/wcui/dist/layer/index.js'
|
|
||||||
import '//unpkg.yutent.top/@bytedo/wcui/dist/form/switch.js'
|
|
||||||
import '//unpkg.yutent.top/@bytedo/wcui/dist/form/radio.js'
|
|
||||||
import '//unpkg.yutent.top/@bytedo/wcui/dist/form/button.js'
|
|
||||||
|
|
||||||
fetch.inject.response(r => r.json())
|
|
||||||
|
|
||||||
Anot({
|
|
||||||
$id: 'app',
|
|
||||||
|
|
||||||
state: {
|
|
||||||
version: '1.10.0',
|
|
||||||
navs: ['代理', '规则', '连接', '订阅', '设置'],
|
|
||||||
tab: +Anot.ls('tab') || 0,
|
|
||||||
contrl: {
|
|
||||||
host: '//127.0.0.1:',
|
|
||||||
port: 6767,
|
|
||||||
key: ''
|
|
||||||
},
|
|
||||||
rules: [],
|
|
||||||
remote: {
|
|
||||||
link: Anot.ls('remote_link') || '',
|
|
||||||
list: []
|
|
||||||
},
|
|
||||||
configs: {
|
|
||||||
proxy: 'rule',
|
|
||||||
http: 0,
|
|
||||||
socks5: 0,
|
|
||||||
mixed: 7890,
|
|
||||||
allowLan: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
if (this.contrl.port) {
|
|
||||||
fetch.BASE_URL = this.contrl.host + this.contrl.port
|
|
||||||
} else {
|
|
||||||
return layer
|
|
||||||
.prompt('请输入Clash本地管理端口', (v, done) => {
|
|
||||||
let n = +v.trim()
|
|
||||||
if (n === n) {
|
|
||||||
done()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(v => {
|
|
||||||
Anot.ls('web_port', v)
|
|
||||||
location.reload()
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
location.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.getVersion()
|
|
||||||
this.getConfig()
|
|
||||||
this.getRule()
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
getVersion() {
|
|
||||||
fetch('/version').then(r => {
|
|
||||||
this.version = r.version
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
getConfig() {
|
|
||||||
fetch('/configs').then(r => {
|
|
||||||
console.log(r)
|
|
||||||
Object.assign(this.configs, {
|
|
||||||
proxy: r.mode,
|
|
||||||
http: r.port,
|
|
||||||
socks5: r['socks-port'],
|
|
||||||
mixed: r['mixed-port'],
|
|
||||||
allowLan: r['allow-lan']
|
|
||||||
})
|
|
||||||
// this.version = r.version
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
getRule() {
|
|
||||||
fetch('/rules').then(r => {
|
|
||||||
console.log(r)
|
|
||||||
this.rules = r.rules
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
updateRemote() {
|
|
||||||
if (this.remote.link) {
|
|
||||||
if (!/^(https?:)?\/\//.test(this.remote.link)) {
|
|
||||||
return layer.toast('订阅地址格式不正确', 'error')
|
|
||||||
}
|
|
||||||
Anot.ls('remote_link', this.remote.link)
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let txt = ''
|
|
||||||
let names = ['DIRECT']
|
|
||||||
let r = (Anot.ss('temp') || '').trim()
|
|
||||||
|
|
||||||
this.remote.list = r.split('\n').map(it => {
|
|
||||||
let tmp = decodeURIComponent(it).split('#')
|
|
||||||
let tmp2 = new URL(tmp[0])
|
|
||||||
let protocol = tmp2.protocol.slice(0, -1)
|
|
||||||
let path = tmp2.pathname.slice(2)
|
|
||||||
let info = { name: tmp.pop(), type: protocol, udp: true }
|
|
||||||
|
|
||||||
path = path.split(':')
|
|
||||||
|
|
||||||
info.port = path.pop()
|
|
||||||
|
|
||||||
path = path[0].split('@')
|
|
||||||
info.server = path.pop()
|
|
||||||
|
|
||||||
switch (protocol) {
|
|
||||||
case 'ss':
|
|
||||||
path = atob(path[0]).split(':')
|
|
||||||
console.log(path)
|
|
||||||
Object.assign(info, {
|
|
||||||
cipher: path[0],
|
|
||||||
password: path[1]
|
|
||||||
})
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'trojan':
|
|
||||||
Object.assign(info, {
|
|
||||||
password: path[0],
|
|
||||||
sni: tmp2.searchParams.get('sni'),
|
|
||||||
'skip-cert-verify': true
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
names.push(info.name)
|
|
||||||
txt += ` - { name: ${info.name}, type: ${info.type}, server: ${info.server}, port: ${
|
|
||||||
info.port
|
|
||||||
}, password: ${info.password}, udp: true, ${info.type === 'ss' ? 'cipher' : 'sni'}: ${
|
|
||||||
info.type === 'ss' ? info.cipher : info.sni
|
|
||||||
}}\n`
|
|
||||||
return [info.name, info.type]
|
|
||||||
})
|
|
||||||
|
|
||||||
// window.foo = txt
|
|
||||||
// window.bar = names.join(', ')
|
|
||||||
// // console.log(txt)
|
|
||||||
|
|
||||||
return
|
|
||||||
window
|
|
||||||
.fetch(this.remote.link, { cors: true })
|
|
||||||
.then(r => r.text())
|
|
||||||
.then(r => {
|
|
||||||
r = atob(r).trim()
|
|
||||||
Anot.ss('temp', r)
|
|
||||||
layer.toast('订阅更新成功', 'success')
|
|
||||||
this.remote.list = r.split('\n').map(it => {
|
|
||||||
let tmp = decodeURIComponent(it).split('#')
|
|
||||||
return [tmp.pop(), tmp[0]?.split('://').shift()]
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import fetch from 'fetch'
|
||||||
|
|
||||||
|
fetch.BASE_URL = '//127.0.0.1:6767'
|
||||||
|
|
||||||
|
fetch.inject.response(function (r) {
|
||||||
|
return r.json()
|
||||||
|
})
|
||||||
|
|
||||||
|
export default fetch
|
|
@ -6,6 +6,13 @@
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
|
||||||
|
import '@/assets/app.scss'
|
||||||
|
|
||||||
|
import '//unpkg.yutent.top/@bytedo/wcui/dist/layer/index.js'
|
||||||
|
import '//unpkg.yutent.top/@bytedo/wcui/dist/form/switch.js'
|
||||||
|
import '//unpkg.yutent.top/@bytedo/wcui/dist/form/radio.js'
|
||||||
|
import '//unpkg.yutent.top/@bytedo/wcui/dist/form/button.js'
|
||||||
|
|
||||||
import App from './app.vue'
|
import App from './app.vue'
|
||||||
|
|
||||||
import store from './store'
|
import store from './store'
|
||||||
|
|
|
@ -4,26 +4,42 @@
|
||||||
* @date 2022/10/09 18:09:20
|
* @date 2022/10/09 18:09:20
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
|
|
||||||
|
import Proxies from './views/proxies.vue'
|
||||||
|
import Rules from './views/rules.vue'
|
||||||
|
import Config from './views/config.vue'
|
||||||
|
import Connects from './views/connects.vue'
|
||||||
|
import Remote from './views/remote.vue'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHashHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
// {
|
{
|
||||||
// path: '/login',
|
path: '/proxies',
|
||||||
// name: 'login',
|
name: 'proxies',
|
||||||
// component: Login
|
component: Proxies
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// path: '/',
|
path: '/rules',
|
||||||
// name: 'main',
|
name: 'rules',
|
||||||
// component: Main
|
component: Rules
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// path: '/room',
|
path: '/connects',
|
||||||
// name: 'room',
|
name: 'connects',
|
||||||
// component: Room
|
component: Connects
|
||||||
// }
|
},
|
||||||
|
{
|
||||||
|
path: '/remote',
|
||||||
|
name: 'remote',
|
||||||
|
component: Remote
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/config',
|
||||||
|
name: 'config',
|
||||||
|
component: Config
|
||||||
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
<template>
|
||||||
|
<main class="tab-content configs">
|
||||||
|
<fieldset class="card">
|
||||||
|
<legend>系统设置</legend>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">开机启动Clash</span>
|
||||||
|
<wc-switch disabled></wc-switch>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">设置为系统代理</span>
|
||||||
|
<wc-switch disabled></wc-switch>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">允许局域网的连接</span>
|
||||||
|
<wc-switch v-model="configs.allowLan"></wc-switch>
|
||||||
|
</section>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset class="card">
|
||||||
|
<legend>Clash设置</legend>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">代理模式</span>
|
||||||
|
<wc-radio-group v-model="configs.proxy">
|
||||||
|
<wc-radio value="global">全局</wc-radio>
|
||||||
|
<wc-radio value="rule">规则</wc-radio>
|
||||||
|
<wc-radio value="direct">直连</wc-radio>
|
||||||
|
</wc-radio-group>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">Socks5 代理端口</span>
|
||||||
|
<wc-input size="small" v-model="configs.socks5"></wc-input>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">HTTP 代理端口</span>
|
||||||
|
<wc-input size="small" v-model="configs.http"></wc-input>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">混合代理端口</span>
|
||||||
|
<wc-input size="small" v-model="configs.mixed"></wc-input>
|
||||||
|
</section>
|
||||||
|
</fieldset>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import fetch from '@/lib/fetch'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
contrl: {
|
||||||
|
host: '//127.0.0.1:',
|
||||||
|
port: 6767,
|
||||||
|
key: ''
|
||||||
|
},
|
||||||
|
configs: {
|
||||||
|
proxy: 'rule',
|
||||||
|
http: 0,
|
||||||
|
socks5: 0,
|
||||||
|
mixed: 7890,
|
||||||
|
allowLan: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.getConfig()
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getVersion() {
|
||||||
|
fetch('/version').then(r => {
|
||||||
|
console.log(r)
|
||||||
|
this.$store.version = r.version
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getConfig() {
|
||||||
|
fetch('/configs').then(r => {
|
||||||
|
console.log(r)
|
||||||
|
Object.assign(this.configs, {
|
||||||
|
proxy: r.mode,
|
||||||
|
http: r.port,
|
||||||
|
socks5: r['socks-port'],
|
||||||
|
mixed: r['mixed-port'],
|
||||||
|
allowLan: r['allow-lan']
|
||||||
|
})
|
||||||
|
// this.version = r.version
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<main class="tab-content"></main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<main class="tab-content"></main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,114 @@
|
||||||
|
<template>
|
||||||
|
<main class="tab-content remote">
|
||||||
|
<fieldset class="card">
|
||||||
|
<legend>订阅配置</legend>
|
||||||
|
|
||||||
|
<section class="field">
|
||||||
|
<span class="label">订阅地址</span>
|
||||||
|
<wc-input class="full" v-model="remote.link"></wc-input>
|
||||||
|
<wc-button type="info" :disabled="!remote.link" @click="updateRemote">更新</wc-button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<wc-scroll class="scroll">
|
||||||
|
<ul class="list">
|
||||||
|
<li class="item" v-for="(it, i) in remote.list">
|
||||||
|
{{ i + 1 }}.
|
||||||
|
<span>{{ it[0] }}</span>
|
||||||
|
<span class="type">{{ it[1] }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</wc-scroll>
|
||||||
|
</fieldset>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import fetch from '@/lib/fetch'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
remote: {
|
||||||
|
link: localStorage.getItem('remote_link') || '',
|
||||||
|
list: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
updateRemote() {
|
||||||
|
if (this.remote.link) {
|
||||||
|
if (!/^(https?:)?\/\//.test(this.remote.link)) {
|
||||||
|
return layer.toast('订阅地址格式不正确', 'error')
|
||||||
|
}
|
||||||
|
localStorage.setItem('remote_link', this.remote.link)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let txt = ''
|
||||||
|
let names = ['DIRECT']
|
||||||
|
let r = (sessionStorage.getItem('temp') || '').trim()
|
||||||
|
|
||||||
|
this.remote.list = r.split('\n').map(it => {
|
||||||
|
let tmp = decodeURIComponent(it).split('#')
|
||||||
|
let tmp2 = new URL(tmp[0])
|
||||||
|
let protocol = tmp2.protocol.slice(0, -1)
|
||||||
|
let path = tmp2.pathname.slice(2)
|
||||||
|
let info = { name: tmp.pop(), type: protocol, udp: true }
|
||||||
|
|
||||||
|
path = path.split(':')
|
||||||
|
|
||||||
|
info.port = path.pop()
|
||||||
|
|
||||||
|
path = path[0].split('@')
|
||||||
|
info.server = path.pop()
|
||||||
|
|
||||||
|
switch (protocol) {
|
||||||
|
case 'ss':
|
||||||
|
path = atob(path[0]).split(':')
|
||||||
|
console.log(path)
|
||||||
|
Object.assign(info, {
|
||||||
|
cipher: path[0],
|
||||||
|
password: path[1]
|
||||||
|
})
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'trojan':
|
||||||
|
Object.assign(info, {
|
||||||
|
password: path[0],
|
||||||
|
sni: tmp2.searchParams.get('sni'),
|
||||||
|
'skip-cert-verify': true
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
names.push(info.name)
|
||||||
|
txt += ` - { name: ${info.name}, type: ${info.type}, server: ${info.server}, port: ${
|
||||||
|
info.port
|
||||||
|
}, password: ${info.password}, udp: true, ${info.type === 'ss' ? 'cipher' : 'sni'}: ${
|
||||||
|
info.type === 'ss' ? info.cipher : info.sni
|
||||||
|
}}\n`
|
||||||
|
return [info.name, info.type]
|
||||||
|
})
|
||||||
|
|
||||||
|
window.foo = txt
|
||||||
|
window.bar = names.join(', ')
|
||||||
|
// // console.log(txt)
|
||||||
|
|
||||||
|
return
|
||||||
|
window
|
||||||
|
.fetch(this.remote.link, { cors: true })
|
||||||
|
.then(r => r.text())
|
||||||
|
.then(r => {
|
||||||
|
r = atob(r).trim()
|
||||||
|
sessionStorage.setItem('temp', r)
|
||||||
|
layer.toast('订阅更新成功', 'success')
|
||||||
|
this.remote.list = r.split('\n').map(it => {
|
||||||
|
let tmp = decodeURIComponent(it).split('#')
|
||||||
|
return [tmp.pop(), tmp[0]?.split('://').shift()]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<main class="tab-content rules">
|
||||||
|
<fieldset class="card">
|
||||||
|
<legend>规则列表</legend>
|
||||||
|
|
||||||
|
<wc-scroll class="scroll">
|
||||||
|
<ul class="list">
|
||||||
|
<li class="item" v-for="it in rules">
|
||||||
|
<span>{{ it.type }}</span>
|
||||||
|
<span>{{ it.payload }}</span>
|
||||||
|
<span class="type">{{ it.proxy }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</wc-scroll>
|
||||||
|
</fieldset>
|
||||||
|
</main>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import fetch from '@/lib/fetch'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
rules: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.getRule()
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getRule() {
|
||||||
|
fetch('/rules').then(r => {
|
||||||
|
console.log(r)
|
||||||
|
this.rules = r.rules
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue