From f60255574ef32c32add5fa41851ad0d30f1cb940 Mon Sep 17 00:00:00 2001 From: eafonyang Date: Tue, 25 Aug 2026 14:18:47 +0800 Subject: [PATCH] =?UTF-8?q?feat(customer-service):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E6=9C=8D=E5=8A=A1=E9=97=AE=E9=A2=98=E5=8F=8D?= =?UTF-8?q?=E9=A6=88=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重命名语言文件中相关关键字,统一改为 customer-service_feedbacks - 新增客户服务反馈页面路由及组件导入,移除旧的 www_support_feedbacks 相关路由 - 实现客户服务反馈列表及详情查看,支持状态筛选、分页查询和消息对话展示 - 支持反馈状态变更,包括待处理、处理中和已解决状态切换 - 支持在对话中发送回复消息,且针对已解决状态自动停止轮询 - 优化状态标签样式,采用更易区分的颜色与视觉样式 - 组件及类型定义中新增 NCollapse 和 NCollapseItem 支持 - 移除旧的 www 支持反馈组件代码,清理无用路由及类型定义相关项 --- dashboard/frontend/src/locales/langs/en-us.ts | 2 +- dashboard/frontend/src/locales/langs/zh-cn.ts | 4 +- .../frontend/src/router/elegant/imports.ts | 2 +- .../frontend/src/router/elegant/routes.ts | 50 ++-- .../frontend/src/router/elegant/transform.ts | 6 +- .../frontend/src/typings/components.d.ts | 4 + .../frontend/src/typings/elegant-router.d.ts | 8 +- .../feedbacks/index.vue | 2 +- www/app/components/SupportFeedback.vue | 261 +++++++++++++----- www/app/components/SupportFeedbackChat.vue | 2 +- 10 files changed, 236 insertions(+), 105 deletions(-) rename dashboard/frontend/src/views/{www/support => customer-service}/feedbacks/index.vue (99%) diff --git a/dashboard/frontend/src/locales/langs/en-us.ts b/dashboard/frontend/src/locales/langs/en-us.ts index a558c01..2db4b69 100644 --- a/dashboard/frontend/src/locales/langs/en-us.ts +++ b/dashboard/frontend/src/locales/langs/en-us.ts @@ -272,7 +272,7 @@ const local: App.I18n.Schema = { www_contact_settings: 'Form Settings', www_contact_submissions: 'Submissions', 'customer-service': 'Customer Service', - www_support_feedbacks: 'Support Feedback', + 'customer-service_feedbacks': 'Support Feedback', 'www_page-seo': 'Page SEO' }, page: { diff --git a/dashboard/frontend/src/locales/langs/zh-cn.ts b/dashboard/frontend/src/locales/langs/zh-cn.ts index 942d6c8..d0027d4 100644 --- a/dashboard/frontend/src/locales/langs/zh-cn.ts +++ b/dashboard/frontend/src/locales/langs/zh-cn.ts @@ -268,8 +268,8 @@ const local: App.I18n.Schema = { www_contact: '联系表单', www_contact_settings: '表单配置', www_contact_submissions: '提交记录', - 'customer-service': '客户服务', - www_support_feedbacks: '问题反馈', + 'customer-service': '客服服务', + 'customer-service_feedbacks': '问题反馈', 'www_page-seo': '页面 SEO' }, page: { diff --git a/dashboard/frontend/src/router/elegant/imports.ts b/dashboard/frontend/src/router/elegant/imports.ts index 0cb3c38..17aeb40 100644 --- a/dashboard/frontend/src/router/elegant/imports.ts +++ b/dashboard/frontend/src/router/elegant/imports.ts @@ -20,6 +20,7 @@ export const views: Record Promise import("@/views/_builtin/500/index.vue"), "iframe-page": () => import("@/views/_builtin/iframe-page/[url].vue"), login: () => import("@/views/_builtin/login/index.vue"), + "customer-service_feedbacks": () => import("@/views/customer-service/feedbacks/index.vue"), headphone_brand: () => import("@/views/headphone/brand/index.vue"), headphone_impedance: () => import("@/views/headphone/impedance/index.vue"), headphone_model: () => import("@/views/headphone/model/index.vue"), @@ -51,5 +52,4 @@ export const views: Record Promise import("@/views/www/product/detail/index.vue"), www_product_list: () => import("@/views/www/product/list/index.vue"), www_product_series: () => import("@/views/www/product/series/index.vue"), - www_support_feedbacks: () => import("@/views/www/support/feedbacks/index.vue"), }; diff --git a/dashboard/frontend/src/router/elegant/routes.ts b/dashboard/frontend/src/router/elegant/routes.ts index 5ed2dd2..b72e52f 100644 --- a/dashboard/frontend/src/router/elegant/routes.ts +++ b/dashboard/frontend/src/router/elegant/routes.ts @@ -39,6 +39,31 @@ export const generatedRoutes: GeneratedRoute[] = [ hideInMenu: true } }, + { + name: 'customer-service', + path: '/customer-service', + component: 'layout.base', + meta: { + title: 'customer-service', + i18nKey: 'route.customer-service', + icon: 'mdi:headset', + order: 7 + }, + children: [ + { + name: 'customer-service_feedbacks', + path: '/customer-service/feedbacks', + component: 'view.customer-service_feedbacks', + meta: { + title: 'customer-service_feedbacks', + i18nKey: 'route.customer-service_feedbacks', + icon: 'mdi:message-alert-outline', + order: 1, + keepAlive: true + } + } + ] + }, { name: 'headphone', path: '/headphone', @@ -585,31 +610,6 @@ export const generatedRoutes: GeneratedRoute[] = [ } } ] - }, - ] - }, - { - name: 'customer-service', - path: '/www/support', - component: 'layout.base', - meta: { - title: 'customer-service', - i18nKey: 'route.customer-service', - icon: 'mdi:headset', - order: 7 - }, - children: [ - { - name: 'www_support_feedbacks', - path: '/www/support/feedbacks', - component: 'view.www_support_feedbacks', - meta: { - title: 'www_support_feedbacks', - i18nKey: 'route.www_support_feedbacks', - icon: 'mdi:message-alert-outline', - order: 1, - keepAlive: true - } } ] } diff --git a/dashboard/frontend/src/router/elegant/transform.ts b/dashboard/frontend/src/router/elegant/transform.ts index f3a7b8a..0044881 100644 --- a/dashboard/frontend/src/router/elegant/transform.ts +++ b/dashboard/frontend/src/router/elegant/transform.ts @@ -166,6 +166,8 @@ const routeMap: RouteMap = { "403": "/403", "404": "/404", "500": "/500", + "customer-service": "/customer-service", + "customer-service_feedbacks": "/customer-service/feedbacks", "headphone": "/headphone", "headphone_brand": "/headphone/brand", "headphone_impedance": "/headphone/impedance", @@ -210,9 +212,7 @@ const routeMap: RouteMap = { "www_product": "/www/product", "www_product_detail": "/www/product/detail", "www_product_list": "/www/product/list", - "www_product_series": "/www/product/series", - "customer-service": "/www/support", - "www_support_feedbacks": "/www/support/feedbacks" + "www_product_series": "/www/product/series" }; /** diff --git a/dashboard/frontend/src/typings/components.d.ts b/dashboard/frontend/src/typings/components.d.ts index 8e2e459..fff6479 100644 --- a/dashboard/frontend/src/typings/components.d.ts +++ b/dashboard/frontend/src/typings/components.d.ts @@ -41,6 +41,8 @@ declare module 'vue' { NButton: typeof import('naive-ui')['NButton'] NCard: typeof import('naive-ui')['NCard'] NCheckbox: typeof import('naive-ui')['NCheckbox'] + NCollapse: typeof import('naive-ui')['NCollapse'] + NCollapseItem: typeof import('naive-ui')['NCollapseItem'] NColorPicker: typeof import('naive-ui')['NColorPicker'] NDataTable: typeof import('naive-ui')['NDataTable'] NDatePicker: typeof import('naive-ui')['NDatePicker'] @@ -132,6 +134,8 @@ declare global { const NButton: typeof import('naive-ui')['NButton'] const NCard: typeof import('naive-ui')['NCard'] const NCheckbox: typeof import('naive-ui')['NCheckbox'] + const NCollapse: typeof import('naive-ui')['NCollapse'] + const NCollapseItem: typeof import('naive-ui')['NCollapseItem'] const NColorPicker: typeof import('naive-ui')['NColorPicker'] const NDataTable: typeof import('naive-ui')['NDataTable'] const NDatePicker: typeof import('naive-ui')['NDatePicker'] diff --git a/dashboard/frontend/src/typings/elegant-router.d.ts b/dashboard/frontend/src/typings/elegant-router.d.ts index 3f6aef8..4eac289 100644 --- a/dashboard/frontend/src/typings/elegant-router.d.ts +++ b/dashboard/frontend/src/typings/elegant-router.d.ts @@ -20,6 +20,8 @@ declare module "@elegant-router/types" { "403": "/403"; "404": "/404"; "500": "/500"; + "customer-service": "/customer-service"; + "customer-service_feedbacks": "/customer-service/feedbacks"; "headphone": "/headphone"; "headphone_brand": "/headphone/brand"; "headphone_impedance": "/headphone/impedance"; @@ -65,8 +67,6 @@ declare module "@elegant-router/types" { "www_product_detail": "/www/product/detail"; "www_product_list": "/www/product/list"; "www_product_series": "/www/product/series"; - "customer-service": "/www/support"; - "www_support_feedbacks": "/www/support/feedbacks"; }; /** @@ -101,6 +101,7 @@ declare module "@elegant-router/types" { | "403" | "404" | "500" + | "customer-service" | "headphone" | "home" | "iframe-page" @@ -111,7 +112,6 @@ declare module "@elegant-router/types" { | "toolbox" | "upgrade" | "www" - | "customer-service" >; /** @@ -133,6 +133,7 @@ declare module "@elegant-router/types" { | "500" | "iframe-page" | "login" + | "customer-service_feedbacks" | "headphone_brand" | "headphone_impedance" | "headphone_model" @@ -164,7 +165,6 @@ declare module "@elegant-router/types" { | "www_product_detail" | "www_product_list" | "www_product_series" - | "www_support_feedbacks" >; /** diff --git a/dashboard/frontend/src/views/www/support/feedbacks/index.vue b/dashboard/frontend/src/views/customer-service/feedbacks/index.vue similarity index 99% rename from dashboard/frontend/src/views/www/support/feedbacks/index.vue rename to dashboard/frontend/src/views/customer-service/feedbacks/index.vue index fc5ea15..1f05529 100644 --- a/dashboard/frontend/src/views/www/support/feedbacks/index.vue +++ b/dashboard/frontend/src/views/customer-service/feedbacks/index.vue @@ -8,7 +8,7 @@ import { fetchUpdateSupportFeedbackStatus, } from '@/service/api'; -defineOptions({ name: 'WwwSupportFeedbacks' }); +defineOptions({ name: 'CustomerServiceFeedbacks' }); const POLL_INTERVAL_MS = 4000; diff --git a/www/app/components/SupportFeedback.vue b/www/app/components/SupportFeedback.vue index 55c032d..255efab 100644 --- a/www/app/components/SupportFeedback.vue +++ b/www/app/components/SupportFeedback.vue @@ -170,10 +170,30 @@ function statusLabel(status: string): string { return t('support.statusPending'); } -function statusClass(status: string): string { - if (status === 'resolved') return 'bg-green-50 text-green-700 border-green-200 dark:bg-green-900/20 dark:text-green-300 dark:border-green-800'; - if (status === 'processing') return 'bg-blue-50 text-blue-700 border-blue-200 dark:bg-blue-900/20 dark:text-blue-300 dark:border-blue-800'; - return 'bg-amber-50 text-amber-700 border-amber-200 dark:bg-amber-900/20 dark:text-amber-300 dark:border-amber-800'; +function statusMeta(status: string): { badge: string; accent: string; dot: string } { + if (status === 'resolved') { + return { + badge: 'bg-emerald-50 text-emerald-700 ring-1 ring-emerald-200/80 dark:bg-emerald-950/40 dark:text-emerald-300 dark:ring-emerald-800/60', + accent: 'bg-emerald-500', + dot: 'bg-emerald-500', + }; + } + if (status === 'processing') { + return { + badge: 'bg-sky-50 text-sky-700 ring-1 ring-sky-200/80 dark:bg-sky-950/40 dark:text-sky-300 dark:ring-sky-800/60', + accent: 'bg-sky-500', + dot: 'bg-sky-500', + }; + } + return { + badge: 'bg-amber-50 text-amber-700 ring-1 ring-amber-200/80 dark:bg-amber-950/40 dark:text-amber-300 dark:ring-amber-800/60', + accent: 'bg-amber-500', + dot: 'bg-amber-500', + }; +} + +function isExpanded(item: SupportFeedbackItem): boolean { + return expandedFeedbackNo.value === item.feedback_no; } function formatTime(iso: string): string { @@ -334,91 +354,198 @@ function handleStatusUpdate(feedbackNo: string, status: string) { -
-

{{ t('support.myFeedback') }}

+ + + diff --git a/www/app/components/SupportFeedbackChat.vue b/www/app/components/SupportFeedbackChat.vue index b3498e4..54c8eb2 100644 --- a/www/app/components/SupportFeedbackChat.vue +++ b/www/app/components/SupportFeedbackChat.vue @@ -143,7 +143,7 @@ onUnmounted(stopPolling);