mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-19 17:24:26 +08:00
add search box in filter account page / dialog
This commit is contained in:
+44
-60
@@ -1,7 +1,7 @@
|
|||||||
import { itemAndIndex, keys, keysIfValueEquals, values } from '@/core/base.ts';
|
import { keys, keysIfValueEquals, values } from '@/core/base.ts';
|
||||||
import { AccountType, AccountCategory } from '@/core/account.ts';
|
import { AccountType, AccountCategory } from '@/core/account.ts';
|
||||||
import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts';
|
import { PARENT_ACCOUNT_CURRENCY_PLACEHOLDER } from '@/consts/currency.ts';
|
||||||
import { type AccountBalance, type CategorizedAccount, type AccountCategoriesWithVisibleCount, Account } from '@/models/account.ts';
|
import { type AccountBalance, type CategorizedAccount, Account } from '@/models/account.ts';
|
||||||
|
|
||||||
export function getCategorizedAccountsMap(allAccounts: Account[]): Record<number, CategorizedAccount> {
|
export function getCategorizedAccountsMap(allAccounts: Account[]): Record<number, CategorizedAccount> {
|
||||||
const ret: Record<number, CategorizedAccount> = {};
|
const ret: Record<number, CategorizedAccount> = {};
|
||||||
@@ -71,67 +71,63 @@ export function getAccountMapByName(allAccounts: Account[]): Record<string, Acco
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCategorizedAccountsWithVisibleCount(categorizedAccountsMap: Record<number, CategorizedAccount>): AccountCategoriesWithVisibleCount[] {
|
export function filterCategorizedAccounts(categorizedAccountsMap: Record<number, CategorizedAccount>, allowAccountName?: string, showHidden?: boolean): Record<number, CategorizedAccount> {
|
||||||
const ret: AccountCategoriesWithVisibleCount[] = [];
|
const ret: Record<number, CategorizedAccount> = {};
|
||||||
const allCategories = AccountCategory.values();
|
const allCategories = AccountCategory.values();
|
||||||
|
const lowercaseFilterContent = allowAccountName ? allowAccountName.toLowerCase() : '';
|
||||||
|
|
||||||
for (const accountCategory of allCategories) {
|
for (const accountCategory of allCategories) {
|
||||||
const categorizedAccount = categorizedAccountsMap[accountCategory.type];
|
const categorizedAccount = categorizedAccountsMap[accountCategory.type];
|
||||||
|
|
||||||
if (!categorizedAccount || !categorizedAccount.accounts) {
|
if (!categorizedAccount || !categorizedAccount.accounts || categorizedAccount.accounts.length < 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const allAccounts = categorizedAccount.accounts;
|
const allFilteredAccounts: Account[] = [];
|
||||||
const allSubAccounts: Record<string, Account[]> = {};
|
|
||||||
const allVisibleSubAccountCounts: Record<string, number> = {};
|
|
||||||
const allFirstVisibleSubAccountIndexes: Record<string, number> = {};
|
|
||||||
let allVisibleAccountCount = 0;
|
|
||||||
let firstVisibleAccountIndex = -1;
|
|
||||||
|
|
||||||
for (const [account, accountIndex] of itemAndIndex(allAccounts)) {
|
for (const account of categorizedAccount.accounts) {
|
||||||
if (!account.hidden) {
|
if (!showHidden && account.hidden) {
|
||||||
allVisibleAccountCount++;
|
continue;
|
||||||
|
|
||||||
if (firstVisibleAccountIndex === -1) {
|
|
||||||
firstVisibleAccountIndex = accountIndex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (account.type === AccountType.MultiSubAccounts.type && account.subAccounts) {
|
const accountMatchesName = !lowercaseFilterContent || account.name.toLowerCase().includes(lowercaseFilterContent);
|
||||||
let visibleSubAccountCount = 0;
|
const filteredSubAccounts: Account[] = [];
|
||||||
let firstVisibleSubAccountIndex = -1;
|
|
||||||
|
|
||||||
for (const [subAccount, subAccountIndex] of itemAndIndex(account.subAccounts)) {
|
if (account.subAccounts) {
|
||||||
if (!subAccount.hidden) {
|
for (const subAccount of account.subAccounts) {
|
||||||
visibleSubAccountCount++;
|
if (!showHidden && subAccount.hidden) {
|
||||||
|
continue;
|
||||||
if (firstVisibleSubAccountIndex === -1) {
|
|
||||||
firstVisibleSubAccountIndex = subAccountIndex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (account.subAccounts.length > 0) {
|
if (!accountMatchesName && lowercaseFilterContent && !subAccount.name.toLowerCase().includes(lowercaseFilterContent)) {
|
||||||
allSubAccounts[account.id] = account.subAccounts;
|
continue;
|
||||||
allVisibleSubAccountCounts[account.id] = visibleSubAccountCount;
|
}
|
||||||
allFirstVisibleSubAccountIndexes[account.id] = firstVisibleSubAccountIndex;
|
|
||||||
|
const filteredSubAccount = subAccount.clone();
|
||||||
|
filteredSubAccounts.push(filteredSubAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!accountMatchesName && filteredSubAccounts.length < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredAccount = account.cloneSelf();
|
||||||
|
|
||||||
|
if (filteredAccount.type === AccountType.MultiSubAccounts.type) {
|
||||||
|
filteredAccount.subAccounts = filteredSubAccounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
allFilteredAccounts.push(filteredAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allAccounts.length > 0) {
|
if (allFilteredAccounts.length > 0) {
|
||||||
ret.push({
|
ret[accountCategory.type] = {
|
||||||
category: accountCategory.type,
|
category: categorizedAccount.category,
|
||||||
name: accountCategory.name,
|
name: categorizedAccount.name,
|
||||||
icon: accountCategory.defaultAccountIconId,
|
icon: categorizedAccount.icon,
|
||||||
allAccounts: allAccounts,
|
accounts: allFilteredAccounts
|
||||||
allVisibleAccountCount: allVisibleAccountCount,
|
};
|
||||||
firstVisibleAccountIndex: firstVisibleAccountIndex,
|
|
||||||
allSubAccounts: allSubAccounts,
|
|
||||||
allVisibleSubAccountCounts: allVisibleSubAccountCounts,
|
|
||||||
allFirstVisibleSubAccountIndexes: allFirstVisibleSubAccountIndexes
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,42 +265,30 @@ export function selectAllVisible(filterAccountIds: Record<string, boolean>, allA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectAll(filterAccountIds: Record<string, boolean>, allAccountsMap: Record<string, Account>, skipHiddenAccount: boolean): void {
|
export function selectAll(filterAccountIds: Record<string, boolean>, allAccountsMap: Record<string, Account>): void {
|
||||||
for (const accountId of keys(filterAccountIds)) {
|
for (const accountId of keys(filterAccountIds)) {
|
||||||
const account = allAccountsMap[accountId];
|
const account = allAccountsMap[accountId];
|
||||||
|
|
||||||
if (skipHiddenAccount && account && account.hidden) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (account && account.type === AccountType.SingleAccount.type) {
|
if (account && account.type === AccountType.SingleAccount.type) {
|
||||||
filterAccountIds[account.id] = false;
|
filterAccountIds[account.id] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectNone(filterAccountIds: Record<string, boolean>, allAccountsMap: Record<string, Account>, skipHiddenAccount: boolean): void {
|
export function selectNone(filterAccountIds: Record<string, boolean>, allAccountsMap: Record<string, Account>): void {
|
||||||
for (const accountId of keys(filterAccountIds)) {
|
for (const accountId of keys(filterAccountIds)) {
|
||||||
const account = allAccountsMap[accountId];
|
const account = allAccountsMap[accountId];
|
||||||
|
|
||||||
if (skipHiddenAccount && account && account.hidden) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (account && account.type === AccountType.SingleAccount.type) {
|
if (account && account.type === AccountType.SingleAccount.type) {
|
||||||
filterAccountIds[account.id] = true;
|
filterAccountIds[account.id] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectInvert(filterAccountIds: Record<string, boolean>, allAccountsMap: Record<string, Account>, skipHiddenAccount: boolean): void {
|
export function selectInvert(filterAccountIds: Record<string, boolean>, allAccountsMap: Record<string, Account>): void {
|
||||||
for (const accountId of keys(filterAccountIds)) {
|
for (const accountId of keys(filterAccountIds)) {
|
||||||
const account = allAccountsMap[accountId];
|
const account = allAccountsMap[accountId];
|
||||||
|
|
||||||
if (skipHiddenAccount && account && account.hidden) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (account && account.type === AccountType.SingleAccount.type) {
|
if (account && account.type === AccountType.SingleAccount.type) {
|
||||||
filterAccountIds[account.id] = !filterAccountIds[account.id];
|
filterAccountIds[account.id] = !filterAccountIds[account.id];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Alle auswählen",
|
"Select All": "Alle auswählen",
|
||||||
"Select None": "Keine auswählen",
|
"Select None": "Keine auswählen",
|
||||||
"Invert Selection": "Auswahl umkehren",
|
"Invert Selection": "Auswahl umkehren",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Alle auf dieser Seite auswählen",
|
"Select All in This Page": "Alle auf dieser Seite auswählen",
|
||||||
"Select None in This Page": "Keine auf dieser Seite auswählen",
|
"Select None in This Page": "Keine auf dieser Seite auswählen",
|
||||||
"Invert Selection in This Page": "Auswahl auf dieser Seite umkehren",
|
"Invert Selection in This Page": "Auswahl auf dieser Seite umkehren",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Select All",
|
"Select All": "Select All",
|
||||||
"Select None": "Select None",
|
"Select None": "Select None",
|
||||||
"Invert Selection": "Invert Selection",
|
"Invert Selection": "Invert Selection",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Select All in This Page",
|
"Select All in This Page": "Select All in This Page",
|
||||||
"Select None in This Page": "Select None in This Page",
|
"Select None in This Page": "Select None in This Page",
|
||||||
"Invert Selection in This Page": "Invert Selection in This Page",
|
"Invert Selection in This Page": "Invert Selection in This Page",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Seleccionar Todo",
|
"Select All": "Seleccionar Todo",
|
||||||
"Select None": "Seleccionar Nada",
|
"Select None": "Seleccionar Nada",
|
||||||
"Invert Selection": "Invertir Selección",
|
"Invert Selection": "Invertir Selección",
|
||||||
"Select All Visible": "Seleccionar Visibles",
|
|
||||||
"Select All in This Page": "Seleccionar Todo en Esta Página",
|
"Select All in This Page": "Seleccionar Todo en Esta Página",
|
||||||
"Select None in This Page": "No Seleccionar Ninguno en Esta Página",
|
"Select None in This Page": "No Seleccionar Ninguno en Esta Página",
|
||||||
"Invert Selection in This Page": "Invertir Selección en Esta Página",
|
"Invert Selection in This Page": "Invertir Selección en Esta Página",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Tout sélectionner",
|
"Select All": "Tout sélectionner",
|
||||||
"Select None": "Ne rien sélectionner",
|
"Select None": "Ne rien sélectionner",
|
||||||
"Invert Selection": "Inverser la sélection",
|
"Invert Selection": "Inverser la sélection",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Tout sélectionner dans cette page",
|
"Select All in This Page": "Tout sélectionner dans cette page",
|
||||||
"Select None in This Page": "Ne rien sélectionner dans cette page",
|
"Select None in This Page": "Ne rien sélectionner dans cette page",
|
||||||
"Invert Selection in This Page": "Inverser la sélection dans cette page",
|
"Invert Selection in This Page": "Inverser la sélection dans cette page",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Seleziona tutto",
|
"Select All": "Seleziona tutto",
|
||||||
"Select None": "Deseleziona tutto",
|
"Select None": "Deseleziona tutto",
|
||||||
"Invert Selection": "Inverti selezione",
|
"Invert Selection": "Inverti selezione",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Seleziona tutto in questa pagina",
|
"Select All in This Page": "Seleziona tutto in questa pagina",
|
||||||
"Select None in This Page": "Deseleziona tutto in questa pagina",
|
"Select None in This Page": "Deseleziona tutto in questa pagina",
|
||||||
"Invert Selection in This Page": "Inverti selezione in questa pagina",
|
"Invert Selection in This Page": "Inverti selezione in questa pagina",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "すべて選択",
|
"Select All": "すべて選択",
|
||||||
"Select None": "選択解除",
|
"Select None": "選択解除",
|
||||||
"Invert Selection": "選択を反転",
|
"Invert Selection": "選択を反転",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "このページをすべて選択",
|
"Select All in This Page": "このページをすべて選択",
|
||||||
"Select None in This Page": "このページの選択を解除",
|
"Select None in This Page": "このページの選択を解除",
|
||||||
"Invert Selection in This Page": "このページの選択を反転",
|
"Invert Selection in This Page": "このページの選択を反転",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "ಎಲ್ಲಾ ಆಯ್ಕೆಮಾಡಿ",
|
"Select All": "ಎಲ್ಲಾ ಆಯ್ಕೆಮಾಡಿ",
|
||||||
"Select None": "ಯಾವುದೂ ಆಯ್ಕೆ ಮಾಡಬೇಡಿ",
|
"Select None": "ಯಾವುದೂ ಆಯ್ಕೆ ಮಾಡಬೇಡಿ",
|
||||||
"Invert Selection": "ಆಯ್ಕೆಯನ್ನು ತಿರುಗಿಸಿ",
|
"Invert Selection": "ಆಯ್ಕೆಯನ್ನು ತಿರುಗಿಸಿ",
|
||||||
"Select All Visible": "ಗೋಚರಿಸುವ ಎಲ್ಲವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ",
|
|
||||||
"Select All in This Page": "ಈ ಪುಟದ ಎಲ್ಲವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ",
|
"Select All in This Page": "ಈ ಪುಟದ ಎಲ್ಲವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ",
|
||||||
"Select None in This Page": "ಈ ಪುಟದಲ್ಲಿ ಯಾವುದನ್ನೂ ಆಯ್ಕೆ ಮಾಡಬೇಡಿ",
|
"Select None in This Page": "ಈ ಪುಟದಲ್ಲಿ ಯಾವುದನ್ನೂ ಆಯ್ಕೆ ಮಾಡಬೇಡಿ",
|
||||||
"Invert Selection in This Page": "ಈ ಪುಟದಲ್ಲಿ ಆಯ್ಕೆಯನ್ನು ತಿರುಗಿಸಿ",
|
"Invert Selection in This Page": "ಈ ಪುಟದಲ್ಲಿ ಆಯ್ಕೆಯನ್ನು ತಿರುಗಿಸಿ",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "전체 선택",
|
"Select All": "전체 선택",
|
||||||
"Select None": "선택 해제",
|
"Select None": "선택 해제",
|
||||||
"Invert Selection": "선택 반전",
|
"Invert Selection": "선택 반전",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "현재 페이지 전체 선택",
|
"Select All in This Page": "현재 페이지 전체 선택",
|
||||||
"Select None in This Page": "현재 페이지 선택 해제",
|
"Select None in This Page": "현재 페이지 선택 해제",
|
||||||
"Invert Selection in This Page": "현재 페이지 선택 반전",
|
"Invert Selection in This Page": "현재 페이지 선택 반전",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Alles selecteren",
|
"Select All": "Alles selecteren",
|
||||||
"Select None": "Niets selecteren",
|
"Select None": "Niets selecteren",
|
||||||
"Invert Selection": "Selectie omkeren",
|
"Invert Selection": "Selectie omkeren",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Alles op deze pagina selecteren",
|
"Select All in This Page": "Alles op deze pagina selecteren",
|
||||||
"Select None in This Page": "Niets op deze pagina selecteren",
|
"Select None in This Page": "Niets op deze pagina selecteren",
|
||||||
"Invert Selection in This Page": "Selectie op deze pagina omkeren",
|
"Invert Selection in This Page": "Selectie op deze pagina omkeren",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Selecionar Todos",
|
"Select All": "Selecionar Todos",
|
||||||
"Select None": "Selecionar Nenhum",
|
"Select None": "Selecionar Nenhum",
|
||||||
"Invert Selection": "Inverter Seleção",
|
"Invert Selection": "Inverter Seleção",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Selecionar Todos nesta Página",
|
"Select All in This Page": "Selecionar Todos nesta Página",
|
||||||
"Select None in This Page": "Selecionar Nenhum nesta Página",
|
"Select None in This Page": "Selecionar Nenhum nesta Página",
|
||||||
"Invert Selection in This Page": "Inverter Seleção nesta Página",
|
"Invert Selection in This Page": "Inverter Seleção nesta Página",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Выбрать все",
|
"Select All": "Выбрать все",
|
||||||
"Select None": "Отменить выбор",
|
"Select None": "Отменить выбор",
|
||||||
"Invert Selection": "Инвертировать выбор",
|
"Invert Selection": "Инвертировать выбор",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Выбрать все на этой странице",
|
"Select All in This Page": "Выбрать все на этой странице",
|
||||||
"Select None in This Page": "Отменить выбор на этой странице",
|
"Select None in This Page": "Отменить выбор на этой странице",
|
||||||
"Invert Selection in This Page": "Инвертировать выбор на этой странице",
|
"Invert Selection in This Page": "Инвертировать выбор на этой странице",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "เลือกทั้งหมด",
|
"Select All": "เลือกทั้งหมด",
|
||||||
"Select None": "ยกเลิกการเลือกทั้งหมด",
|
"Select None": "ยกเลิกการเลือกทั้งหมด",
|
||||||
"Invert Selection": "สลับการเลือก",
|
"Invert Selection": "สลับการเลือก",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "เลือกทั้งหมดในหน้านี้",
|
"Select All in This Page": "เลือกทั้งหมดในหน้านี้",
|
||||||
"Select None in This Page": "ยกเลิกการเลือกทั้งหมดในหน้านี้",
|
"Select None in This Page": "ยกเลิกการเลือกทั้งหมดในหน้านี้",
|
||||||
"Invert Selection in This Page": "สลับการเลือกในหน้านี้",
|
"Invert Selection in This Page": "สลับการเลือกในหน้านี้",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Tümünü Seç",
|
"Select All": "Tümünü Seç",
|
||||||
"Select None": "Hiçbirini Seçme",
|
"Select None": "Hiçbirini Seçme",
|
||||||
"Invert Selection": "Seçimi Tersine Çevir",
|
"Invert Selection": "Seçimi Tersine Çevir",
|
||||||
"Select All Visible": "Görünenlerin Tümünü Seç",
|
|
||||||
"Select All in This Page": "Bu Sayfadakilerin Tümünü Seç",
|
"Select All in This Page": "Bu Sayfadakilerin Tümünü Seç",
|
||||||
"Select None in This Page": "Bu Sayfadakilerin Hiçbirini Seçme",
|
"Select None in This Page": "Bu Sayfadakilerin Hiçbirini Seçme",
|
||||||
"Invert Selection in This Page": "Bu Sayfadaki Seçimi Tersine Çevir",
|
"Invert Selection in This Page": "Bu Sayfadaki Seçimi Tersine Çevir",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Вибрати все",
|
"Select All": "Вибрати все",
|
||||||
"Select None": "Скасувати вибір",
|
"Select None": "Скасувати вибір",
|
||||||
"Invert Selection": "Інвертувати вибір",
|
"Invert Selection": "Інвертувати вибір",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Вибрати все на цій сторінці",
|
"Select All in This Page": "Вибрати все на цій сторінці",
|
||||||
"Select None in This Page": "Скасувати вибір на цій сторінці",
|
"Select None in This Page": "Скасувати вибір на цій сторінці",
|
||||||
"Invert Selection in This Page": "Інвертувати вибір на цій сторінці",
|
"Invert Selection in This Page": "Інвертувати вибір на цій сторінці",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "Chọn tất cả",
|
"Select All": "Chọn tất cả",
|
||||||
"Select None": "Bỏ chọn tất cả",
|
"Select None": "Bỏ chọn tất cả",
|
||||||
"Invert Selection": "Đảo ngược lựa chọn",
|
"Invert Selection": "Đảo ngược lựa chọn",
|
||||||
"Select All Visible": "Select All Visible",
|
|
||||||
"Select All in This Page": "Chọn tất cả trong trang này",
|
"Select All in This Page": "Chọn tất cả trong trang này",
|
||||||
"Select None in This Page": "Bỏ chọn tất cả trong trang này",
|
"Select None in This Page": "Bỏ chọn tất cả trong trang này",
|
||||||
"Invert Selection in This Page": "Đảo ngược lựa chọn trong trang này",
|
"Invert Selection in This Page": "Đảo ngược lựa chọn trong trang này",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "全部选择",
|
"Select All": "全部选择",
|
||||||
"Select None": "全部不选",
|
"Select None": "全部不选",
|
||||||
"Invert Selection": "反向选择",
|
"Invert Selection": "反向选择",
|
||||||
"Select All Visible": "全部选择可见",
|
|
||||||
"Select All in This Page": "本页全选",
|
"Select All in This Page": "本页全选",
|
||||||
"Select None in This Page": "本页不选",
|
"Select None in This Page": "本页不选",
|
||||||
"Invert Selection in This Page": "本页反选",
|
"Invert Selection in This Page": "本页反选",
|
||||||
|
|||||||
@@ -1551,7 +1551,6 @@
|
|||||||
"Select All": "全選",
|
"Select All": "全選",
|
||||||
"Select None": "取消全選",
|
"Select None": "取消全選",
|
||||||
"Invert Selection": "反向選擇",
|
"Invert Selection": "反向選擇",
|
||||||
"Select All Visible": "全部選擇可見",
|
|
||||||
"Select All in This Page": "本頁全選",
|
"Select All in This Page": "本頁全選",
|
||||||
"Select None in This Page": "取消本頁全選",
|
"Select None in This Page": "取消本頁全選",
|
||||||
"Invert Selection in This Page": "本頁反向選擇",
|
"Invert Selection in This Page": "本頁反向選擇",
|
||||||
|
|||||||
+21
-12
@@ -349,6 +349,27 @@ export class Account implements AccountInfoResponse {
|
|||||||
return subAccountCurrencies;
|
return subAccountCurrencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public cloneSelf(): Account {
|
||||||
|
return new Account(
|
||||||
|
this.id,
|
||||||
|
this.name,
|
||||||
|
this.parentId,
|
||||||
|
this.category,
|
||||||
|
this.type,
|
||||||
|
this.icon,
|
||||||
|
this.color,
|
||||||
|
this.currency,
|
||||||
|
this.balance,
|
||||||
|
this.comment,
|
||||||
|
this.displayOrder,
|
||||||
|
this.visible,
|
||||||
|
this.balanceTime,
|
||||||
|
this.creditCardStatementDate,
|
||||||
|
this.isAsset,
|
||||||
|
this.isLiability
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public clone(): Account {
|
public clone(): Account {
|
||||||
return new Account(
|
return new Account(
|
||||||
this.id,
|
this.id,
|
||||||
@@ -658,18 +679,6 @@ export class CategorizedAccountWithDisplayBalance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AccountCategoriesWithVisibleCount {
|
|
||||||
readonly category: number;
|
|
||||||
readonly name: string;
|
|
||||||
readonly icon: string;
|
|
||||||
readonly allAccounts: Account[];
|
|
||||||
readonly allVisibleAccountCount: number;
|
|
||||||
readonly firstVisibleAccountIndex: number;
|
|
||||||
readonly allSubAccounts: Record<string, Account[]>;
|
|
||||||
readonly allVisibleSubAccountCounts: Record<string, number>;
|
|
||||||
readonly allFirstVisibleSubAccountIndexes: Record<string, number>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AccountShowingIds {
|
export interface AccountShowingIds {
|
||||||
readonly accounts: Record<number, string>;
|
readonly accounts: Record<number, string>;
|
||||||
readonly subAccounts: Record<string, string>;
|
readonly subAccounts: Record<string, string>;
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import { useStatisticsStore } from '@/stores/statistics.ts';
|
|||||||
import { useOverviewStore } from '@/stores/overview.ts';
|
import { useOverviewStore } from '@/stores/overview.ts';
|
||||||
|
|
||||||
import { keys, keysIfValueEquals, values } from '@/core/base.ts';
|
import { keys, keysIfValueEquals, values } from '@/core/base.ts';
|
||||||
import type { Account, AccountCategoriesWithVisibleCount } from '@/models/account.ts';
|
import type {Account, CategorizedAccount} from '@/models/account.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getCategorizedAccountsWithVisibleCount,
|
filterCategorizedAccounts,
|
||||||
selectAccountOrSubAccounts,
|
selectAccountOrSubAccounts,
|
||||||
isAccountOrSubAccountsAllChecked
|
isAccountOrSubAccountsAllChecked
|
||||||
} from '@/lib/account.ts';
|
} from '@/lib/account.ts';
|
||||||
@@ -26,6 +26,7 @@ export function useAccountFilterSettingPageBase(type?: AccountFilterType) {
|
|||||||
|
|
||||||
const loading = ref<boolean>(true);
|
const loading = ref<boolean>(true);
|
||||||
const showHidden = ref<boolean>(false);
|
const showHidden = ref<boolean>(false);
|
||||||
|
const filterContent = ref<string>('');
|
||||||
const filterAccountIds = ref<Record<string, boolean>>({});
|
const filterAccountIds = ref<Record<string, boolean>>({});
|
||||||
|
|
||||||
const title = computed<string>(() => {
|
const title = computed<string>(() => {
|
||||||
@@ -48,15 +49,33 @@ export function useAccountFilterSettingPageBase(type?: AccountFilterType) {
|
|||||||
return type === 'statisticsDefault' || type === 'statisticsCurrent' || type === 'homePageOverview' || type === 'transactionListCurrent';
|
return type === 'statisticsDefault' || type === 'statisticsCurrent' || type === 'homePageOverview' || type === 'transactionListCurrent';
|
||||||
});
|
});
|
||||||
|
|
||||||
const allCategorizedAccounts = computed<AccountCategoriesWithVisibleCount[]>(() => getCategorizedAccountsWithVisibleCount(accountsStore.allCategorizedAccountsMap));
|
const allCategorizedAccounts = computed<Record<number, CategorizedAccount>>(() => filterCategorizedAccounts(accountsStore.allCategorizedAccountsMap, filterContent.value, showHidden.value));
|
||||||
const hasAnyAvailableAccount = computed<boolean>(() => accountsStore.allAvailableAccountsCount > 0);
|
const allVisibleAccountMap = computed<Record<string, Account>>(() => {
|
||||||
|
const accountMap: Record<string, Account> = {};
|
||||||
|
|
||||||
const hasAnyVisibleAccount = computed<boolean>(() => {
|
for (const accountCategory of values(allCategorizedAccounts.value)) {
|
||||||
if (showHidden.value) {
|
for (const account of accountCategory.accounts) {
|
||||||
return accountsStore.allAvailableAccountsCount > 0;
|
accountMap[account.id] = account;
|
||||||
} else {
|
|
||||||
return accountsStore.allVisibleAccountsCount > 0;
|
if (account.subAccounts) {
|
||||||
|
for (const subAccount of account.subAccounts) {
|
||||||
|
accountMap[subAccount.id] = subAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return accountMap;
|
||||||
|
});
|
||||||
|
const hasAnyAvailableAccount = computed<boolean>(() => accountsStore.allAvailableAccountsCount > 0);
|
||||||
|
const hasAnyVisibleAccount = computed<boolean>(() => {
|
||||||
|
for (const accountCategory of values(allCategorizedAccounts.value)) {
|
||||||
|
if (accountCategory.accounts.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
function isAccountChecked(account: Account, filterAccountIds: Record<string, boolean>): boolean {
|
function isAccountChecked(account: Account, filterAccountIds: Record<string, boolean>): boolean {
|
||||||
@@ -162,12 +181,14 @@ export function useAccountFilterSettingPageBase(type?: AccountFilterType) {
|
|||||||
// states
|
// states
|
||||||
loading,
|
loading,
|
||||||
showHidden,
|
showHidden,
|
||||||
|
filterContent,
|
||||||
filterAccountIds,
|
filterAccountIds,
|
||||||
// computed states
|
// computed states
|
||||||
title,
|
title,
|
||||||
applyText,
|
applyText,
|
||||||
allowHiddenAccount,
|
allowHiddenAccount,
|
||||||
allCategorizedAccounts,
|
allCategorizedAccounts,
|
||||||
|
allVisibleAccountMap,
|
||||||
hasAnyAvailableAccount,
|
hasAnyAvailableAccount,
|
||||||
hasAnyVisibleAccount,
|
hasAnyVisibleAccount,
|
||||||
// functions
|
// functions
|
||||||
|
|||||||
@@ -1,81 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card :class="{ 'pa-sm-1 pa-md-2': dialogMode }">
|
<v-card :class="{ 'pa-sm-1 pa-md-2': dialogMode }">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="d-flex align-center justify-center" v-if="dialogMode">
|
<v-row>
|
||||||
<div class="w-100 text-center">
|
<v-col cols="6">
|
||||||
<h4 class="text-h4">{{ tt(title) }}</h4>
|
<div :class="{ 'text-h4': dialogMode, 'text-wrap': true }">
|
||||||
</div>
|
{{ tt(title) }}
|
||||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
</div>
|
||||||
:disabled="loading || !hasAnyAvailableAccount" :icon="true">
|
</v-col>
|
||||||
<v-icon :icon="mdiDotsVertical" />
|
<v-col cols="6" class="d-flex align-center">
|
||||||
<v-menu activator="parent">
|
<v-spacer v-if="!dialogMode"/>
|
||||||
<v-list>
|
<v-text-field density="compact" :disabled="loading || !hasAnyAvailableAccount"
|
||||||
<v-list-item :prepend-icon="mdiSelectAll"
|
:prepend-inner-icon="mdiMagnify"
|
||||||
:title="tt('Select All')"
|
:placeholder="tt('Find account')"
|
||||||
:disabled="!hasAnyVisibleAccount"
|
v-model="filterContent"
|
||||||
@click="selectAllAccounts"></v-list-item>
|
v-if="dialogMode"></v-text-field>
|
||||||
<v-list-item :prepend-icon="mdiSelect"
|
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||||
:title="tt('Select None')"
|
:disabled="loading || !hasAnyAvailableAccount" :icon="true">
|
||||||
:disabled="!hasAnyVisibleAccount"
|
<v-icon :icon="mdiDotsVertical" />
|
||||||
@click="selectNoneAccounts"></v-list-item>
|
<v-menu activator="parent">
|
||||||
<v-list-item :prepend-icon="mdiSelectInverse"
|
<v-list>
|
||||||
:title="tt('Invert Selection')"
|
<v-list-item :prepend-icon="mdiSelectAll"
|
||||||
:disabled="!hasAnyVisibleAccount"
|
:title="tt('Select All')"
|
||||||
@click="selectInvertAccounts"></v-list-item>
|
:disabled="!hasAnyVisibleAccount"
|
||||||
<v-divider class="my-2" v-if="allowHiddenAccount"/>
|
@click="selectAllAccounts"></v-list-item>
|
||||||
<v-list-item :prepend-icon="mdiSelectAll"
|
<v-list-item :prepend-icon="mdiSelect"
|
||||||
:title="tt('Select All Visible')"
|
:title="tt('Select None')"
|
||||||
:disabled="!hasAnyVisibleAccount"
|
:disabled="!hasAnyVisibleAccount"
|
||||||
@click="selectAllVisibleAccounts"
|
@click="selectNoneAccounts"></v-list-item>
|
||||||
v-if="allowHiddenAccount"></v-list-item>
|
<v-list-item :prepend-icon="mdiSelectInverse"
|
||||||
<v-divider class="my-2" v-if="allowHiddenAccount"/>
|
:title="tt('Invert Selection')"
|
||||||
<v-list-item :prepend-icon="mdiEyeOutline"
|
:disabled="!hasAnyVisibleAccount"
|
||||||
:title="tt('Show Hidden Accounts')"
|
@click="selectInvertAccounts"></v-list-item>
|
||||||
v-if="allowHiddenAccount && !showHidden" @click="showHidden = true"></v-list-item>
|
<v-divider class="my-2" v-if="allowHiddenAccount"/>
|
||||||
<v-list-item :prepend-icon="mdiEyeOffOutline"
|
<v-list-item :prepend-icon="mdiEyeOutline"
|
||||||
:title="tt('Hide Hidden Accounts')"
|
:title="tt('Show Hidden Accounts')"
|
||||||
v-if="allowHiddenAccount && showHidden" @click="showHidden = false"></v-list-item>
|
v-if="allowHiddenAccount && !showHidden" @click="showHidden = true"></v-list-item>
|
||||||
</v-list>
|
<v-list-item :prepend-icon="mdiEyeOffOutline"
|
||||||
</v-menu>
|
:title="tt('Hide Hidden Accounts')"
|
||||||
</v-btn>
|
v-if="allowHiddenAccount && showHidden" @click="showHidden = false"></v-list-item>
|
||||||
</div>
|
</v-list>
|
||||||
<div class="d-flex align-center" v-else-if="!dialogMode">
|
</v-menu>
|
||||||
<span>{{ tt(title) }}</span>
|
</v-btn>
|
||||||
<v-spacer/>
|
</v-col>
|
||||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
</v-row>
|
||||||
:disabled="loading" :icon="true">
|
|
||||||
<v-icon :icon="mdiDotsVertical" />
|
|
||||||
<v-menu activator="parent">
|
|
||||||
<v-list>
|
|
||||||
<v-list-item :prepend-icon="mdiSelectAll"
|
|
||||||
:title="tt('Select All')"
|
|
||||||
:disabled="!hasAnyVisibleAccount"
|
|
||||||
@click="selectAllAccounts"></v-list-item>
|
|
||||||
<v-list-item :prepend-icon="mdiSelect"
|
|
||||||
:title="tt('Select None')"
|
|
||||||
:disabled="!hasAnyVisibleAccount"
|
|
||||||
@click="selectNoneAccounts"></v-list-item>
|
|
||||||
<v-list-item :prepend-icon="mdiSelectInverse"
|
|
||||||
:title="tt('Invert Selection')"
|
|
||||||
:disabled="!hasAnyVisibleAccount"
|
|
||||||
@click="selectInvertAccounts"></v-list-item>
|
|
||||||
<v-divider class="my-2" v-if="allowHiddenAccount"/>
|
|
||||||
<v-list-item :prepend-icon="mdiSelectAll"
|
|
||||||
:title="tt('Select All Visible')"
|
|
||||||
:disabled="!hasAnyVisibleAccount"
|
|
||||||
@click="selectAllVisibleAccounts"
|
|
||||||
v-if="allowHiddenAccount"></v-list-item>
|
|
||||||
<v-divider class="my-2" v-if="allowHiddenAccount"/>
|
|
||||||
<v-list-item :prepend-icon="mdiEyeOutline"
|
|
||||||
:title="tt('Show Hidden Accounts')"
|
|
||||||
v-if="allowHiddenAccount && !showHidden" @click="showHidden = true"></v-list-item>
|
|
||||||
<v-list-item :prepend-icon="mdiEyeOffOutline"
|
|
||||||
:title="tt('Hide Hidden Accounts')"
|
|
||||||
v-if="allowHiddenAccount && showHidden" @click="showHidden = false"></v-list-item>
|
|
||||||
</v-list>
|
|
||||||
</v-menu>
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div v-if="loading">
|
<div v-if="loading">
|
||||||
@@ -92,18 +59,17 @@
|
|||||||
<v-expansion-panel :key="accountCategory.category"
|
<v-expansion-panel :key="accountCategory.category"
|
||||||
:value="accountCategory.category"
|
:value="accountCategory.category"
|
||||||
class="border"
|
class="border"
|
||||||
v-for="accountCategory in allCategorizedAccounts"
|
v-for="accountCategory in allCategorizedAccounts">
|
||||||
v-show="showHidden || accountCategory.allVisibleAccountCount > 0">
|
|
||||||
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
|
<v-expansion-panel-title class="expand-panel-title-with-bg py-0">
|
||||||
<span class="ms-3">{{ tt(accountCategory.name) }}</span>
|
<span class="ms-3">{{ tt(accountCategory.name) }}</span>
|
||||||
</v-expansion-panel-title>
|
</v-expansion-panel-title>
|
||||||
<v-expansion-panel-text>
|
<v-expansion-panel-text>
|
||||||
<v-list rounded density="comfortable" class="pa-0">
|
<v-list rounded density="comfortable" class="pa-0">
|
||||||
<template :key="account.id"
|
<template :key="account.id"
|
||||||
v-for="(account, idx) in accountCategory.allAccounts">
|
v-for="(account, idx) in accountCategory.accounts">
|
||||||
<v-divider v-if="showHidden ? idx > 0 : (!account.hidden ? idx > accountCategory.firstVisibleAccountIndex : false)"/>
|
<v-divider v-if="idx > 0"/>
|
||||||
|
|
||||||
<v-list-item v-if="showHidden || !account.hidden">
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-checkbox :model-value="isAccountOrSubAccountsAllChecked(account, filterAccountIds)"
|
<v-checkbox :model-value="isAccountOrSubAccountsAllChecked(account, filterAccountIds)"
|
||||||
:indeterminate="isAccountOrSubAccountsHasButNotAllChecked(account, filterAccountIds)"
|
:indeterminate="isAccountOrSubAccountsHasButNotAllChecked(account, filterAccountIds)"
|
||||||
@@ -117,13 +83,13 @@
|
|||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-divider v-if="(showHidden || !account.hidden) && account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])"/>
|
<v-divider v-if="account.type === AccountType.MultiSubAccounts.type && account.subAccounts && account.subAccounts.length > 0"/>
|
||||||
|
|
||||||
<v-list rounded density="comfortable" class="pa-0 ms-4"
|
<v-list rounded density="comfortable" class="pa-0 ms-4"
|
||||||
v-if="(showHidden || !account.hidden) && account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])">
|
v-if="account.type === AccountType.MultiSubAccounts.type && account.subAccounts && account.subAccounts.length > 0">
|
||||||
<template :key="subAccount.id"
|
<template :key="subAccount.id"
|
||||||
v-for="(subAccount, subIdx) in accountCategory.allSubAccounts[account.id]">
|
v-for="(subAccount, subIdx) in account.subAccounts">
|
||||||
<v-divider v-if="showHidden ? subIdx > 0 : (!subAccount.hidden ? subIdx > (accountCategory.allFirstVisibleSubAccountIndexes[account.id] as number) : false)"/>
|
<v-divider v-if="subIdx > 0"/>
|
||||||
|
|
||||||
<v-list-item v-if="showHidden || !subAccount.hidden">
|
<v-list-item v-if="showHidden || !subAccount.hidden">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
@@ -148,7 +114,7 @@
|
|||||||
|
|
||||||
<v-card-text class="overflow-y-visible" v-if="dialogMode">
|
<v-card-text class="overflow-y-visible" v-if="dialogMode">
|
||||||
<div class="w-100 d-flex justify-center flex-wrap mt-sm-1 mt-md-2 gap-4">
|
<div class="w-100 d-flex justify-center flex-wrap mt-sm-1 mt-md-2 gap-4">
|
||||||
<v-btn :disabled="!hasAnyVisibleAccount" @click="save">{{ tt(applyText) }}</v-btn>
|
<v-btn :disabled="!hasAnyAvailableAccount" @click="save">{{ tt(applyText) }}</v-btn>
|
||||||
<v-btn color="secondary" variant="tonal" @click="cancel">{{ tt('Cancel') }}</v-btn>
|
<v-btn color="secondary" variant="tonal" @click="cancel">{{ tt('Cancel') }}</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@@ -175,7 +141,6 @@ import type { Account } from '@/models/account.ts';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
selectAccountOrSubAccounts,
|
selectAccountOrSubAccounts,
|
||||||
selectAllVisible,
|
|
||||||
selectAll,
|
selectAll,
|
||||||
selectNone,
|
selectNone,
|
||||||
selectInvert,
|
selectInvert,
|
||||||
@@ -184,6 +149,7 @@ import {
|
|||||||
} from '@/lib/account.ts';
|
} from '@/lib/account.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
mdiMagnify,
|
||||||
mdiSelectAll,
|
mdiSelectAll,
|
||||||
mdiSelect,
|
mdiSelect,
|
||||||
mdiSelectInverse,
|
mdiSelectInverse,
|
||||||
@@ -209,11 +175,13 @@ const { tt } = useI18n();
|
|||||||
const {
|
const {
|
||||||
loading,
|
loading,
|
||||||
showHidden,
|
showHidden,
|
||||||
|
filterContent,
|
||||||
filterAccountIds,
|
filterAccountIds,
|
||||||
title,
|
title,
|
||||||
applyText,
|
applyText,
|
||||||
allowHiddenAccount,
|
allowHiddenAccount,
|
||||||
allCategorizedAccounts,
|
allCategorizedAccounts,
|
||||||
|
allVisibleAccountMap,
|
||||||
hasAnyAvailableAccount,
|
hasAnyAvailableAccount,
|
||||||
hasAnyVisibleAccount,
|
hasAnyVisibleAccount,
|
||||||
isAccountChecked,
|
isAccountChecked,
|
||||||
@@ -262,7 +230,7 @@ function updateAccountSelected(account: Account, value: boolean | null): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectAllAccounts(): void {
|
function selectAllAccounts(): void {
|
||||||
selectAll(filterAccountIds.value, accountsStore.allAccountsMap, !allowHiddenAccount.value);
|
selectAll(filterAccountIds.value, allVisibleAccountMap.value);
|
||||||
|
|
||||||
if (props.autoSave) {
|
if (props.autoSave) {
|
||||||
save();
|
save();
|
||||||
@@ -270,7 +238,7 @@ function selectAllAccounts(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectNoneAccounts(): void {
|
function selectNoneAccounts(): void {
|
||||||
selectNone(filterAccountIds.value, accountsStore.allAccountsMap, !allowHiddenAccount.value);
|
selectNone(filterAccountIds.value, allVisibleAccountMap.value);
|
||||||
|
|
||||||
if (props.autoSave) {
|
if (props.autoSave) {
|
||||||
save();
|
save();
|
||||||
@@ -278,15 +246,7 @@ function selectNoneAccounts(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectInvertAccounts(): void {
|
function selectInvertAccounts(): void {
|
||||||
selectInvert(filterAccountIds.value, accountsStore.allAccountsMap, !allowHiddenAccount.value);
|
selectInvert(filterAccountIds.value, allVisibleAccountMap.value);
|
||||||
|
|
||||||
if (props.autoSave) {
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectAllVisibleAccounts(): void {
|
|
||||||
selectAllVisible(filterAccountIds.value, accountsStore.allAccountsMap);
|
|
||||||
|
|
||||||
if (props.autoSave) {
|
if (props.autoSave) {
|
||||||
save();
|
save();
|
||||||
|
|||||||
@@ -1,12 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<f7-page @page:afterin="onPageAfterIn">
|
<f7-page with-subnavbar @page:beforein="onPageBeforeIn" @page:afterin="onPageAfterIn">
|
||||||
<f7-navbar>
|
<f7-navbar>
|
||||||
<f7-nav-left :back-link="tt('Back')"></f7-nav-left>
|
<f7-nav-left :back-link="tt('Back')"></f7-nav-left>
|
||||||
<f7-nav-title :title="tt(title)"></f7-nav-title>
|
<f7-nav-title :title="tt(title)"></f7-nav-title>
|
||||||
<f7-nav-right class="navbar-compact-icons">
|
<f7-nav-right class="navbar-compact-icons">
|
||||||
<f7-link icon-f7="ellipsis" :class="{ 'disabled': !hasAnyAvailableAccount }" @click="showMoreActionSheet = true"></f7-link>
|
<f7-link icon-f7="ellipsis" :class="{ 'disabled': !hasAnyAvailableAccount }" @click="showMoreActionSheet = true"></f7-link>
|
||||||
<f7-link icon-f7="checkmark_alt" :class="{ 'disabled': !hasAnyVisibleAccount }" @click="save"></f7-link>
|
<f7-link icon-f7="checkmark_alt" :class="{ 'disabled': !hasAnyAvailableAccount }" @click="save"></f7-link>
|
||||||
</f7-nav-right>
|
</f7-nav-right>
|
||||||
|
|
||||||
|
<f7-subnavbar :inner="false">
|
||||||
|
<f7-searchbar
|
||||||
|
custom-searchs
|
||||||
|
:value="filterContent"
|
||||||
|
:placeholder="tt('Find account')"
|
||||||
|
:disable-button-text="tt('Cancel')"
|
||||||
|
@change="filterContent = $event.target.value"
|
||||||
|
></f7-searchbar>
|
||||||
|
</f7-subnavbar>
|
||||||
</f7-navbar>
|
</f7-navbar>
|
||||||
|
|
||||||
<div class="skeleton-text" v-if="loading">
|
<div class="skeleton-text" v-if="loading">
|
||||||
@@ -45,8 +55,7 @@
|
|||||||
<f7-block class="no-margin no-padding" v-show="!loading && hasAnyVisibleAccount">
|
<f7-block class="no-margin no-padding" v-show="!loading && hasAnyVisibleAccount">
|
||||||
<f7-block class="combination-list-wrapper margin-vertical"
|
<f7-block class="combination-list-wrapper margin-vertical"
|
||||||
:key="accountCategory.category"
|
:key="accountCategory.category"
|
||||||
v-for="accountCategory in allCategorizedAccounts"
|
v-for="accountCategory in allCategorizedAccounts">
|
||||||
v-show="showHidden || accountCategory.allVisibleAccountCount > 0">
|
|
||||||
<f7-accordion-item :opened="collapseStates[accountCategory.category]!.opened"
|
<f7-accordion-item :opened="collapseStates[accountCategory.category]!.opened"
|
||||||
@accordion:open="collapseStates[accountCategory.category]!.opened = true"
|
@accordion:open="collapseStates[accountCategory.category]!.opened = true"
|
||||||
@accordion:close="collapseStates[accountCategory.category]!.opened = false">
|
@accordion:close="collapseStates[accountCategory.category]!.opened = false">
|
||||||
@@ -65,14 +74,13 @@
|
|||||||
<f7-accordion-content :style="{ height: collapseStates[accountCategory.category]!.opened ? 'auto' : '' }">
|
<f7-accordion-content :style="{ height: collapseStates[accountCategory.category]!.opened ? 'auto' : '' }">
|
||||||
<f7-list strong inset dividers accordion-list class="combination-list-content">
|
<f7-list strong inset dividers accordion-list class="combination-list-content">
|
||||||
<f7-list-item checkbox
|
<f7-list-item checkbox
|
||||||
:class="{ 'has-child-list-item': account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id]) }"
|
:class="{ 'has-child-list-item': account.type === AccountType.MultiSubAccounts.type && account.subAccounts && account.subAccounts.length > 0 }"
|
||||||
:title="account.name"
|
:title="account.name"
|
||||||
:value="account.id"
|
:value="account.id"
|
||||||
:checked="isAccountOrSubAccountsAllChecked(account, filterAccountIds)"
|
:checked="isAccountOrSubAccountsAllChecked(account, filterAccountIds)"
|
||||||
:indeterminate="isAccountOrSubAccountsHasButNotAllChecked(account, filterAccountIds)"
|
:indeterminate="isAccountOrSubAccountsHasButNotAllChecked(account, filterAccountIds)"
|
||||||
:key="account.id"
|
:key="account.id"
|
||||||
v-for="account in accountCategory.allAccounts"
|
v-for="account in accountCategory.accounts"
|
||||||
v-show="showHidden || !account.hidden"
|
|
||||||
@change="updateAccountOrSubAccountsSelected">
|
@change="updateAccountOrSubAccountsSelected">
|
||||||
<template #media>
|
<template #media>
|
||||||
<ItemIcon icon-type="account" :icon-id="account.icon" :color="account.color">
|
<ItemIcon icon-type="account" :icon-id="account.icon" :color="account.color">
|
||||||
@@ -84,14 +92,13 @@
|
|||||||
|
|
||||||
<template #root>
|
<template #root>
|
||||||
<ul class="padding-inline-start"
|
<ul class="padding-inline-start"
|
||||||
v-if="account.type === AccountType.MultiSubAccounts.type && ((showHidden && accountCategory.allSubAccounts[account.id]) || accountCategory.allVisibleSubAccountCounts[account.id])">
|
v-if="account.type === AccountType.MultiSubAccounts.type && account.subAccounts && account.subAccounts.length > 0">
|
||||||
<f7-list-item checkbox
|
<f7-list-item checkbox
|
||||||
:title="subAccount.name"
|
:title="subAccount.name"
|
||||||
:value="subAccount.id"
|
:value="subAccount.id"
|
||||||
:checked="isAccountChecked(subAccount, filterAccountIds)"
|
:checked="isAccountChecked(subAccount, filterAccountIds)"
|
||||||
:key="subAccount.id"
|
:key="subAccount.id"
|
||||||
v-for="subAccount in accountCategory.allSubAccounts[account.id]"
|
v-for="subAccount in account.subAccounts"
|
||||||
v-show="showHidden || !subAccount.hidden"
|
|
||||||
@change="updateAccountSelected">
|
@change="updateAccountSelected">
|
||||||
<template #media>
|
<template #media>
|
||||||
<ItemIcon icon-type="account" :icon-id="subAccount.icon" :color="subAccount.color">
|
<ItemIcon icon-type="account" :icon-id="subAccount.icon" :color="subAccount.color">
|
||||||
@@ -116,9 +123,6 @@
|
|||||||
<f7-actions-button :class="{ 'disabled': !hasAnyVisibleAccount }" @click="selectNoneAccounts">{{ tt('Select None') }}</f7-actions-button>
|
<f7-actions-button :class="{ 'disabled': !hasAnyVisibleAccount }" @click="selectNoneAccounts">{{ tt('Select None') }}</f7-actions-button>
|
||||||
<f7-actions-button :class="{ 'disabled': !hasAnyVisibleAccount }" @click="selectInvertAccounts">{{ tt('Invert Selection') }}</f7-actions-button>
|
<f7-actions-button :class="{ 'disabled': !hasAnyVisibleAccount }" @click="selectInvertAccounts">{{ tt('Invert Selection') }}</f7-actions-button>
|
||||||
</f7-actions-group>
|
</f7-actions-group>
|
||||||
<f7-actions-group v-if="allowHiddenAccount">
|
|
||||||
<f7-actions-button :class="{ 'disabled': !hasAnyVisibleAccount }" @click="selectAllVisibleAccounts">{{ tt('Select All Visible') }}</f7-actions-button>
|
|
||||||
</f7-actions-group>
|
|
||||||
<f7-actions-group v-if="allowHiddenAccount">
|
<f7-actions-group v-if="allowHiddenAccount">
|
||||||
<f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ tt('Show Hidden Accounts') }}</f7-actions-button>
|
<f7-actions-button v-if="!showHidden" @click="showHidden = true">{{ tt('Show Hidden Accounts') }}</f7-actions-button>
|
||||||
<f7-actions-button v-if="showHidden" @click="showHidden = false">{{ tt('Hide Hidden Accounts') }}</f7-actions-button>
|
<f7-actions-button v-if="showHidden" @click="showHidden = false">{{ tt('Hide Hidden Accounts') }}</f7-actions-button>
|
||||||
@@ -146,7 +150,6 @@ import { useAccountsStore } from '@/stores/account.ts';
|
|||||||
import { AccountType, AccountCategory } from '@/core/account.ts';
|
import { AccountType, AccountCategory } from '@/core/account.ts';
|
||||||
import {
|
import {
|
||||||
selectAccountOrSubAccounts,
|
selectAccountOrSubAccounts,
|
||||||
selectAllVisible,
|
|
||||||
selectAll,
|
selectAll,
|
||||||
selectNone,
|
selectNone,
|
||||||
selectInvert,
|
selectInvert,
|
||||||
@@ -171,10 +174,12 @@ const { showToast, routeBackOnError } = useI18nUIComponents();
|
|||||||
const {
|
const {
|
||||||
loading,
|
loading,
|
||||||
showHidden,
|
showHidden,
|
||||||
|
filterContent,
|
||||||
filterAccountIds,
|
filterAccountIds,
|
||||||
title,
|
title,
|
||||||
allowHiddenAccount,
|
allowHiddenAccount,
|
||||||
allCategorizedAccounts,
|
allCategorizedAccounts,
|
||||||
|
allVisibleAccountMap,
|
||||||
hasAnyAvailableAccount,
|
hasAnyAvailableAccount,
|
||||||
hasAnyVisibleAccount,
|
hasAnyVisibleAccount,
|
||||||
isAccountChecked,
|
isAccountChecked,
|
||||||
@@ -224,7 +229,7 @@ function init(): void {
|
|||||||
function updateAccountOrSubAccountsSelected(e: Event): void {
|
function updateAccountOrSubAccountsSelected(e: Event): void {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const accountId = target.value;
|
const accountId = target.value;
|
||||||
const account = accountsStore.allAccountsMap[accountId];
|
const account = allVisibleAccountMap.value[accountId];
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return;
|
return;
|
||||||
@@ -236,7 +241,7 @@ function updateAccountOrSubAccountsSelected(e: Event): void {
|
|||||||
function updateAccountSelected(e: Event): void {
|
function updateAccountSelected(e: Event): void {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const accountId = target.value;
|
const accountId = target.value;
|
||||||
const account = accountsStore.allAccountsMap[accountId];
|
const account = allVisibleAccountMap.value[accountId];
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return;
|
return;
|
||||||
@@ -246,19 +251,15 @@ function updateAccountSelected(e: Event): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectAllAccounts(): void {
|
function selectAllAccounts(): void {
|
||||||
selectAll(filterAccountIds.value, accountsStore.allAccountsMap, !allowHiddenAccount.value);
|
selectAll(filterAccountIds.value, allVisibleAccountMap.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNoneAccounts(): void {
|
function selectNoneAccounts(): void {
|
||||||
selectNone(filterAccountIds.value, accountsStore.allAccountsMap, !allowHiddenAccount.value);
|
selectNone(filterAccountIds.value, allVisibleAccountMap.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectInvertAccounts(): void {
|
function selectInvertAccounts(): void {
|
||||||
selectInvert(filterAccountIds.value, accountsStore.allAccountsMap, !allowHiddenAccount.value);
|
selectInvert(filterAccountIds.value, allVisibleAccountMap.value);
|
||||||
}
|
|
||||||
|
|
||||||
function selectAllVisibleAccounts(): void {
|
|
||||||
selectAllVisible(filterAccountIds.value, accountsStore.allAccountsMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function save(): void {
|
function save(): void {
|
||||||
@@ -266,6 +267,10 @@ function save(): void {
|
|||||||
props.f7router.back();
|
props.f7router.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onPageBeforeIn(): void {
|
||||||
|
filterContent.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
function onPageAfterIn(): void {
|
function onPageAfterIn(): void {
|
||||||
routeBackOnError(props.f7router, loadingError);
|
routeBackOnError(props.f7router, loadingError);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user