修改页面渲染

This commit is contained in:
zyj
2025-11-22 17:48:41 +08:00
parent ec3fc77403
commit 1f5eccb7f7
7 changed files with 641 additions and 61 deletions

View File

@@ -129,8 +129,8 @@
v-else
:columns="columns"
:data-source="hostingSites"
:pagination="{ pageSize: 10, showSizeChanger: true, showTotal: (total) => `共 ${total} 个站点` }"
:scroll="{ x: 800 }"
:pagination="{ pageSize: 10, showSizeChanger: true, showTotal: (total: number) => `共 ${total} 个站点` }"
:scroll="{ x: 1050 }"
class="hosting-table"
>
<template #bodyCell="{ column, record }">
@@ -251,8 +251,12 @@
</a-col>
</a-row>
<a-form-item label="网站路径" name="path">
<a-input v-model:value="formData.path" disabled />
<a-form-item label="网站路径" name="path" :rules="[{ required: true, message: '请输入网站路径' }]">
<a-input v-model:value="formData.path" placeholder="相对路径,如: www/example.com" />
<div class="form-tip">
<info-circle-outlined />
<span>相对于项目根目录的路径</span>
</div>
</a-form-item>
<a-form-item label="启用状态">
@@ -309,7 +313,7 @@ const formRef = ref();
const formData = ref({
name: '',
domains: ['127.0.0.1'],
port: 80,
port: 8080,
path: '',
index: 'index.html',
enabled: true
@@ -320,29 +324,31 @@ const columns = [
{
title: '网站',
key: 'site',
width: '25%',
width: 280,
ellipsis: true,
},
{
title: '域名',
key: 'domain',
width: '25%',
width: 250,
ellipsis: true,
},
{
title: '端口',
key: 'port',
width: '10%',
width: 100,
align: 'center',
},
{
title: '状态',
key: 'status',
width: '10%',
width: 100,
align: 'center',
},
{
title: '操作',
key: 'action',
width: '30%',
width: 320,
align: 'center',
fixed: 'right',
},
@@ -357,10 +363,22 @@ onMounted(() => {
const loadData = async () => {
await Promise.all([
getAvailableSites(),
getHostingSites()
getHostingSites(),
checkNginxStatus()
]);
};
const checkNginxStatus = async () => {
try {
const status = await App.CheckNginxStatus();
nginxRunning.value = status;
console.log("Nginx running status:", status);
} catch (error) {
console.error('获取 Nginx 状态失败:', error);
}
};
// 获取可用网站列表(已下载的)
const getAvailableSites = async () => {
try {
@@ -375,19 +393,8 @@ const getAvailableSites = async () => {
const getHostingSites = async () => {
loading.value = true;
try {
// TODO: 调用后端接口获取托管列表
// 暂时使用模拟数据
hostingSites.value = [
{
id: '1',
name: 'example.com',
path: '/www/example.com',
domains: ['example.com', '127.0.0.1'],
port: 80,
index: 'index.html',
enabled: true,
},
];
const sites = await App.GetAllNginxSites();
hostingSites.value = sites || [];
} catch (error) {
console.error('获取托管列表失败:', error);
message.error('获取托管列表失败');
@@ -408,13 +415,13 @@ const toggleNginx = async () => {
try {
if (nginxRunning.value) {
// TODO: 调用后端接口停止 Nginx
await new Promise(resolve => setTimeout(resolve, 1000));
await App.StopNginx();
nginxRunning.value = false;
uptime.value = '--';
message.success('Nginx 已停止');
} else {
// TODO: 调用后端接口启动 Nginx
await new Promise(resolve => setTimeout(resolve, 1000));
await App.StartNginx();
nginxRunning.value = true;
uptime.value = '00:00:00';
message.success('Nginx 已启动');
@@ -432,7 +439,7 @@ const showAddModal = () => {
formData.value = {
name: '',
domains: ['127.0.0.1'],
port: 80,
port: 8080,
path: '',
index: 'index.html',
enabled: true
@@ -451,8 +458,9 @@ const editSite = (record: any) => {
const onSiteSelect = (value: string) => {
const site = availableSites.value.find(s => s.name === value);
if (site) {
formData.value.path = `/www/${value}`;
formData.value.domains = [value];
// 设置网站路径(从工作目录)
formData.value.path = `www/${value}`;
formData.value.domains = [value, '127.0.0.1'];
}
};
@@ -462,24 +470,44 @@ const handleModalOk = async () => {
await formRef.value?.validate();
if (editingRecord.value) {
// 更新
const index = hostingSites.value.findIndex(s => s.id === editingRecord.value.id);
if (index !== -1) {
hostingSites.value[index] = { ...formData.value, id: editingRecord.value.id };
}
// 更新站点配置
await App.UpdateNginxSite({
ID: "",
Name: formData.value.name,
Domains: formData.value.domains,
Port: formData.value.port,
Path: formData.value.path,
Index: formData.value.index,
Enabled: formData.value.enabled
});
message.success('更新成功');
} else {
// 添加
hostingSites.value.push({
...formData.value,
id: Date.now().toString()
// 添加站点配置
await App.AddNginxSite({
ID: "",
Name: formData.value.name,
Domains: formData.value.domains,
Port: formData.value.port,
Path: formData.value.path,
Index: formData.value.index,
Enabled: formData.value.enabled
});
message.success('添加成功');
message.success('站点配置创建成功');
}
// 重新加载站点列表
await getHostingSites();
// 如果 nginx 正在运行,重载配置
if (nginxRunning.value) {
await App.ReloadNginx();
message.info('Nginx 配置已重载');
}
modalVisible.value = false;
} catch (error) {
console.error('验证失败:', error);
} catch (error: any) {
console.error('操作失败:', error);
message.error(error.message || '操作失败');
}
};
@@ -489,16 +517,44 @@ const handleModalCancel = () => {
};
// 切换站点状态
const toggleSiteStatus = (record: any) => {
message.success(record.enabled ? '已启用' : '已禁用');
const toggleSiteStatus = async (record: any) => {
try {
if (record.enabled) {
await App.EnableNginxSite(record.name);
message.success('站点已启用');
} else {
await App.DisableNginxSite(record.name);
message.success('站点已禁用');
}
// 如果 nginx 正在运行,重载配置
if (nginxRunning.value) {
await App.ReloadNginx();
}
} catch (error: any) {
console.error('切换状态失败:', error);
message.error(error.message || '操作失败');
// 回滚状态
record.enabled = !record.enabled;
}
};
// 删除站点
const deleteSite = (record: any) => {
const index = hostingSites.value.findIndex(s => s.id === record.id);
if (index !== -1) {
hostingSites.value.splice(index, 1);
message.success('删除成功');
const deleteSite = async (record: any) => {
try {
await App.DeleteNginxSite(record.name);
message.success('站点配置已删除');
// 重新加载站点列表
await getHostingSites();
// 如果 nginx 正在运行,重载配置
if (nginxRunning.value) {
await App.ReloadNginx();
}
} catch (error: any) {
console.error('删除失败:', error);
message.error(error.message || '删除失败');
}
};
@@ -727,6 +783,7 @@ const getAvatarColor = (name: string) => {
font-weight: 600;
color: #333;
border-bottom: 2px solid #1890ff;
padding: 16px;
}
:deep(.hosting-table .ant-table-tbody > tr) {
@@ -737,15 +794,22 @@ const getAvatarColor = (name: string) => {
background: #e6f7ff !important;
}
:deep(.hosting-table .ant-table-tbody > tr > td) {
padding: 16px;
border-bottom: 1px solid #f0f0f0;
}
.site-cell {
display: flex;
align-items: center;
gap: 12px;
max-width: 100%;
}
.site-details {
flex: 1;
min-width: 0;
overflow: hidden;
}
.site-name {
@@ -753,6 +817,10 @@ const getAvatarColor = (name: string) => {
font-weight: 600;
color: #333;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.site-path {
@@ -761,12 +829,22 @@ const getAvatarColor = (name: string) => {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.domain-cell {
display: flex;
flex-wrap: wrap;
gap: 4px;
max-width: 100%;
overflow: hidden;
}
.domain-cell :deep(.ant-tag) {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 加载和空状态 */

View File

@@ -61,7 +61,7 @@
:columns="columns"
:loading="loading"
:pagination="paginationConfig"
:scroll="{ x: 800 }"
:scroll="{ x: 950 }"
class="custom-table"
>
<template #bodyCell="{ column, record, index }">
@@ -167,33 +167,33 @@ const columns = [
title: '站点名称',
dataIndex: 'name',
key: 'name',
width: '35%',
width: 300,
ellipsis: true,
},
{
title: '文件大小',
dataIndex: 'size',
key: 'size',
width: '15%',
width: 130,
sorter: (a, b) => a.size - b.size,
},
{
title: '权限',
dataIndex: 'mode',
key: 'mode',
width: '15%',
width: 120,
},
{
title: '最后修改时间',
key: 'modTime',
dataIndex: 'modTime',
width: '20%',
width: 180,
sorter: (a, b) => new Date(a.modTime) - new Date(b.modTime),
},
{
title: '操作',
key: 'action',
width: '15%',
width: 220,
fixed: 'right',
},
]
@@ -455,6 +455,11 @@ onMounted(() => {
animation: fadeInUp 0.6s ease-out 0.2s both;
}
:deep(.table-card .ant-card-body) {
padding: 0;
overflow: hidden;
}
:deep(.table-card .ant-card-head) {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-bottom: 2px solid #f0f0f0;
@@ -505,6 +510,9 @@ onMounted(() => {
:deep(.custom-table .ant-table-tbody > tr > td) {
padding: 16px;
border-bottom: 1px solid #f0f0f0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 名称单元格 */
@@ -512,11 +520,13 @@ onMounted(() => {
display: flex;
align-items: center;
gap: 12px;
max-width: 100%;
}
.name-info {
flex: 1;
min-width: 0;
overflow: hidden;
}
.site-name {
@@ -527,6 +537,7 @@ onMounted(() => {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.site-path {
@@ -535,6 +546,7 @@ onMounted(() => {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
/* 大小标签 */