refactor: 统一四页面交互模式(列表全宽→编辑双栏)

This commit is contained in:
mediabot-pt
2026-07-05 21:15:46 +08:00
parent 91bd6e6aeb
commit 4d928ead51
3 changed files with 190 additions and 268 deletions

View File

@@ -1,5 +1,6 @@
<template>
<div style="display:flex;flex-direction:column;height:calc(100vh - 80px)">
<!-- 列表模式 -->
<div v-if="!editSiteId">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">
<div style="display:flex;align-items:center;gap:12px">
<h2 style="margin:0">站点列表</h2>
@@ -9,53 +10,62 @@
</div>
<div style="display:flex;gap:8px">
<el-button size="small" @click="refresh" :loading="loading">刷新</el-button>
<el-button size="small" @click="newSite">新建</el-button>
<el-button size="small" type="primary" @click="saveSite" :loading="saving" v-if="editSiteId">保存</el-button>
<el-button size="small" type="primary" @click="newSite">新建站点</el-button>
</div>
</div>
<el-table :data="sites" stripe v-loading="loading" border empty-text="暂无站点" style="font-size:13px" :row-style="{height:'44px'}">
<el-table-column prop="siteId" label="站点ID" width="110" />
<el-table-column label="名称" min-width="130">
<template #default="s">{{ (s.row.names||[]).join(' / ') || '-' }}</template>
</el-table-column>
<el-table-column label="地址" min-width="180" show-overflow-tooltip>
<template #default="s">{{ (s.row.urls||[]).join(' / ') }}</template>
</el-table-column>
<el-table-column prop="siteType" label="类型" width="100" />
<el-table-column label="状态" width="80">
<template #default="s">
<el-tag size="small" :type="s.row.status==='active'?'success':'info'">{{ s.row.status||'active' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="适配" width="90">
<template #default="s">
<el-tag v-if="s.row.latestVersion" size="small" type="primary">v{{ s.row.latestVersion }}</el-tag>
<span v-else style="color:#909399">-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="s">
<el-button size="small" @click="editSite(s.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 编辑模式:全屏双栏 -->
<div v-else style="display:flex;flex-direction:column;height:calc(100vh - 80px)">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">
<h2 style="margin:0">站点编辑: {{ editSiteId }}</h2>
<div style="display:flex;gap:8px">
<el-button size="small" type="primary" @click="saveSite" :loading="saving">保存</el-button>
<el-button size="small" @click="editSiteId=''">返回列表</el-button>
</div>
</div>
<div style="display:flex;gap:12px;flex:1;min-height:0">
<!-- 左侧:编辑器(当前选中站点) -->
<div style="flex:0 0 420px;display:flex;flex-direction:column;min-height:0">
<div style="font-size:13px;font-weight:500;margin-bottom:4px;display:flex;justify-content:space-between;align-items:center">
<span>{{ editSiteId ? '编辑: '+editSiteId : '选择站点编辑' }}</span>
</div>
<div style="flex:0 0 400px;display:flex;flex-direction:column;min-height:0">
<div style="font-size:13px;font-weight:500;margin-bottom:4px">JSON 配置</div>
<div style="flex:1;min-height:0;border-radius:4px;overflow:hidden">
<CodeEditor v-model="editorJson" language="json" />
</div>
</div>
<!-- 右侧:所有站点可视化 -->
<div style="flex:1;overflow:auto;min-height:0">
<el-table :data="sites" stripe v-loading="loading" border empty-text="暂无站点"
style="font-size:13px" :row-style="{height:'44px'}" @row-click="editSite" highlight-current-row
:row-class-name="rowClass">
<el-table-column prop="siteId" label="站点ID" width="110" />
<el-table-column label="名称" min-width="130">
<template #default="s">{{ (s.row.names||[]).join(' / ') || '-' }}</template>
</el-table-column>
<el-table-column label="地址" min-width="180" show-overflow-tooltip>
<template #default="s">{{ (s.row.urls||[]).join(' / ') }}</template>
</el-table-column>
<el-table-column prop="siteType" label="类型" width="100" />
<el-table-column label="状态" width="80">
<template #default="s">
<el-tag size="small" :type="s.row.status==='active'?'success':'info'">{{ s.row.status||'active' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="适配" width="90">
<template #default="s">
<el-tag v-if="s.row.latestVersion" size="small" type="primary">v{{ s.row.latestVersion }}</el-tag>
<span v-else style="color:#909399">-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template #default="s">
<el-button size="small" @click.stop="editSite(s.row)">编辑</el-button>
<el-button size="small" type="danger" text @click.stop="deleteSite(s.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div style="font-size:13px;font-weight:500;margin-bottom:8px">预览</div>
<el-form label-width="70px" label-position="left" size="small">
<el-form-item label="站点ID"><span style="font-weight:500">{{ preview.siteId||'-' }}</span></el-form-item>
<el-form-item label="名称"><span>{{ (preview.names||[]).join(' / ') }}</span></el-form-item>
<el-form-item label="地址"><span>{{ (preview.urls||[]).join(' / ') }}</span></el-form-item>
<el-form-item label="类型"><el-tag size="small">{{ preview.siteType }}</el-tag></el-form-item>
<el-form-item label="状态"><el-tag size="small" :type="preview.status==='active'?'success':'info'">{{ preview.status }}</el-tag></el-form-item>
</el-form>
</div>
</div>
</div>
@@ -66,56 +76,37 @@ import api from '../api'
const loading = ref(false), saving = ref(false), pendingCount = ref(0)
const sites = ref([]), editSiteId = ref(''), editorJson = ref('{}')
const rowClass = ({row}) => row.siteId === editSiteId.value ? 'current-row' : ''
const preview = computed(() => { try { return JSON.parse(editorJson.value) } catch { return {} } })
const refresh = async () => {
loading.value = true
try {
const r = await api.raw.get('/admin/sites')
sites.value = Array.isArray(r?.data) ? r.data : r || []
try { pendingCount.value = ((await api.sites.pendingChanges()).data || []).length } catch { pendingCount.value = 0 }
const r = await api.raw.get('/admin/sites'); sites.value = r?.data || r || []
try { pendingCount.value = ((await api.sites.pendingChanges()).data||[]).length } catch { pendingCount.value=0 }
} catch { ElMessage.error('加载失败') }
finally { loading.value = false }
}
const editSite = (row) => {
editSiteId.value = row.siteId
editorJson.value = JSON.stringify({siteId: row.siteId, names: row.names, urls: row.urls, siteType: row.siteType, status: row.status||'active'}, null, 2)
editorJson.value = JSON.stringify({siteId:row.siteId,names:row.names,urls:row.urls,siteType:row.siteType,status:row.status||'active'}, null, 2)
}
const newSite = () => {
editSiteId.value = ''
editSiteId.value = '(新建)'
editorJson.value = JSON.stringify({siteId:'',names:[''],urls:[''],siteType:'nexusphp',status:'active'}, null, 2)
}
const deleteSite = async (row) => {
try { await ElMessageBox.confirm('确认删除 '+row.siteId+' ?','删除',{type:'warning'}) } catch { return }
try {
await api.raw.put('/admin/sites/'+row.siteId, {siteId:row.siteId,names:row.names,urls:row.urls,siteType:row.siteType,status:'deprecated'})
ElMessage.success('已弃用')
refresh()
if (editSiteId.value === row.siteId) editSiteId.value = ''
} catch { ElMessage.error('操作失败') }
}
const saveSite = async () => {
saving.value = true
try {
const site = JSON.parse(editorJson.value)
if (!site.siteId) { ElMessage.warning('siteId不能为空'); return }
await api.raw.put('/admin/sites/'+site.siteId, {
names: site.names||[], urls: site.urls||[], siteType: site.siteType||'unknown', status: site.status||'active',
})
ElMessage.success('已保存')
refresh()
const s = JSON.parse(editorJson.value)
if (!s.siteId) { ElMessage.warning('siteId不能为空'); return }
await api.raw.put('/admin/sites/'+s.siteId, {names:s.names||[],urls:s.urls||[],siteType:s.siteType||'unknown',status:s.status||'active'})
ElMessage.success('已保存'); editSiteId.value = ''; refresh()
} catch { ElMessage.error('保存失败') }
finally { saving.value = false }
}
onMounted(refresh)
</script>
<style scoped>
:deep(.current-row) { background-color: #ecf5ff !important }
</style>