2.9 KiB
2.9 KiB
description, globs
| description | globs | |||
|---|---|---|---|---|
| 后台页面(列表/表单/详情)开发范式 —— 新增或修改 views 下页面时必读 |
|
页面开发范式
标准列表页结构
一个规范的列表页自上而下固定为四段:
<template>
<div class="app-container">
<!-- 1. 搜索栏:el-form inline + 查询/重置 -->
<!-- 2. 工具栏:新增 / 批量删除 / 导入导出 -->
<!-- 3. 表格:el-table + 操作列 -->
<!-- 4. 分页:el-pagination -->
</div>
</template>
- 搜索栏支持回车查询与"重置"重置到初始查询条件。
- 表格必须
v-loading="loading"、border、操作列fixed="right"。 - 分页器
layout="total, sizes, prev, pager, next, jumper",与queryParams.pageNum/pageSize双向联动。 - 查询条件与分页状态变更时用
watch或统一handleQuery重新拉取,禁止在模板里调用接口。
标准数据流
const loading = ref(false)
const total = ref(0)
const list = ref<UserVO[]>([])
const queryParams = reactive<UserQuery>({ pageNum: 1, pageSize: 10 })
async function handleQuery() {
loading.value = true
try {
const { list: rows, total: t } = await UserAPI.query(queryParams)
list.value = rows
total.value = t
} finally {
loading.value = false // loading 必须在 finally 里关闭
}
}
onMounted(handleQuery)
- 请求失败由
request拦截器统一提示,页面只负责数据与 loading;确需额外处理时才catch。 loading必须放在finally关闭,避免异常时永久转圈。
表单弹窗
- 弹窗组件独立文件,父组件通过
ref+defineExpose({ open })调用:<UserForm ref="formRef" @submit="handleQuery" /> - 弹窗内部:
el-dialog+el-form,必须有ref、rules、:model;关闭时resetFields()并清空隐藏主键。 - 提交按钮在请求期间设置
confirmLoading,防止重复提交。 - 新增与编辑复用同一弹窗,通过是否有
id区分,标题用 computed 切换。
删除与危险操作
- 删除必须走
ElMessageBox.confirm二次确认,成功后ElMessage.success+ 刷新列表。 - 若当前页删完且非第一页,需回退
pageNum再查询。
表单校验
- 规则写在
rules常量里(const rules = reactive<FormRules<UserForm>>({...})),不在模板内联。 - 提交前必须
await formRef.value.validate(),校验失败直接返回。 - 后端返回字段级错误需映射到
formRef对应字段。
页面内复用
- 仅当前页面使用的子组件放
views/{module}/components/,不要放进全局src/components/。 - 跨页面复用的逻辑抽成
useXxx组合式函数,放src/composables/。 - 字典/枚举下拉数据统一走 Pinia 的字典 store 缓存,不得每次打开弹窗都重新请求。