mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-14 05:23:09 +00:00
New feature: Bulk add #28 (plus adjust methods)
This commit is contained in:
107
web/html/xui/client_bulk_modal.html
Normal file
107
web/html/xui/client_bulk_modal.html
Normal file
@@ -0,0 +1,107 @@
|
||||
{{define "clientsBulkModal"}}
|
||||
<a-modal id="client-bulk-modal" v-model="clientsBulkModal.visible" :title="clientsBulkModal.title" @ok="clientsBulkModal.ok"
|
||||
:closable="true" :mask-closable="false"
|
||||
:ok-text="clientsBulkModal.okText" cancel-text='{{ i18n "close" }}'>
|
||||
<a-form layout="inline">
|
||||
<a-form-item>
|
||||
<span slot="label">{{ i18n "pages.client.clientCount" }}</span>
|
||||
<a-input-number v-model="clientsBulkModal.quantity" :min="1" :max="100"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
<span >{{ i18n "pages.inbounds.totalFlow" }}</span>(GB)
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span>
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-input-number v-model="clientsBulkModal.totalGB" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<span slot="label">
|
||||
<span >{{ i18n "pages.inbounds.expireDate" }}</span>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<span>{{ i18n "pages.inbounds.leaveBlankToNeverExpire" }}</span>
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled"></a-icon>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
<a-date-picker :show-time="{ format: 'HH:mm' }" format="YYYY-MM-DD HH:mm"
|
||||
v-model="clientsBulkModal.expiryTime" style="width: 300px;"></a-date-picker>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
<script>
|
||||
|
||||
const clientsBulkModal = {
|
||||
visible: false,
|
||||
title: '',
|
||||
okText: '',
|
||||
confirm: null,
|
||||
dbInbound: new DBInbound(),
|
||||
inbound: new Inbound(),
|
||||
clients: [],
|
||||
quantity: 1,
|
||||
totalGB: 0,
|
||||
expiryTime: '',
|
||||
ok() {
|
||||
for (let i = 0; i < clientsBulkModal.quantity; i++) {
|
||||
newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol);
|
||||
newClient._totalGB = clientsBulkModal.totalGB;
|
||||
newClient._expiryTime = clientsBulkModal.expiryTime;
|
||||
clientsBulkModal.clients.push(newClient);
|
||||
}
|
||||
ObjectUtil.execute(clientsBulkModal.confirm, clientsBulkModal.inbound, clientsBulkModal.dbInbound);
|
||||
},
|
||||
show({ title='', okText='{{ i18n "sure" }}', dbInbound=null, confirm=(inbound, dbInbound)=>{} }) {
|
||||
this.visible = true;
|
||||
this.title = title;
|
||||
this.okText = okText;
|
||||
this.confirm = confirm;
|
||||
this.quantity = 1;
|
||||
this.totalGB = 0;
|
||||
this.expiryTime = '';
|
||||
this.dbInbound = new DBInbound(dbInbound);
|
||||
this.inbound = dbInbound.toInbound();
|
||||
this.clients = this.getClients(this.inbound.protocol, this.inbound.settings);
|
||||
},
|
||||
getClients(protocol, clientSettings) {
|
||||
switch(protocol){
|
||||
case Protocols.VMESS: return clientSettings.vmesses;
|
||||
case Protocols.VLESS: return clientSettings.vlesses;
|
||||
case Protocols.TROJAN: return clientSettings.trojans;
|
||||
default: return null;
|
||||
}
|
||||
},
|
||||
newClient(protocol) {
|
||||
switch (protocol) {
|
||||
case Protocols.VMESS: return new Inbound.VmessSettings.Vmess();
|
||||
case Protocols.VLESS: return new Inbound.VLESSSettings.VLESS();
|
||||
case Protocols.TROJAN: return new Inbound.TrojanSettings.Trojan();
|
||||
default: return null;
|
||||
}
|
||||
},
|
||||
close() {
|
||||
clientsBulkModal.visible = false;
|
||||
clientsBulkModal.loading(false);
|
||||
},
|
||||
loading(loading) {
|
||||
clientsBulkModal.confirmLoading = loading;
|
||||
},
|
||||
};
|
||||
|
||||
const clientsBulkModalApp = new Vue({
|
||||
delimiters: ['[[', ']]'],
|
||||
el: '#client-bulk-modal',
|
||||
data: {
|
||||
clientsBulkModal,
|
||||
get inbound() {
|
||||
return this.clientsBulkModal.inbound;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
@@ -77,6 +77,10 @@
|
||||
<a-icon type="user"></a-icon>
|
||||
{{ i18n "pages.client.add"}}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="addBulkClient">
|
||||
<a-icon type="team"></a-icon>
|
||||
{{ i18n "pages.client.bulk"}}
|
||||
</a-menu-item>
|
||||
<a-menu-item key="export">
|
||||
<a-icon type="export"></a-icon>
|
||||
{{ i18n "pages.inbounds.export"}}
|
||||
@@ -113,7 +117,7 @@
|
||||
<template v-else>{{ i18n "none" }}</template>
|
||||
</template>
|
||||
<template slot="enable" slot-scope="text, dbInbound">
|
||||
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound)"></a-switch>
|
||||
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound.id)"></a-switch>
|
||||
</template>
|
||||
<template slot="expiryTime" slot-scope="text, dbInbound">
|
||||
<template v-if="dbInbound.expiryTime > 0">
|
||||
@@ -283,20 +287,23 @@
|
||||
case "qrcode":
|
||||
this.showQrcode(dbInbound);
|
||||
break;
|
||||
case "export":
|
||||
this.inboundLinks(dbInbound.id);
|
||||
break;
|
||||
case "edit":
|
||||
this.openEditInbound(dbInbound.id);
|
||||
break;
|
||||
case "addClient":
|
||||
this.openAddClient(dbInbound)
|
||||
this.openAddClient(dbInbound.id)
|
||||
break;
|
||||
case "addBulkClient":
|
||||
this.openAddBulkClient(dbInbound.id)
|
||||
break;
|
||||
case "export":
|
||||
this.inboundLinks(dbInbound.id);
|
||||
break;
|
||||
case "resetTraffic":
|
||||
this.resetTraffic(dbInbound);
|
||||
this.resetTraffic(dbInbound.id);
|
||||
break;
|
||||
case "delete":
|
||||
this.delInbound(dbInbound);
|
||||
this.delInbound(dbInbound.id);
|
||||
break;
|
||||
}
|
||||
},
|
||||
@@ -313,8 +320,8 @@
|
||||
isEdit: false
|
||||
});
|
||||
},
|
||||
openEditInbound(dbInbound_id) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === dbInbound_id);
|
||||
openEditInbound(dbInboundId) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||
const inbound = dbInbound.toInbound();
|
||||
inModal.show({
|
||||
title: '{{ i18n "pages.inbounds.modifyInbound"}}',
|
||||
@@ -366,8 +373,8 @@
|
||||
};
|
||||
await this.submit(`/xui/inbound/update/${dbInbound.id}`, data, inModal);
|
||||
},
|
||||
openAddClient(inbound) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === inbound.id);
|
||||
openAddClient(dbInboundId) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||
clientModal.show({
|
||||
title: '{{ i18n "pages.client.add"}}',
|
||||
okText: '{{ i18n "pages.client.submitAdd"}}',
|
||||
@@ -380,6 +387,19 @@
|
||||
isEdit: false
|
||||
});
|
||||
},
|
||||
openAddBulkClient(dbInboundId) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||
clientsBulkModal.show({
|
||||
title: '{{ i18n "pages.client.bulk"}} ' + dbInbound.remark,
|
||||
okText: '{{ i18n "pages.client.bulk"}}',
|
||||
dbInbound: dbInbound,
|
||||
confirm: async (inbound, dbInbound) => {
|
||||
clientsBulkModal.loading();
|
||||
await this.addClient(inbound, dbInbound);
|
||||
clientsBulkModal.close();
|
||||
},
|
||||
});
|
||||
},
|
||||
openEditClient(dbInboundId, client) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||
clients = this.getInboundClients(dbInbound);
|
||||
@@ -406,16 +426,17 @@
|
||||
id: dbInbound.id,
|
||||
settings: inbound.settings.toString(),
|
||||
};
|
||||
await this.submit('/xui/inbound/addClient', data, clientModal);
|
||||
await this.submit('/xui/inbound/addClient', data);
|
||||
},
|
||||
async updateClient(inbound, dbInbound, index) {
|
||||
const data = {
|
||||
id: dbInbound.id,
|
||||
settings: inbound.settings.toString(),
|
||||
};
|
||||
await this.submit(`/xui/inbound/updateClient/${index}`, data, clientModal);
|
||||
await this.submit(`/xui/inbound/updateClient/${index}`, data);
|
||||
},
|
||||
resetTraffic(dbInbound) {
|
||||
resetTraffic(dbInboundId) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||
this.$confirm({
|
||||
title: '{{ i18n "pages.inbounds.resetTraffic"}}',
|
||||
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
||||
@@ -429,13 +450,13 @@
|
||||
},
|
||||
});
|
||||
},
|
||||
delInbound(dbInbound) {
|
||||
delInbound(dbInboundId) {
|
||||
this.$confirm({
|
||||
title: '{{ i18n "pages.inbounds.deleteInbound"}}',
|
||||
content: '{{ i18n "pages.inbounds.deleteInboundContent"}}',
|
||||
okText: '{{ i18n "delete"}}',
|
||||
cancelText: '{{ i18n "cancel"}}',
|
||||
onOk: () => this.submit('/xui/inbound/del/' + dbInbound.id),
|
||||
onOk: () => this.submit('/xui/inbound/del/' + dbInboundId),
|
||||
});
|
||||
},
|
||||
delClient(dbInboundId,client) {
|
||||
@@ -472,11 +493,12 @@
|
||||
showInfo(dbInbound, index) {
|
||||
infoModal.show(dbInbound, index);
|
||||
},
|
||||
switchEnable(dbInbound) {
|
||||
this.submit(`/xui/inbound/update/${dbInbound.id}`, dbInbound);
|
||||
switchEnable(dbInboundId) {
|
||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||
this.submit(`/xui/inbound/update/${dbInboundId}`, dbInbound);
|
||||
},
|
||||
async submit(url, data, modal) {
|
||||
const msg = await HttpUtil.postWithModal(url, data, modal);
|
||||
async submit(url, data) {
|
||||
const msg = await HttpUtil.postWithModal(url, data);
|
||||
if (msg.success) {
|
||||
await this.getDBInbounds();
|
||||
}
|
||||
@@ -490,13 +512,13 @@
|
||||
return dbInbound.toInbound().settings.trojans
|
||||
}
|
||||
},
|
||||
resetClientTraffic(client,dbInbound_Id) {
|
||||
resetClientTraffic(client,dbInboundId) {
|
||||
this.$confirm({
|
||||
title: '{{ i18n "pages.inbounds.resetTraffic"}}',
|
||||
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
||||
okText: '{{ i18n "reset"}}',
|
||||
cancelText: '{{ i18n "cancel"}}',
|
||||
onOk: () => this.submit('/xui/inbound/' + dbInbound_Id + '/resetClientTraffic/'+ client.email),
|
||||
onOk: () => this.submit('/xui/inbound/' + dbInboundId + '/resetClientTraffic/'+ client.email),
|
||||
})
|
||||
},
|
||||
isExpiry(dbInbound, index) {
|
||||
@@ -586,5 +608,6 @@
|
||||
{{template "textModal"}}
|
||||
{{template "inboundInfoModal"}}
|
||||
{{template "clientsModal"}}
|
||||
{{template "clientsBulkModal"}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -251,11 +251,21 @@ func (s *InboundService) AddInboundClient(inbound *model.Inbound) error {
|
||||
return err
|
||||
}
|
||||
|
||||
oldClients, err := s.getClients(oldInbound)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldInbound.Settings = inbound.Settings
|
||||
|
||||
if len(clients[len(clients)-1].Email) > 0 {
|
||||
s.AddClientStat(inbound.Id, &clients[len(clients)-1])
|
||||
}
|
||||
for i := len(oldClients); i < len(clients); i++ {
|
||||
if len(clients[i].Email) > 0 {
|
||||
s.AddClientStat(inbound.Id, &clients[i])
|
||||
}
|
||||
}
|
||||
db := database.GetDB()
|
||||
return db.Save(oldInbound).Error
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
"submitAdd" = "Add client"
|
||||
"submitEdit" = "Save changes"
|
||||
"clientCount" = "Number of clients"
|
||||
"bulk" = "Add bulk"
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "Obtain"
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
"submitAdd" = "اضافه کردن"
|
||||
"submitEdit" = "ذخیره تغییرات"
|
||||
"clientCount" = "تعداد کاربران"
|
||||
"bulk" = "انبوه سازی"
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "Obtain"
|
||||
|
||||
@@ -134,6 +134,7 @@
|
||||
"submitAdd" = "添加客户端"
|
||||
"submitEdit" = "保存修改"
|
||||
"clientCount" = "客户数量"
|
||||
"bulk" = "批量创建"
|
||||
|
||||
[pages.inbounds.toasts]
|
||||
"obtain" = "获取"
|
||||
|
||||
Reference in New Issue
Block a user