bulk client creation #285

This commit is contained in:
Alireza Ahmadi
2024-10-28 13:22:29 +01:00
parent 5f3963ff1c
commit d255905907
8 changed files with 289 additions and 6 deletions
+199
View File
@@ -0,0 +1,199 @@
<template>
<v-dialog transition="dialog-bottom-transition" width="800">
<v-card class="rounded-lg">
<v-card-title>
{{ $t('bulk.add') }}
</v-card-title>
<v-divider></v-divider>
<v-card-text style="padding: 0 16px; overflow-y: scroll;">
<v-container style="padding: 0;">
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model.number="count" type="number" min="1" max="100" :label="$t('count')" hide-details></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="8">
<v-combobox
chips
multiple
v-model="bulkData.name"
:items="patterns"
:label="$t('client.name')"
hide-details>
</v-combobox>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="8">
<v-combobox
chips
multiple
v-model="bulkData.desc"
:items="patterns"
:label="$t('client.desc')"
hide-details>
</v-combobox>
</v-col>
</v-row>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-combobox v-model="bulkData.group" :items="groups" :label="$t('client.group')" hide-details></v-combobox>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field v-model.number="bulkData.Volume" type="number" min="0" :label="$t('stats.volume')" suffix="GiB" hide-details></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<DatePick :expiry="bulkData.expiry" @submit="setDate" />
</v-col>
</v-row>
<v-row>
<v-col>
<v-combobox
v-model="bulkData.clientInbounds"
:items="inboundTags"
:label="$t('client.inboundTags')"
multiple
chips
hide-details
></v-combobox>
</v-col>
</v-row>
<v-row>
<v-col cols="auto">
<v-switch v-model="bulkData.clientStats" color="primary" :label="$t('stats.enable')" hide-details></v-switch>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="blue-darken-1"
variant="outlined"
@click="closeModal"
>
{{ $t('actions.close') }}
</v-btn>
<v-btn
color="blue-darken-1"
variant="tonal"
:loading="loading"
@click="saveChanges"
>
{{ $t('actions.save') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script lang="ts">
import DatePick from '@/components/DateTime.vue'
import { push } from 'notivue'
import RandomUtil from '@/plugins/randomUtil'
import { Client, createClient, randomConfigs } from '@/types/clients'
import { i18n } from '@/locales';
export default {
props: ['visible', 'inboundTags', 'groups'],
emits: ['close', 'save'],
data() {
return {
count: 1,
clients: <Client[]>[],
bulkData: {
name: <any[]>[],
desc: <any[]>[],
group: '',
clientInbounds: [],
expiry: 0,
Volume: 0,
clientStats: false,
},
patterns: [
{ title: i18n.global.t("bulk.random"), value: "random" },
{ title: i18n.global.t("bulk.order"), value: "order" },
],
loading: false,
}
},
methods: {
resetData() {
this.count = 1,
this.clients = [],
this.bulkData = {
name: [this.patterns[1], "-", this.patterns[0]],
desc: [],
group: '',
clientInbounds: [],
expiry: 0,
Volume: 0,
clientStats: false,
}
},
closeModal() {
this.$emit('close')
},
saveChanges() {
if (this.bulkData.name.findIndex(n => typeof(n) == 'object') == -1) {
push.error(i18n.global.t('error.dplData'))
return
}
this.loading = true
for(let i=0;i<this.count;i++){
const name = this.genByPattern(this.bulkData.name, i)
this.clients.push(createClient({
enable: true,
name: name,
config: randomConfigs(name),
inbounds: this.bulkData.clientInbounds,
links: [],
volume: this.bulkData.Volume*(1024 ** 3),
expiry: this.bulkData.expiry,
up: 0,
down: 0,
desc: this.genByPattern(this.bulkData.desc, i),
group: this.bulkData.group
}))
}
this.$emit('save', this.clients, this.bulkData.clientInbounds, this.bulkData.clientStats)
this.resetData() // reset to default
this.loading = false
},
genByPattern(pattern: any[], order :number){
if (pattern.length == 0) return RandomUtil.randomSeq(8)
let result = ''
pattern.forEach(p => {
switch(typeof p){
case 'object':
switch(p.value){
case "random":
result += RandomUtil.randomSeq(8)
break
case "order":
result += order+1
}
break
default:
result += p
}
})
return result
},
setDate(v:number){
this.bulkData.expiry = v
}
},
computed: {},
watch: {
visible(newValue) {
if (newValue) {
this.resetData()
}
},
},
components: { DatePick },
}
</script>
+5
View File
@@ -165,6 +165,11 @@ export default {
external: "External Link",
sub: "External Subscription",
},
bulk: {
add: "Add Bulk",
order: "Order",
random: "Random",
},
types: {
un: "Username",
pw: "Password",
+5
View File
@@ -164,6 +164,11 @@ export default {
external: "لینک‌ خارجی",
sub: "سابسکریپشن خارجی",
},
bulk: {
add: "ایجاد انبوه",
order: "ترتیب",
random: "تصادفی",
},
types: {
un: "نام کاربری",
pw: "رمز",
+5
View File
@@ -165,6 +165,11 @@ export default {
external: "Внешняя ссылка",
sub: "Внешняя подписка",
},
bulk: {
add: "Добавить пакетно",
order: "Порядок",
random: "Случайный",
},
types: {
un: "Имя пользователя",
pw: "Пароль",
+5
View File
@@ -165,6 +165,11 @@ export default {
external: "Liên kết bên ngoài",
sub: "Đăng ký bên ngoài",
},
bulk: {
add: "Thêm Hàng loạt",
order: "Sắp xếp",
random: "Ngẫu nhiên",
},
types: {
un: "Tên người dùng",
pw: "Mật khẩu",
+5
View File
@@ -165,6 +165,11 @@ export default {
external: "外部链接",
sub: "外部订阅",
},
bulk: {
add: "批量添加",
order: "排序",
random: "随机",
},
types: {
un: "用户名",
pw: "密码",
+5
View File
@@ -166,6 +166,11 @@ export default {
external: "外部鏈接",
sub: "外部訂閱",
},
bulk: {
add: "批量添加",
order: "排序",
random: "隨機",
},
types: {
un: "用戶名",
pw: "密碼",
+60 -6
View File
@@ -11,6 +11,14 @@
@close="closeModal"
@save="saveModal"
/>
<ClientBulk
v-model="addBulkModal"
:visible="addBulkModal"
:groups="groups"
:inboundTags="inboundTags"
@close="closeBulk"
@save="saveBulk"
/>
<QrCode
v-model="qrcode.visible"
:visible="qrcode.visible"
@@ -28,11 +36,28 @@
<v-col cols="auto">
<v-btn color="primary" @click="showModal(-1)">{{ $t('actions.add') }}</v-btn>
</v-col>
<v-col cols="auto">
<v-menu v-model="actionMenu" :close-on-content-click="false" location="bottom center">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" hide-details variant="text" icon>
<v-icon icon="mdi-tools" color="primary" />
</v-btn>
</template>
<v-list density="compact" nav>
<v-list-item link @click="addBulk">
<template v-slot:prepend>
<v-icon icon="mdi-account-multiple-plus"></v-icon>
</template>
<v-list-item-title v-text="$t('bulk.add')"></v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-col>
<v-col cols="auto">
<v-menu v-model="filterMenu" :close-on-content-click="false" location="bottom center">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" hide-details variant="tonal">{{ $t('filter') }}
<v-badge color="error" dot v-if="filterSettings.enabled" floating />
<v-btn v-bind="props" hide-details variant="text" icon>
<v-icon :icon="filterSettings.enabled ? 'mdi-filter-check-outline' : 'mdi-filter-menu-outline'" :color="filterSettings.enabled ? 'primary' : ''" />
</v-btn>
</template>
<v-card>
@@ -93,9 +118,9 @@
</v-menu>
</v-col>
<v-col cols="auto">
<v-switch v-model="tableView" color="primary" hide-details>
<template v-slot:label><v-icon icon="mdi-table"></v-icon></template>
</v-switch>
<v-btn hide-details variant="text" icon @click="toggleClientView">
<v-icon :icon="tableView ? 'mdi-table-eye' : 'mdi-table-eye-off'" :color="tableView ? 'primary' : ''"></v-icon>
</v-btn>
</v-col>
</v-row>
<template v-for="group in groups" v-if="!tableView">
@@ -319,6 +344,7 @@
<script lang="ts" setup>
import Data from '@/store/modules/data'
import ClientModal from '@/layouts/modals/Client.vue'
import ClientBulk from '@/layouts/modals/ClientBulk.vue'
import QrCode from '@/layouts/modals/QrCode.vue'
import Stats from '@/layouts/modals/Stats.vue'
import { Client, createClient } from '@/types/clients'
@@ -364,6 +390,7 @@ const groups = computed((): string[] => {
return Array.from(new Set(clients.value?.map(c => c.group)))
})
const actionMenu = ref(false)
const filterMenu = ref(false)
const filterSettings = ref({
enabled: false,
@@ -372,7 +399,12 @@ const filterSettings = ref({
text: '',
filteredClients: <any[]>[]
})
const tableView = ref(false)
const tableView = ref(localStorage.getItem('clientView') == 'table')
const toggleClientView = () => {
localStorage.setItem('clientView',tableView.value ? 'tile' : 'table')
tableView.value = !tableView.value
}
const filterItems = [
{ title: i18n.global.t('none'), value: '' },
@@ -592,4 +624,26 @@ const clearFilter = () => {
}
filterMenu.value = false
}
const addBulkModal = ref(false)
const addBulk = () => {
addBulkModal.value = true
actionMenu.value = false
}
const closeBulk = () => {
addBulkModal.value = false
}
const saveBulk = (bulkClients: Client[], clientInbounds: string[], clientStats: boolean) => {
bulkClients.forEach((c,c_index) => {
bulkClients[c_index].links = updateLinks(c)
})
clients.value.push(...bulkClients)
buildInboundsUsers(clientInbounds)
// Stats
if (clientStats) v2rayStats.value.users.push(...bulkClients.map(bc => bc.name))
closeBulk()
}
</script>