WIP: can hover icon-delete. can have self on the first row on list.
API get all users done
This commit is contained in:
@@ -5,20 +5,31 @@
|
||||
<SearchBar/>
|
||||
</div>
|
||||
<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"
|
||||
<DataTable :value="internalInfiniteAcctData" dataKey="username" tableClass="w-full mt-4 text-sm relative table-fixed"
|
||||
>
|
||||
<Column field="account" :header="i18next.t('AcctMgmt.Account')" bodyClass="font-medium" sortable>
|
||||
<template #body="slotProps">
|
||||
<div class="flex w-full h-full whole-row"
|
||||
:class="{
|
||||
'hover:bg-[#CBD5E1]': slotProps.data.isRowHovered,
|
||||
}"
|
||||
@mouseover="handleRowMouseOver(slotProps.data.username)"
|
||||
@mouseout="handleRowMouseOut(slotProps.data.username)"
|
||||
> <!--處理一整列的互動監聽-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<Column field="username" :header="i18next.t('AcctMgmt.Account')" bodyClass="font-medium" sortable>
|
||||
<template #body="slotProps">
|
||||
<div @dblclick="onAcctDoubleClick()" class="cursor-pointer">
|
||||
{{ slotProps.data.account }}
|
||||
{{ slotProps.data.username }}
|
||||
</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 flex justify-center"
|
||||
<Column field="name" :header="i18next.t('AcctMgmt.FullName')" bodyClass="text-neutral-500" sortable></Column>
|
||||
<Column field="is_admin" :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"
|
||||
<img v-if="slotProps.data.is_admin" 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"
|
||||
@@ -26,24 +37,36 @@
|
||||
/>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="accountActivation" :header="i18next.t('AcctMgmt.AccountActivation')" bodyClass="text-neutral-500"
|
||||
<Column field="is_active" :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-if="slotProps.data.is_active" 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">
|
||||
<Column :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)"/>
|
||||
<img src="@/assets/icon-detail-card.svg" alt="Detail" class="cursor-pointer" @click="onDetailBtnClick(slotProps.data.username)"/>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="edit" :header="i18next.t('AcctMgmt.Edit')" bodyClass="text-neutral-500">
|
||||
<Column :header="i18next.t('AcctMgmt.Edit')" bodyClass="text-neutral-500">
|
||||
<template #body="slotProps">
|
||||
<img src="@/assets/icon-edit.svg" alt="Edit" class="cursor-pointer" @click="onEditBtnClick(slotProps.data.id)"/>
|
||||
</template></Column>
|
||||
<img src="@/assets/icon-edit.svg" alt="Edit" class="cursor-pointer" @click="onEditBtnClick(slotProps.data.username)"/>
|
||||
</template>
|
||||
</Column>
|
||||
<Column :header="i18next.t('AcctMgmt.Delete')" bodyClass="text-neutral-500">
|
||||
<template #body="slotProps">
|
||||
<img :src="slotProps.data.isDeleteHovered ? iconDeleteRed : iconDeleteGray"
|
||||
:alt="slotProps.data.isDeleteHovered ? 'hovered' : 'not-hovered'"
|
||||
class="cursor-pointer"
|
||||
@mouseover="handleDeleteMouseOver(slotProps.data.username)"
|
||||
@mouseout="handleDeleteMouseOut(slotProps.data.username)"
|
||||
@click="onDeleteBtnClick(slotProps.data.username)"
|
||||
>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,10 +74,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed, onBeforeMount, watch, } from 'vue';
|
||||
import { storeToRefs, mapState, mapActions, } from 'pinia';
|
||||
import LoadingStore from '@/stores/loading.js';
|
||||
import { useModalStore } from '@/stores/modal.js';
|
||||
import useAcctMgmtStore from '@/stores/acctMgmt.js';
|
||||
import piniaLoginStore from '@/stores/login.js';
|
||||
import SearchBar from '../../../components/AccountMenu/SearchBar.vue';
|
||||
import i18next from '@/i18n/i18n.js';
|
||||
import {
|
||||
@@ -63,6 +88,8 @@ import {
|
||||
MODAL_ACCT_INFO,
|
||||
accountList,
|
||||
} from "@/constants/constants.js";
|
||||
import iconDeleteGray from '@/assets/icon-delete-gray.svg';
|
||||
import iconDeleteRed from '@/assets/icon-delete-red.svg';
|
||||
|
||||
const ONCE_RENDER_NUM_OF_DATA = 9;
|
||||
|
||||
@@ -81,23 +108,90 @@ function repeatAccountList(accountList, N) {
|
||||
return repeatedList;
|
||||
}
|
||||
|
||||
// 這是製作假資料,在正式環境不會用到
|
||||
const repeatedAccountList = repeatAccountList(accountList, 20);
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
setup(props) {
|
||||
const acctMgmtStore = useAcctMgmtStore();
|
||||
const loadingStore = LoadingStore();
|
||||
const modalStore = useModalStore();
|
||||
const { isLoading } = storeToRefs(loadingStore);
|
||||
const loginStore = piniaLoginStore();
|
||||
const internalInfiniteAcctData = ref([]);
|
||||
|
||||
const loginUserData = ref(null);
|
||||
const allUserAccoutList = computed(() => acctMgmtStore.allUserAccoutList);
|
||||
|
||||
const fetchLoginUserData = async () => {
|
||||
await loginStore.getUserData();
|
||||
loginUserData.value = loginStore.userData;
|
||||
};
|
||||
|
||||
const moveCurrentLoginUserToFirstRow = () => {
|
||||
const currentLoginUsername = loginUserData.value.username;
|
||||
if(internalInfiniteAcctData.value && internalInfiniteAcctData.value.length){
|
||||
const index = internalInfiniteAcctData.value.findIndex(user => user.username === currentLoginUsername);
|
||||
|
||||
if (index !== -1) {
|
||||
// 移除匹配的對象(現正登入的使用者)並將其插入到陣列的第一位"
|
||||
const [user] = internalInfiniteAcctData.value.splice(index, 1);
|
||||
internalInfiniteAcctData.value.unshift(user);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getFirstPageUserData = async() => {
|
||||
await acctMgmtStore.getAllUserAccounts();
|
||||
internalInfiniteAcctData.value = allUserAccoutList.value.slice(0, ONCE_RENDER_NUM_OF_DATA)
|
||||
};
|
||||
|
||||
const handleDeleteMouseOver = (username) => {
|
||||
acctMgmtStore.changeIsDeleteHoveredByUser(username, true);
|
||||
};
|
||||
|
||||
const handleDeleteMouseOut = (username) => {
|
||||
acctMgmtStore.changeIsDeleteHoveredByUser(username, false);
|
||||
};
|
||||
|
||||
const handleRowMouseOver = (username) => {
|
||||
acctMgmtStore.changeIsRowHoveredByUser(username, true);
|
||||
};
|
||||
|
||||
const handleRowMouseOut = (username) => {
|
||||
acctMgmtStore.changeIsRowHoveredByUser(username, false);
|
||||
};
|
||||
|
||||
|
||||
const onDeleteBtnClick = (usernameToDelete) => {
|
||||
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await fetchLoginUserData();
|
||||
await getFirstPageUserData();
|
||||
moveCurrentLoginUserToFirstRow();
|
||||
});
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
modalStore,
|
||||
loginUserData,
|
||||
internalInfiniteAcctData,
|
||||
onDeleteBtnClick,
|
||||
handleDeleteMouseOver,
|
||||
handleDeleteMouseOut,
|
||||
handleRowMouseOver,
|
||||
handleRowMouseOut,
|
||||
iconDeleteGray,
|
||||
iconDeleteRed,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
i18next: i18next,
|
||||
repeatedAccountList: repeatedAccountList,
|
||||
infiniteAcctData: repeatedAccountList.slice(0, ONCE_RENDER_NUM_OF_DATA),
|
||||
infiniteAcctData: [],
|
||||
infiniteStart: 0,
|
||||
isInfiniteFinish: true,
|
||||
isInfinitMaxItemsMet: false,
|
||||
@@ -106,6 +200,9 @@ export default {
|
||||
components: {
|
||||
SearchBar,
|
||||
},
|
||||
computed: {
|
||||
...mapState(useAcctMgmtStore, ['allUserAccoutList']),
|
||||
},
|
||||
methods: {
|
||||
onAcctDoubleClick(){
|
||||
|
||||
@@ -139,25 +236,30 @@ export default {
|
||||
this.infiniteFinish = false;
|
||||
this.infiniteStart += ONCE_RENDER_NUM_OF_DATA;
|
||||
// await this.acctMgmtStore.getAccountDetail();
|
||||
this.infiniteAcctData = await [...this.infiniteAcctData, ...this.repeatedAccountList.slice(
|
||||
this.infiniteAcctData = await [...this.infiniteAcctData, ...this.allUserAccoutList.slice(
|
||||
this.infiniteStart, this.infiniteStart + ONCE_RENDER_NUM_OF_DATA)];
|
||||
this.isInfiniteFinish = true;
|
||||
this.isLoading = false;
|
||||
|
||||
},
|
||||
onDetailBtnClick(dataId){
|
||||
onDetailBtnClick(dataKey){
|
||||
this.openModal(MODAL_ACCT_INFO);
|
||||
this.setCurrentViewingUser(dataId);
|
||||
this.setCurrentViewingUser(dataKey);
|
||||
},
|
||||
onEditBtnClick(dataId){
|
||||
onEditBtnClick(dataKey){
|
||||
this.openModal(MODAL_ACCT_EDIT);
|
||||
this.setCurrentViewingUser(dataId);
|
||||
this.setCurrentViewingUser(dataKey);
|
||||
},
|
||||
moveCurrentLoginUserToFirstRow(){
|
||||
|
||||
},
|
||||
...mapActions(useModalStore, ['openModal']),
|
||||
...mapActions(useAcctMgmtStore, ['setCurrentViewingUser']),
|
||||
...mapActions(useAcctMgmtStore, [
|
||||
'setCurrentViewingUser',
|
||||
'getAllUserAccounts',
|
||||
]),
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.isLoading = false; //TODO:
|
||||
|
||||
Reference in New Issue
Block a user