feat: 将首页由Strapi迁移至Directus
- 相关路由界面修改 - 增添响应的视图模型与转换方法
This commit is contained in:
@ -8,3 +8,4 @@ export * from './useQuestionList';
|
||||
export * from './useDocumentList';
|
||||
export * from './useContactInfo';
|
||||
export * from './useCompanyProfile';
|
||||
export * from './useHomepage';
|
||||
|
||||
54
app/composables/directus/useHomepage.ts
Normal file
54
app/composables/directus/useHomepage.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { readSingleton } from '@directus/sdk';
|
||||
|
||||
export const useHomepage = () => {
|
||||
const { $directus } = useNuxtApp();
|
||||
const { getDirectusLocale } = useLocalizations();
|
||||
const locale = getDirectusLocale();
|
||||
|
||||
return useAsyncData(`homepage-${locale}`, async () => {
|
||||
return await $directus.request(
|
||||
readSingleton('homepage', {
|
||||
fields: [
|
||||
'id',
|
||||
{
|
||||
carousel: ['id', 'directus_files_id'],
|
||||
},
|
||||
{
|
||||
recommend_products: [
|
||||
'id',
|
||||
{
|
||||
translations: ['id', 'name', 'summary'],
|
||||
},
|
||||
'cover',
|
||||
],
|
||||
},
|
||||
{
|
||||
recommend_solutions: [
|
||||
'id',
|
||||
{
|
||||
translations: ['id', 'title', 'summary'],
|
||||
},
|
||||
'cover',
|
||||
],
|
||||
},
|
||||
],
|
||||
deep: {
|
||||
recommend_products: {
|
||||
translations: {
|
||||
_filter: {
|
||||
languages_code: { _eq: locale },
|
||||
},
|
||||
},
|
||||
},
|
||||
recommend_solutions: {
|
||||
translations: {
|
||||
_filter: {
|
||||
languages_code: { _eq: locale },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
};
|
||||
51
app/models/mappers/homepageMapper.ts
Normal file
51
app/models/mappers/homepageMapper.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 将 Directus 返回的 Homepage 数据转换为 HomepageView 视图模型
|
||||
*
|
||||
* @param raw: 原始的 Homepage 数据
|
||||
* @returns 转换后的 HomepageView 对象
|
||||
*
|
||||
* @example
|
||||
* const view = toHomepageView(rawHomepage);
|
||||
*/
|
||||
export function toHomepageView(raw: Homepage): HomepageView {
|
||||
const carousel = (raw.carousel ?? [])
|
||||
.filter(isObject<HomepageFile>)
|
||||
.map((item) => item.directus_files_id)
|
||||
.filter((item) => typeof item === 'string');
|
||||
|
||||
const products = (raw.recommend_products ?? [])
|
||||
.filter(isObject<Product>)
|
||||
.map((item) => {
|
||||
const cover = isObject<DirectusFile>(item.cover)
|
||||
? item.cover.id
|
||||
: item.cover;
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.translations?.[0].name,
|
||||
summary: item.translations?.[0].summary,
|
||||
cover: cover,
|
||||
} satisfies HomepageProductView;
|
||||
});
|
||||
|
||||
const solutions = (raw.recommend_solutions ?? [])
|
||||
.filter(isObject<Solution>)
|
||||
.map((item) => {
|
||||
const cover = isObject<DirectusFile>(item.cover)
|
||||
? item.cover.id
|
||||
: item.cover;
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.translations?.[0].title,
|
||||
summary: item.translations?.[0].summary,
|
||||
cover: cover,
|
||||
} satisfies HomepageSolutionView;
|
||||
});
|
||||
|
||||
return {
|
||||
id: raw.id,
|
||||
carousel: carousel ?? [],
|
||||
recommendProducts: products ?? [],
|
||||
recommendSolutions: solutions ?? [],
|
||||
};
|
||||
}
|
||||
50
app/models/views/HomepageView.ts
Normal file
50
app/models/views/HomepageView.ts
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 主页推荐产品视图模型
|
||||
*/
|
||||
export interface HomepageProductView {
|
||||
/** 唯一标识符 **/
|
||||
id: number;
|
||||
|
||||
/** 产品名称 **/
|
||||
name: string;
|
||||
|
||||
/** 产品简介 **/
|
||||
summary: string;
|
||||
|
||||
/** 产品封面 **/
|
||||
cover: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主页推荐解决方案视图模型
|
||||
*/
|
||||
export interface HomepageSolutionView {
|
||||
/** 唯一标识符 **/
|
||||
id: number;
|
||||
|
||||
/** 解决方案标题 **/
|
||||
title: string;
|
||||
|
||||
/** 解决方案摘要 **/
|
||||
summary: string;
|
||||
|
||||
/** 解决方案封面 **/
|
||||
cover: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主页视图模型
|
||||
*/
|
||||
export interface HomepageView {
|
||||
/** 唯一标识符 **/
|
||||
id: number;
|
||||
|
||||
/** 首页图片 **/
|
||||
carousel: string[];
|
||||
|
||||
/** 首页推荐产品 **/
|
||||
recommendProducts: HomepageProductView[];
|
||||
|
||||
/** 首页推荐解决方案 **/
|
||||
recommendSolutions: HomepageSolutionView[];
|
||||
}
|
||||
@ -12,14 +12,11 @@
|
||||
<div class="carousel-item">
|
||||
<el-image
|
||||
class="carousel-image"
|
||||
:src="useStrapiMedia(item.url || '')"
|
||||
:alt="item.alternativeText || `Carousel Image ${index + 1}`"
|
||||
:src="getImageUrl(item)"
|
||||
:alt="`Carousel Image ${index + 1}`"
|
||||
fit="contain"
|
||||
lazy
|
||||
/>
|
||||
<p v-if="item.caption" class="carousel-image-caption">
|
||||
{{ item.caption }}
|
||||
</p>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
@ -42,24 +39,24 @@
|
||||
:autoplay="false"
|
||||
>
|
||||
<el-carousel-item
|
||||
v-for="n in Math.floor(recommend_productions.length / 3) + 1"
|
||||
v-for="n in Math.floor(recommend_products.length / 3) + 1"
|
||||
:key="n"
|
||||
class="recommend-list"
|
||||
>
|
||||
<div class="recommend-card-group">
|
||||
<el-card
|
||||
v-for="(item, index) in recommend_productions.slice(
|
||||
v-for="(item, index) in recommend_products.slice(
|
||||
(n - 1) * 3,
|
||||
n * 3
|
||||
)"
|
||||
:key="index"
|
||||
class="recommend-card"
|
||||
@click="handleProductionCardClick(item.documentId || '')"
|
||||
@click="handleProductionCardClick(item.id.toString() || '')"
|
||||
>
|
||||
<template #header>
|
||||
<el-image
|
||||
:src="useStrapiMedia(item.cover?.url || '')"
|
||||
:alt="item.cover?.alternativeText || item.title"
|
||||
:src="getImageUrl(item.cover)"
|
||||
:alt="item.name"
|
||||
fit="cover"
|
||||
lazy
|
||||
/>
|
||||
@ -67,7 +64,7 @@
|
||||
<div class="recommend-card-body">
|
||||
<!-- Title -->
|
||||
<div class="text-center">
|
||||
<span class="recommend-card-title">{{ item.title }}</span>
|
||||
<span class="recommend-card-title">{{ item.name }}</span>
|
||||
</div>
|
||||
<!-- Description -->
|
||||
<div class="recommend-card-description text-left opacity-25">
|
||||
@ -107,12 +104,12 @@
|
||||
)"
|
||||
:key="index"
|
||||
class="recommend-card"
|
||||
@click="handleSolutionCardClick(item.documentId || '')"
|
||||
@click="handleSolutionCardClick(item.id.toString() || '')"
|
||||
>
|
||||
<template #header>
|
||||
<el-image
|
||||
:src="useStrapiMedia(item.cover?.url || '')"
|
||||
:alt="item.cover?.alternativeText || item.title"
|
||||
:src="getImageUrl(item.cover)"
|
||||
:alt="item.title"
|
||||
fit="cover"
|
||||
lazy
|
||||
/>
|
||||
@ -140,43 +137,27 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { findOne } = useStrapi();
|
||||
const { getStrapiLocale } = useLocalizations();
|
||||
const strapiLocale = getStrapiLocale();
|
||||
const { getImageUrl } = useDirectusImage();
|
||||
|
||||
const { data, pending, error } = useAsyncData('homepage', () =>
|
||||
findOne<StrapiHomepage>('homepage', undefined, {
|
||||
populate: {
|
||||
carousel: {
|
||||
populate: '*',
|
||||
},
|
||||
recommend_productions: {
|
||||
populate: {
|
||||
cover: {
|
||||
populate: '*',
|
||||
},
|
||||
},
|
||||
},
|
||||
recommend_solutions: {
|
||||
populate: {
|
||||
cover: {
|
||||
populate: '*',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
locale: strapiLocale,
|
||||
})
|
||||
);
|
||||
const { data, pending, error } = await useHomepage();
|
||||
|
||||
const carousel = computed(() => data.value?.data.carousel || []);
|
||||
const recommend_productions = computed(
|
||||
() => data.value?.data.recommend_productions || []
|
||||
const homepageData = computed(() => {
|
||||
return toHomepageView(data.value);
|
||||
});
|
||||
|
||||
const carousel = computed(() => homepageData.value?.carousel);
|
||||
|
||||
const recommend_products = computed(
|
||||
() => homepageData.value?.recommendProducts
|
||||
);
|
||||
const recommend_solutions = computed(
|
||||
() => data.value?.data.recommend_solutions || []
|
||||
() => homepageData.value?.recommendSolutions
|
||||
);
|
||||
|
||||
watch(pending, () => {
|
||||
console.log(data.value);
|
||||
});
|
||||
|
||||
watch(error, (value) => {
|
||||
if (value) {
|
||||
console.error('数据获取失败: ', value);
|
||||
|
||||
Reference in New Issue
Block a user