feat(proxy): add toggle functionality for proxies and update styles
This commit is contained in:
+2
-1
@@ -27,4 +27,5 @@ dist/
|
||||
node_modules/
|
||||
design.md
|
||||
agent.md
|
||||
api-backend.md
|
||||
api-backend.md
|
||||
CLAUDE.md
|
||||
+3
-1
@@ -107,7 +107,9 @@ export const instanceApi = {
|
||||
modifyProxy: (instanceID, proxyInfo) =>
|
||||
api.post('/frpcAct/proxyMgr/modify', { instanceID, proxyInfo }),
|
||||
deleteProxy: (instanceID, proxyName) =>
|
||||
api.post('/frpcAct/proxyMgr/delete', { instanceID, proxyName })
|
||||
api.post('/frpcAct/proxyMgr/delete', { instanceID, proxyName }),
|
||||
switchProxy: (instanceID, proxyName, action) =>
|
||||
api.post('/frpcAct/proxyMgr/switch', { instanceID, proxyName, action })
|
||||
};
|
||||
|
||||
export const logApi = {
|
||||
|
||||
@@ -172,20 +172,30 @@
|
||||
</button>
|
||||
</h3>
|
||||
<div v-if="proxies.length > 0" class="proxy-list">
|
||||
<div v-for="proxy in proxies" :key="proxy.name" class="proxy-item">
|
||||
<div v-for="proxy in proxies" :key="proxy.name" class="proxy-item" :class="{ 'proxy-disabled': !proxy.enabled }">
|
||||
<div class="proxy-header">
|
||||
<span class="proxy-name">{{ proxy.name }}</span>
|
||||
<div class="proxy-header-left">
|
||||
<span class="proxy-name">{{ proxy.name }}</span>
|
||||
<label class="toggle-switch" @click.stop>
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="proxy.enabled"
|
||||
@change="toggleProxy(proxy)"
|
||||
>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="proxy-actions-right">
|
||||
<span class="proxy-type">{{ proxy.type }}</span>
|
||||
<div class="proxy-actions">
|
||||
<button
|
||||
class="common-btn edit-btn"
|
||||
<button
|
||||
class="common-btn edit-btn"
|
||||
@click="editProxy(proxy)"
|
||||
>
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</button>
|
||||
<button
|
||||
class="common-btn delete-btn"
|
||||
<button
|
||||
class="common-btn delete-btn"
|
||||
@click="deleteProxy(proxy)"
|
||||
>
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
@@ -442,7 +452,8 @@ export default {
|
||||
type: proxy.type,
|
||||
localIP: proxy.localIP,
|
||||
localPort: proxy.localPort,
|
||||
remotePort: proxy.remotePort
|
||||
remotePort: proxy.remotePort,
|
||||
enabled: proxy.enabled !== undefined ? proxy.enabled : true
|
||||
}));
|
||||
} catch (error) {
|
||||
showNotification(error.message || 'Load proxy list failed', 'error');
|
||||
@@ -581,6 +592,17 @@ export default {
|
||||
showDeleteProxyModal.value = true;
|
||||
}
|
||||
|
||||
const toggleProxy = async (proxy) => {
|
||||
const action = proxy.enabled ? 0 : 1;
|
||||
try {
|
||||
const result = await instanceApi.switchProxy(+instanceID.value, proxy.name, action);
|
||||
showNotification(result.message || `Proxy "${proxy.name}" ${proxy.enabled ? 'disabled' : 'enabled'}`, 'success');
|
||||
await loadProxies();
|
||||
} catch (error) {
|
||||
showNotification(error.message || 'Failed to toggle proxy', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const closeDeleteProxyModal = () => {
|
||||
showDeleteProxyModal.value = false;
|
||||
selectedProxyName.value = '';
|
||||
@@ -601,8 +623,8 @@ export default {
|
||||
try {
|
||||
const result = await instanceApi.deleteProxy(instanceID.value, selectedProxyName.value);
|
||||
showNotification(result.message || 'Proxy deleted successfully', 'success');
|
||||
closeDeleteProxyModal();
|
||||
await loadProxies();
|
||||
closeDeleteProxyModal();
|
||||
} catch (error) {
|
||||
showNotification(error.message || 'Delete proxy failed', 'error');
|
||||
} finally {
|
||||
@@ -751,6 +773,7 @@ export default {
|
||||
addProxy,
|
||||
editProxy,
|
||||
deleteProxy,
|
||||
toggleProxy,
|
||||
closeAddProxyModal,
|
||||
closeDeleteProxyModal,
|
||||
confirmDeleteProxy,
|
||||
@@ -810,6 +833,12 @@ export default {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.proxy-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.proxy-name {
|
||||
font-family: 'SF Pro Display', 'SF Pro Icons', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 18px;
|
||||
@@ -1204,4 +1233,54 @@ export default {
|
||||
.section:last-child .logs-container::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 44px;
|
||||
height: 24px;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.toggle-switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.toggle-slider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: var(--surface-hover);
|
||||
border-radius: 24px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.toggle-slider::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.toggle-switch input:checked + .toggle-slider {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
||||
.toggle-switch input:checked + .toggle-slider::before {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.proxy-disabled {
|
||||
opacity: 0.48;
|
||||
}
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
const APP_TARGET = '192.168.1.4:7000'
|
||||
const APP_TARGET = '192.168.20.4:19090'
|
||||
|
||||
export default defineConfig({
|
||||
define: {
|
||||
|
||||
Reference in New Issue
Block a user