refactor: 重构项目的数据获取方法
All checks were successful
deploy to server / build-and-deploy (push) Successful in 3m1s

- 将相关数据获取由REST转为GraphQL
- 声明GraphQL模块
- 修改相关的Mapper与测试方法
This commit is contained in:
2025-11-11 17:05:44 +08:00
37 changed files with 377 additions and 402 deletions

5
.graphqlrc.yaml Normal file
View File

@ -0,0 +1,5 @@
schema:
- 'http://192.168.86.5:8055/graphql':
headers:
Authorization: 'Bearer ixSWeViHIqwj6_r7NM-uZVR3NNOyBa_W'
documents: 'app/graphql/**/*.{graphql,js,ts,jsx,tsx}'

View File

@ -1,4 +1,4 @@
import { readSingleton } from '@directus/sdk'; import GetCompanyProfile from '@/graphql/companyProfile.graphql?raw';
export const useCompanyProfile = () => { export const useCompanyProfile = () => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -6,24 +6,11 @@ export const useCompanyProfile = () => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`company-profile-${locale}`, async () => { return useAsyncData(`company-profile-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ company_profile: CompanyProfile }>(
readSingleton('company_profile', { GetCompanyProfile,
fields: [ {
'id', locale: locale,
{ }
translations: ['id', 'content'],
},
],
deep: {
translations: {
_filter: {
languages_code: {
_eq: locale,
},
},
},
},
})
); );
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readSingleton } from '@directus/sdk'; import GetContactInfo from '@/graphql/contactInfo.graphql?raw';
export const useContactInfo = () => { export const useContactInfo = () => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -6,24 +6,11 @@ export const useContactInfo = () => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`contact-info-${locale}`, async () => { return useAsyncData(`contact-info-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ contact_info: ContactInfo }>(
readSingleton('contact_info', { GetContactInfo,
fields: [ {
'id', locale: locale,
{ }
translations: ['id', 'content'],
},
],
deep: {
translations: {
_filter: {
languages_code: {
_eq: locale,
},
},
},
},
})
); );
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readItems } from '@directus/sdk'; import GetDocumentList from '@/graphql/documentList.graphql?raw';
export const useDocumentList = () => { export const useDocumentList = () => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -6,62 +6,11 @@ export const useDocumentList = () => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`document-list-${locale}`, async () => { return useAsyncData(`document-list-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ product_documents: ProductDocument[] }>(
readItems('product_documents', { GetDocumentList,
fields: [ {
'id', locale: locale,
{ }
file: ['id', 'filesize', 'filename_download'],
},
{
translations: ['id', 'title'],
},
{
products: [
'id',
{
products_id: [
'id',
{
translations: ['id', 'name'],
},
{
product_type: [
'id',
{
translations: ['id', 'name'],
},
],
},
],
},
],
},
],
deep: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
products: {
products_id: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
product_type: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
},
},
},
})
); );
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readSingleton } from '@directus/sdk'; import GetHomepage from '@/graphql/homepage.graphql?raw';
export const useHomepage = () => { export const useHomepage = () => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -6,49 +6,8 @@ export const useHomepage = () => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`homepage-${locale}`, async () => { return useAsyncData(`homepage-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ homepage: Homepage }>(GetHomepage, {
readSingleton('homepage', { locale: locale,
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 },
},
},
},
},
})
);
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readItem } from '@directus/sdk'; import GetProduct from '@/graphql/product.graphql?raw';
export const useProduct = (id: string) => { export const useProduct = (id: string) => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -7,104 +7,9 @@ export const useProduct = (id: string) => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`product-${id}-${locale}`, async () => { return useAsyncData(`product-${id}-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ products_by_id: Product }>(GetProduct, {
readItem('products', id, { id: id,
fields: [ locale: locale,
'id', });
{ translations: ['id', 'name', 'summary', 'description'] },
{
images: [
'id',
{
product_images_id: [
'id',
'image',
{ translations: ['id', 'caption'] },
],
},
],
},
{
specs: [
'id',
{
translations: ['*'],
},
{
specs: [
'id',
{
translations: ['id', 'key', 'value'],
},
],
},
],
},
{
faqs: [
'id',
{
questions_id: [
'id',
{
translations: ['id', 'title', 'content'],
},
],
},
],
},
{
documents: [
'id',
{
product_documents_id: [
'id',
{
file: ['id', 'filesize', 'filename_download'],
},
{
translations: ['id', 'title'],
},
],
},
],
},
],
deep: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
images: {
product_images_id: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
},
faqs: {
questions_id: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
},
documents: {
documents_id: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
},
},
})
);
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readItems } from '@directus/sdk'; import GetProductList from '@/graphql/productList.graphql?raw';
export const useProductList = () => { export const useProductList = () => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -7,37 +7,8 @@ export const useProductList = () => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`product-list-${locale}`, async () => { return useAsyncData(`product-list-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ products: Product[] }>(GetProductList, {
readItems('products', { locale: locale,
fields: [ });
'id',
{ translations: ['id', 'name', 'summary'] },
'cover',
{
product_type: [
'id',
{
translations: ['id', 'name'],
},
'sort',
],
},
],
deep: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
product_type: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
},
})
);
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readItems } from '@directus/sdk'; import GetQuestionList from '@/graphql/questionList.graphql?raw';
export const useQuestionList = () => { export const useQuestionList = () => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -7,57 +7,8 @@ export const useQuestionList = () => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`question-list-${locale}`, async () => { return useAsyncData(`question-list-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ questions: Question[] }>(GetQuestionList, {
readItems('questions', { locale: locale,
fields: [ });
'id',
{
translations: ['*'],
},
{
products: [
'id',
{
products_id: [
'id',
{
product_type: [
'id',
{
translations: ['id', 'name'],
},
],
},
{ translations: ['id', 'name'] },
],
},
],
},
],
deep: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
products: {
products_id: {
product_type: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
},
},
})
);
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readItem } from '@directus/sdk'; import GetSolution from '@/graphql/solution.graphql?raw';
export const useSolution = (id: string) => { export const useSolution = (id: string) => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -6,23 +6,9 @@ export const useSolution = (id: string) => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`solution-${id}-${locale}`, async () => { return useAsyncData(`solution-${id}-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ solutions_by_id: Solution }>(GetSolution, {
readItem('solutions', id, { id: id,
fields: [ locale: locale,
'id', });
{
translations: ['*'],
},
'create_at',
],
deep: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
})
);
}); });
}; };

