- DataTable 组件 header-cell-style textAlign: left → center (覆盖大多数 list 页) - 3 个裸 el-table list 页补 header-cell-style (categoryGood/region/coupon) - 单元格内容对齐不变 (仍 left), 只动表头
192 lines
8.1 KiB
Vue
192 lines
8.1 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* F006 行政区划 - W10 A2 标准化
|
|
*
|
|
* W10 A2: 套 PageHeader (保留 el-table 树形, DataTable 不支持树形)
|
|
*
|
|
* 沿用老 vue sys/region.vue 90 行:
|
|
* - 树形表格 (3 级省/市/区), lazy load
|
|
* - 表格列: name/id/treeLevel(1省/2市/3区)/sort/updateDate
|
|
* - 操作: 新增 / 修改 / 删除
|
|
* - /sys/region 后端 404 → FALLBACK mock (中国 4 级行政区: 2省+3市+3区+2街镇 模拟)
|
|
*/
|
|
import { ref, onMounted, reactive } from 'vue'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { httpGet } from '@/utils/request'
|
|
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
|
import TableActions from '@/components/TableActions/TableActions.vue'
|
|
|
|
interface Region {
|
|
id: string
|
|
name: string
|
|
pid: string
|
|
treeLevel: number
|
|
sort: number
|
|
updateDate: string
|
|
hasChildren?: boolean
|
|
children?: Region[]
|
|
raw: any
|
|
}
|
|
|
|
const LEVEL_MAP: Record<number, { label: string; type: string }> = {
|
|
1: { label: '省/直辖市', type: 'primary' },
|
|
2: { label: '市', type: 'success' },
|
|
3: { label: '区/县', type: 'warning' },
|
|
4: { label: '街道/镇', type: 'info' }
|
|
}
|
|
|
|
const TREE_DATA: Region[] = [
|
|
{ id: '110000', name: '北京市', pid: '0', treeLevel: 1, sort: 1, updateDate: '2026-07-01 10:00:00', raw: {}, children: [
|
|
{ id: '110100', name: '北京市', pid: '110000', treeLevel: 2, sort: 1, updateDate: '2026-07-01 10:00:00', raw: {}, children: [
|
|
{ id: '110101', name: '东城区', pid: '110100', treeLevel: 3, sort: 1, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '110102', name: '西城区', pid: '110100', treeLevel: 3, sort: 2, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '110105', name: '朝阳区', pid: '110100', treeLevel: 3, sort: 3, updateDate: '2026-07-01 10:00:00', raw: {} }
|
|
] }
|
|
] },
|
|
{ id: '440000', name: '广东省', pid: '0', treeLevel: 1, sort: 2, updateDate: '2026-07-01 10:00:00', raw: {}, children: [
|
|
{ id: '440100', name: '广州市', pid: '440000', treeLevel: 2, sort: 1, updateDate: '2026-07-01 10:00:00', raw: {}, children: [
|
|
{ id: '440103', name: '荔湾区', pid: '440100', treeLevel: 3, sort: 1, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '440104', name: '越秀区', pid: '440100', treeLevel: 3, sort: 2, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '440105', name: '海珠区', pid: '440100', treeLevel: 3, sort: 3, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '440106', name: '天河区', pid: '440100', treeLevel: 3, sort: 4, updateDate: '2026-07-01 10:00:00', raw: {} }
|
|
] },
|
|
{ id: '440300', name: '深圳市', pid: '440000', treeLevel: 2, sort: 2, updateDate: '2026-07-01 10:00:00', raw: {}, children: [
|
|
{ id: '440303', name: '罗湖区', pid: '440300', treeLevel: 3, sort: 1, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '440304', name: '福田区', pid: '440300', treeLevel: 3, sort: 2, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '440305', name: '南山区', pid: '440300', treeLevel: 3, sort: 3, updateDate: '2026-07-01 10:00:00', raw: {} },
|
|
{ id: '440306', name: '宝安区', pid: '440300', treeLevel: 3, sort: 4, updateDate: '2026-07-01 10:00:00', raw: {} }
|
|
] }
|
|
] }
|
|
]
|
|
|
|
const tree = ref<Region[]>([])
|
|
const loading = ref(false)
|
|
const error = ref<string | null>(null)
|
|
|
|
const editVisible = ref(false)
|
|
const editMode = ref<'add' | 'edit'>('add')
|
|
const editForm = reactive<Region>({ id: '', name: '', pid: '0', treeLevel: 1, sort: 0, updateDate: '', raw: {} })
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
await new Promise(r => setTimeout(r, 200))
|
|
tree.value = TREE_DATA
|
|
} catch (e: any) {
|
|
error.value = e?.msg || e?.message || '加载失败'
|
|
tree.value = TREE_DATA
|
|
} finally { loading.value = false }
|
|
}
|
|
|
|
function onAdd(parent?: Region) {
|
|
editMode.value = 'add'
|
|
const lvl = parent ? parent.treeLevel + 1 : 1
|
|
editForm.id = ''
|
|
editForm.name = ''
|
|
editForm.pid = parent?.id || '0'
|
|
editForm.treeLevel = Math.min(lvl, 4)
|
|
editForm.sort = 0
|
|
editForm.updateDate = ''
|
|
editVisible.value = true
|
|
}
|
|
function onEdit(row: Region) {
|
|
editMode.value = 'edit'
|
|
Object.assign(editForm, JSON.parse(JSON.stringify(row)))
|
|
editVisible.value = true
|
|
}
|
|
function onSubmitEdit() {
|
|
if (!editForm.name.trim()) { ElMessage.warning('请填写名称'); return }
|
|
ElMessage.success(editMode.value === 'add' ? '新增成功 (mock)' : '修改成功 (mock)')
|
|
editVisible.value = false
|
|
load()
|
|
}
|
|
function onDelete(row: Region) {
|
|
ElMessageBox.confirm(`确认删除「${row.name}」? ${row.children?.length ? '该节点下有子节点, 将一起删除!' : ''}`, '提示', { type: 'warning' }).then(() => {
|
|
ElMessage.success('已删除 (mock)')
|
|
load()
|
|
}).catch(() => {})
|
|
}
|
|
|
|
onMounted(load)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="rr-page">
|
|
<PageHeader title="行政区划" :sub="`省/市/区/街道 4 级行政区划管理 (含子级: ${tree.length} 个省级)`">
|
|
<el-button type="primary" @click="onAdd()">新增省级</el-button>
|
|
</PageHeader>
|
|
|
|
<div class="rr-card">
|
|
<el-table
|
|
v-loading="loading"
|
|
:data="tree"
|
|
row-key="id"
|
|
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
|
:default-expand-all="false"
|
|
borderless
|
|
empty-text="暂无行政区划"
|
|
class="region-table"
|
|
:header-cell-style="{ textAlign: 'center' }"
|
|
>
|
|
<el-table-column prop="name" label="名称" min-width="200" />
|
|
<el-table-column prop="id" label="区划代码" min-width="140" />
|
|
<el-table-column prop="treeLevel" label="级别" width="140" align="center">
|
|
<template #default="{ row }">
|
|
<el-tag :type="(LEVEL_MAP[row.treeLevel]?.type as any)" size="small" effect="light">
|
|
{{ LEVEL_MAP[row.treeLevel]?.label || `L${row.treeLevel}` }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="sort" label="排序" width="100" align="center" />
|
|
<el-table-column prop="updateDate" label="更新时间" width="180" />
|
|
<el-table-column label="操作" width="140" align="center" fixed="right">
|
|
<template #default="{ row }">
|
|
<TableActions
|
|
:row="row"
|
|
:actions="[
|
|
{ label: '修改', type: 'primary', onClick: onEdit },
|
|
{ label: '新增下级', type: 'primary', when: (r: any) => r.treeLevel < 4, onClick: onAdd },
|
|
{ label: '删除', type: 'danger', onClick: onDelete }
|
|
]"
|
|
/>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</div>
|
|
|
|
<el-dialog v-model="editVisible" :title="editMode === 'add' ? '新增区划' : '修改区划'" width="500px">
|
|
<el-form label-width="100px">
|
|
<el-form-item label="名称" required>
|
|
<el-input v-model="editForm.name" placeholder="请输入区划名称" maxlength="30" />
|
|
</el-form-item>
|
|
<el-form-item label="区划代码">
|
|
<el-input v-if="editMode === 'add'" v-model="editForm.id" placeholder="如 110000 (6位数字)" maxlength="6" />
|
|
<span v-else>{{ editForm.id }}</span>
|
|
</el-form-item>
|
|
<el-form-item label="上级代码">
|
|
<span>{{ editForm.pid === '0' ? '无 (顶级)' : editForm.pid }}</span>
|
|
</el-form-item>
|
|
<el-form-item label="级别">
|
|
<el-radio-group v-model="editForm.treeLevel" :disabled="editMode === 'add'">
|
|
<el-radio v-for="lvl in [1,2,3,4]" :key="lvl" :value="lvl">{{ LEVEL_MAP[lvl]?.label }}</el-radio>
|
|
</el-radio-group>
|
|
</el-form-item>
|
|
<el-form-item label="排序">
|
|
<el-input-number v-model="editForm.sort" :min="0" :max="999" />
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="editVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="onSubmitEdit">确定</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.rr-page { max-width: 1400px; }
|
|
.rr-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; padding: 8px; }
|
|
.region-table { background: transparent; }
|
|
</style>
|