From e05f248b66b699389271a9d2d76ed9fd7e39d26f Mon Sep 17 00:00:00 2001 From: R2m1liA <15258427350@163.com> Date: Mon, 13 Oct 2025 16:53:13 +0800 Subject: [PATCH 01/30] =?UTF-8?q?chore:=20=E5=AF=BC=E5=85=A5Directus?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 导入Directus SDK - 配置Directus RuntimeConfig --- nuxt.config.ts | 5 +++++ package.json | 2 ++ pnpm-lock.yaml | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/nuxt.config.ts b/nuxt.config.ts index f11a1bc..45c1ad9 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -38,6 +38,10 @@ export default defineNuxtConfig({ cookie: {}, cookieName: 'strapi_jwt', }, + directus: { + url: process.env.DIRECTUS_URL || 'http://localhost:8055', + token: process.env.DIRECTUS_TOKEN || undefined, + }, }, }, @@ -129,5 +133,6 @@ export default defineNuxtConfig({ '@element-plus/nuxt', '@nuxtjs/i18n', '@nuxtjs/strapi', + 'nuxt-directus', ], }); diff --git a/package.json b/package.json index 12d5ce2..537ddb7 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "prepare": "husky" }, "dependencies": { + "@directus/sdk": "^20.1.0", "@mdi/font": "^7.4.47", "@nuxt/eslint": "1.8.0", "@nuxt/fonts": "0.11.4", @@ -28,6 +29,7 @@ "markdown-it": "^14.1.0", "meilisearch": "^0.53.0", "nuxt": "^4.0.3", + "nuxt-directus": "5.7.0", "sass": "^1.90.0", "sharp": "^0.34.3", "vue": "^3.5.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aefb60f..c8f9ea5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@directus/sdk': + specifier: ^20.1.0 + version: 20.1.0 '@mdi/font': specifier: ^7.4.47 version: 7.4.47 @@ -59,6 +62,9 @@ importers: nuxt: specifier: ^4.0.3 version: 4.1.2(@parcel/watcher@2.5.1)(@types/node@24.4.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.2)(sass@1.92.1)(terser@5.44.0)(typescript@5.9.2)(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))(yaml@2.8.1) + nuxt-directus: + specifier: 5.7.0 + version: 5.7.0(magicast@0.3.5) sass: specifier: ^1.90.0 version: 1.92.1 @@ -323,6 +329,10 @@ packages: resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} engines: {node: '>=10'} + '@directus/sdk@20.1.0': + resolution: {integrity: sha512-EV2bwfiOXc1QFYAIqfGgyZ7JcKgHF43UVEYivUpMjOLiihI9tpmNfcz/qmOXju7LCZrBmSwTOHMRtOXPdZWiLQ==} + engines: {node: '>=22'} + '@element-plus/icons-vue@2.3.2': resolution: {integrity: sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==} peerDependencies: @@ -4123,6 +4133,9 @@ packages: nuxt-define@1.0.0: resolution: {integrity: sha512-CYZ2WjU+KCyCDVzjYUM4eEpMF0rkPmkpiFrybTqqQCRpUbPt2h3snswWIpFPXTi+osRCY6Og0W/XLAQgDL4FfQ==} + nuxt-directus@5.7.0: + resolution: {integrity: sha512-hoNXbhQ8UgDrCXqzqxC0wngi64AVqYYGGU/bwylgZWbKyU0m6kyNQVLGuQuXmFbogr2WMaw+FtXSgLz+DS32hA==} + nuxt@4.1.2: resolution: {integrity: sha512-g5mwszCZT4ZeGJm83nxoZvtvZoAEaY65VDdn7p7UgznePbRaEJJ1KS1OIld4FPVkoDZ8TEVuDNqI9gUn12Exvg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5879,6 +5892,8 @@ snapshots: '@ctrl/tinycolor@3.6.1': {} + '@directus/sdk@20.1.0': {} + '@element-plus/icons-vue@2.3.2(vue@3.5.21(typescript@5.9.2))': dependencies: vue: 3.5.21(typescript@5.9.2) @@ -10058,6 +10073,12 @@ snapshots: nuxt-define@1.0.0: {} + nuxt-directus@5.7.0(magicast@0.3.5): + dependencies: + '@nuxt/kit': 3.19.2(magicast@0.3.5) + transitivePeerDependencies: + - magicast + nuxt@4.1.2(@parcel/watcher@2.5.1)(@types/node@24.4.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.2)(sass@1.92.1)(terser@5.44.0)(typescript@5.9.2)(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))(yaml@2.8.1): dependencies: '@nuxt/cli': 3.28.0(magicast@0.3.5) -- 2.49.0 From 33c94fb88559b6090a75755c01b0b56593dc7520 Mon Sep 17 00:00:00 2001 From: R2m1liA <15258427350@163.com> Date: Mon, 13 Oct 2025 16:56:28 +0800 Subject: [PATCH 02/30] =?UTF-8?q?style(types):=20directus=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=A0=87=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用directus-sdk-typegen生成Directus类型 --- app/types/common.ts | 7 + app/types/directus/index.ts | 1 + app/types/directus/my-schema.ts | 835 ++++++++++++++++++++++++++++++++ 3 files changed, 843 insertions(+) create mode 100644 app/types/common.ts create mode 100644 app/types/directus/index.ts create mode 100644 app/types/directus/my-schema.ts diff --git a/app/types/common.ts b/app/types/common.ts new file mode 100644 index 0000000..3d4e2ce --- /dev/null +++ b/app/types/common.ts @@ -0,0 +1,7 @@ +export type JsonPrimitive = string | number | boolean | null; + +export type JsonArray = JsonValue[]; + +export type JsonObject = { [key: string]: JsonValue }; + +export type JsonValue = JsonPrimitive | JsonArray | JsonObject; diff --git a/app/types/directus/index.ts b/app/types/directus/index.ts new file mode 100644 index 0000000..eb148e7 --- /dev/null +++ b/app/types/directus/index.ts @@ -0,0 +1 @@ +export * from './my-schema'; diff --git a/app/types/directus/my-schema.ts b/app/types/directus/my-schema.ts new file mode 100644 index 0000000..706719b --- /dev/null +++ b/app/types/directus/my-schema.ts @@ -0,0 +1,835 @@ +import type { JsonValue } from '../common'; + +export interface CompanyProfile { + /** @primaryKey */ + id: number; + translations?: CompanyProfileTranslation[] | null; +} + +export interface CompanyProfileTranslation { + /** @primaryKey */ + id: number; + company_profile_id?: CompanyProfile | string | null; + languages_code?: Language | string | null; + content?: 'json' | null; +} + +export interface ContactInfo { + /** @primaryKey */ + id: number; + translations?: ContactInfoTranslation[] | null; +} + +export interface ContactInfoTranslation { + /** @primaryKey */ + id: number; + contact_info_id?: ContactInfo | string | null; + languages_code?: Language | string | null; + content?: 'json' | null; +} + +export interface Document { + /** @primaryKey */ + id: number; + status?: 'published' | 'draft' | 'archived'; + file?: DirectusFile | string | null; + /** @description i18n字段 */ + translations?: DocumentsTranslation[] | null; + products?: ProductsDocument[] | string[]; +} + +export interface DocumentsTranslation { + /** @primaryKey */ + id: number; + documents_id?: Document | string | null; + languages_code?: Language | string | null; + title?: string | null; +} + +export interface Homepage { + /** @primaryKey */ + id: number; + carousel?: HomepageFile[] | string[]; + recommend_products?: Product[] | string[]; + recommend_solutions?: Solution[] | string[]; +} + +export interface HomepageFile { + /** @primaryKey */ + id: number; + homepage_id?: Homepage | string | null; + directus_files_id?: DirectusFile | string | null; +} + +export interface Language { + /** @primaryKey */ + code: string; + name?: string | null; + direction?: 'ltr' | 'rtl' | null; +} + +export interface ProductImage { + /** @primaryKey */ + id: number; + image?: DirectusFile | string | null; + translations?: ProductImagesTranslation[] | null; + products?: ProductsProductImage[] | string[]; +} + +export interface ProductImagesTranslation { + /** @primaryKey */ + id: number; + product_images_id?: ProductImage | string | null; + languages_code?: Language | string | null; + caption?: string | null; +} + +export interface ProductSpecGroup { + /** @primaryKey */ + id: number; + product?: Product | string | null; + sort?: number | null; + translations?: ProductSpecGroupsTranslation[] | null; + specs?: ProductSpec[] | string[]; +} + +export interface ProductSpecGroupsTranslation { + /** @primaryKey */ + id: number; + product_spec_groups_id?: ProductSpecGroup | string | null; + languages_code?: Language | string | null; + name?: string | null; +} + +export interface ProductSpec { + /** @primaryKey */ + id: number; + group?: ProductSpecGroup | string | null; + sort?: number | null; + value?: string | null; + translations?: ProductSpecsTranslation[] | null; +} + +export interface ProductSpecsTranslation { + /** @primaryKey */ + id: number; + product_specs_id?: ProductSpec | string | null; + languages_code?: Language | string | null; + key?: string | null; +} + +export interface ProductType { + /** @primaryKey */ + id: number; + /** @description 当前产品条目的状态 */ + status?: 'published' | 'draft' | 'archived'; + /** @description i18n文本 */ + translations?: ProductTypesTranslation[] | null; +} + +export interface ProductTypesTranslation { + /** @primaryKey */ + id: number; + product_types_id?: ProductType | string | null; + languages_code?: Language | string | null; + /** @required */ + name: string; +} + +export interface Product { + /** @primaryKey */ + id: number; + /** @description 当前产品条目的状态 */ + status?: 'published' | 'draft' | 'archived'; + product_type?: ProductType | string | null; + /** @description 在产品列表中显示 */ + cover?: DirectusFile | string | null; + homepage_recommend?: Homepage | string | null; + recommend_sort?: number | null; + faqs?: ProductsQuestion[] | string[]; + /** @description i18n字段 */ + translations?: ProductsTranslation[] | null; + /** @description 在产品详情页中展示 */ + images?: ProductsProductImage[] | string[]; + documents?: ProductsDocument[] | string[]; + specs?: ProductSpecGroup[] | string[]; +} + +export interface ProductsDocument { + /** @primaryKey */ + id: number; + products_id?: Product | string | null; + documents_id?: Document | string | null; + sort?: number | null; +} + +export interface ProductsProductImage { + /** @primaryKey */ + id: number; + products_id?: Product | string | null; + product_images_id?: ProductImage | string | null; + sort?: number | null; +} + +export interface ProductsQuestion { + /** @primaryKey */ + id: number; + products_id?: Product | string | null; + questions_id?: Question | string | null; + sort?: number | null; +} + +export interface ProductsTranslation { + /** @primaryKey */ + id: number; + products_id?: Product | string | null; + languages_code?: Language | string | null; + /** @required */ + name: string; + summary?: string | null; + description?: JsonValue | null; +} + +export interface Question { + /** @primaryKey */ + id: number; + status?: 'published' | 'draft' | 'archived'; + /** @description i18n字段 */ + translations?: QuestionsTranslation[] | null; + products?: ProductsQuestion[] | string[]; +} + +export interface QuestionsTranslation { + /** @primaryKey */ + id: number; + questions_id?: Question | string | null; + languages_code?: Language | string | null; + /** @required */ + title: string; + content?: 'json' | null; +} + +export interface SolutionType { + /** @primaryKey */ + id: number; + status?: 'published' | 'draft' | 'archived'; + /** @description i18n字段 */ + translations?: SolutionTypesTranslation[] | null; +} + +export interface SolutionTypesTranslation { + /** @primaryKey */ + id: number; + solution_types_id?: SolutionType | string | null; + languages_code?: Language | string | null; + name?: string | null; +} + +export interface Solution { + /** @primaryKey */ + id: number; + status?: 'published' | 'draft' | 'archived'; + type?: SolutionType | string | null; + cover?: DirectusFile | string | null; + homepage_recommend?: Homepage | string | null; + recommend_sort?: number | null; + translations?: SolutionsTranslation[] | null; +} + +export interface SolutionsTranslation { + /** @primaryKey */ + id: number; + solutions_id?: Solution | string | null; + languages_code?: Language | string | null; + title?: string | null; + summary?: string | null; + content?: 'json' | null; +} + +export interface DirectusAccess { + /** @primaryKey */ + id: string; + role?: DirectusRole | string | null; + user?: DirectusUser | string | null; + policy?: DirectusPolicy | string; + sort?: number | null; +} + +export interface DirectusActivity { + /** @primaryKey */ + id: number; + action?: string; + user?: DirectusUser | string | null; + timestamp?: string; + ip?: string | null; + user_agent?: string | null; + collection?: string; + item?: string; + origin?: string | null; + revisions?: DirectusRevision[] | string[]; +} + +export interface DirectusCollection { + /** @primaryKey */ + collection: string; + icon?: string | null; + note?: string | null; + display_template?: string | null; + hidden?: boolean; + singleton?: boolean; + translations?: Array<{ + language: string; + translation: string; + singular: string; + plural: string; + }> | null; + archive_field?: string | null; + archive_app_filter?: boolean; + archive_value?: string | null; + unarchive_value?: string | null; + sort_field?: string | null; + accountability?: 'all' | 'activity' | null | null; + color?: string | null; + item_duplication_fields?: 'json' | null; + sort?: number | null; + group?: DirectusCollection | string | null; + collapse?: string; + preview_url?: string | null; + versioning?: boolean; +} + +export interface DirectusComment { + /** @primaryKey */ + id: string; + collection?: DirectusCollection | string; + item?: string; + comment?: string; + date_created?: string | null; + date_updated?: string | null; + user_created?: DirectusUser | string | null; + user_updated?: DirectusUser | string | null; +} + +export interface DirectusField { + /** @primaryKey */ + id: number; + collection?: DirectusCollection | string; + field?: string; + special?: string[] | null; + interface?: string | null; + options?: 'json' | null; + display?: string | null; + display_options?: 'json' | null; + readonly?: boolean; + hidden?: boolean; + sort?: number | null; + width?: string | null; + translations?: 'json' | null; + note?: string | null; + conditions?: 'json' | null; + required?: boolean | null; + group?: DirectusField | string | null; + validation?: 'json' | null; + validation_message?: string | null; +} + +export interface DirectusFile { + /** @primaryKey */ + id: string; + storage?: string; + filename_disk?: string | null; + filename_download?: string; + title?: string | null; + type?: string | null; + folder?: DirectusFolder | string | null; + uploaded_by?: DirectusUser | string | null; + created_on?: string; + modified_by?: DirectusUser | string | null; + modified_on?: string; + charset?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + duration?: number | null; + embed?: string | null; + description?: string | null; + location?: string | null; + tags?: string[] | null; + metadata?: 'json' | null; + focal_point_x?: number | null; + focal_point_y?: number | null; + tus_id?: string | null; + tus_data?: 'json' | null; + uploaded_on?: string | null; +} + +export interface DirectusFolder { + /** @primaryKey */ + id: string; + name?: string; + parent?: DirectusFolder | string | null; +} + +export interface DirectusMigration { + /** @primaryKey */ + version: string; + name?: string; + timestamp?: string | null; +} + +export interface DirectusPermission { + /** @primaryKey */ + id: number; + collection?: string; + action?: string; + permissions?: 'json' | null; + validation?: 'json' | null; + presets?: 'json' | null; + fields?: string[] | null; + policy?: DirectusPolicy | string; +} + +export interface DirectusPolicy { + /** @primaryKey */ + id: string; + /** @required */ + name: string; + icon?: string; + description?: string | null; + ip_access?: string[] | null; + enforce_tfa?: boolean; + admin_access?: boolean; + app_access?: boolean; + permissions?: DirectusPermission[] | string[]; + users?: DirectusAccess[] | string[]; + roles?: DirectusAccess[] | string[]; +} + +export interface DirectusPreset { + /** @primaryKey */ + id: number; + bookmark?: string | null; + user?: DirectusUser | string | null; + role?: DirectusRole | string | null; + collection?: string | null; + search?: string | null; + layout?: string | null; + layout_query?: 'json' | null; + layout_options?: 'json' | null; + refresh_interval?: number | null; + filter?: 'json' | null; + icon?: string | null; + color?: string | null; +} + +export interface DirectusRelation { + /** @primaryKey */ + id: number; + many_collection?: string; + many_field?: string; + one_collection?: string | null; + one_field?: string | null; + one_collection_field?: string | null; + one_allowed_collections?: string[] | null; + junction_field?: string | null; + sort_field?: string | null; + one_deselect_action?: string; +} + +export interface DirectusRevision { + /** @primaryKey */ + id: number; + activity?: DirectusActivity | string; + collection?: string; + item?: string; + data?: 'json' | null; + delta?: 'json' | null; + parent?: DirectusRevision | string | null; + version?: DirectusVersion | string | null; +} + +export interface DirectusRole { + /** @primaryKey */ + id: string; + /** @required */ + name: string; + icon?: string; + description?: string | null; + parent?: DirectusRole | string | null; + children?: DirectusRole[] | string[]; + policies?: DirectusAccess[] | string[]; + users?: DirectusUser[] | string[]; +} + +export interface DirectusSession { + /** @primaryKey */ + token: string; + user?: DirectusUser | string | null; + expires?: string; + ip?: string | null; + user_agent?: string | null; + share?: DirectusShare | string | null; + origin?: string | null; + next_token?: string | null; +} + +export interface DirectusSettings { + /** @primaryKey */ + id: number; + project_name?: string; + project_url?: string | null; + project_color?: string; + project_logo?: DirectusFile | string | null; + public_foreground?: DirectusFile | string | null; + public_background?: DirectusFile | string | null; + public_note?: string | null; + auth_login_attempts?: number | null; + auth_password_policy?: + | null + | `/^.{8,}$/` + | `/(?=^.{8,}$)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{';'?>.<,])(?!.*\\s).*$/` + | null; + storage_asset_transform?: 'all' | 'none' | 'presets' | null; + storage_asset_presets?: Array<{ + key: string; + fit: 'contain' | 'cover' | 'inside' | 'outside'; + width: number; + height: number; + quality: number; + withoutEnlargement: boolean; + format: 'auto' | 'jpeg' | 'png' | 'webp' | 'tiff' | 'avif'; + transforms: 'json'; + }> | null; + custom_css?: string | null; + storage_default_folder?: DirectusFolder | string | null; + basemaps?: Array<{ + name: string; + type: 'raster' | 'tile' | 'style'; + url: string; + tileSize: number; + attribution: string; + }> | null; + mapbox_key?: string | null; + module_bar?: 'json' | null; + project_descriptor?: string | null; + default_language?: string; + custom_aspect_ratios?: Array<{ text: string; value: number }> | null; + public_favicon?: DirectusFile | string | null; + default_appearance?: 'auto' | 'light' | 'dark'; + default_theme_light?: string | null; + theme_light_overrides?: 'json' | null; + default_theme_dark?: string | null; + theme_dark_overrides?: 'json' | null; + report_error_url?: string | null; + report_bug_url?: string | null; + report_feature_url?: string | null; + public_registration?: boolean; + public_registration_verify_email?: boolean; + public_registration_role?: DirectusRole | string | null; + public_registration_email_filter?: 'json' | null; + visual_editor_urls?: Array<{ url: string }> | null; + accepted_terms?: boolean | null; + project_id?: string | null; + mcp_enabled?: boolean; + mcp_allow_deletes?: boolean; + mcp_prompts_collection?: string | null; + mcp_system_prompt_enabled?: boolean; + mcp_system_prompt?: string | null; +} + +export interface DirectusUser { + /** @primaryKey */ + id: string; + first_name?: string | null; + last_name?: string | null; + email?: string | null; + password?: string | null; + location?: string | null; + title?: string | null; + description?: string | null; + tags?: string[] | null; + avatar?: DirectusFile | string | null; + language?: string | null; + tfa_secret?: string | null; + status?: + | 'draft' + | 'invited' + | 'unverified' + | 'active' + | 'suspended' + | 'archived'; + role?: DirectusRole | string | null; + token?: string | null; + last_access?: string | null; + last_page?: string | null; + provider?: string; + external_identifier?: string | null; + auth_data?: 'json' | null; + email_notifications?: boolean | null; + appearance?: null | 'auto' | 'light' | 'dark' | null; + theme_dark?: string | null; + theme_light?: string | null; + theme_light_overrides?: 'json' | null; + theme_dark_overrides?: 'json' | null; + text_direction?: 'auto' | 'ltr' | 'rtl'; + policies?: DirectusAccess[] | string[]; +} + +export interface DirectusWebhook { + /** @primaryKey */ + id: number; + name?: string; + method?: null; + url?: string; + status?: 'active' | 'inactive'; + data?: boolean; + actions?: 'create' | 'update' | 'delete'; + collections?: string[]; + headers?: Array<{ header: string; value: string }> | null; + was_active_before_deprecation?: boolean; + migrated_flow?: DirectusFlow | string | null; +} + +export interface DirectusDashboard { + /** @primaryKey */ + id: string; + name?: string; + icon?: string; + note?: string | null; + date_created?: string | null; + user_created?: DirectusUser | string | null; + color?: string | null; + panels?: DirectusPanel[] | string[]; +} + +export interface DirectusPanel { + /** @primaryKey */ + id: string; + dashboard?: DirectusDashboard | string; + name?: string | null; + icon?: string | null; + color?: string | null; + show_header?: boolean; + note?: string | null; + type?: string; + position_x?: number; + position_y?: number; + width?: number; + height?: number; + options?: 'json' | null; + date_created?: string | null; + user_created?: DirectusUser | string | null; +} + +export interface DirectusNotification { + /** @primaryKey */ + id: number; + timestamp?: string | null; + status?: string | null; + recipient?: DirectusUser | string; + sender?: DirectusUser | string | null; + subject?: string; + message?: string | null; + collection?: string | null; + item?: string | null; +} + +export interface DirectusShare { + /** @primaryKey */ + id: string; + name?: string | null; + collection?: DirectusCollection | string; + item?: string; + role?: DirectusRole | string | null; + password?: string | null; + user_created?: DirectusUser | string | null; + date_created?: string | null; + date_start?: string | null; + date_end?: string | null; + times_used?: number | null; + max_uses?: number | null; +} + +export interface DirectusFlow { + /** @primaryKey */ + id: string; + name?: string; + icon?: string | null; + color?: string | null; + description?: string | null; + status?: string; + trigger?: string | null; + accountability?: string | null; + options?: 'json' | null; + operation?: DirectusOperation | string | null; + date_created?: string | null; + user_created?: DirectusUser | string | null; + operations?: DirectusOperation[] | string[]; +} + +export interface DirectusOperation { + /** @primaryKey */ + id: string; + name?: string | null; + key?: string; + type?: string; + position_x?: number; + position_y?: number; + options?: 'json' | null; + resolve?: DirectusOperation | string | null; + reject?: DirectusOperation | string | null; + flow?: DirectusFlow | string; + date_created?: string | null; + user_created?: DirectusUser | string | null; +} + +export interface DirectusTranslation { + /** @primaryKey */ + id: string; + /** @required */ + language: string; + /** @required */ + key: string; + /** @required */ + value: string; +} + +export interface DirectusVersion { + /** @primaryKey */ + id: string; + key?: string; + name?: string | null; + collection?: DirectusCollection | string; + item?: string; + hash?: string | null; + date_created?: string | null; + date_updated?: string | null; + user_created?: DirectusUser | string | null; + user_updated?: DirectusUser | string | null; + delta?: 'json' | null; +} + +export interface DirectusExtension { + enabled?: boolean; + /** @primaryKey */ + id: string; + folder?: string; + source?: string; + bundle?: string | null; +} + +export interface Schema { + company_profile: CompanyProfile; + company_profile_translations: CompanyProfileTranslation[]; + contact_info: ContactInfo; + contact_info_translations: ContactInfoTranslation[]; + documents: Document[]; + documents_translations: DocumentsTranslation[]; + homepage: Homepage; + homepage_files: HomepageFile[]; + languages: Language[]; + product_images: ProductImage[]; + product_images_translations: ProductImagesTranslation[]; + product_spec_groups: ProductSpecGroup[]; + product_spec_groups_translations: ProductSpecGroupsTranslation[]; + product_specs: ProductSpec[]; + product_specs_translations: ProductSpecsTranslation[]; + product_types: ProductType[]; + product_types_translations: ProductTypesTranslation[]; + products: Product[]; + products_documents: ProductsDocument[]; + products_product_images: ProductsProductImage[]; + products_questions: ProductsQuestion[]; + products_translations: ProductsTranslation[]; + questions: Question[]; + questions_translations: QuestionsTranslation[]; + solution_types: SolutionType[]; + solution_types_translations: SolutionTypesTranslation[]; + solutions: Solution[]; + solutions_translations: SolutionsTranslation[]; + directus_access: DirectusAccess[]; + directus_activity: DirectusActivity[]; + directus_collections: DirectusCollection[]; + directus_comments: DirectusComment[]; + directus_fields: DirectusField[]; + directus_files: DirectusFile[]; + directus_folders: DirectusFolder[]; + directus_migrations: DirectusMigration[]; + directus_permissions: DirectusPermission[]; + directus_policies: DirectusPolicy[]; + directus_presets: DirectusPreset[]; + directus_relations: DirectusRelation[]; + directus_revisions: DirectusRevision[]; + directus_roles: DirectusRole[]; + directus_sessions: DirectusSession[]; + directus_settings: DirectusSettings; + directus_users: DirectusUser[]; + directus_webhooks: DirectusWebhook[]; + directus_dashboards: DirectusDashboard[]; + directus_panels: DirectusPanel[]; + directus_notifications: DirectusNotification[]; + directus_shares: DirectusShare[]; + directus_flows: DirectusFlow[]; + directus_operations: DirectusOperation[]; + directus_translations: DirectusTranslation[]; + directus_versions: DirectusVersion[]; + directus_extensions: DirectusExtension[]; +} + +export enum CollectionNames { + company_profile = 'company_profile', + company_profile_translations = 'company_profile_translations', + contact_info = 'contact_info', + contact_info_translations = 'contact_info_translations', + documents = 'documents', + documents_translations = 'documents_translations', + homepage = 'homepage', + homepage_files = 'homepage_files', + languages = 'languages', + product_images = 'product_images', + product_images_translations = 'product_images_translations', + product_spec_groups = 'product_spec_groups', + product_spec_groups_translations = 'product_spec_groups_translations', + product_specs = 'product_specs', + product_specs_translations = 'product_specs_translations', + product_types = 'product_types', + product_types_translations = 'product_types_translations', + products = 'products', + products_documents = 'products_documents', + products_product_images = 'products_product_images', + products_questions = 'products_questions', + products_translations = 'products_translations', + questions = 'questions', + questions_translations = 'questions_translations', + solution_types = 'solution_types', + solution_types_translations = 'solution_types_translations', + solutions = 'solutions', + solutions_translations = 'solutions_translations', + directus_access = 'directus_access', + directus_activity = 'directus_activity', + directus_collections = 'directus_collections', + directus_comments = 'directus_comments', + directus_fields = 'directus_fields', + directus_files = 'directus_files', + directus_folders = 'directus_folders', + directus_migrations = 'directus_migrations', + directus_permissions = 'directus_permissions', + directus_policies = 'directus_policies', + directus_presets = 'directus_presets', + directus_relations = 'directus_relations', + directus_revisions = 'directus_revisions', + directus_roles = 'directus_roles', + directus_sessions = 'directus_sessions', + directus_settings = 'directus_settings', + directus_users = 'directus_users', + directus_webhooks = 'directus_webhooks', + directus_dashboards = 'directus_dashboards', + directus_panels = 'directus_panels', + directus_notifications = 'directus_notifications', + directus_shares = 'directus_shares', + directus_flows = 'directus_flows', + directus_operations = 'directus_operations', + directus_translations = 'directus_translations', + directus_versions = 'directus_versions', + directus_extensions = 'directus_extensions', +} -- 2.49.0 From e158ec8cf50e4575b5e6d60219a80397347c7b4a Mon Sep 17 00:00:00 2001 From: R2m1liA <15258427350@163.com> Date: Wed, 15 Oct 2025 16:45:50 +0800 Subject: [PATCH 03/30] =?UTF-8?q?fix:=20directus=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=A0=87=E6=B3=A8=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用Directus-sdk-typegen生成Directus类型标注 --- app/types/directus/my-schema.ts | 52 ++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/app/types/directus/my-schema.ts b/app/types/directus/my-schema.ts index 706719b..ca919b7 100644 --- a/app/types/directus/my-schema.ts +++ b/app/types/directus/my-schema.ts @@ -1,5 +1,3 @@ -import type { JsonValue } from '../common'; - export interface CompanyProfile { /** @primaryKey */ id: number; @@ -28,20 +26,9 @@ export interface ContactInfoTranslation { content?: 'json' | null; } -export interface Document { - /** @primaryKey */ - id: number; - status?: 'published' | 'draft' | 'archived'; - file?: DirectusFile | string | null; - /** @description i18n字段 */ - translations?: DocumentsTranslation[] | null; - products?: ProductsDocument[] | string[]; -} - export interface DocumentsTranslation { /** @primaryKey */ id: number; - documents_id?: Document | string | null; languages_code?: Language | string | null; title?: string | null; } @@ -68,6 +55,22 @@ export interface Language { direction?: 'ltr' | 'rtl' | null; } +export interface ProductDocument { + /** @primaryKey */ + id: number; + status?: 'published' | 'draft' | 'archived'; + file?: DirectusFile | string | null; + translations?: ProductDocumentsTranslation[] | null; +} + +export interface ProductDocumentsTranslation { + /** @primaryKey */ + id: number; + product_documents_id?: ProductDocument | string | null; + languages_code?: Language | string | null; + title?: string | null; +} + export interface ProductImage { /** @primaryKey */ id: number; @@ -146,21 +149,20 @@ export interface Product { cover?: DirectusFile | string | null; homepage_recommend?: Homepage | string | null; recommend_sort?: number | null; - faqs?: ProductsQuestion[] | string[]; /** @description i18n字段 */ translations?: ProductsTranslation[] | null; + faqs?: ProductsQuestion[] | string[]; /** @description 在产品详情页中展示 */ images?: ProductsProductImage[] | string[]; - documents?: ProductsDocument[] | string[]; specs?: ProductSpecGroup[] | string[]; + documents?: ProductsProductDocument[] | string[]; } -export interface ProductsDocument { +export interface ProductsProductDocument { /** @primaryKey */ id: number; products_id?: Product | string | null; - documents_id?: Document | string | null; - sort?: number | null; + product_documents_id?: ProductDocument | string | null; } export interface ProductsProductImage { @@ -187,7 +189,7 @@ export interface ProductsTranslation { /** @required */ name: string; summary?: string | null; - description?: JsonValue | null; + description?: string | null; } export interface Question { @@ -206,7 +208,7 @@ export interface QuestionsTranslation { languages_code?: Language | string | null; /** @required */ title: string; - content?: 'json' | null; + content?: string | null; } export interface SolutionType { @@ -723,11 +725,12 @@ export interface Schema { company_profile_translations: CompanyProfileTranslation[]; contact_info: ContactInfo; contact_info_translations: ContactInfoTranslation[]; - documents: Document[]; documents_translations: DocumentsTranslation[]; homepage: Homepage; homepage_files: HomepageFile[]; languages: Language[]; + product_documents: ProductDocument[]; + product_documents_translations: ProductDocumentsTranslation[]; product_images: ProductImage[]; product_images_translations: ProductImagesTranslation[]; product_spec_groups: ProductSpecGroup[]; @@ -737,7 +740,7 @@ export interface Schema { product_types: ProductType[]; product_types_translations: ProductTypesTranslation[]; products: Product[]; - products_documents: ProductsDocument[]; + products_product_documents: ProductsProductDocument[]; products_product_images: ProductsProductImage[]; products_questions: ProductsQuestion[]; products_translations: ProductsTranslation[]; @@ -781,11 +784,12 @@ export enum CollectionNames { company_profile_translations = 'company_profile_translations', contact_info = 'contact_info', contact_info_translations = 'contact_info_translations', - documents = 'documents', documents_translations = 'documents_translations', homepage = 'homepage', homepage_files = 'homepage_files', languages = 'languages', + product_documents = 'product_documents', + product_documents_translations = 'product_documents_translations', product_images = 'product_images', product_images_translations = 'product_images_translations', product_spec_groups = 'product_spec_groups', @@ -795,7 +799,7 @@ export enum CollectionNames { product_types = 'product_types', product_types_translations = 'product_types_translations', products = 'products', - products_documents = 'products_documents', + products_product_documents = 'products_product_documents', products_product_images = 'products_product_images', products_questions = 'products_questions', products_translations = 'products_translations', -- 2.49.0 From de7c03a7a941278d2036f140eb60340d1415f615 Mon Sep 17 00:00:00 2001 From: R2m1liA <15258427350@163.com> Date: Wed, 15 Oct 2025 16:47:33 +0800 Subject: [PATCH 04/30] =?UTF-8?q?feat:=20directus=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E4=B8=8E=E7=BB=84=E5=90=88=E5=BC=8F=E5=87=BD=E6=95=B0=E7=BC=96?= =?UTF-8?q?=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - plugins:Directus插件 - composable:Directus图片/文件的相关组合式函数 --- app/composables/useDirectusFiles.ts | 22 ++++++++++++++++++++ app/composables/useDirectusImage.ts | 32 +++++++++++++++++++++++++++++ app/plugins/directus.ts | 12 +++++++++++ nuxt.config.ts | 3 +-- 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 app/composables/useDirectusFiles.ts create mode 100644 app/composables/useDirectusImage.ts create mode 100644 app/plugins/directus.ts diff --git a/app/composables/useDirectusFiles.ts b/app/composables/useDirectusFiles.ts new file mode 100644 index 0000000..38af82b --- /dev/null +++ b/app/composables/useDirectusFiles.ts @@ -0,0 +1,22 @@ +export const useDirectusFiles = () => { + const config = useRuntimeConfig(); + const baseUrl = config.public.directus.url; + + const getFileUrl = ( + id?: string | null, + options?: Record + ): string => { + if (!id) return ''; + const query = options + ? '?' + + new URLSearchParams( + Object.entries(options).map(([key, value]) => [key, String(value)]) + ).toString() + : ''; + return `${baseUrl}/assets/${id}${query}`; + }; + + return { + getFileUrl, + }; +}; diff --git a/app/composables/useDirectusImage.ts b/app/composables/useDirectusImage.ts new file mode 100644 index 0000000..08215d6 --- /dev/null +++ b/app/composables/useDirectusImage.ts @@ -0,0 +1,32 @@ +export const useDirectusImage = () => { + const config = useRuntimeConfig(); + const baseUrl = config.public.directus.url; + const token = config.public.directus.token; + + type DirectusAssetParams = { + width?: number; + height?: number; + fit?: 'cover' | 'contain' | 'inside' | 'outside'; + quality?: number; + format?: 'webp' | 'jpg' | 'png' | 'auto'; + } & Record; + + const getImageUrl = (id?: string | null, options?: DirectusAssetParams) => { + if (!id) return ''; + const queryToken = token ? 'access_token=' + token : ''; + const queryOptions = options + ? new URLSearchParams( + Object.fromEntries( + Object.entries(options).map(([key, value]) => [key, String(value)]) + ) + ).toString + : ''; + const query = + queryToken || queryOptions + ? `?${[queryToken, queryOptions].filter(Boolean).join('&')}` + : ''; + return `${baseUrl}/assets/${id}${query}`; + }; + + return { getImageUrl }; +}; diff --git a/app/plugins/directus.ts b/app/plugins/directus.ts new file mode 100644 index 0000000..a68bc1b --- /dev/null +++ b/app/plugins/directus.ts @@ -0,0 +1,12 @@ +import { createDirectus, rest, staticToken } from '@directus/sdk'; + +export default defineNuxtPlugin(() => { + const config = useRuntimeConfig(); + + const directus = createDirectus(config.public.directus.url) + .with(rest()) + .with(staticToken(config.public.directus.token || '')); + return { + provide: { directus }, + }; +}); diff --git a/nuxt.config.ts b/nuxt.config.ts index 45c1ad9..639a4ca 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -118,7 +118,7 @@ export default defineNuxtConfig({ }, imports: { - dirs: ['types/**'], + dirs: ['types/**', 'models/**'], }, modules: [ @@ -133,6 +133,5 @@ export default defineNuxtConfig({ '@element-plus/nuxt', '@nuxtjs/i18n', '@nuxtjs/strapi', - 'nuxt-directus', ], }); -- 2.49.0 From 98f978484c484261336374ac141d33e14a6f1995 Mon Sep 17 00:00:00 2001 From: R2m1liA <15258427350@163.com> Date: Wed, 15 Oct 2025 16:48:38 +0800 Subject: [PATCH 05/30] =?UTF-8?q?feat:=20directus=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E4=B8=8E=E8=BD=AC=E6=8D=A2=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - views: 用于前端渲染的视图模型 - mapper: 用于视图模型转换的转换函数 - utils: 相关工具函数 --- app/models/mappers/documentMapper.ts | 29 +++++ app/models/mappers/productMapper.ts | 134 +++++++++++++++++++++++ app/models/mappers/questionMapper.ts | 18 +++ app/models/utils/object.ts | 30 +++++ app/models/views/ProductDocumentView.ts | 20 ++++ app/models/views/ProductListView.ts | 20 ++++ app/models/views/ProductSpecGroupView.ts | 29 +++++ app/models/views/ProductView.ts | 38 +++++++ app/models/views/QuestionView.ts | 14 +++ 9 files changed, 332 insertions(+) create mode 100644 app/models/mappers/documentMapper.ts create mode 100644 app/models/mappers/productMapper.ts create mode 100644 app/models/mappers/questionMapper.ts create mode 100644 app/models/utils/object.ts create mode 100644 app/models/views/ProductDocumentView.ts create mode 100644 app/models/views/ProductListView.ts create mode 100644 app/models/views/ProductSpecGroupView.ts create mode 100644 app/models/views/ProductView.ts create mode 100644 app/models/views/QuestionView.ts diff --git a/app/models/mappers/documentMapper.ts b/app/models/mappers/documentMapper.ts new file mode 100644 index 0000000..01f08ab --- /dev/null +++ b/app/models/mappers/documentMapper.ts @@ -0,0 +1,29 @@ +/** + * 将 Directus 返回的 Document 数据转换为 DocumentView 视图模型 + * + * @param raw: 原始的 Document 数据 + * @returns 转换后的 DocumentView 对象 + * + * @example + * const view = toDocumentView(rawDocument); + */ +export function toDocumentView(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, + filename: file.filename_download, + title: trans.title, + url: url, + size: file.filesize, + }; +} diff --git a/app/models/mappers/productMapper.ts b/app/models/mappers/productMapper.ts new file mode 100644 index 0000000..0ef72aa --- /dev/null +++ b/app/models/mappers/productMapper.ts @@ -0,0 +1,134 @@ +/** + * 将 Directus返回的 Product 数据转换为 ProductListView 视图模型 + * + * @param raw: 原始的 Product 数据 + * @returns 转换后的 ProductListView 对象 + * + * @example + * const view = toProductListView(rawProduct); + */ +export function toProductListView(raw: Product): ProductListView { + const trans = raw.translations?.[0] ?? { name: '', summary: '' }; + + return { + id: raw.id, + product_type: + typeof raw.product_type === 'string' + ? raw.product_type + : typeof raw.product_type === 'object' && raw.product_type + ? raw.product_type.translations[0].name || '' + : '', + name: trans.name, + summary: trans.summary, + cover: raw.cover.toString(), + }; +} + +/** + * 将 Directus 返回的 ProductSpecGroup 数据转换为 ProductSpecGroupView 视图模型 + * + * @param raw: 原始的 ProductSpecGroup 数据 + * @returns 转换后的 ProductSpecGroupView 对象 + * + * @example + * const view = toProductSpecGroupView(rawSpecGroup); + */ +export function toProductSpecGroupView( + raw: ProductSpecGroup +): ProductSpecGroupView { + const trans = raw.translations?.[0] ?? { + name: '', + }; + + return { + id: raw.id, + name: trans.name, + specs: raw.specs + .filter(isObject) + .map((item) => toProductSpecView(item)), + }; +} + +/** + * 将 Directus 返回的 ProductSpec 数据转换为 ProductSpecView 视图模型 + * + * @param raw: 原始的 ProductSpec 数据 + * @returns 转换后的 ProductSpecView 对象 + * + * @example + * const view = toProductSpecView(rawSpecGroup); + */ +export function toProductSpecView(raw: ProductSpec): ProductSpecView { + const trans = raw.translations?.[0] ?? { + key: '', + }; + + return { + id: raw.id, + key: trans.key, + value: raw.value, + }; +} + +/** + * 将 Directus 返回的 Product 数据转换为 ProductView 视图模型 + * + * @param raw: 原始的 Product 数据 + * @returns 转换后的 ProductView 对象 + * + * @example + * const view = toProductView(rawProduct); + */ +export function toProductView(raw: Product): ProductView { + const trans = raw.translations?.[0] ?? { + name: '', + summary: '', + description: '', + }; + + const images = (raw.images ?? []) + .filter(isObject) + .map((item) => item.product_images_id) + .filter(isObject) + .map((item) => { + return { + id: item.id, + image: item.image.toString(), + caption: item.translations?.[0]?.caption || '', + }; + }); + + const specs = (raw.specs ?? []) + .filter(isObject) + .map((item) => toProductSpecGroupView(item)); + + const faqs = (raw.faqs ?? []) + .filter(isObject) + .map((item) => item.questions_id) + .filter(isObject) + .map((item) => toQuestionView(item)); + + const documents = (raw.documents ?? []) + .filter(isObject) + .map((item) => item.product_documents_id) + .filter(isObject) + .map((item) => toDocumentView(item)); + + return { + id: raw.id, + + product_type: + typeof raw.product_type === 'string' + ? raw.product_type + : typeof raw.product_type === 'object' && raw.product_type + ? raw.product_type.translations[0].name || '' + : '', + name: trans.name, + summary: trans.summary, + images: images, + description: trans.description, + specs: specs, + faqs: faqs, + documents: documents, + }; +} diff --git a/app/models/mappers/questionMapper.ts b/app/models/mappers/questionMapper.ts new file mode 100644 index 0000000..45ec955 --- /dev/null +++ b/app/models/mappers/questionMapper.ts @@ -0,0 +1,18 @@ +/** + * 将 Directus 返回的 Question 数据转换为 QuestionView 视图模型 + * + * @param raw: 原始的 Question 数据 + * @returns 转换后的 QuestionView 对象 + * + * @example + * const view = toQuestionView(rawQuestion); + */ +export function toQuestionView(raw: Question): QuestionView { + const trans = raw.translations?.[0] ?? { title: '', content: '' }; + + return { + id: raw.id, + title: trans.title, + content: trans.content, + }; +} diff --git a/app/models/utils/object.ts b/app/models/utils/object.ts new file mode 100644 index 0000000..37ef512 --- /dev/null +++ b/app/models/utils/object.ts @@ -0,0 +1,30 @@ +/** + * 判断某一值是否为非null对象 + * + * @template T 泛型类型,用于推断目标对象的类型 + * @param value: 需要判断的值 + * @returns 如果值是非null对象则返回true,否则返回false + * + * @example + * if (isObject(value)) value.id + */ +export const isObject = (value: unknown): value is T => + typeof value === 'object' && value !== null; + +/** + * 判断某一值是否为非null对象组成的数组 + * + * @template T 泛型类型,用于推断目标对象的类型 + * @param value: 需要判断的值 + * @returns 如果值是非null对象组成的数组则返回true,否则返回false + * + * @example + * const data: unknown = [{ id: 1 }, { id: 2 }]; + * if (isArrayOfObject)<{ id: number }>(data) { + * // TypeScript 知道 data 是 { id: number }[] 类型 + * console.log(data[0].id); + * } + */ +export const isArrayOfObject = (arr: unknown): arr is T[] => { + return Array.isArray(arr) && arr.every(isObject); +}; diff --git a/app/models/views/ProductDocumentView.ts b/app/models/views/ProductDocumentView.ts new file mode 100644 index 0000000..3c72533 --- /dev/null +++ b/app/models/views/ProductDocumentView.ts @@ -0,0 +1,20 @@ +/** + * 文档视图模型 + * 用于文档页(/support/documents)渲染的数据结构 + */ +export interface ProductDocumentView { + /** 唯一标识符 **/ + id: number; + + /** 文件名 **/ + filename: string; + + /** 文档标题 **/ + title: string; + + /** 文档大小 **/ + size: number; + + /** 文档链接 **/ + url: string; +} diff --git a/app/models/views/ProductListView.ts b/app/models/views/ProductListView.ts new file mode 100644 index 0000000..14912fe --- /dev/null +++ b/app/models/views/ProductListView.ts @@ -0,0 +1,20 @@ +/** + * 产品列表视图模型 + * 用于产品列表(/products)渲染的数据结构 + */ +export interface ProductListView { + /** 唯一标识符 **/ + id: number; + + /** 产品名称 **/ + name: string; + + /** 产品简介 **/ + summary: string; + + /** 产品类型 **/ + product_type: string; + + /** 产品封面(图片的id) **/ + cover: string; +} diff --git a/app/models/views/ProductSpecGroupView.ts b/app/models/views/ProductSpecGroupView.ts new file mode 100644 index 0000000..361fa71 --- /dev/null +++ b/app/models/views/ProductSpecGroupView.ts @@ -0,0 +1,29 @@ +/** + * 产品规格模型 + * 用于产品规格渲染的数据结构 + */ +export interface ProductSpecView { + /** 唯一标识符 **/ + id: number; + + /** 规格名称 **/ + key: string; + + /** 规格值 **/ + value: string; +} + +/** + * 产品规格表模型 + * 用于产品规格表渲染的数据结构 + */ +export interface ProductSpecGroupView { + /** 唯一标识符 **/ + id: number; + + /** 规格组名称 **/ + name: string; + + /** 规格组 **/ + specs: ProductSpecView[]; +} diff --git a/app/models/views/ProductView.ts b/app/models/views/ProductView.ts new file mode 100644 index 0000000..f91e061 --- /dev/null +++ b/app/models/views/ProductView.ts @@ -0,0 +1,38 @@ +interface ImageView { + id: number; + image: string; + caption: string; +} + +/** + * 产品视图模型 + * 用于产品详情页(/products/[slug])渲染的数据结构 + */ +export interface ProductView { + /** 唯一标识符 **/ + id: number; + + /** 产品名称 **/ + name: string; + + /** 产品简介 **/ + summary: string; + + /** 产品类型 **/ + product_type: string; + + /** 产品图片 **/ + images: ImageView[]; + + /** 产品详情 **/ + description: string; + + /** 产品规格 **/ + specs: ProductSpecGroupView[]; + + /** 产品常见问题 **/ + faqs: QuestionView[]; + + /** 产品文档 **/ + documents: ProductDocumentView[]; +} diff --git a/app/models/views/QuestionView.ts b/app/models/views/QuestionView.ts new file mode 100644 index 0000000..310afd0 --- /dev/null +++ b/app/models/views/QuestionView.ts @@ -0,0 +1,14 @@ +/** + * 常见问题视图模型 + * 用于常见问题(/support/faqs)渲染的数据结构 + */ +export interface QuestionView { + /** 唯一标识符 **/ + id: number; + + /** 问题标题 **/ + title: string; + + /** 问题内容 **/ + content: string; +} -- 2.49.0 From 1704a7b5c16d4805c0787202946378914eecd1ed Mon Sep 17 00:00:00 2001 From: R2m1liA <15258427350@163.com> Date: Wed, 15 Oct 2025 16:49:08 +0800 Subject: [PATCH 06/30] =?UTF-8?q?feat:=20production=E9=A1=B5=E7=9A=84CMS?= =?UTF-8?q?=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/DocumentList.vue | 11 +- app/components/QuestionList.vue | 10 +- app/components/SpecTable.vue | 18 +-- app/pages/productions/[...slug].vue | 168 +++++++++++++++++++++------- app/pages/productions/index.vue | 89 ++++++++++----- 5 files changed, 202 insertions(+), 94 deletions(-) diff --git a/app/components/DocumentList.vue b/app/components/DocumentList.vue index c30953a..0061070 100644 --- a/app/components/DocumentList.vue +++ b/app/components/DocumentList.vue @@ -6,18 +6,19 @@ class="document-card" >
-

{{ doc.caption || doc.name }}

+

{{ doc.title }}

大小: {{ formatFileSize(doc.size) }} - 格式: {{ formatFileExtension(doc.ext) }}格式: + {{ formatFileExtension(getFileExtension(doc.filename)) }} 下载 @@ -30,7 +31,7 @@ diff --git a/app/pages/productions/[...slug].vue b/app/pages/productions/[...slug].vue index 21e95fc..02851b1 100644 --- a/app/pages/productions/[...slug].vue +++ b/app/pages/productions/[...slug].vue @@ -15,7 +15,7 @@ }} {{ - production.title + production.name }} @@ -23,9 +23,9 @@
-

