feat: 更新 EditableGrid 元件以支持分頁功能並改善顯示資訊
This commit is contained in:
@@ -1,16 +1,41 @@
|
||||
# 1. 強制檢查 Node 版本
|
||||
engine-strict=true
|
||||
# 指定下載來源
|
||||
registry=https://registry.npmjs.org/
|
||||
|
||||
# 2. 自動安裝 Peer Dependencies
|
||||
auto-install-peers=true
|
||||
|
||||
# 3. 提升特定套件 (選配)
|
||||
# 如果遇到某些舊套件找不到 Vue 或 Vuetify,開啟這個可以模擬 npm 的扁平化結構
|
||||
# shamefully-hoist=true
|
||||
|
||||
# 4. 鎖定版本 (如果您希望版本極度穩定)
|
||||
# 自動儲存精確版本號 (不帶 ^ 或 ~),避免版本漂移
|
||||
# save-exact=true
|
||||
|
||||
# 5. 針對 WSL 的優化 (選配)
|
||||
# 如果您在 WSL 存取 Windows 磁碟區(如 /mnt/c)時遇到權限問題,可以開啟
|
||||
# node-linker=hoisted
|
||||
# 安全防禦:禁止安裝發布未滿 7 天的套件 (預防供應鏈攻擊)
|
||||
# npm v11.10+
|
||||
min-release-age=7
|
||||
# pnpm
|
||||
minimum-release-age=10080
|
||||
|
||||
# 嚴格版本檢查:若 Node 或 pnpm 版本不符 package.json 定義則報錯
|
||||
# engine-strict=true
|
||||
|
||||
# 讓 pnpm 自動安裝缺失的 peer dependencies,減少手動維護的負擔
|
||||
auto-install-peers=true
|
||||
|
||||
# 效能優化:讓 pnpm 盡可能解析出唯一的依賴版本
|
||||
resolution-mode=highest
|
||||
|
||||
# ==========================================
|
||||
# 團隊協作規範
|
||||
# ==========================================
|
||||
# 當 Lockfile 有變動但未對應安裝時,在 CI 環境直接報錯
|
||||
# frozen-lockfile=true
|
||||
|
||||
# ==========================================
|
||||
# Monorepo 結構與依賴管理
|
||||
# ==========================================
|
||||
# 強制使用 workspace: 協議,確保子專案互相引用時是指向原始碼而非 npm 上的版本
|
||||
# save-workspace-protocol=true
|
||||
|
||||
# 禁止子專案之間出現循環依賴,避免構建時陷入死循環
|
||||
# disallow-workspace-cycles=true
|
||||
|
||||
# 從根目錄解析 peerDependencies,確保全專案的 peer 依賴版本統一,減少重複打包
|
||||
# resolve-peers-from-workspace-root=true
|
||||
|
||||
# 執行遞迴指令 (pnpm -r) 時包含根目錄 (適用於根目錄有腳本或工具時)
|
||||
# include-workspace-root=true
|
||||
|
||||
@@ -85,15 +85,16 @@
|
||||
|
||||
<div ref="tableContainerRef">
|
||||
<v-data-table
|
||||
v-model:page="currentPage"
|
||||
class="student-table"
|
||||
density="comfortable"
|
||||
fixed-header
|
||||
:headers="tableHeaders"
|
||||
:height="tableHeight"
|
||||
hide-default-footer
|
||||
item-value="id"
|
||||
:items="filteredStudents"
|
||||
:items-per-page="10"
|
||||
items-per-page-text="每頁筆數"
|
||||
page-text="第 {0}-{1} 筆 / 共 {2} 筆"
|
||||
:items-per-page="itemsPerPage"
|
||||
>
|
||||
<template #[`header.select`]>
|
||||
<v-checkbox-btn
|
||||
@@ -295,6 +296,48 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
<template #bottom>
|
||||
<div class="d-flex align-center justify-space-between px-4 py-3">
|
||||
<div class="text-body-2 text-medium-emphasis">
|
||||
{{ pageSummary }}
|
||||
</div>
|
||||
<div class="d-flex align-center ga-2">
|
||||
<v-btn
|
||||
:disabled="currentPage <= 1"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="currentPage = 1"
|
||||
>
|
||||
第一頁
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:disabled="currentPage <= 1"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="currentPage -= 1"
|
||||
>
|
||||
上一頁
|
||||
</v-btn>
|
||||
<span class="text-body-2">{{ currentPage }} / {{ pageCount }}</span>
|
||||
<v-btn
|
||||
:disabled="currentPage >= pageCount"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="currentPage += 1"
|
||||
>
|
||||
下一頁
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:disabled="currentPage >= pageCount"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="currentPage = pageCount"
|
||||
>
|
||||
最後頁
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
</v-card-text>
|
||||
@@ -330,7 +373,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { mdiContentSave, mdiDelete, mdiMagnify, mdiRestore } from '@mdi/js'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import ConfirmDialog from '@/components/maint/CommonConfirmDialog.vue'
|
||||
import { useEditableStudentGrid } from '@/composables/maint/useEditableStudentGrid'
|
||||
|
||||
@@ -360,6 +403,18 @@ const {
|
||||
resetAllRows,
|
||||
} = useEditableStudentGrid()
|
||||
|
||||
const itemsPerPage = 10
|
||||
const currentPage = ref(1)
|
||||
const pageCount = computed(() => Math.max(1, Math.ceil(filteredStudents.value.length / itemsPerPage)))
|
||||
const pageSummary = computed(() => {
|
||||
const total = filteredStudents.value.length
|
||||
if (total === 0) return '第 0-0 筆 / 共 0 筆'
|
||||
|
||||
const start = (currentPage.value - 1) * itemsPerPage + 1
|
||||
const end = Math.min(currentPage.value * itemsPerPage, total)
|
||||
return `第 ${start}-${end} 筆 / 共 ${total} 筆`
|
||||
})
|
||||
|
||||
const confirmDeleteSingleVisible = ref(false)
|
||||
const confirmDeleteSelectedVisible = ref(false)
|
||||
const confirmSaveVisible = ref(false)
|
||||
@@ -383,6 +438,12 @@ const selectedDeleteMessage = computed(
|
||||
`確定要刪除目前選取的 ${selectedRowIds.value.length} 筆資料嗎?此操作會在儲存後正式生效。`
|
||||
)
|
||||
|
||||
watch(pageCount, (value) => {
|
||||
if (currentPage.value > value) {
|
||||
currentPage.value = value
|
||||
}
|
||||
})
|
||||
|
||||
function requestDeleteSingleRow(id: number) {
|
||||
pendingDeleteRowId.value = id
|
||||
confirmDeleteSingleVisible.value = true
|
||||
@@ -427,8 +488,4 @@ function confirmSaveAllRows() {
|
||||
padding-bottom: 0 !important;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
:deep(.v-data-table-footer) {
|
||||
padding: 4px 0 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
"composite": true,
|
||||
"rootDir": ".",
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
|
||||
Reference in New Issue
Block a user