feat(@vben/web-antd): 客户画像页面与二级抽屉
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
import { computed, onActivated, onMounted, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import type { CustomerProfileDto } from '#/api/customer';
|
||||
import type { StoreListItemDto } from '#/api/store';
|
||||
|
||||
import { createDefaultListFilters } from './customer-profile-page/constants';
|
||||
import { createDataActions } from './customer-profile-page/data-actions';
|
||||
import {
|
||||
buildRouteQuery,
|
||||
parseRouteQueryValue,
|
||||
} from './customer-profile-page/helpers';
|
||||
|
||||
export function useCustomerProfilePage() {
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const stores = ref<StoreListItemDto[]>([]);
|
||||
const selectedStoreId = ref('');
|
||||
const activeCustomerKey = ref('');
|
||||
const profile = ref<CustomerProfileDto | null>(null);
|
||||
|
||||
const isStoreLoading = ref(false);
|
||||
const isProfileLoading = ref(false);
|
||||
|
||||
const filters = createDefaultListFilters();
|
||||
|
||||
const { loadStores, pickDefaultCustomerKey, loadProfile } = createDataActions({
|
||||
stores,
|
||||
profile,
|
||||
filters,
|
||||
isStoreLoading,
|
||||
isProfileLoading,
|
||||
});
|
||||
|
||||
const emptyDescription = computed(() => {
|
||||
if (isStoreLoading.value || isProfileLoading.value) {
|
||||
return '';
|
||||
}
|
||||
if (stores.value.length === 0) {
|
||||
return '暂无门店,请先创建门店';
|
||||
}
|
||||
if (!activeCustomerKey.value) {
|
||||
return '当前门店暂无客户';
|
||||
}
|
||||
return '暂无画像';
|
||||
});
|
||||
|
||||
async function syncRouteQuery(storeId: string, customerKey: string) {
|
||||
const currentStoreId = parseRouteQueryValue(route.query.storeId);
|
||||
const currentCustomerKey = parseRouteQueryValue(route.query.customerKey);
|
||||
if (currentStoreId === storeId && currentCustomerKey === customerKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
await router.replace({
|
||||
path: '/customer/profile',
|
||||
query: buildRouteQuery(
|
||||
route.query as Record<string, unknown>,
|
||||
storeId,
|
||||
customerKey,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
function resolveStoreId(routeStoreId: string) {
|
||||
if (!routeStoreId) {
|
||||
return stores.value[0]?.id || '';
|
||||
}
|
||||
|
||||
const matched = stores.value.find((item) => item.id === routeStoreId);
|
||||
return matched?.id || stores.value[0]?.id || '';
|
||||
}
|
||||
|
||||
async function loadProfileByRoute() {
|
||||
if (stores.value.length === 0) {
|
||||
await loadStores();
|
||||
}
|
||||
if (stores.value.length === 0) {
|
||||
selectedStoreId.value = '';
|
||||
activeCustomerKey.value = '';
|
||||
profile.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const routeStoreId = parseRouteQueryValue(route.query.storeId);
|
||||
const routeCustomerKey = parseRouteQueryValue(route.query.customerKey);
|
||||
|
||||
const nextStoreId = resolveStoreId(routeStoreId);
|
||||
selectedStoreId.value = nextStoreId;
|
||||
|
||||
let nextCustomerKey = routeCustomerKey;
|
||||
if (!nextCustomerKey) {
|
||||
nextCustomerKey = await pickDefaultCustomerKey(nextStoreId);
|
||||
}
|
||||
|
||||
activeCustomerKey.value = nextCustomerKey;
|
||||
if (!nextCustomerKey) {
|
||||
profile.value = null;
|
||||
await syncRouteQuery(nextStoreId, '');
|
||||
return;
|
||||
}
|
||||
|
||||
await loadProfile(nextStoreId, nextCustomerKey);
|
||||
await syncRouteQuery(nextStoreId, nextCustomerKey);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => route.fullPath,
|
||||
() => {
|
||||
void loadProfileByRoute();
|
||||
},
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
void loadProfileByRoute();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
if (stores.value.length === 0) {
|
||||
void loadProfileByRoute();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
activeCustomerKey,
|
||||
emptyDescription,
|
||||
isProfileLoading,
|
||||
isStoreLoading,
|
||||
profile,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user