From 23f2700c0fd96f8f449181c6cd2709e13001ffd8 Mon Sep 17 00:00:00 2001 From: R2m1liA <15258427350@163.com> Date: Thu, 13 Nov 2025 20:45:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=B0=86Data=E5=88=B0ViewModel?= =?UTF-8?q?=E7=9A=84=E8=BD=AC=E6=8D=A2=E7=94=B1App=E8=BD=AC=E7=A7=BB?= =?UTF-8?q?=E8=87=B3Server=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将逻辑转移到Server端后,简化前端逻辑 --- app/models/mappers/documentMapper.test.ts | 106 ----------------- app/models/mappers/documentMapper.ts | 79 ------------- app/pages/about/index.vue | 6 +- app/pages/index.vue | 16 +-- app/pages/products/[slug].vue | 11 +- app/pages/products/index.vue | 10 +- app/pages/solutions/[slug].vue | 9 +- app/pages/solutions/index.vue | 7 +- app/pages/support/contact-us.vue | 6 +- app/pages/support/documents.vue | 6 +- app/pages/support/faq.vue | 6 +- server/api/cms/companyProfile.get.ts | 7 ++ server/api/cms/companyProfile.ts | 24 ---- server/api/cms/contactInfo.get.ts | 7 ++ server/api/cms/contactInfo.ts | 21 ---- server/api/cms/documentList.get.ts | 7 ++ server/api/cms/documentList.ts | 24 ---- server/api/cms/homepage.get.ts | 7 ++ server/api/cms/homepage.ts | 21 ---- server/api/cms/product/[id].get.ts | 13 +++ server/api/cms/product/[id].ts | 33 ------ server/api/cms/productList.get.ts | 6 + server/api/cms/productList.ts | 21 ---- server/api/cms/questionList.get.ts | 6 + server/api/cms/questionList.ts | 21 ---- server/api/cms/solution/[id].get.ts | 14 +++ server/api/cms/solution/[id].ts | 33 ------ server/api/cms/solutionList.get.ts | 7 ++ server/api/cms/solutionList.ts | 21 ---- .../mappers/companyProfileMapper.test.ts | 13 ++- .../mappers/companyProfileMapper.ts | 4 +- .../mappers/contactInfoMapper.test.ts | 10 +- .../mappers/contactInfoMapper.ts | 4 +- server/mappers/documentMapper.test.ts | 109 ++++++++++++++++++ server/mappers/documentMapper.ts | 76 ++++++++++++ .../mappers/homepageMapper.test.ts | 17 ++- .../mappers/homepageMapper.ts | 24 ++-- .../mappers/productMapper.test.ts | 6 + .../mappers/productMapper.ts | 58 +++++----- .../mappers/questionMapper.test.ts | 50 ++++---- .../mappers/questionMapper.ts | 31 ++--- .../mappers/searchItemMapper.ts | 2 +- .../mappers/solutionMapper.test.ts | 64 +++++----- .../mappers/solutionMapper.ts | 37 +++--- server/services/cms/companyProfileService.ts | 25 ++++ server/services/cms/contactInfoService.ts | 22 ++++ server/services/cms/documentService.ts | 27 +++++ server/services/cms/homepageService.ts | 22 ++++ server/services/cms/productService.ts | 55 +++++++++ server/services/cms/questionService.ts | 24 ++++ server/services/cms/solutionService.ts | 55 +++++++++ server/utils/object.test.ts | 66 +++++++++++ server/utils/object.ts | 30 +++++ server/utils/search-converter.test.ts | 76 ++++++++++++ server/utils/search-converters.ts | 36 ++++++ shared/types/index.ts | 1 + .../types/views/company-profile-view.ts | 0 .../types/views/contact-info-view.ts | 0 .../types/views/document-list-view.ts | 0 .../types/views/homepage-view.ts | 0 shared/types/views/index.ts | 13 +++ .../types/views/product-document-view.ts | 0 .../types/views/product-list-view.ts | 0 .../types/views/product-question-view.ts | 0 .../types/views/product-spec-group-view.ts | 0 .../types/views/product-view.ts | 4 + .../types/views/question-list-view.ts | 0 .../types/views/search-item-view.ts | 2 +- .../types/views/solution-list-view.ts | 0 .../types/views/solution-view.ts | 0 70 files changed, 904 insertions(+), 614 deletions(-) delete mode 100644 app/models/mappers/documentMapper.test.ts delete mode 100644 app/models/mappers/documentMapper.ts create mode 100644 server/api/cms/companyProfile.get.ts delete mode 100644 server/api/cms/companyProfile.ts create mode 100644 server/api/cms/contactInfo.get.ts delete mode 100644 server/api/cms/contactInfo.ts create mode 100644 server/api/cms/documentList.get.ts delete mode 100644 server/api/cms/documentList.ts create mode 100644 server/api/cms/homepage.get.ts delete mode 100644 server/api/cms/homepage.ts create mode 100644 server/api/cms/product/[id].get.ts delete mode 100644 server/api/cms/product/[id].ts create mode 100644 server/api/cms/productList.get.ts delete mode 100644 server/api/cms/productList.ts create mode 100644 server/api/cms/questionList.get.ts delete mode 100644 server/api/cms/questionList.ts create mode 100644 server/api/cms/solution/[id].get.ts delete mode 100644 server/api/cms/solution/[id].ts create mode 100644 server/api/cms/solutionList.get.ts delete mode 100644 server/api/cms/solutionList.ts rename {app/models => server}/mappers/companyProfileMapper.test.ts (72%) rename {app/models => server}/mappers/companyProfileMapper.ts (81%) rename {app/models => server}/mappers/contactInfoMapper.test.ts (72%) rename {app/models => server}/mappers/contactInfoMapper.ts (80%) create mode 100644 server/mappers/documentMapper.test.ts create mode 100644 server/mappers/documentMapper.ts rename {app/models => server}/mappers/homepageMapper.test.ts (88%) rename {app/models => server}/mappers/homepageMapper.ts (69%) rename {app/models => server}/mappers/productMapper.test.ts (97%) rename {app/models => server}/mappers/productMapper.ts (79%) rename {app/models => server}/mappers/questionMapper.test.ts (73%) rename {app/models => server}/mappers/questionMapper.ts (62%) rename {app/models => server}/mappers/searchItemMapper.ts (88%) rename {app/models => server}/mappers/solutionMapper.test.ts (67%) rename {app/models => server}/mappers/solutionMapper.ts (68%) create mode 100644 server/services/cms/companyProfileService.ts create mode 100644 server/services/cms/contactInfoService.ts create mode 100644 server/services/cms/documentService.ts create mode 100644 server/services/cms/homepageService.ts create mode 100644 server/services/cms/productService.ts create mode 100644 server/services/cms/questionService.ts create mode 100644 server/services/cms/solutionService.ts create mode 100644 server/utils/object.test.ts create mode 100644 server/utils/object.ts create mode 100644 server/utils/search-converter.test.ts create mode 100644 server/utils/search-converters.ts rename app/models/views/CompanyProfileView.ts => shared/types/views/company-profile-view.ts (100%) rename app/models/views/ContactInfoView.ts => shared/types/views/contact-info-view.ts (100%) rename app/models/views/DocumentListView.ts => shared/types/views/document-list-view.ts (100%) rename app/models/views/HomepageView.ts => shared/types/views/homepage-view.ts (100%) create mode 100644 shared/types/views/index.ts rename app/models/views/ProductDocumentView.ts => shared/types/views/product-document-view.ts (100%) rename app/models/views/ProductListView.ts => shared/types/views/product-list-view.ts (100%) rename app/models/views/ProductQuestionView.ts => shared/types/views/product-question-view.ts (100%) rename app/models/views/ProductSpecGroupView.ts => shared/types/views/product-spec-group-view.ts (100%) rename app/models/views/ProductView.ts => shared/types/views/product-view.ts (75%) rename app/models/views/QuestionListVuew.ts => shared/types/views/question-list-view.ts (100%) rename app/models/views/SearchItemView.ts => shared/types/views/search-item-view.ts (92%) rename app/models/views/SolutionListView.ts => shared/types/views/solution-list-view.ts (100%) rename app/models/views/SolutionView.ts => shared/types/views/solution-view.ts (100%) diff --git a/app/models/mappers/documentMapper.test.ts b/app/models/mappers/documentMapper.test.ts deleted file mode 100644 index 319ba4c..0000000 --- a/app/models/mappers/documentMapper.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { describe, test, expect } from 'vitest'; - -/** - * 单元测试: toProductDocumentView - */ -describe('toProductDocumentView', () => { - test('convert raw data with fileId to ProductDocumentView correctly', () => { - const rawData: ProductDocument = { - id: 1, - file: 'rand-om__-uuid-1234', - translations: [{ id: 10, title: 'Document Title' }], - }; - - expect(toProductDocumentView(rawData)).toEqual({ - id: 1, - fileId: 'rand-om__-uuid-1234', - filename: undefined, - title: 'Document Title', - url: 'http://localhost:8055/assets/rand-om__-uuid-1234', - size: undefined, - }); - }); - - test('convert raw data with fileMeta to ProductDocumentView correctly', () => { - const rawData: ProductDocument = { - id: 1, - file: { - id: 'rand-om__-uuid-1234', - filename_download: 'document.pdf', - filesize: 2048, - }, - translations: [{ id: 10, title: 'Document Title' }], - }; - - expect(toProductDocumentView(rawData)).toEqual({ - id: 1, - fileId: 'rand-om__-uuid-1234', - filename: 'document.pdf', - title: 'Document Title', - url: 'http://localhost:8055/assets/rand-om__-uuid-1234', - size: 2048, - }); - }); - - test('convert raw data with missing translations', () => { - const rawData: ProductDocument = { - id: 1, - file: 'rand-om__-uuid-1234', - translations: [], - }; - - expect(toProductDocumentView(rawData)).toEqual({ - id: 1, - fileId: 'rand-om__-uuid-1234', - filename: undefined, - title: '', - url: 'http://localhost:8055/assets/rand-om__-uuid-1234', - size: undefined, - }); - }); -}); - -/** - * 单元测试: toDocumentListView - */ -describe('toProductDocumentView', () => { - test('convert raw data with fileId to DocumentListView correctly', () => { - const rawData: ProductDocument = { - id: 1, - file: 'rand-om__-uuid-1234', - translations: [{ id: 10, title: 'Document Title' }], - products: [ - { - id: 10, - products_id: { - id: 1, - translations: [{ id: 1, name: 'Product A' }], - product_type: { - id: 1, - translations: [{ id: 1, name: 'Type A' }], - }, - }, - }, - ], - }; - - expect(toDocumentListView(rawData)).toEqual({ - id: 1, - fileId: 'rand-om__-uuid-1234', - filename: undefined, - title: 'Document Title', - url: 'http://localhost:8055/assets/rand-om__-uuid-1234', - size: undefined, - products: [ - { - id: 1, - name: 'Product A', - type: { - id: 1, - name: 'Type A', - }, - }, - ], - }); - }); -}); diff --git a/app/models/mappers/documentMapper.ts b/app/models/mappers/documentMapper.ts deleted file mode 100644 index d5c855d..0000000 --- a/app/models/mappers/documentMapper.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * 将 Directus 返回的 Document 数据转换为 ProductDocumentView 视图模型 - * - * @param raw: 原始的 Document 数据 - * @returns 转换后的 ProductDocumentView 对象 - * - * @example - * const view = toProductDocumentView(rawDocument); - */ -export function toProductDocumentView( - raw: ProductDocument -): ProductDocumentView { - const trans = raw.translations?.[0] ?? { - title: '', - }; - - const fileId = typeof raw.file === 'string' ? raw.file : raw.file?.id; - const file = raw.file as DirectusFile; - - const { getFileUrl } = useDirectusFiles(); - - const url = getFileUrl(fileId); - - return { - id: raw.id, - fileId: fileId, - filename: file.filename_download, - title: trans.title, - url: url, - size: file.filesize, - }; -} - -/** - * 将 Directus 返回的 Document 数据转换为 DocumentListView 视图模型 - * - * @param raw: 原始的 Document 数据 - * @returns 转换后的 DocumentListView 对象 - * - * @example - * const view = toDocumentListView(rawDocument); - */ -export function toDocumentListView(raw: ProductDocument): DocumentListView { - const trans = raw.translations?.[0] ?? { title: '' }; - - const fileId = typeof raw.file === 'string' ? raw.file : raw.file?.id; - const file = raw.file as DirectusFile; - - const { getFileUrl } = useDirectusFiles(); - const url = getFileUrl(fileId); - - const related_products: DocumentListProduct[] = raw.products - ?.filter(isObject) - .map((item) => item.products_id) - .filter(isObject) - .map((item) => { - const productType = - isObject(item.product_type) && - ({ - id: item.product_type.id, - name: item.product_type.translations?.[0]?.name, - } satisfies DocumentListProductType); - return { - id: item.id, - name: item.translations?.[0]?.name, - type: productType, - }; - }); - - return { - id: raw.id, - fileId: fileId, - filename: file.filename_download, - title: trans.title, - url: url, - size: file.filesize, - products: related_products, - }; -} diff --git a/app/pages/about/index.vue b/app/pages/about/index.vue index 64dd05f..28a237a 100644 --- a/app/pages/about/index.vue +++ b/app/pages/about/index.vue @@ -4,7 +4,7 @@
- +
{{ $t('learn-more') }} @@ -32,9 +32,7 @@ { label: $t('navigation.home'), to: localePath('/') }, { label: $t('navigation.about-us') }, ]; - const { data, pending, error } = await useCompanyProfile(); - - const content = computed(() => toCompanyProfileView(data.value)); + const { data: companyProfile, pending, error } = await useCompanyProfile(); watch(error, (value) => { if (value) { diff --git a/app/pages/index.vue b/app/pages/index.vue index f2eb413..d9ecd28 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,24 +1,14 @@