WIP account mgmt data-table prototype and modal prototype.

This commit is contained in:
Cindy Chang
2024-06-19 15:55:02 +08:00
parent 50c98892c4
commit b7862ab164
9 changed files with 252 additions and 11 deletions

View File

@@ -4,15 +4,46 @@
<div class="flex w-full justify-end py-2">
<SearchBar/>
</div>
<div id="acct_mgmt_data_grid" class="flex w-full">
<DataTable dataKey="id" tableClass="w-full mt-4 text-sm cursor-pointer relative table-fixed"
<div id="acct_mgmt_data_grid" class="flex w-full overflow-y-auto h-[570px]" @scroll="handleScroll">
<DataTable :value="infiniteAcctData" dataKey="id" tableClass="w-full mt-4 text-sm relative table-fixed"
>
<Column field="account" :header="i18next.t('AcctMgmt.Account')" bodyClass="font-medium" sortable></Column>
<Column field="account" :header="i18next.t('AcctMgmt.Account')" bodyClass="font-medium" sortable>
<template #body="slotProps">
<div @dblclick="onAcctDoubleClick()" class="cursor-pointer">
{{ slotProps.data.account }}
</div>
</template>
</Column>
<Column field="fullName" :header="i18next.t('AcctMgmt.FullName')" bodyClass="text-neutral-500" sortable></Column>
<Column field="adminRights" :header="i18next.t('AcctMgmt.AdminRights')" bodyClass="text-neutral-500"></Column>
<Column field="accountActivation" :header="i18next.t('AcctMgmt.AccountActivation')" bodyClass="text-neutral-500"></Column>
<Column field="detail" :header="i18next.t('AcctMgmt.Detail')" bodyClass="text-neutral-500"></Column>
<Column field="edit" :header="i18next.t('AcctMgmt.Edit')" bodyClass="text-neutral-500"></Column>
<Column field="adminRights" :header="i18next.t('AcctMgmt.AdminRights')" bodyClass="text-neutral-500 flex justify-center"
headerClass="header-center">
<template #body="slotProps">
<img v-if="slotProps.data.adminRights" src="@/assets/radioOn.svg" alt="Radio On" class="cursor-pointer flex"
@click="onAdminRightsBtnClick(true)"
/>
<img v-else src="@/assets/radioOff.svg" alt="Radio Off" class="cursor-pointer flex"
@click="onAdminRightsBtnClick(false)"
/>
</template>
</Column>
<Column field="accountActivation" :header="i18next.t('AcctMgmt.AccountActivation')" bodyClass="text-neutral-500"
headerClass="header-center">
<template #body="slotProps">
<div class="w-full flex justify-center">
<img v-if="slotProps.data.accountActivation" src="@/assets/radioOn.svg" alt="Radio On" class="cursor-pointer flex"/>
<img v-else src="@/assets/radioOff.svg" alt="Radio Off" class="cursor-pointer flex"/>
</div>
</template>
</Column>
<Column field="detail" :header="i18next.t('AcctMgmt.Detail')" bodyClass="text-neutral-500">
<template #body="slotProps">
<img src="@/assets/icon-detail-card.svg" alt="Detail" class="cursor-pointer" @click="onDetailBtnClick(slotProps.data.id)"/>
</template>
</Column>
<Column field="edit" :header="i18next.t('AcctMgmt.Edit')" bodyClass="text-neutral-500">
<template #body="slotProps">
<img src="@/assets/icon-edit.svg" alt="Edit" class="cursor-pointer"/>
</template></Column>
</DataTable>
</div>
</div>
@@ -20,28 +51,125 @@
</template>
<script>
import { storeToRefs, mapState, } from 'pinia';
import { storeToRefs, mapState, mapActions, } from 'pinia';
import LoadingStore from '@/stores/loading.js';
import { useModalStore } from '@/stores/modal.js';
import SearchBar from '../../../components/AccountMenu/SearchBar.vue';
import i18next from '@/i18n/i18n.js';
const ONCE_RENDER_NUM_OF_DATA = 9;
function repeatAccountList(accountList, N) {
const repeatedList = [];
for (let i = 0; i < N; i++) {
// 复制每次的对象并将其添加到新数组中
accountList.forEach(account => {
// 创建一个新的对象,避免直接引用
const newAccount = { ...account };
repeatedList.push(newAccount);
});
}
return repeatedList;
}
const accountList = [
{
id: 12345,
account: "REDACTED-USER1",
fullName: "Alice Zheng",
adminRights: true,
accountActivation: true,
detail: "abcde",
},
{
id: 345,
account: "REDACTED-USER2",
fullName: "Mike Chen",
adminRights: true,
accountActivation: true,
detail: "abcde",
},
{
id: 88,
account: "REDACTED-USER3",
fullName: "Tory Cheng",
adminRights: true,
accountActivation: true,
detail: "abcde",
},
];
const repeatedAccountList = repeatAccountList(accountList, 20);
export default {
setup() {
const loadingStore = LoadingStore();
const modalStore = useModalStore();
const { isLoading } = storeToRefs(loadingStore);
return {
isLoading,
modalStore,
};
},
data() {
return {
i18next: i18next,
repeatedAccountList: repeatedAccountList,
infiniteAcctData: repeatedAccountList.slice(0, ONCE_RENDER_NUM_OF_DATA),
infiniteStart: 0,
isInfiniteFinish: true,
isInfinitMaxItemsMet: false,
};
},
components: {
SearchBar,
},
methods: {
onAcctDoubleClick(){
},
onAdminRightsBtnClick(isOn){
},
/**
* 無限滾動: 監聽 scroll 有沒有滾到底部
* @param {element} event 滾動傳入的事件
*/
handleScroll(event) {
if(this.infinitMaxItems || this.infiniteAcctData.length < ONCE_RENDER_NUM_OF_DATA || this.isInfiniteFinish === false) {
return;
}
const container = event.target;
const smallValue = 4;
const overScrollHeight = container.scrollTop + container.clientHeight >= container.scrollHeight - smallValue;
if(overScrollHeight){
this.fetchMoreData();
}
},
/**
* 無限滾動: 滾到底後,要載入數據
*/
async fetchMoreData() {
this.isLoading = true;
this.infiniteFinish = false;
this.infiniteStart += ONCE_RENDER_NUM_OF_DATA;
// await this.acctMgmtStore.getAccountDetail();
this.infiniteAcctData = await [...this.infiniteAcctData, ...this.repeatedAccountList.slice(
this.infiniteStart, this.infiniteStart + ONCE_RENDER_NUM_OF_DATA)];
this.isInfiniteFinish = true;
this.isLoading = false;
},
onDetailBtnClick(dataId){
this.openModal();
},
...mapActions(useModalStore, ['openModal']),
},
created() {
},
@@ -50,3 +178,9 @@ export default {
},
};
</script>
<style>
/*為了讓 radio 按鈕可以置中,所以讓欄位的文字也置中 */
.header-center .p-column-header-content{
justify-content: center;
}
</style>