View File

@ -1,4 +1,4 @@
import { readItems } from '@directus/sdk'; import GetSolutionList from '@/graphql/solutionList.graphql?raw';
export const useSolutionList = () => { export const useSolutionList = () => {
const { $directus } = useNuxtApp(); const { $directus } = useNuxtApp();
@ -6,33 +6,8 @@ export const useSolutionList = () => {
const locale = getDirectusLocale(); const locale = getDirectusLocale();
return useAsyncData(`solution-list-${locale}`, async () => { return useAsyncData(`solution-list-${locale}`, async () => {
return await $directus.request( return await $directus.query<{ solutions: Solution[] }>(GetSolutionList, {
readItems('solutions', { locale: locale,
fields: [ });
'id',
'cover',
{
type: ['id', { translations: ['id', 'name'] }, 'sort'],
},
{
translations: ['id', 'title', 'summary'],
},
],
deep: {
type: {
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
translations: {
_filter: {
languages_code: { _eq: locale },
},
},
},
})
);
}); });
}; };

View File

@ -0,0 +1,9 @@
query GetCompanyProfile($locale: String!) {
company_profile {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
content
}
}
}

View File

@ -0,0 +1,9 @@
query GetContactInfo($locale: String!) {
contact_info {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
content
}
}
}

View File

@ -0,0 +1,31 @@
query GetDocumentList($locale: String!) {
product_documents {
id
file {
id
filesize
filename_download
}
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
title
}
products {
id
products_id {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
}
product_type {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
}
}
}
}
}
}

View File

@ -0,0 +1,33 @@
query GetHomepage($locale: String!) {
homepage {
id
carousel {
id
directus_files_id {
id
}
}
recommend_products {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
summary
}
cover {
id
}
}
recommend_solutions {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
title
summary
}
cover {
id
}
}
}
}

View File

@ -0,0 +1,65 @@
query GetProduct($id: ID!, $locale: String!) {
products_by_id(id: $id) {
id
status
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
summary
description
}
images {
id
product_images_id {
id
image {
id
}
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
caption
}
}
}
specs {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
}
specs {
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
key
value
}
}
}
faqs {
id
questions_id {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
title
content
}
}
}
documents {
id
product_documents_id {
id
file {
id
filesize
filename_download
}
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
title
}
}
}
}
}

View File

@ -0,0 +1,22 @@
query GetProductList($locale: String!) {
products(filter: { status: { _eq: "in-production" } }) {
id
status
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
summary
}
cover {
id
}
product_type {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
}
sort
}
}
}

View File

@ -0,0 +1,27 @@
query GetQuestionList($locale: String!) {
questions {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
title
content
}
products {
id
products_id {
id
product_type {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
}
}
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
}
}
}
}
}

View File

