migrate two column list item selection sheet to composition API and typescript

This commit is contained in:
MaysWind
2025-01-14 00:38:15 +08:00
parent 30125f0faa
commit 8ce871e9bb
3 changed files with 118 additions and 110 deletions
@@ -5,7 +5,7 @@
<div class="swipe-handler"></div> <div class="swipe-handler"></div>
<div class="left"></div> <div class="left"></div>
<div class="right"> <div class="right">
<f7-link sheet-close :text="$t('Done')"></f7-link> <f7-link sheet-close :text="tt('Done')"></f7-link>
</div> </div>
</f7-toolbar> </f7-toolbar>
<f7-page-content> <f7-page-content>
@@ -15,16 +15,16 @@
<f7-list dividers class="primary-list no-margin-vertical"> <f7-list dividers class="primary-list no-margin-vertical">
<f7-list-item link="#" no-chevron <f7-list-item link="#" no-chevron
:class="{ 'primary-list-item-selected': item === selectedPrimaryItem }" :class="{ 'primary-list-item-selected': item === selectedPrimaryItem }"
:value="primaryValueField ? item[primaryValueField] : item" :value="primaryValueField ? (item as Record<string, unknown>)[primaryValueField] : item"
:title="$tIf(item[primaryTitleField], primaryTitleI18n)" :title="ti(primaryTitleField ? (item as Record<string, unknown>)[primaryTitleField] as string : '', !!primaryTitleI18n)"
:header="$tIf(item[primaryHeaderField], primaryHeaderI18n)" :header="ti(primaryHeaderField ? (item as Record<string, unknown>)[primaryHeaderField] as string : '', !!primaryHeaderI18n)"
:footer="$tIf(item[primaryFooterField], primaryFooterI18n)" :footer="ti(primaryFooterField ? (item as Record<string, unknown>)[primaryFooterField] as string : '', !!primaryFooterI18n)"
:key="primaryKeyField ? item[primaryKeyField] : item" :key="primaryKeyField ? (item as Record<string, unknown>)[primaryKeyField] : item"
v-for="item in items" v-for="item in items"
v-show="item && (!primaryHiddenField || !item[primaryHiddenField])" v-show="item && (!primaryHiddenField || !(item as Record<string, unknown>)[primaryHiddenField])"
@click="onPrimaryItemClicked(item)"> @click="onPrimaryItemClicked(item)">
<template #media> <template #media>
<ItemIcon :icon-type="primaryIconType" :icon-id="item[primaryIconField]" :color="item[primaryColorField]"></ItemIcon> <ItemIcon :icon-type="primaryIconType" :icon-id="primaryIconField ? (item as Record<string, unknown>)[primaryIconField] : undefined" :color="primaryColorField ? (item as Record<string, unknown>)[primaryColorField] : undefined"></ItemIcon>
</template> </template>
<template #after> <template #after>
<f7-icon class="list-item-showing" f7="chevron_right" v-if="item === selectedPrimaryItem"></f7-icon> <f7-icon class="list-item-showing" f7="chevron_right" v-if="item === selectedPrimaryItem"></f7-icon>
@@ -35,19 +35,19 @@
</div> </div>
<div> <div>
<div class="secondary-list-container"> <div class="secondary-list-container">
<f7-list dividers class="secondary-list no-margin-vertical" v-if="selectedPrimaryItem && primarySubItemsField && selectedPrimaryItem[primarySubItemsField]"> <f7-list dividers class="secondary-list no-margin-vertical" v-if="selectedPrimaryItem && primarySubItemsField && (selectedPrimaryItem as Record<string, unknown>)[primarySubItemsField]">
<f7-list-item link="#" no-chevron <f7-list-item link="#" no-chevron
:class="{ 'secondary-list-item-selected': isSecondarySelected(subItem) }" :class="{ 'secondary-list-item-selected': isSecondarySelected(subItem) }"
:value="secondaryValueField ? subItem[secondaryValueField] : subItem" :value="secondaryValueField ? subItem[secondaryValueField] : subItem"
:title="$tIf(subItem[secondaryTitleField], secondaryTitleI18n)" :title="ti(secondaryTitleField ? subItem[secondaryTitleField] as string : '', !!secondaryTitleI18n)"
:header="$tIf(subItem[secondaryHeaderField], secondaryHeaderI18n)" :header="ti(secondaryHeaderField ? subItem[secondaryHeaderField] as string : '', !!secondaryHeaderI18n)"
:footer="$tIf(subItem[secondaryFooterField], secondaryFooterI18n)" :footer="ti(secondaryFooterField ? subItem[secondaryFooterField] as string : '', !!secondaryFooterI18n)"
:key="secondaryKeyField ? subItem[secondaryKeyField] : subItem" :key="secondaryKeyField ? subItem[secondaryKeyField] : subItem"
v-for="subItem in selectedPrimaryItem[primarySubItemsField]" v-for="subItem in (selectedPrimaryItem as Record<string, unknown>)[primarySubItemsField]"
v-show="subItem && (!secondaryHiddenField || !subItem[secondaryHiddenField])" v-show="subItem && (!secondaryHiddenField || !subItem[secondaryHiddenField])"
@click="onSecondaryItemClicked(subItem)"> @click="onSecondaryItemClicked(subItem)">
<template #media> <template #media>
<ItemIcon :icon-type="secondaryIconType" :icon-id="subItem[secondaryIconField]" :color="subItem[secondaryColorField]"></ItemIcon> <ItemIcon :icon-type="secondaryIconType" :icon-id="secondaryIconField ? subItem[secondaryIconField] : undefined" :color="secondaryColorField ? subItem[secondaryColorField] : undefined"></ItemIcon>
</template> </template>
<template #after> <template #after>
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="isSecondarySelected(subItem)"></f7-icon> <f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="isSecondarySelected(subItem)"></f7-icon>
@@ -61,107 +61,110 @@
</f7-sheet> </f7-sheet>
</template> </template>
<script> <script setup lang="ts">
import { ref, computed } from 'vue';
import { useI18n } from '@/locales/helpers.ts';
import { import {
getItemByKeyValue, getItemByKeyValue,
getPrimaryValueBySecondaryValue getPrimaryValueBySecondaryValue
} from '@/lib/common.ts'; } from '@/lib/common.ts';
import { scrollToSelectedItem } from '@/lib/ui/mobile.ts'; import { type Framework7Dom, scrollToSelectedItem } from '@/lib/ui/mobile.ts';
export default { const props = defineProps<{
props: [ modelValue: unknown;
'modelValue', primaryKeyField?: string;
'primaryKeyField', primaryValueField?: string;
'primaryValueField', primaryTitleField?: string;
'primaryTitleField', primaryTitleI18n?: boolean;
'primaryTitleI18n', primaryHeaderField?: string;
'primaryHeaderField', primaryHeaderI18n?: boolean;
'primaryHeaderI18n', primaryFooterField?: string;
'primaryFooterField', primaryFooterI18n?: boolean;
'primaryFooterI18n', primaryIconField?: string;
'primaryIconField', primaryIconType?: string;
'primaryIconType', primaryColorField?: string;
'primaryColorField', primaryHiddenField?: string;
'primaryHiddenField', primarySubItemsField?: string;
'primarySubItemsField', secondaryKeyField?: string;
'secondaryKeyField', secondaryValueField?: string;
'secondaryValueField', secondaryTitleField?: string;
'secondaryTitleField', secondaryTitleI18n?: boolean;
'secondaryTitleI18n', secondaryHeaderField?: string;
'secondaryHeaderField', secondaryHeaderI18n?: boolean;
'secondaryHeaderI18n', secondaryFooterField?: string;
'secondaryFooterField', secondaryFooterI18n?: boolean;
'secondaryFooterI18n', secondaryIconField?: string;
'secondaryIconField', secondaryIconType?: string;
'secondaryIconType', secondaryColorField?: string;
'secondaryColorField', secondaryHiddenField?: string;
'secondaryHiddenField', items: unknown[];
'items', show: boolean;
'show' }>();
], const emit = defineEmits<{
emits: [ (e: 'update:modelValue', value: unknown): void;
'update:modelValue', (e: 'update:show', value: boolean): void;
'update:show' }>();
],
data() {
const self = this;
return { const { tt, ti } = useI18n();
currentPrimaryValue: self.getPrimaryValueBySecondaryValue(self.modelValue),
currentSecondaryValue: self.modelValue
}
},
computed: {
selectedPrimaryItem() {
if (this.primaryValueField) {
return getItemByKeyValue(this.items, this.currentPrimaryValue, this.primaryValueField);
} else {
return this.currentPrimaryValue;
}
}
},
methods: {
onSheetOpen(event) {
this.currentPrimaryValue = this.getPrimaryValueBySecondaryValue(this.modelValue);
this.currentSecondaryValue = this.modelValue;
scrollToSelectedItem(event.$el, '.primary-list-container', 'li.primary-list-item-selected');
scrollToSelectedItem(event.$el, '.secondary-list-container', 'li.secondary-list-item-selected');
},
onSheetClosed() {
this.close();
},
onPrimaryItemClicked(item) {
if (this.primaryValueField) {
this.currentPrimaryValue = item[this.primaryValueField];
} else {
this.currentPrimaryValue = item;
}
},
onSecondaryItemClicked(subItem) {
if (this.secondaryValueField) {
this.currentSecondaryValue = subItem[this.secondaryValueField];
} else {
this.currentSecondaryValue = subItem;
}
this.$emit('update:modelValue', this.currentSecondaryValue); const currentPrimaryValue = ref<unknown>(getCurrentPrimaryValueBySecondaryValue(props.modelValue));
this.close(); const currentSecondaryValue = ref<unknown>(props.modelValue);
},
isSecondarySelected(subItem) { function getCurrentPrimaryValueBySecondaryValue(secondaryValue: unknown): unknown {
if (this.secondaryValueField) { return getPrimaryValueBySecondaryValue(props.items as Record<string, Record<string, unknown>[]>[] | Record<string, Record<string, Record<string, unknown>[]>>, props.primarySubItemsField, props.primaryValueField, props.primaryHiddenField, props.secondaryValueField, props.secondaryHiddenField, secondaryValue);
return this.currentSecondaryValue === subItem[this.secondaryValueField]; }
} else {
return this.currentSecondaryValue === subItem; function isSecondarySelected(subItem: unknown): boolean {
} if (props.secondaryValueField) {
}, return currentSecondaryValue.value === (subItem as Record<string, unknown>)[props.secondaryValueField];
getPrimaryValueBySecondaryValue(secondaryValue) { } else {
return getPrimaryValueBySecondaryValue(this.items, this.primarySubItemsField, this.primaryValueField, this.primaryHiddenField, this.secondaryValueField, this.secondaryHiddenField, secondaryValue); return currentSecondaryValue.value === subItem;
},
close() {
this.$emit('update:show', false);
}
} }
} }
const selectedPrimaryItem = computed<unknown>(() => {
if (props.primaryValueField) {
return getItemByKeyValue(props.items as Record<string, unknown>[] | Record<string, Record<string, unknown>>, currentPrimaryValue.value, props.primaryValueField);
} else {
return currentPrimaryValue.value;
}
});
function close() {
emit('update:show', false);
}
function onPrimaryItemClicked(item: unknown): void {
if (props.primaryValueField) {
currentPrimaryValue.value = (item as Record<string, unknown>)[props.primaryValueField];
} else {
currentPrimaryValue.value = item;
}
}
function onSecondaryItemClicked(subItem: unknown): void {
if (props.secondaryValueField) {
currentSecondaryValue.value = (subItem as Record<string, unknown>)[props.secondaryValueField];
} else {
currentSecondaryValue.value = subItem;
}
emit('update:modelValue', currentSecondaryValue.value);
close();
}
function onSheetOpen(event: { $el: Framework7Dom }): void {
currentPrimaryValue.value = getCurrentPrimaryValueBySecondaryValue(props.modelValue);
currentSecondaryValue.value = props.modelValue;
scrollToSelectedItem(event.$el, '.primary-list-container', 'li.primary-list-item-selected');
scrollToSelectedItem(event.$el, '.secondary-list-container', 'li.secondary-list-item-selected');
}
function onSheetClosed() {
close();
}
</script> </script>
<style> <style>
+2 -2
View File
@@ -530,7 +530,7 @@ export function selectInvert(filterItemIds: Record<string, boolean>, allItemsMap
} }
} }
export function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, Record<string, unknown>[]>, primarySubItemsField: string, secondaryValueField: string, secondaryHiddenField: string, secondaryValue: unknown): boolean { export function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, Record<string, unknown>[]>, primarySubItemsField: string, secondaryValueField: string | undefined, secondaryHiddenField: string | undefined, secondaryValue: unknown): boolean {
for (let i = 0; i < primaryItem[primarySubItemsField].length; i++) { for (let i = 0; i < primaryItem[primarySubItemsField].length; i++) {
const secondaryItem = primaryItem[primarySubItemsField][i]; const secondaryItem = primaryItem[primarySubItemsField][i];
@@ -548,7 +548,7 @@ export function isPrimaryItemHasSecondaryValue(primaryItem: Record<string, Recor
return false; return false;
} }
export function getPrimaryValueBySecondaryValue<T>(items: Record<string, Record<string, T>[]>[] | Record<string, Record<string, Record<string, T>[]>>, primarySubItemsField: string, primaryValueField: string, primaryHiddenField: string, secondaryValueField: string, secondaryHiddenField: string, secondaryValue: T): Record<string, T>[] | Record<string, Record<string, T>[]> | null { export function getPrimaryValueBySecondaryValue<T>(items: Record<string, Record<string, T>[]>[] | Record<string, Record<string, Record<string, T>[]>>, primarySubItemsField: string | undefined, primaryValueField: string | undefined, primaryHiddenField: string | undefined, secondaryValueField: string | undefined, secondaryHiddenField: string | undefined, secondaryValue: T): Record<string, T>[] | Record<string, Record<string, T>[]> | null {
if (primarySubItemsField) { if (primarySubItemsField) {
if (isArray(items)) { if (isArray(items)) {
const arr = items as Record<string, Record<string, T>[]>[]; const arr = items as Record<string, Record<string, T>[]>[];
+7 -2
View File
@@ -77,6 +77,7 @@ import { KnownErrorCode, SPECIFIED_API_NOT_FOUND_ERRORS, PARAMETERIZED_ERRORS }
import type { LatestExchangeRateResponse, LocalizedLatestExchangeRate } from '@/models/exchange_rate.ts'; import type { LatestExchangeRateResponse, LocalizedLatestExchangeRate } from '@/models/exchange_rate.ts';
import { import {
isDefined,
isObject, isObject,
isString, isString,
isNumber, isNumber,
@@ -478,8 +479,12 @@ export function useI18n() {
} }
// public functions // public functions
function translateIf(text: string, isTranslate: boolean): string { function translateIf(text: string | undefined, isTranslate: boolean): string | undefined {
if (isTranslate) { if (!isDefined(text)) {
return undefined;
}
if (text && isTranslate) {
return t(text); return t(text);
} }