7b0cfe4448
Split the login page into smaller reusable components for branding, toolbar, header, form, announcements, and mobile layout behavior. This keeps the view responsible for orchestration while moving UI sections into focused components. Update page creation docs to reflect the simplified flow where views render sections/items directly and composables coordinate store/service access when needed.refactor(login): compose page from focused login components Split the login page into smaller reusable components for branding, toolbar, header, form, announcements, and mobile layout behavior. This keeps the view responsible for orchestration while moving UI sections into focused components. Update page creation docs to reflect the simplified flow where views render sections/items directly and composables coordinate store/service access when needed.
186 lines
8.9 KiB
Markdown
186 lines
8.9 KiB
Markdown
# LLM 開發操作指南
|
||
|
||
## 文件目的
|
||
|
||
本專案是給其他 Vue/Vuetify 專案使用的 template。LLM 協助修改時,預設應在 `src` 底下依分層規則新增或修改頁面、元件、store、service 與 composable。
|
||
|
||
本文件只保留全域操作順序與導覽。各層細節規範放在 `src/**/GUIDE.md`,避免重複維護。
|
||
|
||
## 建議閱讀順序
|
||
|
||
1. `src/GUIDE.md`
|
||
2. `docs/architecture-strategy.md`
|
||
3. 依 `maintenanceContract.pageKind` 閱讀對應的 demo 與 `src/**/GUIDE.md`(查 `docs/architecture-strategy.md` 的分層說明)
|
||
4. `docs/add-page-example.md`(需要新增頁面時)
|
||
|
||
`frontend-layering.md` 是歷史參考,後續以 `docs/architecture-strategy.md` 與 `src/**/GUIDE.md` 為準。
|
||
|
||
## GUIDE 索引
|
||
|
||
| 範圍 | 指南 |
|
||
|------|------|
|
||
| `src` 總覽、資料流、template core、demo 邊界 | `src/GUIDE.md` |
|
||
| route view 與薄 view 規則 | `src/views/GUIDE.md` |
|
||
| maintenance demo view | `src/views/maint/GUIDE.md` |
|
||
| Vue component 分層 | `src/components/GUIDE.md` |
|
||
| base 元件 | `src/components/base/GUIDE.md` |
|
||
| section 元件 | `src/components/sections/GUIDE.md` |
|
||
| layout 邊界 | `src/components/layouts/GUIDE.md` |
|
||
| page driver、command、layout composable | `src/composables/GUIDE.md` |
|
||
| route 與 guard | `src/router/GUIDE.md` |
|
||
| AppShell、tabs、global overlays | `src/shell/GUIDE.md` |
|
||
| Pinia store | `src/stores/GUIDE.md` |
|
||
| HTTP service / ky / API module | `src/services/GUIDE.md` |
|
||
| domain model 與 page model 型別 | `src/models/GUIDE.md` |
|
||
| 跨模組共用 API 型別 | `src/types/GUIDE.md` |
|
||
| i18n 文案 | `src/language/GUIDE.md` |
|
||
|
||
## 預設修改策略
|
||
|
||
一般功能需求優先修改:
|
||
|
||
- `src/views/*`
|
||
- `src/components/sections/*`
|
||
- `src/components/items/*`
|
||
- `src/composables/page-drivers/*`
|
||
- `src/composables/commands/*`
|
||
- `src/stores/*`
|
||
- `src/services/modules/*`
|
||
- `src/router/routes.ts`
|
||
- `src/language/*.json`
|
||
|
||
除非使用者明確要求,避免先修改 template core。template core 清單與 demo/example 邊界見 `src/GUIDE.md`。
|
||
|
||
## 常用判斷
|
||
|
||
- 新 route:讀 `src/router/GUIDE.md`。
|
||
- 一般頁面:讀 `src/views/GUIDE.md`、`src/components/GUIDE.md`、`src/composables/GUIDE.md`。
|
||
- 維護頁:讀 `src/views/maint/GUIDE.md`。
|
||
- 查詢/列表頁(篩選 + 表格):讀 `src/components/sections/GUIDE.md`(`SectionQueryPage`)。
|
||
- 申請/填寫頁(送出按鈕):讀 `src/components/sections/GUIDE.md`(`SectionFormPage`)。
|
||
- layout / AppShell / tabs / global overlay:讀 `src/shell/GUIDE.md` 與 `src/components/layouts/GUIDE.md`。
|
||
- API 串接:讀 `src/services/GUIDE.md`。
|
||
- 跨頁共享狀態:讀 `src/stores/GUIDE.md`。
|
||
- 定義 page model 或 domain model 型別:讀 `src/models/GUIDE.md`。
|
||
- 共用 API 型別定義:讀 `src/types/GUIDE.md`。
|
||
- 錯誤頁:讀 `src/views/GUIDE.md`(ErrorShell 模式)與 `src/router/GUIDE.md`(錯誤頁路由慣例)。
|
||
- 語系文案:讀 `src/language/GUIDE.md`。
|
||
|
||
## 修改前檢查
|
||
|
||
- 是否碰到 template core。
|
||
- 是否已有同類型範例可沿用。
|
||
- 是否需要新增 route。
|
||
- 是否應拆成 section / item。
|
||
- 是否應新增 page driver 或 command composable。
|
||
- 是否需要 store,或只需要頁面內 state。
|
||
- 是否應定義新的 model 型別(`src/models/`)。
|
||
- 是否需要更新語系、menu、breadcrumb、favorites。
|
||
|
||
## 從視覺特徵選擇 section 元件
|
||
|
||
當收到 prototype 截圖或設計稿時,依畫面特徵選擇 section 外殼:
|
||
|
||
| 特徵 | 選擇 |
|
||
|------|------|
|
||
| 有「送出/存檔」按鈕,且畫面為填寫表單(欄位 + 配合事項 + 動作按鈕) | `SectionFormPage` |
|
||
| 有「查詢」按鈕,且畫面為篩選條件 + 結果表格/列表 | `SectionQueryPage` |
|
||
| 純粹表格列表(無送出/查詢按鈕,只有 CRUD 操作) | 不用 section 外殼,直接組合 `v-data-table` |
|
||
| 混合結構(有查詢也有表單填寫) | 評估是否拆成兩頁;若必須同頁,不用通用外殼 |
|
||
|
||
判斷順序:先看有無「送出/存檔」→ 再看有無「查詢」→ 其餘視為一般列表頁。
|
||
|
||
## `.spec.json` 對照指南
|
||
|
||
當 LLM 依照 `GEN-FE-PROMPT` 讀取 `.ht/spec/{page}.spec.json` 後,依 `maintenanceContract.pageKind` 決定對應的 demo 與 composable 界面,再將 `.spec.json` 的 evidence 欄位對應到 composable 的 reactive state、computed 與 API calls。
|
||
|
||
### query(查詢頁)→ `SectionQueryPage`
|
||
|
||
參考:`src/views/demos/SectionQueryPageDemo.vue`、`src/composables/page-drivers/useSectionsDemoPage.ts`
|
||
|
||
架構:
|
||
```
|
||
View(自含 page model + UI) → SectionQueryPage
|
||
↓
|
||
composable (page driver)
|
||
```
|
||
|
||
**composable 必須回傳:**
|
||
|
||
| 名稱 | 型別 | 對應 `.spec.json` 來源 |
|
||
|------|------|------------------------|
|
||
| `queryFilters` | `Ref<{ 每個欄位 }>` | `pageContract.forms[0].fields` — 每個 field 建一個 key,型別依 `field.type`(text→string, select→string \| null,選項取自 `field.options`) |
|
||
| `pageModel` | `ComputedRef<{ title, ... }>` | `title` 來自 `pageContract.title`;`backLabel` 固定為 `'返回'` |
|
||
| `handleQuerySearch()` | 函式 | 觸發 `apiContract.endpoints` 中 `usage=search` 的 API call;呼叫時機對應 `bddContract.scenarios` 中 `type=query` 的 When |
|
||
| `handleQueryBack()` | 函式 | 對應 `pageContract.actions` 中 `actionType=back` |
|
||
| 表格資料 | 在 `pageModel` 中 | `tables[].headers` 對應表格欄;`sampleRows` 對應欄位格式 |
|
||
|
||
**page component props:**
|
||
- `v-model:query-filters` — 雙向綁定 `queryFilters`
|
||
- `:page` — 傳入 `pageModel`
|
||
|
||
**page component emits:**
|
||
- `@search` → 呼叫 `handleQuerySearch`
|
||
- `@back` → 呼叫 `handleQueryBack`
|
||
|
||
### application(申請/表單頁)→ `SectionFormPage`
|
||
|
||
參考:`src/views/demos/SectionFormPageDemo.vue`
|
||
|
||
架構:
|
||
```
|
||
View(自含 page model + UI) → SectionFormPage
|
||
↓
|
||
composable (page driver)
|
||
```
|
||
|
||
**composable 必須回傳:**
|
||
|
||
| 名稱 | 型別 | 對應 `.spec.json` 來源 |
|
||
|------|------|------------------------|
|
||
| `demoForm`(應改名為 `formState`) | `Ref<{ 每個欄位 }>` | `pageContract.forms[0].fields` — text/select 建 key;不可編輯的 `readonly` 欄位不放進 formState,改從 `pageModel` 單向顯示 |
|
||
| `pageModel` | `ComputedRef` | `title` 來自 `pageContract.title` |
|
||
| `handleFormSubmit()` | 函式 | 觸發 `apiContract.endpoints` 中 `usage=create` 的 POST endpoint;呼叫前驗證 `apiCatalog.fieldRules`;呼叫時機對應 `bddContract.scenarios` 中 `type=application-submit` 的 When/Then |
|
||
| `resetDemoForm()`(改為 `resetForm`) | 函式 | 對應 `pageContract.actions` 中 `actionType=reset` |
|
||
| `handleFormBack()` | 函式 | 對應 `actionType=back` |
|
||
|
||
**提交 payload 規則:**
|
||
- `apiCatalog.fieldRules` 中的 `field` 與 `rule` 決定必填、長度、格式驗證
|
||
- 型別轉換依 `field.type`:number 欄位不可包成 string 送出
|
||
|
||
### maintenance(維護/CRUD 頁)→ `maint/*`
|
||
|
||
參考:`src/views/maint/README.md` — 依資料結構選擇最接近的範本(EditableGrid / SingleRecord / MasterDetail A/B/C)
|
||
|
||
**composable 必須回傳:**
|
||
|
||
| 名稱 | 對應 `.spec.json` 來源 |
|
||
|------|------------------------|
|
||
| `search filters` | `pageContract.forms[0].fields` |
|
||
| `table data / headers` | `pageContract.tables[].headers` + search API response |
|
||
| `row action handlers` | `maintenanceContract.rowActions` — 每個 action 對應一個 handler;`enabledWhen` 決定啟用條件(如 `aprvYn === 'Z'` 時才能修改) |
|
||
| `create/update/delete calls` | `apiContract.endpoints` 中對應的 POST/PUT/DELETE |
|
||
|
||
**row action 狀態規則:**
|
||
- `enabledWhen` 直接轉為 template 中的 `:disabled` 或 `v-if` 條件
|
||
- `maintenanceContract.businessRules` 中的額外限制一併套用
|
||
|
||
### 通用規則
|
||
|
||
**entity 命名:** 所有 composable、component、store 的名稱以 `maintenanceContract.dataModel.primaryEntity` 為 entity 名,例如 primaryEntity=`FacilityApply` → `useFacilityApplyPage.ts` → `PageFacilityApply.vue`。
|
||
|
||
**API 串接:** 在 `src/services/modules/` 新增對應 entity 的 API module,method 名稱對齊 `apiContract.endpoints[].usage`(search/create/update/delete/print),path 對齊 `endpoint.path`。
|
||
|
||
**錯誤處理:** 檢查 `apiContract.errorHandling.format` — 若為 `ProblemDetailsWithValidationErrors`,須處理 `errors` 物件中的逐欄錯誤訊息;若為 `ProblemDetails`,只顯示 `detail`。
|
||
|
||
**語系文案:** 欄位 label 與按鈕文字取自 `pageContract.forms[].fields[].label` 和 `pageContract.actions[].label`,放入 `src/language/` 對應語系 key。
|
||
|
||
## 完成前驗證
|
||
|
||
- Vue / TypeScript 結構有變更:`pnpm -s type-check`
|
||
- 需要確認產物可建置:`pnpm -s build`
|
||
- Markdown 或大量搬移:`git diff --check`
|
||
- route、layout 或主要畫面流程有變更:啟動 dev server 並用瀏覽器確認,除非使用者明確不需要。
|
||
|
||
如果無法執行驗證,回報原因,不要宣稱已驗證。
|