初始化

This commit is contained in:
2026-03-05 21:27:11 +08:00
commit 130de0fd5d
140 changed files with 21972 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
# Vue Page — 页面模板与 Store
> 主流程见 SKILL.md本文档为列表页/详情页/路由/Pinia/Provider 的完整实现。
>
> **⚠️ 双前端区分**:本文件中使用 `el-*` 组件的模板**仅适用于管理端** (`Case-Database-Frontend-admin/`)。
> 用户端 (`Case-Database-Frontend-user/`) 使用 Headless UI + Tailwind CSS**禁止引入 Element Plus**。
## 列表页模板
```vue
<script setup>
import { useTable } from '@/hooks/useTable'
document.title = '{{PageTitle}} - {{AppName}}'
const { loading, dataList, pagination, loadData } = useTable((params) => {{resource}}Api.list(params))
const searchForm = reactive({ keyword: '', status: '' })
function handleSearch() { pagination.current = 1; loadData() }
onMounted(() => loadData())
</script>
<template>
<div class="p-4 space-y-4">
<el-card><el-form :model="searchForm" inline>...</el-form></el-card>
<el-card>
<template #header><span>{{PageTitle}}</span><el-button @click="handleCreate">新增</el-button></template>
<el-table v-loading="loading" :data="dataList" border stripe>...</el-table>
<el-pagination v-model:current-page="pagination.current" ... @current-change="loadData" />
</el-card>
</div>
</template>
```
## 详情页模板
使用 useRoute/useRouterfetchDetail 加载数据el-skeleton 加载态el-page-header + el-descriptions。
## 路由配置
```typescript
const routes = [
{ path: '/{{module}}/{{route-path}}', name: '{{RouteName}}', component: () => import('@/views/...'), meta: { title, requiresAuth: true, permission } },
{ path: '/{{module}}/{{route-path}}/:id', name: '{{RouteName}}Detail', ... }
]
```
## Pinia Store — List 与 Detail 分离
ListItem 类型:轻量,排除大文本/复杂对象/大数组。Detail 类型完整字段。Storelist (array)、detailMap (Record<id, Detail>)、loadingDetailIds、getDetail(id)、isDetailLoading(id)、fetchList、fetchDetail有缓存则返回、invalidateDetail、invalidateAll。
## 页面级 Provider 模式
当 ≥3 个子组件共享状态时provider.vue provide 状态+actionskeys.ts 定义 PAGE_KEY + usePageContext子组件 inject。文件结构index.vue、provider.vue、keys.ts、components/SearchBar/DataTable/BatchActions、composables/usePageData。
## 动态路由 (RBAC)
loadDynamicRoutesmenuStore.fetchMenus()router.addRoute('layout', { path, name, component: () => import(...), meta })。