feat(instance): add proxy creation functionality

- Add createProxy API method to instanceApi
- Implement proxy creation form in InstanceDetail view
- Add modal for proxy creation with required fields
- Include validation for port numbers
This commit is contained in:
2026-03-19 17:33:45 +08:00
parent 8c62e25c12
commit 2e445de6e3
2 changed files with 112 additions and 6 deletions

View File

@@ -86,7 +86,9 @@ export const instanceApi = {
getInstanceLogs: (instanceName) =>
api.get('/frpcAct/instanceMgr/logs', { params: { instanceName } }),
getInstanceProxies: (instanceName) =>
api.get('/frpcAct/instanceMgr/proxies', { params: { instanceName } })
api.get('/frpcAct/instanceMgr/proxies', { params: { instanceName } }),
createProxy: (instanceID, proxyInfo) =>
api.post('/frpcAct/proxyMgr/create', { instanceID, proxyInfo })
};
export const logApi = {

View File

@@ -117,16 +117,18 @@
</div>
<div class="form-actions">
<button type="button" class="cancel-btn" @click="closeEditConfigModal">Cancel</button>
<button type="submit" class="submit-btn" :disabled="loading">
{{ loading ? 'Processing...' : 'Save' }}
</button>
<button type="submit" class="submit-btn" :disabled="loading">{{ loading ? 'Processing...' : 'Save' }}</button>
</div>
</form>
</div>
</div>
<div class="section">
<h3>Proxy List</h3>
<h3>Proxy List
<button class="common-btn" @click="addProxy">
<i class="fas fa-plus"></i> Add Proxy
</button>
</h3>
<div v-if="proxies.length > 0" class="proxy-list">
<div v-for="proxy in proxies" :key="proxy.name" class="proxy-item">
<div class="proxy-header">
@@ -148,6 +150,64 @@
</div>
</div>
<div v-if="showAddProxyModal" class="modal-overlay" @click="closeAddProxyModal">
<div class="modal" @click.stop>
<h3>Add Proxy</h3>
<form @submit.prevent="handleSubmit" class="form">
<div class="form-group">
<label>Proxy Name</label>
<input
type="text"
v-model="formData.name"
required
>
</div>
<div class="form-group">
<label>Type</label>
<input
type="text"
v-model="formData.type"
required
>
</div>
<div class="form-group">
<label>Local IP</label>
<input
type="text"
v-model="formData.localIP"
required
>
</div>
<div class="form-group">
<label>Local Port</label>
<input
type="number"
v-model="formData.localPort"
required
min="0"
max="65535"
step="1"
>
</div>
<div class="form-group">
<label>Remote Port</label>
<input
type="number"
v-model="formData.remotePort"
required
min="0"
max="65535"
step="1"
>
</div>
<div class="form-actions">
<button type="button" class="cancel-btn" @click="closeAddProxyModal">Cancel</button>
<button type="submit" class="submit-btn" :disabled="loading">{{ loading ? 'Processing...' : 'Submit' }}</button>
</div>
</form>
</div>
</div>
<div class="section">
<h3>Logs</h3>
<div class="logs-container">
@@ -184,6 +244,7 @@ export default {
const proxies = ref([]);
const logs = ref([]);
const showEditConfigModal = ref(false);
const showAddProxyModal = ref(false);
const loading = ref(false);
const formData = ref({
name: '',
@@ -277,10 +338,18 @@ export default {
showEditConfigModal.value = true;
};
const addProxy = () => {
showAddProxyModal.value = true;
}
const closeEditConfigModal = () => {
showEditConfigModal.value = false;
};
const closeAddProxyModal = () => {
showAddProxyModal.value = false;
};
const handleEditConfiguration = async () => {
loading.value = true;
try {
@@ -321,6 +390,7 @@ export default {
showNotification('Configuration saved successfully', 'success');
closeEditConfigModal();
closeAddProxyModal();
// 重新加载配置
instanceName.value = formData.value.name;
await loadInstanceConfig();
@@ -331,6 +401,29 @@ export default {
}
};
const handleSubmit = async () => {
loading.value = true;
try {
const proxyInfo = {
name: formData.value.name,
type: formData.value.type,
localIP: formData.value.localIP,
localPort: formData.value.localPort.toString(),
remotePort: formData.value.remotePort.toString()
};
await instanceApi.createProxy(instanceID.value, proxyInfo);
showNotification('Proxy created successfully', 'success');
closeAddProxyModal();
await loadProxies();
} catch (error) {
showNotification(error.message || 'Create proxy failed', 'error');
} finally {
loading.value = false;
}
};
onMounted(() => {
loadInstanceConfig();
loadProxies();
@@ -343,12 +436,16 @@ export default {
proxies,
logs,
showEditConfigModal,
showAddProxyModal,
loading,
formData,
goBack,
editConfig,
closeEditConfigModal,
handleEditConfiguration
addProxy,
closeAddProxyModal,
handleEditConfiguration,
handleSubmit
};
}
};
@@ -483,4 +580,11 @@ export default {
background: var(--disabled-bg);
cursor: not-allowed;
}
.section h3 {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
</style>