feature: just create badge. Important thing is the await keyword
This commit is contained in:
4
src/assets/icon-new.svg
Normal file
4
src/assets/icon-new.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="35" height="16" viewBox="0 0 35 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M34.11 14.49L30.19 7.87L34.07 1.52C34.1621 1.36868 34.2124 1.1956 34.2157 1.01848C34.2189 0.841351 34.1751 0.666534 34.0886 0.511912C34.0022 0.35729 33.8762 0.228414 33.7236 0.138469C33.5709 0.0485231 33.3972 0.000737145 33.22 0H2C1.46957 0 0.960859 0.210714 0.585786 0.585787C0.210714 0.96086 0 1.46957 0 2L0 14C0 14.5304 0.210714 15.0391 0.585786 15.4142C0.960859 15.7893 1.46957 16 2 16H33.25C33.4265 16 33.5999 15.9532 33.7524 15.8645C33.905 15.7758 34.0314 15.6483 34.1188 15.4949C34.2061 15.3415 34.2513 15.1678 34.2498 14.9913C34.2482 14.8148 34.2 14.6418 34.11 14.49ZM10.51 11.18H9.39L6.13 6.84V11.19H5V5H6.13L9.4 9.35V5H10.52L10.51 11.18ZM16.84 6H13.31V7.49H16.51V8.49H13.31V10.1H16.84V11.1H12.18V5H16.83L16.84 6ZM25.13 11.16H24L22.45 6.57L20.9 11.18H19.78L17.78 5H19L20.32 9.43L21.84 5H23.06L24.52 9.43L25.85 5H27.08L25.13 11.16Z" fill="#FFCC44"/>
|
||||||
|
<path d="M34.11 14.49L30.19 7.87L34.07 1.52C34.1621 1.36868 34.2124 1.1956 34.2157 1.01848C34.2189 0.841351 34.1751 0.666534 34.0886 0.511912C34.0022 0.35729 33.8762 0.228414 33.7236 0.138469C33.5709 0.0485231 33.3972 0.000737145 33.22 0H2C1.46957 0 0.960859 0.210714 0.585786 0.585787C0.210714 0.96086 0 1.46957 0 2L0 14C0 14.5304 0.210714 15.0391 0.585786 15.4142C0.960859 15.7893 1.46957 16 2 16H33.25C33.4265 16 33.5999 15.9532 33.7524 15.8645C33.905 15.7758 34.0314 15.6483 34.1188 15.4949C34.2061 15.3415 34.2513 15.1678 34.2498 14.9913C34.2482 14.8148 34.2 14.6418 34.11 14.49ZM10.51 11.18H9.39L6.13 6.84V11.19H5V5H6.13L9.4 9.35V5H10.52L10.51 11.18ZM16.84 6H13.31V7.49H16.51V8.49H13.31V10.1H16.84V11.1H12.18V5H16.83L16.84 6ZM25.13 11.16H24L22.45 6.57L20.9 11.18H19.78L17.78 5H19L20.32 9.43L21.84 5H23.06L24.52 9.43L25.85 5H27.08L25.13 11.16Z" fill="#FFAA44"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -8,6 +8,8 @@ export const MODAL_ACCT_EDIT = 'MODAL_ACCT_EDIT';
|
|||||||
export const MODAL_ACCT_INFO = 'MODAL_ACCT_INFO';
|
export const MODAL_ACCT_INFO = 'MODAL_ACCT_INFO';
|
||||||
export const MODAL_DELETE = 'MODAL_DELETE';
|
export const MODAL_DELETE = 'MODAL_DELETE';
|
||||||
|
|
||||||
|
export const JUST_CREATE_ACCOUNT_HOT_DURATION_MINS = 2;
|
||||||
|
|
||||||
export const knownLayoutChartOption = {
|
export const knownLayoutChartOption = {
|
||||||
padding: {
|
padding: {
|
||||||
top: 16,
|
top: 16,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import Map from '@/views/Discover/Map/index.vue';
|
|||||||
import Conformance from '@/views/Discover/Conformance/index.vue';
|
import Conformance from '@/views/Discover/Conformance/index.vue';
|
||||||
import Performance from '@/views/Discover/Performance/index.vue';
|
import Performance from '@/views/Discover/Performance/index.vue';
|
||||||
import CompareDashboard from '@/views/Compare/Dashboard/index.vue';
|
import CompareDashboard from '@/views/Compare/Dashboard/index.vue';
|
||||||
import AccountAdmin from '@/views/AccountManagement/AccountAdmin/index.vue';
|
import AccountAdmin from '@/views/AccountManagement/AccountAdmin/AccountAdmin.vue';
|
||||||
import MemberArea from '@/views/MemberArea/index.vue';
|
import MemberArea from '@/views/MemberArea/index.vue';
|
||||||
import NotFound404 from '@/views/NotFound404.vue';
|
import NotFound404 from '@/views/NotFound404.vue';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import apiError from '@/module/apiError.js';
|
import apiError from '@/module/apiError.js';
|
||||||
|
import { JUST_CREATE_ACCOUNT_HOT_DURATION_MINS } from '@/constants/constants.js';
|
||||||
|
|
||||||
export default defineStore('acctMgmtStore', {
|
export default defineStore('acctMgmtStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -12,6 +13,9 @@ export default defineStore('acctMgmtStore', {
|
|||||||
response: {
|
response: {
|
||||||
deleteAccount: null,
|
deleteAccount: null,
|
||||||
},
|
},
|
||||||
|
isOneAccountJustCreate: false, //如果有一個帳號剛剛建立,則會在列表上的第一列顯示這個帳號,並且右置一個徽章
|
||||||
|
justCreateUsername: "", // unique username
|
||||||
|
shouldUpdateList: false, // 控制是否該刷新列表
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
},
|
},
|
||||||
@@ -90,6 +94,11 @@ export default defineStore('acctMgmtStore', {
|
|||||||
|
|
||||||
try{
|
try{
|
||||||
const response = await this.$axios.post(apiCreateAccount, userToCreate);
|
const response = await this.$axios.post(apiCreateAccount, userToCreate);
|
||||||
|
if(response.status === 200) {
|
||||||
|
this.isOneAccountJustCreate = true;
|
||||||
|
this.justCreateUsername = userToCreate.username;
|
||||||
|
setTimeout(this.resetJustCreateFlag, JUST_CREATE_ACCOUNT_HOT_DURATION_MINS * 1000 * 60);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(error) {
|
catch(error) {
|
||||||
apiError(error, 'Failed to add a new account.');
|
apiError(error, 'Failed to add a new account.');
|
||||||
@@ -132,7 +141,7 @@ export default defineStore('acctMgmtStore', {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(error) {
|
catch(error) {
|
||||||
apiError(error, 'Failed to get user detail.');
|
//不需要跳出錯誤,因為如果是錯誤反而是好事,表示帳號是獨一的
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -180,5 +189,17 @@ export default defineStore('acctMgmtStore', {
|
|||||||
userToChange.isDetailHovered = isDetailHovered;
|
userToChange.isDetailHovered = isDetailHovered;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Reset isOneAccountJustCreate to false, causing the badge to disappear.
|
||||||
|
*/
|
||||||
|
resetJustCreateFlag(){
|
||||||
|
this.isOneAccountJustCreate = false;
|
||||||
|
},
|
||||||
|
/** Set the value of shouldUpdateList variable.
|
||||||
|
* @param {boolean} shouldUpdateBoolean
|
||||||
|
*/
|
||||||
|
setShouldUpdateList(shouldUpdateBoolean) {
|
||||||
|
this.shouldUpdateList = shouldUpdateBoolean;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -14,11 +14,15 @@
|
|||||||
>
|
>
|
||||||
<Column field="username" :header="i18next.t('AcctMgmt.Account')" bodyClass="font-medium" sortable>
|
<Column field="username" :header="i18next.t('AcctMgmt.Account')" bodyClass="font-medium" sortable>
|
||||||
<template #body="slotProps">
|
<template #body="slotProps">
|
||||||
<div class="row-container flex-w-full-hoverable w-full" @mouseenter="handleRowMouseOver(slotProps.data.username)"
|
<div class="row-container flex-w-full-hoverable w-full flex" @mouseenter="handleRowMouseOver(slotProps.data.username)"
|
||||||
@mouseout="handleRowMouseOut(slotProps.data.username)">
|
@mouseout="handleRowMouseOut(slotProps.data.username)">
|
||||||
<div @dblclick="onAcctDoubleClick(slotProps.data.username)" class="cursor-pointer">
|
<div @dblclick="onAcctDoubleClick(slotProps.data.username)" class="cursor-pointer flex">
|
||||||
{{ slotProps.data.username }}
|
{{ slotProps.data.username }}
|
||||||
</div>
|
</div>
|
||||||
|
<span id="just_create_badge" class="flex ml-4"
|
||||||
|
v-if="isOneAccountJustCreate && slotProps.data.username === justCreateUsername">
|
||||||
|
<img src="@/assets/icon-new.svg" alt="New">
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
@@ -100,7 +104,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, computed, onBeforeMount, watch, } from 'vue';
|
import { ref, computed, onMounted, watch, } from 'vue';
|
||||||
import { storeToRefs, mapState, mapActions, } from 'pinia';
|
import { storeToRefs, mapState, mapActions, } from 'pinia';
|
||||||
import LoadingStore from '@/stores/loading.js';
|
import LoadingStore from '@/stores/loading.js';
|
||||||
import { useModalStore } from '@/stores/modal.js';
|
import { useModalStore } from '@/stores/modal.js';
|
||||||
@@ -128,9 +132,7 @@ function repeatAccountList(accountList, N) {
|
|||||||
const repeatedList = [];
|
const repeatedList = [];
|
||||||
|
|
||||||
for (let i = 0; i < N; i++) {
|
for (let i = 0; i < N; i++) {
|
||||||
// 复制每次的对象并将其添加到新数组中
|
|
||||||
accountList.forEach(account => {
|
accountList.forEach(account => {
|
||||||
// 创建一个新的对象,避免直接引用
|
|
||||||
const newAccount = { ...account, id: account.id + i };
|
const newAccount = { ...account, id: account.id + i };
|
||||||
repeatedList.push(newAccount);
|
repeatedList.push(newAccount);
|
||||||
});
|
});
|
||||||
@@ -150,10 +152,16 @@ export default {
|
|||||||
const { isLoading } = storeToRefs(loadingStore);
|
const { isLoading } = storeToRefs(loadingStore);
|
||||||
const loginStore = piniaLoginStore();
|
const loginStore = piniaLoginStore();
|
||||||
const infiniteStart = ref(0);
|
const infiniteStart = ref(0);
|
||||||
const infiniteAcctData = computed(() => acctMgmtStore.allUserAccoutList.slice(0, infiniteStart.value + ONCE_RENDER_NUM_OF_DATA));
|
|
||||||
|
|
||||||
|
const shouldUpdateList = computed(() => acctMgmtStore.shouldUpdateList);
|
||||||
|
|
||||||
|
const allAccountResponsive = computed(() => acctMgmtStore.allUserAccoutList);
|
||||||
|
const infiniteAcctData = computed(() => allAccountResponsive.value.slice(0, infiniteStart.value + ONCE_RENDER_NUM_OF_DATA));
|
||||||
const loginUserData = ref(null);
|
const loginUserData = ref(null);
|
||||||
|
|
||||||
|
const isOneAccountJustCreate = computed(() => acctMgmtStore.isOneAccountJustCreate);
|
||||||
|
const justCreateUsername = computed(() => acctMgmtStore.justCreateUsername);
|
||||||
|
|
||||||
const fetchLoginUserData = async () => {
|
const fetchLoginUserData = async () => {
|
||||||
await loginStore.getUserData();
|
await loginStore.getUserData();
|
||||||
loginUserData.value = loginStore.userData;
|
loginUserData.value = loginStore.userData;
|
||||||
@@ -162,16 +170,27 @@ export default {
|
|||||||
const moveCurrentLoginUserToFirstRow = () => {
|
const moveCurrentLoginUserToFirstRow = () => {
|
||||||
const currentLoginUsername = loginUserData.value.username;
|
const currentLoginUsername = loginUserData.value.username;
|
||||||
if(infiniteAcctData.value && infiniteAcctData.value.length){
|
if(infiniteAcctData.value && infiniteAcctData.value.length){
|
||||||
const index = infiniteAcctData.value.findIndex(user => user.username === currentLoginUsername);
|
const index = allAccountResponsive.value.findIndex(user => user.username === currentLoginUsername);
|
||||||
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
// 移除匹配的對象(現正登入的使用者)並將其插入到陣列的第一位"
|
// 移除匹配的對象(現正登入的使用者)並將其插入到陣列的第一位
|
||||||
const [user] = infiniteAcctData.value.splice(index, 1);
|
const [loginUser] = allAccountResponsive.value.splice(index, 1);
|
||||||
infiniteAcctData.value.unshift(user);
|
infiniteAcctData.value.unshift(loginUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const moveJustCreateUserToFirstRow = () => {
|
||||||
|
if(infiniteAcctData.value && infiniteAcctData.value.length){
|
||||||
|
const index = acctMgmtStore.allUserAccoutList.findIndex(user => user.username === acctMgmtStore.justCreateUsername);
|
||||||
|
if (index !== -1) {
|
||||||
|
// 移除匹配的對象(剛剛新增的使用者)並將其插入到陣列的第一位
|
||||||
|
const [justCreateUser] = acctMgmtStore.allUserAccoutList.splice(index, 1);
|
||||||
|
infiniteAcctData.value.unshift(justCreateUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onCreateNewClick = () => {
|
const onCreateNewClick = () => {
|
||||||
acctMgmtStore.clearCurrentViewingUser();
|
acctMgmtStore.clearCurrentViewingUser();
|
||||||
modalStore.openModal(MODAL_CREATE_NEW);
|
modalStore.openModal(MODAL_CREATE_NEW);
|
||||||
@@ -225,7 +244,19 @@ export default {
|
|||||||
return curData?.isRowHovered ? 'bg-[#F1F5F9]' : '';
|
return curData?.isRowHovered ? 'bg-[#F1F5F9]' : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
watch(shouldUpdateList, async(newShouldUpdateList) => {
|
||||||
|
if (newShouldUpdateList) {
|
||||||
|
await acctMgmtStore.getAllUserAccounts();
|
||||||
|
acctMgmtStore.setShouldUpdateList(false);
|
||||||
|
|
||||||
|
// 當夾帶有infiniteStart.value,就表示依然考慮到無限捲動的需求
|
||||||
|
infiniteAcctData.value = allAccountResponsive.value.slice(0, infiniteStart.value + ONCE_RENDER_NUM_OF_DATA);
|
||||||
|
moveCurrentLoginUserToFirstRow();
|
||||||
|
moveJustCreateUserToFirstRow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
await fetchLoginUserData();
|
await fetchLoginUserData();
|
||||||
await acctMgmtStore.getAllUserAccounts();
|
await acctMgmtStore.getAllUserAccounts();
|
||||||
moveCurrentLoginUserToFirstRow();
|
moveCurrentLoginUserToFirstRow();
|
||||||
@@ -271,6 +302,8 @@ export default {
|
|||||||
modalStore,
|
modalStore,
|
||||||
loginUserData,
|
loginUserData,
|
||||||
infiniteAcctData,
|
infiniteAcctData,
|
||||||
|
isOneAccountJustCreate,
|
||||||
|
justCreateUsername,
|
||||||
onCreateNewClick,
|
onCreateNewClick,
|
||||||
onAcctDoubleClick,
|
onAcctDoubleClick,
|
||||||
handleScroll,
|
handleScroll,
|
||||||
@@ -163,10 +163,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
const whichCurrentModal = computed(() => modalStore.whichModal);
|
const whichCurrentModal = computed(() => modalStore.whichModal);
|
||||||
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
} = currentViewingUser;
|
|
||||||
|
|
||||||
const isSSO = computed(() => acctMgmtStore.currentViewingUser.is_sso);
|
const isSSO = computed(() => acctMgmtStore.currentViewingUser.is_sso);
|
||||||
const username = computed(() => acctMgmtStore.currentViewingUser.username);
|
const username = computed(() => acctMgmtStore.currentViewingUser.username);
|
||||||
const name = computed(() => acctMgmtStore.currentViewingUser.name);
|
const name = computed(() => acctMgmtStore.currentViewingUser.name);
|
||||||
@@ -246,7 +242,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
await toast.success(i18next.t("AcctMgmt.MsgAccountAdded"));
|
await toast.success(i18next.t("AcctMgmt.MsgAccountAdded"));
|
||||||
await modalStore.closeModal();
|
await modalStore.closeModal();
|
||||||
await acctMgmtStore.getAllUserAccounts();
|
acctMgmtStore.setShouldUpdateList(true);
|
||||||
await router.push('/account/account-admin');
|
await router.push('/account/account-admin');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -277,7 +273,6 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
isConfirmDisabled,
|
isConfirmDisabled,
|
||||||
username,
|
username,
|
||||||
id,
|
|
||||||
name,
|
name,
|
||||||
isSSO,
|
isSSO,
|
||||||
isPwdEyeOn,
|
isPwdEyeOn,
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
flex justify-center items-center">
|
flex justify-center items-center">
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<ModalAccountEdit v-if="whichModal === MODAL_ACCT_EDIT || whichModal === MODAL_CREATE_NEW "/>
|
<ModalAccountEditCreate v-if="whichModal === MODAL_ACCT_EDIT || whichModal === MODAL_CREATE_NEW "/>
|
||||||
<ModalAccountInfo v-if="whichModal === MODAL_ACCT_INFO"/>
|
<ModalAccountInfo v-if="whichModal === MODAL_ACCT_INFO"/>
|
||||||
<ModalDeleteAlert v-if="whichModal === MODAL_DELETE" />
|
<ModalDeleteAlert v-if="whichModal === MODAL_DELETE" />
|
||||||
</div>
|
</div>
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { watch, computed, } from 'vue';
|
import { computed, } from 'vue';
|
||||||
import { useModalStore } from '@/stores/modal.js';
|
import { useModalStore } from '@/stores/modal.js';
|
||||||
import ModalAccountEdit from './ModalAccountEdit.vue';
|
import ModalAccountEditCreate from './ModalAccountEditCreate.vue';
|
||||||
import ModalAccountInfo from './ModalAccountInfo.vue';
|
import ModalAccountInfo from './ModalAccountInfo.vue';
|
||||||
import ModalDeleteAlert from './ModalDeleteAlert.vue';
|
import ModalDeleteAlert from './ModalDeleteAlert.vue';
|
||||||
import {
|
import {
|
||||||
@@ -29,10 +29,6 @@
|
|||||||
const modalStore = useModalStore();
|
const modalStore = useModalStore();
|
||||||
const whichModal = computed(() => modalStore.whichModal);
|
const whichModal = computed(() => modalStore.whichModal);
|
||||||
|
|
||||||
watch(() => whichModal, (newVal, oldVal) => {
|
|
||||||
// (`whichModal changed from ${oldVal} to ${newVal}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
modalStore,
|
modalStore,
|
||||||
whichModal,
|
whichModal,
|
||||||
@@ -43,7 +39,7 @@
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ModalAccountEdit,
|
ModalAccountEditCreate,
|
||||||
ModalAccountInfo,
|
ModalAccountInfo,
|
||||||
ModalDeleteAlert,
|
ModalDeleteAlert,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export default defineComponent({
|
|||||||
if(acctMgmtStore.deleteAccount(acctMgmtStore.currentViewingUser.username)){
|
if(acctMgmtStore.deleteAccount(acctMgmtStore.currentViewingUser.username)){
|
||||||
toast.success(i18next.t("AcctMgmt.MsgAccountDeleteSuccess"));
|
toast.success(i18next.t("AcctMgmt.MsgAccountDeleteSuccess"));
|
||||||
modalStore.closeModal();
|
modalStore.closeModal();
|
||||||
await acctMgmtStore.getAllUserAccounts();
|
acctMgmtStore.setShouldUpdateList(true);
|
||||||
router.push("/account/account-admin");
|
router.push("/account/account-admin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user