refactor(instance): migrate from name-based to ID-based instance management
feat(instanceDetail): add instance status display and restart && stop/start control - Change instance identification from name to ID in API endpoints and routes - Add instance status management functionality with start/stop/restart - Implement user type checks for instance operations - Update UI to reflect instance status changes - Remove completed TODO notes for implemented APIs
This commit is contained in:
@@ -67,32 +67,33 @@ export const instanceApi = {
|
|||||||
runUser,
|
runUser,
|
||||||
additionalProperties
|
additionalProperties
|
||||||
}),
|
}),
|
||||||
deleteInstance: (instanceName) =>
|
deleteInstance: (instanceID) =>
|
||||||
api.post('/frpcAct/instanceMgr/delete', { instanceName }),
|
api.post('/frpcAct/instanceMgr/delete', { instanceID }),
|
||||||
modifyInstance: (instanceName, instanceID, type, modifiedData) =>
|
modifyInstance: (instanceID, type, modifiedData) =>
|
||||||
api.post('/frpcAct/instanceMgr/modify', {
|
api.post('/frpcAct/instanceMgr/modify', {
|
||||||
instanceName,
|
|
||||||
instanceID,
|
instanceID,
|
||||||
type,
|
type,
|
||||||
modifiedData
|
modifiedData
|
||||||
}),
|
}),
|
||||||
listInstances: () => api.get('/frpcAct/instanceMgr/list'),
|
listInstances: () => api.get('/frpcAct/instanceMgr/list'),
|
||||||
startInstance: (instanceName) =>
|
startInstance: (instanceID) =>
|
||||||
api.post('/frpcAct/instanceMgr/start', { instanceName }),
|
api.post('/frpcAct/instanceMgr/start', { instanceID }),
|
||||||
stopInstance: (instanceName) =>
|
stopInstance: (instanceID) =>
|
||||||
api.post('/frpcAct/instanceMgr/stop', { instanceName }),
|
api.post('/frpcAct/instanceMgr/stop', { instanceID }),
|
||||||
restartInstance: (instanceName) =>
|
restartInstance: (instanceID) =>
|
||||||
api.post('/frpcAct/instanceMgr/restart', { instanceName }),
|
api.post('/frpcAct/instanceMgr/restart', { instanceID }),
|
||||||
getInstanceLogs: (instanceName) =>
|
getInstanceStatus: (instanceID) =>
|
||||||
api.get('/frpcAct/instanceMgr/logs', { params: { instanceName } }),
|
api.post('/frpcAct/instanceMgr/status', { instanceID }),
|
||||||
|
getInstanceLogs: (instanceID) =>
|
||||||
|
api.post('/frpcAct/instanceMgr/logs', { instanceID }),
|
||||||
getInstanceProxies: (instanceID) =>
|
getInstanceProxies: (instanceID) =>
|
||||||
api.get('/frpcAct/proxyMgr/list', { params: { instanceID } }),
|
api.get(`/frpcAct/proxyMgr/list?instanceID=${instanceID}`),
|
||||||
createProxy: (instanceID, proxyInfo) =>
|
createProxy: (instanceID, proxyInfo) =>
|
||||||
api.post('/frpcAct/proxyMgr/create', { instanceID, proxyInfo })
|
api.post('/frpcAct/proxyMgr/create', { instanceID, proxyInfo })
|
||||||
};
|
};
|
||||||
|
|
||||||
export const logApi = {
|
export const logApi = {
|
||||||
getLogs: (level) => api.get('/logMgr/list', { params: { level } })
|
getLogs: (level) => api.post('/logMgr/list', { level })
|
||||||
};
|
};
|
||||||
|
|
||||||
export const monitorApi = {
|
export const monitorApi = {
|
||||||
@@ -106,9 +107,6 @@ export const systemInfoApi = {
|
|||||||
export default api;
|
export default api;
|
||||||
|
|
||||||
export const TODO_API_NOTES = {
|
export const TODO_API_NOTES = {
|
||||||
instanceStart: 'TODO: /frpcAct/instanceMgr/start - 启动实例 API 未在 api-backend.md 中定义',
|
|
||||||
instanceStop: 'TODO: /frpcAct/instanceMgr/stop - 停止实例 API 未在 api-backend.md 中定义',
|
|
||||||
instanceRestart: 'TODO: /frpcAct/instanceMgr/restart - 重启实例 API 未在 api-backend.md 中定义',
|
|
||||||
instanceLogs: 'TODO: /frpcAct/instanceMgr/logs - 获取实例日志 API 未在 api-backend.md 中定义',
|
instanceLogs: 'TODO: /frpcAct/instanceMgr/logs - 获取实例日志 API 未在 api-backend.md 中定义',
|
||||||
instanceProxies: 'TODO: /frpcAct/instanceMgr/proxies - 获取实例代理列表 API 未在 api-backend.md 中定义',
|
instanceProxies: 'TODO: /frpcAct/instanceMgr/proxies - 获取实例代理列表 API 未在 api-backend.md 中定义',
|
||||||
logList: 'TODO: /logMgr/list - 获取系统日志 API 未在 api-backend.md 中定义',
|
logList: 'TODO: /logMgr/list - 获取系统日志 API 未在 api-backend.md 中定义',
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export default {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
checkStatus();
|
checkStatus();
|
||||||
getSoftwareInfo();
|
getSoftwareInfo();
|
||||||
setInterval(checkStatus, 5000);
|
setInterval(checkStatus, 60000);
|
||||||
document.addEventListener('click', closeMenu);
|
document.addEventListener('click', closeMenu);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const routes = [
|
|||||||
component: () => import('../views/Instances.vue')
|
component: () => import('../views/Instances.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'instances/:name',
|
path: 'instances/:id',
|
||||||
name: 'InstanceDetail',
|
name: 'InstanceDetail',
|
||||||
component: () => import('../views/InstanceDetail.vue')
|
component: () => import('../views/InstanceDetail.vue')
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,10 +4,53 @@
|
|||||||
<button class="common-btn" @click="goBack">
|
<button class="common-btn" @click="goBack">
|
||||||
<i class="fas fa-arrow-left"></i> Back
|
<i class="fas fa-arrow-left"></i> Back
|
||||||
</button>
|
</button>
|
||||||
<h2>{{ instanceName }} - Details</h2>
|
<h2>{{ instanceID }} - Details</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detail-content">
|
<div class="detail-content">
|
||||||
|
<div class="section">
|
||||||
|
<h3>Instance Status
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button
|
||||||
|
v-if="userType !== 'visitor' && instanceStatus === 'running'"
|
||||||
|
class="common-btn restart-btn"
|
||||||
|
@click="restartInstance"
|
||||||
|
>
|
||||||
|
<i class="fas fa-redo"></i> Restart
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="userType !== 'visitor'"
|
||||||
|
class="common-btn status-btn"
|
||||||
|
:class="instanceStatus === 'running' ? 'stop-btn' : 'start-btn'"
|
||||||
|
@click="handleStatusClick"
|
||||||
|
>
|
||||||
|
<i :class="['fas', instanceStatus === 'running' ? 'fa-stop' : 'fa-play']"></i>
|
||||||
|
{{ instanceStatus === 'running' ? 'Stop' : 'Start' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
<div class="status-list">
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-key">Status:</span>
|
||||||
|
<span :class="['status-value', instanceStatus]">
|
||||||
|
{{ instanceStatus === 'running' ? 'Running' : 'Stopped' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item" v-if="instanceStatus === 'running' && statusInfo.pid">
|
||||||
|
<span class="status-key">PID:</span>
|
||||||
|
<span class="status-value">{{ statusInfo.pid }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item" v-if="statusInfo.initSystem">
|
||||||
|
<span class="status-key">Init System:</span>
|
||||||
|
<span class="status-value">{{ statusInfo.initSystem }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-item" v-if="statusInfo.serviceName">
|
||||||
|
<span class="status-key">Service Name:</span>
|
||||||
|
<span class="status-value">{{ statusInfo.serviceName }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h3>Configuration
|
<h3>Configuration
|
||||||
<button class="common-btn" @click="editConfig">
|
<button class="common-btn" @click="editConfig">
|
||||||
@@ -233,21 +276,23 @@
|
|||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { instanceApi } from '../api/index.js';
|
import { instanceApi } from '../api/index.js';
|
||||||
import { showNotification, formatDate } from '../utils/functions.js';
|
import { showNotification, formatDate, getCookie } from '../utils/functions.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InstanceDetail',
|
name: 'InstanceDetail',
|
||||||
setup() {
|
setup() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const instanceName = ref(route.params.name);
|
const instanceID = ref(route.params.id);
|
||||||
const instanceID = ref('');
|
|
||||||
const instanceConfig = ref({});
|
const instanceConfig = ref({});
|
||||||
const proxies = ref([]);
|
const proxies = ref([]);
|
||||||
const logs = ref([]);
|
const logs = ref([]);
|
||||||
|
const instanceStatus = ref('stopped');
|
||||||
|
const statusInfo = ref({});
|
||||||
const showEditConfigModal = ref(false);
|
const showEditConfigModal = ref(false);
|
||||||
const showAddProxyModal = ref(false);
|
const showAddProxyModal = ref(false);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const userType = ref(getCookie('user-type') || 'visitor');
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
name: '',
|
name: '',
|
||||||
auth_method: 'token',
|
auth_method: 'token',
|
||||||
@@ -265,9 +310,8 @@ export default {
|
|||||||
const loadInstanceConfig = async () => {
|
const loadInstanceConfig = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await instanceApi.listInstances();
|
const result = await instanceApi.listInstances();
|
||||||
const instance = result.data.find(i => i.name === instanceName.value);
|
const instance = result.data.find(i => String(i.instanceID) === instanceID.value);
|
||||||
if (instance) {
|
if (instance) {
|
||||||
instanceID.value = String(instance.instanceID);
|
|
||||||
instanceConfig.value = {
|
instanceConfig.value = {
|
||||||
'Server Address': instance.serverAddr,
|
'Server Address': instance.serverAddr,
|
||||||
'Server Port': instance.serverPort,
|
'Server Port': instance.serverPort,
|
||||||
@@ -283,6 +327,54 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadInstanceStatus = async () => {
|
||||||
|
try {
|
||||||
|
const result = await instanceApi.getInstanceStatus(instanceID.value);
|
||||||
|
instanceStatus.value = result.data.status;
|
||||||
|
statusInfo.value = result.data;
|
||||||
|
} catch (error) {
|
||||||
|
showNotification('Load instance status failed', 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const startInstance = async () => {
|
||||||
|
try {
|
||||||
|
await instanceApi.startInstance(instanceID.value);
|
||||||
|
showNotification('Instance started successfully', 'success');
|
||||||
|
await loadInstanceStatus();
|
||||||
|
} catch (error) {
|
||||||
|
showNotification(error.message || 'Start instance failed', 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopInstance = async () => {
|
||||||
|
try {
|
||||||
|
await instanceApi.stopInstance(instanceID.value);
|
||||||
|
showNotification('Instance stopped successfully', 'success');
|
||||||
|
await loadInstanceStatus();
|
||||||
|
} catch (error) {
|
||||||
|
showNotification(error.message || 'Stop instance failed', 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const restartInstance = async () => {
|
||||||
|
try {
|
||||||
|
await instanceApi.restartInstance(instanceID.value);
|
||||||
|
showNotification('Instance restarted successfully', 'success');
|
||||||
|
await loadInstanceStatus();
|
||||||
|
} catch (error) {
|
||||||
|
showNotification(error.message || 'Restart instance failed', 'error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleStatusClick = async () => {
|
||||||
|
if (instanceStatus.value === 'running') {
|
||||||
|
await stopInstance();
|
||||||
|
} else {
|
||||||
|
await startInstance();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const loadProxies = async () => {
|
const loadProxies = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await instanceApi.getInstanceProxies(instanceID.value);
|
const result = await instanceApi.getInstanceProxies(instanceID.value);
|
||||||
@@ -301,7 +393,7 @@ export default {
|
|||||||
|
|
||||||
const loadLogs = async () => {
|
const loadLogs = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await instanceApi.getInstanceLogs(instanceName.value);
|
const result = await instanceApi.getInstanceLogs(instanceID.value);
|
||||||
logs.value = result.data.map(log => ({
|
logs.value = result.data.map(log => ({
|
||||||
time: formatDate(log.timestamp),
|
time: formatDate(log.timestamp),
|
||||||
level: log.level,
|
level: log.level,
|
||||||
@@ -318,10 +410,8 @@ export default {
|
|||||||
|
|
||||||
const editConfig = async () => {
|
const editConfig = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await instanceApi.listInstances();
|
const instance = instanceID.value;
|
||||||
const instance = result.data.find(i => i.name === instanceName.value);
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
instanceID.value = String(instance.instanceID);
|
|
||||||
formData.value = {
|
formData.value = {
|
||||||
name: instance.name,
|
name: instance.name,
|
||||||
auth_method: instance.auth_method || 'token',
|
auth_method: instance.auth_method || 'token',
|
||||||
@@ -365,7 +455,6 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
await instanceApi.modifyInstance(
|
await instanceApi.modifyInstance(
|
||||||
instanceName.value,
|
|
||||||
instanceID.value,
|
instanceID.value,
|
||||||
'systemConfig',
|
'systemConfig',
|
||||||
systemConfigData
|
systemConfigData
|
||||||
@@ -387,7 +476,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await instanceApi.modifyInstance(
|
await instanceApi.modifyInstance(
|
||||||
instanceName.value,
|
|
||||||
instanceID.value,
|
instanceID.value,
|
||||||
'configFile',
|
'configFile',
|
||||||
configFileData
|
configFileData
|
||||||
@@ -397,7 +485,6 @@ export default {
|
|||||||
closeEditConfigModal();
|
closeEditConfigModal();
|
||||||
closeAddProxyModal();
|
closeAddProxyModal();
|
||||||
// 重新加载配置
|
// 重新加载配置
|
||||||
instanceName.value = formData.value.name;
|
|
||||||
await loadInstanceConfig();
|
await loadInstanceConfig();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showNotification(error.message || 'Save configuration failed', 'error');
|
showNotification(error.message || 'Save configuration failed', 'error');
|
||||||
@@ -431,15 +518,19 @@ export default {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadInstanceConfig();
|
await loadInstanceConfig();
|
||||||
|
await loadInstanceStatus();
|
||||||
await loadProxies();
|
await loadProxies();
|
||||||
await loadLogs();
|
await loadLogs();
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
instanceName,
|
instanceID,
|
||||||
instanceConfig,
|
instanceConfig,
|
||||||
proxies,
|
proxies,
|
||||||
logs,
|
logs,
|
||||||
|
instanceStatus,
|
||||||
|
statusInfo,
|
||||||
|
userType,
|
||||||
showEditConfigModal,
|
showEditConfigModal,
|
||||||
showAddProxyModal,
|
showAddProxyModal,
|
||||||
loading,
|
loading,
|
||||||
@@ -450,7 +541,9 @@ export default {
|
|||||||
addProxy,
|
addProxy,
|
||||||
closeAddProxyModal,
|
closeAddProxyModal,
|
||||||
handleEditConfiguration,
|
handleEditConfiguration,
|
||||||
handleAddProxySubmit
|
handleAddProxySubmit,
|
||||||
|
handleStatusClick,
|
||||||
|
restartInstance
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -643,4 +736,94 @@ export default {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section h3 .action-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-item {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-key {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-weight: 500;
|
||||||
|
min-width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value {
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value.running {
|
||||||
|
color: #52c41a;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-value.stopped {
|
||||||
|
color: #ff4d4f;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-btn.status-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #52c41a;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-btn.status-btn:hover {
|
||||||
|
background: #40a412;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-btn.stop-btn {
|
||||||
|
background: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-btn.stop-btn:hover {
|
||||||
|
background: #cf1616;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-btn.restart-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #1890ff;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.common-btn.restart-btn:hover {
|
||||||
|
background: #096dd9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-btn i,
|
||||||
|
.restart-btn i {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
<div class="instances-grid">
|
<div class="instances-grid">
|
||||||
<div
|
<div
|
||||||
v-for="instance in filteredInstances"
|
v-for="instance in filteredInstances"
|
||||||
:key="instance.name"
|
:key="instance.instanceID"
|
||||||
class="instance-card"
|
class="instance-card"
|
||||||
@click="goToDetail(instance.name)"
|
@click="goToDetail(instance.instanceID)"
|
||||||
>
|
>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="instance-name">{{ highlightText(instance.name, searchQuery) }}</h3>
|
<h3 class="instance-name">{{ highlightText(instance.name, searchQuery) }}</h3>
|
||||||
@@ -35,18 +35,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-footer" @click.stop>
|
<div class="card-footer" @click.stop>
|
||||||
<button
|
<button
|
||||||
v-if="instance.status !== 'running'"
|
v-if="userType !== 'visitor' && instance.status !== 'running'"
|
||||||
class="action-btn start-btn"
|
class="action-btn start-btn"
|
||||||
@click="startInstance(instance.name)"
|
@click="startInstance(instance.instanceID)"
|
||||||
>
|
>
|
||||||
Start
|
<i class="fas fa-play"></i> Start
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-if="userType !== 'visitor' && instance.status === 'running'"
|
||||||
class="action-btn stop-btn"
|
class="action-btn stop-btn"
|
||||||
@click="stopInstance(instance.name)"
|
@click="stopInstance(instance.instanceID)"
|
||||||
>
|
>
|
||||||
Stop
|
<i class="fas fa-stop"></i> Stop
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { instanceApi } from '../api/index.js';
|
import { instanceApi } from '../api/index.js';
|
||||||
import { showNotification, formatDate, highlightText } from '../utils/functions.js';
|
import { showNotification, formatDate, highlightText, getCookie } from '../utils/functions.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Instances',
|
name: 'Instances',
|
||||||
@@ -179,6 +179,7 @@ export default {
|
|||||||
const instances = ref([]);
|
const instances = ref([]);
|
||||||
const showAddModal = ref(false);
|
const showAddModal = ref(false);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const userType = ref(getCookie('user-type') || 'visitor');
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
name: '',
|
name: '',
|
||||||
auth_method: 'token',
|
auth_method: 'token',
|
||||||
@@ -207,14 +208,23 @@ export default {
|
|||||||
...instance,
|
...instance,
|
||||||
status: 'stopped'
|
status: 'stopped'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
for (const instance of instances.value) {
|
||||||
|
try {
|
||||||
|
const statusResult = await instanceApi.getInstanceStatus(String(instance.instanceID));
|
||||||
|
instance.status = statusResult.data.status;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to load status for instance ${instance.instanceID}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showNotification('Load instance list failed', 'error');
|
showNotification('Load instance list failed', 'error');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const startInstance = async (instanceName) => {
|
const startInstance = async (instanceID) => {
|
||||||
try {
|
try {
|
||||||
await instanceApi.startInstance(instanceName);
|
await instanceApi.startInstance(instanceID);
|
||||||
showNotification('Instance started successfully', 'success');
|
showNotification('Instance started successfully', 'success');
|
||||||
await loadInstances();
|
await loadInstances();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -222,9 +232,9 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopInstance = async (instanceName) => {
|
const stopInstance = async (instanceID) => {
|
||||||
try {
|
try {
|
||||||
await instanceApi.stopInstance(instanceName);
|
await instanceApi.stopInstance(instanceID);
|
||||||
showNotification('Instance stopped successfully', 'success');
|
showNotification('Instance stopped successfully', 'success');
|
||||||
await loadInstances();
|
await loadInstances();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -232,8 +242,8 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const goToDetail = (instanceName) => {
|
const goToDetail = (instanceID) => {
|
||||||
router.push(`/instances/${instanceName}`);
|
router.push(`/instances/${instanceID}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddInstance = async () => {
|
const handleAddInstance = async () => {
|
||||||
@@ -297,6 +307,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
instances,
|
instances,
|
||||||
filteredInstances,
|
filteredInstances,
|
||||||
|
userType,
|
||||||
startInstance,
|
startInstance,
|
||||||
stopInstance,
|
stopInstance,
|
||||||
goToDetail,
|
goToDetail,
|
||||||
|
|||||||
Reference in New Issue
Block a user