Files
cma-management/frontend/src/views/MapList.vue
T

160 lines
6.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<div style="display:flex;justify-content:space-between;margin-bottom:16px;">
<h3>战略地图</h3>
<div>
<button class="map-btn map-btn-danger" :disabled="selectedIds.length === 0" @click="batchDelete">批量删除{{ selectedIds.length }}</button>
<el-button type="primary" @click="showForm=true;form={}">新建地图</el-button>
</div>
</div>
<el-table :data="maps" style="width:100%" @selection-change="onSelectionChange">
<el-table-column type="selection" width="40" />
<el-table-column prop="title" label="地图名称" min-width="200" />
<el-table-column prop="version" label="版本" width="80" />
<el-table-column prop="status" label="状态" width="80">
<template #default="{ row }">{{ row.status === "published" ? "已发布" : "草稿" }}</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" width="180" />
<el-table-column label="操作" width="250">
<template #default="{ row }">
<el-button size="small" @click='goCanvas(row.id)'>画布</el-button>
<el-button size="small" @click='editMap(row)'>编辑</el-button>
<el-button size="small" @click='goVersion(row.id)'>版本</el-button>
<el-button size="small" type="danger" @click="deleteMap(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新建/编辑弹窗内联v-show -->
<div v-show="showForm" class="map-form-overlay" @click.self="showForm=false">
<div class="map-form-dialog">
<div class="map-form-header">
<span>{{ editingMap ? '编辑地图' : '新建战略地图' }}</span>
<button class="map-form-close" @click="showForm=false">×</button>
</div>
<div class="map-form-body">
<div class="map-form-field">
<label>地图名称</label>
<input v-model="form.title" class="map-input" placeholder="请输入地图名称" />
</div>
<div class="map-form-field">
<label>版本号</label>
<input v-model="form.version" class="map-input" placeholder="v1.0" />
</div>
<div class="map-form-field" v-if="!editingMap">
<label>创建方式</label>
<div class="map-radio-group">
<label class="map-radio"><input type="radio" v-model="createMode" value="blank" /> 空白地图</label>
<label class="map-radio"><input type="radio" v-model="createMode" value="template" /> 快速模板4维度+预设目标</label>
</div>
</div>
</div>
<div class="map-form-footer">
<button class="map-btn" @click="showForm=false">取消</button>
<button class="map-btn map-btn-primary" @click="saveMap">保存</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue"
import { useRouter } from "vue-router"
import { ElMessage, ElMessageBox } from "element-plus"
import { mapApi } from "../api/index"
const router = useRouter()
const maps = ref<any[]>([])
const showForm = ref(false)
const editingMap = ref<any>(null)
const form = ref<any>({})
const createMode = ref("blank")
const selectedIds = ref<number[]>([])
function onSelectionChange(rows: any[]) {
selectedIds.value = rows.map(r => r.id)
}
async function batchDelete() {
if (selectedIds.value.length === 0) return
try {
const r: any = await mapApi.batchDelete(selectedIds.value)
ElMessage.success(r?.message || `已删除 ${selectedIds.value.length} 个地图`)
selectedIds.value = []
load()
} catch (e: any) {
ElMessage.error("批量删除失败: " + (e?.response?.data?.detail || e?.message || "未知错误"))
}
}
async function load() {
try { const r: any = await mapApi.list(); maps.value = r.data || [] } catch (e) {}
}
function goCanvas(id: number) { router.push('/maps/canvas/' + id) }
function goVersion(id: number) { router.push('/maps/versions/' + id) }
async function saveMap() {
try {
if (editingMap.value) {
await mapApi.update(editingMap.value.id, form.value)
ElMessage.success("已更新")
} else if (createMode.value === "template") {
await mapApi.createWithTemplate ? await mapApi.createWithTemplate(form.value) : await mapApi.create(form.value)
ElMessage.success("模板地图已创建")
} else {
await mapApi.create(form.value)
ElMessage.success("创建成功")
}
showForm.value = false
editingMap.value = null
load()
} catch (e) {
ElMessage.error("操作失败")
}
}
function editMap(map: any) {
editingMap.value = map
form.value = { title: map.title, version: map.version }
showForm.value = true
}
function handleClick(path: string) { window.location.href = path }
async function deleteMap(map: any) {
try {
await ElMessageBox.confirm(`确定删除「${map.title}」?`)
await mapApi.delete ? await mapApi.delete(map.id) : ElMessage.warning("当前API不支持删除")
ElMessage.success("已删除")
load()
} catch (e: any) {
if (e !== "cancel") ElMessage.error("删除失败")
}
}
onMounted(load)
</script>
<style scoped>
.map-form-overlay { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.5); z-index:9999; display:flex; align-items:center; justify-content:center; }
.map-form-dialog { background:#fff; border-radius:12px; width:520px; box-shadow:0 8px 32px rgba(0,0,0,0.18); overflow:hidden; }
.map-form-header { display:flex; justify-content:space-between; align-items:center; padding:16px 20px; border-bottom:1px solid #f0f0f0; font-weight:600; font-size:16px; }
.map-form-close { background:none; border:none; font-size:22px; color:#999; cursor:pointer; padding:0 4px; }
.map-form-close:hover { color:#333; }
.map-form-body { padding:20px; }
.map-form-field { margin-bottom:16px; }
.map-form-field label { display:block; font-size:13px; color:#666; margin-bottom:6px; font-weight:500; }
.map-input { width:100%; padding:8px 12px; border:1px solid #dcdfe6; border-radius:6px; font-size:14px; outline:none; box-sizing:border-box; }
.map-input:focus { border-color:#409eff; }
.map-radio-group { display:flex; flex-direction:column; gap:8px; }
.map-radio { display:inline-flex; align-items:center; gap:4px; font-size:13px; color:#666; cursor:pointer; }
.map-radio input { margin:0; }
.map-form-footer { display:flex; justify-content:flex-end; gap:10px; padding:12px 20px; border-top:1px solid #f0f0f0; }
.map-btn { padding:8px 20px; border:1px solid #dcdfe6; border-radius:6px; background:#fff; color:#333; font-size:14px; cursor:pointer; }
.map-btn-primary { background:#409eff; color:#fff; border-color:#409eff; }
.map-btn-danger { background:#f56c6c; color:#fff; border-color:#f56c6c; }
.map-btn:disabled { opacity:0.5; cursor:not-allowed; }
.map-btn:hover:not(:disabled) { opacity:0.85; }
</style>