完成批量化 的支持

This commit is contained in:
lingling 2023-03-20 16:49:07 +08:00
parent 1880a8a135
commit 1f979b9b85
12 changed files with 294 additions and 41 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ node_modules
# Quasar core related directories # Quasar core related directories
.quasar .quasar
/dist /dist
/public/res
# Cordova related directories and files # Cordova related directories and files
/src-cordova/node_modules /src-cordova/node_modules

BIN
public/img/clash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
public/img/v2ray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
public/img/v2rayNG.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -4,10 +4,10 @@
<h6 style="text-align: center;margin: 1rem;">{{ props.serve.tips }} <q-icon v-show="online" title="在线" <h6 style="text-align: center;margin: 1rem;">{{ props.serve.tips }} <q-icon v-show="online" title="在线"
name="check_circle_outline" style="color: green;" /> <q-icon v-show="!online" title="离线" name="highlight_off" name="check_circle_outline" style="color: green;" /> <q-icon v-show="!online" title="离线" name="highlight_off"
style="color: red;" /></h6> style="color: red;" /></h6>
<q-input v-model="outtext" filled autogrow /> <q-input v-model="outtext" filled autogrow readonly />
<div style="text-align: center;margin-top: 1rem;display: flex;justify-content: space-around;"> <div style="text-align: center;margin-top: 1rem;display: flex;justify-content: space-around;">
<q-btn color="white" text-color="black" @click="copy('link')" label="复制" /> <q-btn color="white" text-color="black" @click="copy('link')" label="复制" />
<q-btn color="white" text-color="black" @click="copy('sub')" label="复制订阅" /> <!-- <q-btn color="white" text-color="black" @click="copy('sub')" label="复制订阅" /> -->
</div> </div>
</div> </div>
</div> </div>
@ -36,12 +36,8 @@ export default defineComponent({
}, },
setup(props) { setup(props) {
const online = ref(false); const online = ref(false);
const isonline = () => { const isonline = (ip: string) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let obj = JSON.parse(decode(props.text!.replace('vmess://', '')));
let http = props.serve.istls == 0 ? 'http' : 'https' let http = props.serve.istls == 0 ? 'http' : 'https'
let reg = new RegExp(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/);
let ip = obj.ps.match(reg)[0];
api.text_server(`${http}://${props.serve.ip}:${props.serve.port}/${ip}`).then(res => { api.text_server(`${http}://${props.serve.ip}:${props.serve.port}/${ip}`).then(res => {
online.value = res.data.sataus == 400 online.value = res.data.sataus == 400
}) })
@ -49,18 +45,29 @@ export default defineComponent({
const api = new getdata; const api = new getdata;
const $q = useQuasar() const $q = useQuasar()
const outtext = computed(() => { const outtext = computed(() => {
let tmp = ''
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let text = props.text!.replace(/\ +/g, '');
text = text.replace(/[\r\n]/g, '');
let arr = text.split('vmess://');
for (let iterator of arr) {
if (!(iterator.length > 0)) continue
// eslint-disable-next-line vue/no-side-effects-in-computed-properties // eslint-disable-next-line vue/no-side-effects-in-computed-properties
online.value = false online.value = false
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let obj = JSON.parse(decode(props.text!.replace('vmess://', ''))); let obj = JSON.parse(decode(iterator));
obj.add = props.serve.ip obj.add = props.serve.ip
obj.port = props.serve.port obj.port = props.serve.port
obj.host = props.serve.host obj.host = props.serve.host
obj.tls = props.serve.istls == 0 ? '' : 'tls' obj.tls = props.serve.istls == 0 ? '' : 'tls'
let reg = new RegExp(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/); let reg = new RegExp(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/);
obj.path = '/' + obj.ps.match(reg)[0]; obj.path = '/' + obj.ps.match(reg)[0];
isonline() let ip = obj.ps.match(reg)[0]
return 'vmess://' + encode(JSON.stringify(obj)) isonline(ip)
tmp += 'vmess://' + encode(JSON.stringify(obj)) + '\n'
}
return tmp
}) })
const copy = (type: string) => { const copy = (type: string) => {
let tmp = '' let tmp = ''

View File

@ -65,11 +65,13 @@ const menuList = [
{ {
icon: 'file_download', icon: 'file_download',
label: '下载程序', label: '下载程序',
path: 'download',
separator: false separator: false
}, },
{ {
icon: 'error', icon: 'share',
label: 'Spam', label: '生成订阅',
path: 'subscription',
separator: true separator: true
}, },
{ {
@ -85,6 +87,7 @@ const menuList = [
{ {
icon: 'help_outline', icon: 'help_outline',
iconColor: 'primary', iconColor: 'primary',
path: 'help',
label: '帮助', label: '帮助',
separator: false separator: false
} }

View File

@ -35,20 +35,28 @@ export default defineComponent({
return reg.test(ip); return reg.test(ip);
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
watch(() => text.value, (newValue, oldValue) => { // watch(() => text.value, (newValue, oldValue) => { //
let obj = JSON.parse(decode(def_link)) let obj = JSON.parse(decode(def_link))
console.log(newValue) let array = newValue.split(/[\s\n]/)
if (!is_ip(newValue)) { for (let index = 0; index < array.length; index++) {
if (!is_ip(array[index])) {
outlink.value = 'erroe ip' outlink.value = 'erroe ip'
return return
} }
api.get_country(newValue).then(res => { }
outlink.value = ''
for (let index = 0; index < array.length; index++) {
api.get_country(array[index]).then(res => {
let name = res.data.country == '中国' ? res.data.province : res.data.country let name = res.data.country == '中国' ? res.data.province : res.data.country
obj.ps = name + newValue obj.ps = name + array[index]
obj.add = newValue obj.add = array[index]
outlink.value = 'vmess://' + encode(JSON.stringify(obj)) outlink.value += 'vmess://' + encode(JSON.stringify(obj)) + '\n'
}) })
}
}) })
return { return {

88
src/pages/Download.vue Normal file
View File

@ -0,0 +1,88 @@
<template>
<div class="row ">
<div v-for="(item, index) in array" :key="index" class="col-sm-8 col-md-4 col-lg-2 col-xl-1 q-pa-md">
<q-card class="my-card">
<img class="rounded-full" :src="item.picture">
<q-card-section class="text-center">
<div class="text-h6 text-center">{{ item.name }}</div>
<q-btn @click="dow(`res/${item.name}_phone.apk`)" color="positive">
<q-icon left name="file_download" />
<div>安卓手机</div>
</q-btn>
<q-btn @click="dow(`res/${item.name}_moni.apk`)" class="q-ma-md" color="positive">
<q-icon left name="file_download" />
<div>模拟器</div>
</q-btn>
<q-btn @click="dow(`res/${item.name}_pc.zip`)" color="positive">
<q-icon left name="file_download" />
<div>PC</div>
</q-btn>
</q-card-section>
<q-card-section class="q-pt-none">
</q-card-section>
</q-card>
</div>
<!-- <div class="col-sm-8 col-md-4 col-lg-2 col-xl-1 q-pa-md">
<q-card class="my-card">
<img class="rounded-full q-pa-md" src="img/v2rayng.png">
<q-card-section class="text-center">
<div class="text-h6 text-center">v2ray</div>
<q-btn color="positive">
<q-icon left name="file_download" />
<div>安卓手机</div>
</q-btn>
<q-btn class="q-ma-md" color="positive">
<q-icon left name="file_download" />
<div>模拟器</div>
</q-btn>
<q-btn color="positive">
<q-icon left name="file_download" />
<div>PC</div>
</q-btn>
</q-card-section>
<q-card-section class="q-pt-none">
</q-card-section>
</q-card>
</div> -->
</div>
</template>
<style scoped>
.box {
display: flex;
justify-content: space-around;
}
.rounded-full {
border-radius: 9999px;
}
</style>
<script lang="ts">
import { defineComponent } from 'vue';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const array = [{ 'name': 'v2ray', 'picture': 'img/v2rayng.png' }, { 'name': 'clash', 'picture': 'img/clash.png' }]
export default defineComponent({
// eslint-disable-next-line vue/multi-word-component-names
name: 'Download',
setup() {
return {
array,
dow(url: string) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
window.open('', '_self')!.location.href = url
}
};
}
});
</script>

84
src/pages/Help.vue Normal file
View File

@ -0,0 +1,84 @@
<template>
<div class="row ">
Help
</div>
</template>
<style scoped>
.box {
display: flex;
justify-content: space-around;
}
.rounded-full {
border-radius: 9999px;
}
</style>
<script lang="ts">
import { defineComponent, ref, watch } from 'vue';
import { getdata } from 'src/api/api'
import { decode, encode } from 'js-base64';
import { copyToClipboard, useQuasar } from 'quasar';
const array = [{ 'name': '', 'url': '', 'picture': '' }]
export default defineComponent({
// eslint-disable-next-line vue/multi-word-component-names
name: 'Help',
setup() {
const $q = useQuasar()
const api = new getdata;
const text = ref('');
const outlink = ref('');
const def_link = 'ew0KICAidiI6ICIyIiwNCiAgInBzIjogIjAiLA0KICAiYWRkIjogIjE4NS4yMTguNi4xMDgiLA0KICAicG9ydCI6ICI5MDAwIiwNCiAgImlkIjogIjJlZTU3ODA2LWY2ZTQtNDgyYS1lZjA4LTczNjBjMDRjZDNlNSIsDQogICJhaWQiOiAiMCIsDQogICJzY3kiOiAiYXV0byIsDQogICJuZXQiOiAid3MiLA0KICAidHlwZSI6ICJub25lIiwNCiAgImhvc3QiOiAiIiwNCiAgInBhdGgiOiAiLyIsDQogICJ0bHMiOiAiIiwNCiAgInNuaSI6ICIiLA0KICAiYWxwbiI6ICIiDQp9'
const is_ip = (ip: string) => {
var reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
return reg.test(ip);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
watch(() => text.value, (newValue, oldValue) => { //
let obj = JSON.parse(decode(def_link))
console.log(newValue)
if (!is_ip(newValue)) {
outlink.value = 'erroe ip'
return
}
api.get_country(newValue).then(res => {
let name = res.data.country == '中国' ? res.data.province : res.data.country
obj.ps = name + newValue
obj.add = newValue
outlink.value = 'vmess://' + encode(JSON.stringify(obj))
})
})
return {
text,
outlink,
copy() {
copyToClipboard(outlink.value)
.then(() => {
// success!
$q.notify({
message: '复制成功',
color: 'positive',
position: 'top'
})
})
.catch(() => {
// fail
$q.notify({
message: '复制失败',
color: 'negative'
})
})
}
};
}
});
</script>

View File

@ -44,24 +44,34 @@ export default defineComponent({
}) })
const isobj = computed(() => { const isobj = computed(() => {
try { try {
if (text.value.length <= 0) {
return false
}
let texttmp = text.value!.replace(/\ +/g, '');
texttmp = texttmp.replace(/[\r\n]/g, '');
let arr = texttmp.split('vmess://');
for (let iterator of arr) {
// eslint-disable-next-line vue/no-side-effects-in-computed-properties // eslint-disable-next-line vue/no-side-effects-in-computed-properties
online.value = false online.value = false
let obj = JSON.parse(decode(text.value.replace('vmess://', ''))); if (iterator.length > 0) {
let obj = JSON.parse(decode(iterator));
if (obj.id != '2ee57806-f6e4-482a-ef08-7360c04cd3e5' || obj.net != 'ws') { if (obj.id != '2ee57806-f6e4-482a-ef08-7360c04cd3e5' || obj.net != 'ws') {
return false return false
} }
isonline() let reg = new RegExp(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/);
let ip = obj.ps.match(reg)[0];
isonline(ip)
}
}
} catch (error) { } catch (error) {
console.log(error);
return false return false
} }
return true return true
}) })
const isonline = () => { const isonline = (ip: string) => {
let obj = JSON.parse(decode(text.value?.replace('vmess://', '')));
let reg = new RegExp(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/);
let ip = obj.ps.match(reg)[0];
api.text_server(`http://${ip}:9000/`).then(res => { api.text_server(`http://${ip}:9000/`).then(res => {
online.value = res.data.sataus == 400 online.value = res.data.sataus == 400
}) })

View File

@ -0,0 +1,52 @@
<template lang="">
<div>
<div class="row" style="text-align:center">
<div class="col-xs-1 col-md-4"></div>
<div class="col-xs-10 col-md-4">
<h6 style="text-align: center;margin: 1rem;">生成订阅</h6>
<q-input v-model="text" filled autogrow placeholder="vmess" />
<div style="height:1rem"></div>
<q-btn color="white" text-color="black" @click="copy" label="复制" />
</div>
</div>
</div>
</template>
<style lang="">
</style>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { copyToClipboard, useQuasar } from 'quasar';
export default defineComponent({
// eslint-disable-next-line vue/multi-word-component-names
name: 'Subscription',
setup() {
const $q = useQuasar()
const text = ref('');
return {
text,
copy() {
copyToClipboard(`http://149.129.107.38/link.php?link=${text.value}`)
.then(() => {
// success!
$q.notify({
message: '复制成功',
color: 'positive',
position: 'top'
})
})
.catch(() => {
// fail
$q.notify({
message: '复制失败',
color: 'negative'
})
})
}
};
}
});
</script>

View File

@ -4,7 +4,7 @@ const routes: RouteRecordRaw[] = [
{ {
path: '/', path: '/',
component: () => import('layouts/MainLayout.vue'), component: () => import('layouts/MainLayout.vue'),
children: [{ path: '', name: 'home', component: () => import('pages/IndexPage.vue') }, { path: 'createlink', name: 'createlink', component: () => import('pages/CreateLink.vue') }], children: [{ path: '', name: 'home', component: () => import('pages/IndexPage.vue') }, { path: 'createlink', name: 'createlink', component: () => import('pages/CreateLink.vue') }, { path: 'download', name: 'download', component: () => import('pages/Download.vue') }, { path: 'help', name: 'help', component: () => import('pages/Help.vue') }, { path: 'subscription', name: 'subscription', component: () => import('pages/Subscription.vue') }],
}, },
// Always leave this as last one, // Always leave this as last one,