{{ production.title }}

+

{{ production.name }}

{{ production.summary }}

@@ -65,24 +65,16 @@
- + - + - + - +
@@ -114,40 +106,130 @@ diff --git a/app/components/JinshenFooter.vue b/app/components/JinshenFooter.vue index fea2407..002e5e9 100644 --- a/app/components/JinshenFooter.vue +++ b/app/components/JinshenFooter.vue @@ -20,8 +20,8 @@ {{ $t('navigation.home') }}
  • - {{ - $t('navigation.productions') + {{ + $t('navigation.products') }}
  • diff --git a/app/components/JinshenHeader.vue b/app/components/JinshenHeader.vue index 78b2f16..0fd55ca 100644 --- a/app/components/JinshenHeader.vue +++ b/app/components/JinshenHeader.vue @@ -21,8 +21,8 @@ :persistent="false" router > - - {{ $t('navigation.productions') }} + + {{ $t('navigation.products') }} {{ $t('navigation.solutions') }} @@ -81,8 +81,8 @@ const refreshMenu = () => { const path = router.currentRoute.value.path; - if (path.startsWith('/productions')) { - activeName.value = 'productions'; + if (path.startsWith('/products')) { + activeName.value = 'products'; } else if (path.startsWith('/solutions')) { activeName.value = 'solutions'; } else if (path.startsWith('/support')) { diff --git a/app/components/ProductionCard.vue b/app/components/ProductCard.vue similarity index 77% rename from app/components/ProductionCard.vue rename to app/components/ProductCard.vue index bdfa568..397a0a4 100644 --- a/app/components/ProductionCard.vue +++ b/app/components/ProductCard.vue @@ -1,14 +1,14 @@