Skip to content

Commit e6af684

Browse files
committed
pref: 优化vpn账号节点右键菜单及编辑账号选择节点显示
1 parent eeb6c20 commit e6af684

File tree

2 files changed

+95
-6
lines changed

2 files changed

+95
-6
lines changed

src/openvpn-web/templates/index.html

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@
9696
}
9797

9898
/* 左侧树形菜单样式 */
99+
#treeMenu ul:first-of-type {
100+
overflow-y: auto;
101+
max-height: 75vh;
102+
}
99103
.tree-menu {
100104
list-style: none;
101105
padding-left: 0;
@@ -142,6 +146,20 @@
142146
z-index: 1050;
143147
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
144148
}
149+
150+
#editUserModal .dropdown-menu {
151+
width: 100%;
152+
max-height: 300px;
153+
overflow-y: auto;
154+
padding: 0;
155+
font-size: 0.875rem;
156+
}
157+
158+
#editUserModal .dropdown-item:hover,
159+
.dropdown-item:focus {
160+
background-color: selecteditem;
161+
color: selecteditemtext;
162+
}
145163
</style>
146164
</head>
147165

@@ -541,7 +559,18 @@ <h5 class="modal-title">编辑账号</h5>
541559
</div>
542560
<div class="form-group mb-3">
543561
<label>节点</label>
544-
<select class="form-select form-select-sm float-end w-75" name="gid"></select>
562+
<div class="dropdown float-end w-75">
563+
<button
564+
class="form-select form-select-sm text-start"
565+
data-bs-toggle="dropdown"
566+
aria-expanded="false"
567+
name="groupBtn"
568+
>
569+
&nbsp;
570+
</button>
571+
<input type="hidden" name="gid" />
572+
<ul class="dropdown-menu" name="groupList"></ul>
573+
</div>
545574
</div>
546575
<div class="form-group mb-3">
547576
<label>

src/openvpn-web/templates/static/js/user.js

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,11 @@ $(document).on('click', '#editUser', function () {
410410
$('#editUserModal select[name="ovpnConfig"]').val(u.ovpnConfig);
411411

412412
request.get('/ovpn/group').then((data) => {
413-
$('#editUserModal select[name="gid"]').html(data.map((i) => `<option value="${i.id}">${i.name}</option>`));
414-
$('#editUserModal select[name="gid"]').val(cgid);
413+
$('#editUserModal ul[name="groupList"]').html(renderDropdownItems(buildTree(data)));
414+
415+
const item = $(`#editUserModal [data-id="${u.gid}"]`);
416+
item.addClass('selected');
417+
$('#editUserModal button[name="groupBtn"]').text(item.data('name'));
415418
});
416419

417420
const elem = document.querySelector('#editUserModal input[name="expireDate"]');
@@ -436,7 +439,7 @@ $('#editUserModal form').submit(function () {
436439
const ipAddr = $('#editUserModal input[name="ipAddr"]').val();
437440
const expireDate = $('#editUserModal input[name="expireDate"]').val();
438441
const ovpnConfig = $('#editUserModal select[name="ovpnConfig"]').val() || '';
439-
const gid = $('#editUserModal select[name="gid"]').val();
442+
const gid = $('#editUserModal input[name="gid"]').val();
440443

441444
request.patch('/ovpn/user', { id, name, username, ipAddr, expireDate, ovpnConfig, gid }).then((data) => {
442445
vtable.ajax.reload(null, false);
@@ -669,6 +672,31 @@ function renderTree(nodes, container) {
669672
});
670673
}
671674

675+
function renderDropdownItems(treeData) {
676+
let html = '';
677+
treeData.forEach((node) => {
678+
const indent = '&nbsp;&nbsp;&nbsp;&nbsp;'.repeat(node.depth);
679+
const symbol = node.depth > 0 ? '└─ ' : '';
680+
const displayName = indent + symbol + node.name;
681+
682+
html += `
683+
<li>
684+
<a class="dropdown-item group-select-item"
685+
href="#"
686+
data-id="${node.id}"
687+
data-name="${node.name}"
688+
onmouseenter="this.focus()"
689+
>
690+
${displayName}
691+
</a>
692+
</li>
693+
`;
694+
if (node.children) html += renderDropdownItems(node.children);
695+
});
696+
697+
return html;
698+
}
699+
672700
function refreshTree(data) {
673701
treeMenu.innerHTML = '';
674702
const tree = buildTree(data);
@@ -709,8 +737,26 @@ function handleContextMenu(e, node) {
709737
}
710738

711739
contextMenu.style.display = 'block';
712-
contextMenu.style.left = `${e.pageX}px`;
713-
contextMenu.style.top = `${e.pageY}px`;
740+
741+
const menuWidth = contextMenu.offsetWidth;
742+
const menuHeight = contextMenu.offsetHeight;
743+
744+
const pageWidth = window.innerWidth;
745+
const pageHeight = window.innerHeight;
746+
747+
let x = e.pageX;
748+
let y = e.pageY;
749+
750+
if (x + menuWidth > pageWidth) {
751+
x -= menuWidth;
752+
}
753+
754+
if (y + menuHeight > pageHeight) {
755+
y -= menuHeight;
756+
}
757+
758+
contextMenu.style.left = `${x}px`;
759+
contextMenu.style.top = `${y}px`;
714760
}
715761

716762
menuAdd.addEventListener('click', () => {
@@ -769,6 +815,20 @@ document.addEventListener('click', (e) => {
769815
}
770816
});
771817

818+
$('#editUserModal .dropdown').on('shown.bs.dropdown', function () {
819+
$('#editUserModal .group-select-item.selected').focus();
820+
});
821+
822+
$(document).on('click', '.group-select-item', function (e) {
823+
e.preventDefault();
824+
825+
$('#editUserModal .group-select-item').removeClass('selected');
826+
$(this).addClass('selected');
827+
828+
$('#editUserModal button[name="groupBtn"]').text($(this).data('name'));
829+
$('#editUserModal input[name="gid"]').val($(this).data('id'));
830+
});
831+
772832
$('#treeVpnConfigSumbit').click(function () {
773833
const config = $('#treeVpnConfigModal textarea[name="config"]').val();
774834
request.patch('/ovpn/group', { id: currentNode.id, config: config?.trim()?.replace(/\n/g, '\\n') }).then(() => {

0 commit comments

Comments
 (0)