@ -0,0 +1,12 @@
query GetSolution($id: ID!, $locale: String!) {
solutions_by_id(id: $id) {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
title
summary
content
}
create_at
}
}

View File

@ -0,0 +1,21 @@
query GetSolutionList($locale: String!) {
solutions {
id
cover {
id
}
type {
id
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
name
}
sort
}
translations(filter: { languages_code: { code: { _eq: $locale } } }) {
id
title
summary
}
}
}

View File

@ -8,8 +8,18 @@ describe('toHomepageView', () => {
const rawData: Homepage = { const rawData: Homepage = {
id: 1, id: 1,
carousel: [ carousel: [
{ id: 1, directus_files_id: 'file-uuid-1' }, {
{ id: 2, directus_files_id: 'file-uuid-2' }, id: 1,
directus_files_id: {
id: 'file-uuid-1',
},
},
{
id: 2,
directus_files_id: {
id: 'file-uuid-2',
},
},
], ],
recommend_products: [ recommend_products: [
{ {

View File

@ -11,7 +11,8 @@ export function toHomepageView(raw: Homepage): HomepageView {
const carousel = (raw.carousel ?? []) const carousel = (raw.carousel ?? [])
.filter(isObject<HomepageFile>) .filter(isObject<HomepageFile>)
.map((item) => item.directus_files_id) .map((item) => item.directus_files_id)
.filter((item) => typeof item === 'string'); .filter(isObject<DirectusFile>)
.map((file) => file.id);
const products = (raw.recommend_products ?? []) const products = (raw.recommend_products ?? [])
.filter(isObject<Product>) .filter(isObject<Product>)

View File

@ -10,7 +10,9 @@ describe('toProductListView', () => {
translations: [ translations: [
{ id: 10, name: 'Product Name', summary: 'Product Summary' }, { id: 10, name: 'Product Name', summary: 'Product Summary' },
], ],
cover: 'cover-file-uuid-1234', cover: {
id: 'cover-file-uuid-1234',
},
product_type: { product_type: {
id: 1, id: 1,
translations: [{ id: 20, name: 'Type Name' }], translations: [{ id: 20, name: 'Type Name' }],
@ -35,7 +37,9 @@ describe('toProductListView', () => {
const rawData: Product = { const rawData: Product = {
id: 1, id: 1,
translations: [], translations: [],
cover: 'cover-file-uuid-1234', cover: {
id: 'cover-file-uuid-1234',
},
product_type: { product_type: {
id: 20, id: 20,
translations: [], translations: [],

View File

@ -33,12 +33,14 @@ export function toProductListView(raw: Product): ProductListView {
? toProductTypeView(raw.product_type) ? toProductTypeView(raw.product_type)
: undefined; : undefined;
const cover = isObject<DirectusFile>(raw.cover) ? raw.cover.id : '';
return { return {
id: raw.id, id: raw.id,
product_type: type, product_type: type,
name: trans.name, name: trans.name,
summary: trans.summary, summary: trans.summary,
cover: raw.cover.toString(), cover: cover,
}; };
} }
@ -110,9 +112,10 @@ export function toProductView(raw: Product): ProductView {
.map((item) => item.product_images_id) .map((item) => item.product_images_id)
.filter(isObject<ProductImage>) .filter(isObject<ProductImage>)
.map((item) => { .map((item) => {
const image = isObject<DirectusFile>(item.image) ? item.image.id : '';
return { return {
id: item.id, id: item.id,
image: item.image.toString(), image: image,
caption: item.translations?.[0]?.caption || '', caption: item.translations?.[0]?.caption || '',
}; };
}); });

View File

@ -34,7 +34,9 @@
]; ];
const { data, pending, error } = await useCompanyProfile(); const { data, pending, error } = await useCompanyProfile();
const content = computed(() => toCompanyProfileView(data.value)); const content = computed(() =>
toCompanyProfileView(data.value.company_profile)
);
watch(error, (value) => { watch(error, (value) => {
if (value) { if (value) {

View File

@ -16,7 +16,7 @@
const { data, pending, error } = await useHomepage(); const { data, pending, error } = await useHomepage();
const homepageData = computed(() => { const homepageData = computed(() => {
return toHomepageView(data.value); return toHomepageView(data.value.homepage);
}); });
const pageTilte = $t('page-title.homepage'); const pageTilte = $t('page-title.homepage');

View File

@ -35,11 +35,12 @@
const localePath = useLocalePath(); const localePath = useLocalePath();
// //
const id = computed(() => route.params.slug as string); const id = route.params.slug as string;
const { data, pending, error } = await useProduct(id.value); const { data, pending, error } = await useProduct(id);
const rawProduct = computed(() => data.value.products_by_id ?? null);
const rawProduct = computed(() => data.value ?? null);
const product = computed(() => { const product = computed(() => {
if (rawProduct.value === null) { if (rawProduct.value === null) {
return null; return null;
@ -60,10 +61,10 @@
}); });
// SEO // SEO
usePageSeo({ // usePageSeo({
title: product.value.name || $t('page-title.products'), // title: product.value.name || $t('page-title.products'),
description: product.value.summary || '', // description: product.value.summary || '',
}); // });
</script> </script>
<style scoped> <style scoped>

View File

@ -37,7 +37,7 @@
const localePath = useLocalePath(); const localePath = useLocalePath();
const { getImageUrl } = useDirectusImage(); const { getImageUrl } = useDirectusImage();
const { data, pending, error } = useProductList(); const { data, pending, error } = await useProductList();
const activeNames = ref<string[]>([]); const activeNames = ref<string[]>([]);
@ -46,12 +46,13 @@
{ label: $t('navigation.products') }, { label: $t('navigation.products') },
]; ];
const productsRaw = computed(() => data.value ?? []); const productsRaw = computed(() => data.value.products ?? []);
const products = computed(() => const products = computed(() =>
productsRaw.value.map((item) => toProductListView(item)) productsRaw.value.map((item) => toProductListView(item))
); );
logger.debug('products: ', products.value); logger.debug('产品列表数据: ', products.value);
// 按类型分组 // 按类型分组
const groupedProducts = computed(() => { const groupedProducts = computed(() => {

View File

@ -26,16 +26,16 @@
const route = useRoute(); const route = useRoute();
const localePath = useLocalePath(); const localePath = useLocalePath();
// (documentId) //
const id = computed(() => route.params.slug as string); const id = route.params.slug as string;
const { data, pending, error } = await useSolution(id.value); const { data, pending, error } = await useSolution(id);
const solution = computed(() => { const solution = computed(() => {
if (!data.value) { if (!data.value) {
return null; return null;
} }
return toSolutionView(data.value); return toSolutionView(data.value.solutions_by_id);
}); });
const breadcrumbItems = computed(() => [ const breadcrumbItems = computed(() => [

View File

@ -54,7 +54,7 @@
const { data, pending, error } = await useSolutionList(); const { data, pending, error } = await useSolutionList();
const solutionsRaw = computed(() => data.value ?? []); const solutionsRaw = computed(() => data.value.solutions ?? []);
const solutions = computed(() => const solutions = computed(() =>
solutionsRaw.value.map((item) => toSolutionListView(item)) solutionsRaw.value.map((item) => toSolutionListView(item))
); );

View File

@ -24,7 +24,7 @@
]; ];
const { data, pending, error } = await useContactInfo(); const { data, pending, error } = await useContactInfo();
const content = computed(() => toContactInfoView(data.value)); const content = computed(() => toContactInfoView(data.value.contact_info));
watch(error, (value) => { watch(error, (value) => {
if (value) { if (value) {

View File

@ -38,7 +38,9 @@
const { data, pending, error } = await useDocumentList(); const { data, pending, error } = await useDocumentList();
const documents = computed( const documents = computed(
() => data?.value.map((item) => toDocumentListView(item)) ?? [] () =>
data?.value.product_documents.map((item) => toDocumentListView(item)) ??
[]
); );
const productTypeOptions = computed(() => { const productTypeOptions = computed(() => {

View File

@ -41,7 +41,7 @@
const { data, pending, error } = await useQuestionList(); const { data, pending, error } = await useQuestionList();
const questions = computed( const questions = computed(
() => data.value.map((item) => toQuestionListView(item)) ?? null () => data.value.questions.map((item) => toQuestionListView(item)) ?? null
); );
const productTypeOptions = computed(() => { const productTypeOptions = computed(() => {

View File

@ -1,10 +1,11 @@
import { createDirectus, rest, staticToken } from '@directus/sdk'; import { createDirectus, rest, staticToken, graphql } from '@directus/sdk';
export default defineNuxtPlugin(() => { export default defineNuxtPlugin(() => {
const config = useRuntimeConfig(); const config = useRuntimeConfig();
const directus = createDirectus<Schema>(config.public.directus.url) const directus = createDirectus<Schema>(config.public.directus.url)
.with(rest()) .with(rest())
.with(graphql())
.with(staticToken(config.public.directus.token || '')); .with(staticToken(config.public.directus.token || ''));
return { return {
provide: { directus }, provide: { directus },

View File

@ -1,4 +1,6 @@
// https://nuxt.com/docs/api/configuration/nuxt-config // https://nuxt.com/docs/api/configuration/nuxt-config
import GraphQLLoader from 'vite-plugin-graphql-loader';
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: '2025-07-15', compatibilityDate: '2025-07-15',
devtools: { enabled: true }, devtools: { enabled: true },
@ -90,6 +92,7 @@ export default defineNuxtConfig({
}, },
}, },
}, },
plugins: [GraphQLLoader()],
}, },
devServer: { devServer: {

View File

@ -25,12 +25,14 @@
"dompurify": "^3.2.6", "dompurify": "^3.2.6",
"element-plus": "^2.10.7", "element-plus": "^2.10.7",
"fuse.js": "^7.1.0", "fuse.js": "^7.1.0",
"graphql": "^16.12.0",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"meilisearch": "^0.53.0", "meilisearch": "^0.53.0",
"nuxt": "^4.0.3", "nuxt": "^4.0.3",
"nuxt-directus": "5.7.0", "nuxt-directus": "5.7.0",
"sass": "^1.90.0", "sass": "^1.90.0",
"sharp": "^0.34.3", "sharp": "^0.34.3",
"vite-plugin-graphql-loader": "^4.0.4",
"vue": "^3.5.18", "vue": "^3.5.18",
"vue-router": "^4.5.1" "vue-router": "^4.5.1"
}, },

32
pnpm-lock.yaml generated
View File

@ -50,6 +50,9 @@ importers:
fuse.js: fuse.js:
specifier: ^7.1.0 specifier: ^7.1.0
version: 7.1.0 version: 7.1.0
graphql:
specifier: ^16.12.0
version: 16.12.0
markdown-it: markdown-it:
specifier: ^14.1.0 specifier: ^14.1.0
version: 14.1.0 version: 14.1.0
@ -68,6 +71,9 @@ importers:
sharp: sharp:
specifier: ^0.34.3 specifier: ^0.34.3
version: 0.34.3 version: 0.34.3
vite-plugin-graphql-loader:
specifier: ^4.0.4
version: 4.0.4
vue: vue:
specifier: ^3.5.18 specifier: ^3.5.18
version: 3.5.21(typescript@5.9.2) version: 3.5.21(typescript@5.9.2)
@ -3498,6 +3504,16 @@ packages:
graphemer@1.4.0: graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
graphql-tag@2.12.6:
resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==}
engines: {node: '>=10'}
peerDependencies:
graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
graphql@16.12.0:
resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==}
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
gzip-size@6.0.0: gzip-size@6.0.0:
resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -5388,6 +5404,9 @@ packages:
vue-tsc: vue-tsc:
optional: true optional: true
vite-plugin-graphql-loader@4.0.4:
resolution: {integrity: sha512-lYnpQ2luV2fcuXmOJADljuktfMbDW00Y+6QS+Ek8Jz1Vdzlj/51LSGJwZqyjJ24a5YQ+o29Hr6el/5+nlZetvg==}
vite-plugin-inspect@11.3.3: vite-plugin-inspect@11.3.3:
resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -9479,6 +9498,13 @@ snapshots:
graphemer@1.4.0: {} graphemer@1.4.0: {}
graphql-tag@2.12.6(graphql@16.12.0):
dependencies:
graphql: 16.12.0
tslib: 2.8.1
graphql@16.12.0: {}
gzip-size@6.0.0: gzip-size@6.0.0:
dependencies: dependencies:
duplexer: 0.1.2 duplexer: 0.1.2
@ -11725,6 +11751,12 @@ snapshots:
optionator: 0.9.4 optionator: 0.9.4
typescript: 5.9.2 typescript: 5.9.2
vite-plugin-graphql-loader@4.0.4:
dependencies:
graphql: 16.12.0
graphql-tag: 2.12.6(graphql@16.12.0)
magic-string: 0.30.19
vite-plugin-inspect@11.3.3(@nuxt/kit@3.19.2(magicast@0.3.5))(vite@7.1.5(@types/node@24.4.0)(jiti@2.5.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1)): vite-plugin-inspect@11.3.3(@nuxt/kit@3.19.2(magicast@0.3.5))(vite@7.1.5(@types/node@24.4.0)(jiti@2.5.1)(sass@1.92.1)(terser@5.44.0)(yaml@2.8.1)):
dependencies: dependencies:
ansis: 4.1.0 ansis: 4.1.0

9
shared/types/graphql.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
declare module '*.graphql' {
const Query: import('graphql').DocumentNode;
export default Query;
export const _queries: Record<string, import('graphql').DocumentNode>;
export const _fragments: Record<
string,
import('graphql').FragmentDefinitionNode
>;
}