diff --git a/src/constants/case-detail.ts b/src/constants/case-detail.ts new file mode 100644 index 0000000..33ef350 --- /dev/null +++ b/src/constants/case-detail.ts @@ -0,0 +1,34 @@ +import { CASE_LIBRARY_LIST } from '@/constants/case-library' +import type { CaseDetail } from '@/types/case-library' + +const SHARED_BACKGROUND = '随着我国城镇化进程不断加快,园区管理面临着从传统粗放式管理向精细化、智能化管理转型的迫切需求。在"数字中国"战略背景下,各地园区纷纷探索通过信息化手段提升运营效率、优化资源配置、改善企业服务体验。' + +const SHARED_PAIN_POINTS = '传统园区管理方式依赖人工巡检和纸质记录,信息孤岛严重,各部门数据无法互通,导致管理效率低下。企业服务响应慢,缺乏统一的服务入口,企业诉求难以快速传达和处理。能耗管理粗放,无法实时监控和分析,造成资源浪费。' + +const SHARED_REQUIREMENT = '建设一套集园区管理、企业服务、数据分析于一体的综合管理平台,实现园区运营的数字化、智能化。平台需支持多端访问,包括Web管理端、移动端APP,满足不同角色的使用需求。' + +const SHARED_DELIVERABLES = '交付园区综合管理平台一套,包含Web管理端、移动端APP、数据可视化大屏,并提供完整的源代码、技术文档、用户手册及一年免费运维服务。' + +const DEFAULT_ATTACHMENTS = [ + { id: '1', name: '需求文档.pdf', icon: '/static/icons/PDF.png' }, + { id: '2', name: '系统....pdf', icon: '/static/icons/PDF.png' }, + { id: '3', name: '参考图.png', icon: '/static/icons/PNG.png' }, +] + +const CASE_DETAIL_MAP: Record = Object.fromEntries( + CASE_LIBRARY_LIST.map(item => [ + item.id, + { + ...item, + background: SHARED_BACKGROUND, + painPoints: SHARED_PAIN_POINTS, + requirement: SHARED_REQUIREMENT, + deliverables: SHARED_DELIVERABLES, + attachments: DEFAULT_ATTACHMENTS, + }, + ]), +) + +export function getCaseDetail(id: string): CaseDetail | null { + return CASE_DETAIL_MAP[id] || null +} diff --git a/src/constants/customer-service.ts b/src/constants/customer-service.ts new file mode 100644 index 0000000..8cf8433 --- /dev/null +++ b/src/constants/customer-service.ts @@ -0,0 +1,18 @@ +import type { ChatMessage } from '@/types/customer-service' + +export const CUSTOMER_SERVICE_MESSAGES: ChatMessage[] = [ + { + id: '1', + role: 'user', + nickname: '昵称', + content: '怎么购买?怎么购买?', + avatar: '/static/icons/hi.png', + }, + { + id: '2', + role: 'service', + nickname: '昵称', + content: '怎么购买?怎么购买?', + avatar: '/static/icons/quick-service.png', + }, +] diff --git a/src/constants/message-center.ts b/src/constants/message-center.ts new file mode 100644 index 0000000..d6003b3 --- /dev/null +++ b/src/constants/message-center.ts @@ -0,0 +1,29 @@ +import type { MessageItem } from '@/types/message-center' + +export const MESSAGE_LIST: MessageItem[] = [ + { + id: '1', + type: 'service', + icon: '/static/icons/icon-message-service.png', + title: '在线客服', + preview: '您好,请问有什么可以帮您的?', + time: '刚刚', + unread: true, + }, + { + id: '2', + type: 'workorder', + icon: '/static/icons/icon-message-workorder.png', + title: '工单状态通知', + preview: '您的「社区康养服务系统」项目已进入开发阶段,请关注进度', + time: '10:23', + }, + { + id: '3', + type: 'system', + icon: '/static/icons/icon-message-system.png', + title: '系统通知', + preview: '平台将于2026年7月31日00:00:00进行系统维护', + time: '昨天', + }, +] diff --git a/src/constants/project-center.ts b/src/constants/project-center.ts new file mode 100644 index 0000000..c1191d7 --- /dev/null +++ b/src/constants/project-center.ts @@ -0,0 +1,44 @@ +import type { ProjectCategory, ProjectCenterItem } from '@/types/project-center' + +export const PROJECT_CATEGORIES: ProjectCategory[] = [ + '全部', + '互联网软件', + '硬件电路', + '物联网全案', + '生产制造', +] + +export const PROJECT_CENTER_LIST: ProjectCenterItem[] = [ + { + id: '1', + title: '社区康养智能服务系统', + category: '互联网软件', + projectNo: '20260813RJ251545', + status: '进行中', + industry: '医疗健康', + scale: '320万', + completedAt: '2026/8/10', + progress: 65, + updateTime: '2026-8-13 11:04:12', + }, + { + id: '2', + title: '社区康养智能服务系统', + category: '生产制造', + projectNo: '20260813RJ251545', + status: '待立项', + industry: '电商零售', + scale: '500万', + completedAt: '2026/3/8', + }, + { + id: '3', + title: '社区康养智能服务系统', + category: '互联网软件', + projectNo: '20260813RJ251545', + status: '售后中', + industry: '医疗健康', + scale: '320万', + completedAt: '2026/6/15', + }, +] diff --git a/src/constants/project-detail.ts b/src/constants/project-detail.ts new file mode 100644 index 0000000..6341e98 --- /dev/null +++ b/src/constants/project-detail.ts @@ -0,0 +1,72 @@ +import { PROJECT_CENTER_LIST } from '@/constants/project-center' +import type { ProjectDetail } from '@/types/project-detail' + +const DEFAULT_STEPS = [ + { + id: '1', + title: '需求确认', + status: 'done' as const, + time: '2026-8-13 11:04:12', + }, + { + id: '2', + title: '原型设计', + status: 'done' as const, + time: '2026-8-13 11:04:12', + }, + { + id: '3', + title: '开发实现', + status: 'active' as const, + statusText: '进行中', + }, + { + id: '4', + title: '测试验收', + status: 'pending' as const, + statusText: '待开始', + }, + { + id: '5', + title: '项目交付', + status: 'pending' as const, + statusText: '待开始', + }, +] + +const DEFAULT_TEAM = [ + { id: '1', name: '张三', role: '项目经理' }, + { id: '2', name: '张三', role: '项目经理' }, + { id: '3', name: '张三', role: '项目经理' }, + { id: '4', name: '张三', role: '项目经理' }, +] + +const DEFAULT_FILES = [ + { id: '1', name: '需求文档.pdf', icon: '/static/icons/PDF.png' }, + { id: '2', name: '系统....pdf', icon: '/static/icons/PDF.png' }, + { id: '3', name: '参考图.png', icon: '/static/icons/PNG.png' }, +] + +function buildDetail(item: typeof PROJECT_CENTER_LIST[number]): ProjectDetail { + const progress = item.progress ?? 0 + + return { + ...item, + progressStartTime: '2026-8-17', + progressEndTime: '2026-8-17', + steps: DEFAULT_STEPS.map(step => ({ ...step })), + team: DEFAULT_TEAM.map(member => ({ ...member })), + files: DEFAULT_FILES.map(file => ({ ...file })), + financeSummary: '合同金额已确认,当前处于开发阶段付款节点,发票与回款记录可在后台查看。', + afterSalesSummary: '项目交付后将提供一年免费运维服务,支持 7×24 小时远程技术支持与故障响应。', + progress, + } +} + +const PROJECT_DETAIL_MAP: Record = Object.fromEntries( + PROJECT_CENTER_LIST.map(item => [item.id, buildDetail(item)]), +) + +export function getProjectDetail(id: string): ProjectDetail | null { + return PROJECT_DETAIL_MAP[id] || null +} diff --git a/src/constants/status-notification.ts b/src/constants/status-notification.ts new file mode 100644 index 0000000..c80a51c --- /dev/null +++ b/src/constants/status-notification.ts @@ -0,0 +1,25 @@ +import type { StatusNotificationItem } from '@/types/status-notification' + +export const STATUS_NOTIFICATION_ICON = '/static/icons/icon-message-workorder.png' + +export const STATUS_NOTIFICATION_LIST: StatusNotificationItem[] = [ + { + id: '1', + title: '项目待立项确认', + preview: '您的需求已收到,等待确认立项,请留意后续进展', + time: '刚刚', + unread: true, + }, + { + id: '2', + title: '合同生效', + preview: '您的合同已正式生效 合同编号 xxxx 已开始生效,可随时查看详情及履约进度', + time: '10:23', + }, + { + id: '3', + title: '您有一笔新账单待支付', + preview: '账单金额 ¥xxx,请尽快完成付款,以免影响服务', + time: '昨天', + }, +] diff --git a/src/constants/system-notification.ts b/src/constants/system-notification.ts new file mode 100644 index 0000000..6315628 --- /dev/null +++ b/src/constants/system-notification.ts @@ -0,0 +1,24 @@ +import type { StatusNotificationItem } from '@/types/status-notification' + +export const SYSTEM_NOTIFICATION_ICON = '/static/icons/icon-message-system.png' + +export const SYSTEM_NOTIFICATION_LIST: StatusNotificationItem[] = [ + { + id: '1', + title: '系统通知', + preview: '平台将于2026年7月31日00:00:00进行系统维护', + time: '昨天', + }, + { + id: '2', + title: '系统通知', + preview: '平台将于2026年7月31日00:00:00进行系统维护', + time: '昨天', + }, + { + id: '3', + title: '系统通知', + preview: '平台将于2026年7月31日00:00:00进行系统维护', + time: '昨天', + }, +] diff --git a/src/hooks/use-case-favorites.ts b/src/hooks/use-case-favorites.ts new file mode 100644 index 0000000..338295e --- /dev/null +++ b/src/hooks/use-case-favorites.ts @@ -0,0 +1,73 @@ +import { computed, ref } from 'vue' +import { CASE_LIBRARY_LIST } from '@/constants/case-library' +import type { CaseItem } from '@/types/case-library' + +export const CASE_FAVORITES_STORAGE_KEY = 'case-favorites' + +function getDefaultFavoriteIds(): string[] { + return CASE_LIBRARY_LIST + .filter(item => item.favorite) + .map(item => item.id) +} + +function loadFavoriteIds(): string[] { + try { + const stored = uni.getStorageSync(CASE_FAVORITES_STORAGE_KEY) + if (Array.isArray(stored)) + return stored + } + catch { + // ignore storage read errors + } + + return getDefaultFavoriteIds() +} + +function saveFavoriteIds(ids: string[]) { + uni.setStorageSync(CASE_FAVORITES_STORAGE_KEY, ids) +} + +const favoriteIds = ref(loadFavoriteIds()) + +export function useCaseFavorites() { + const favoriteCases = computed(() => + CASE_LIBRARY_LIST + .filter(item => favoriteIds.value.includes(item.id)) + .map(item => ({ ...item, favorite: true })), + ) + + function syncFavoriteIds() { + favoriteIds.value = loadFavoriteIds() + } + + function isFavorite(id: string) { + return favoriteIds.value.includes(id) + } + + function toggleFavorite(id: string) { + if (favoriteIds.value.includes(id)) { + favoriteIds.value = favoriteIds.value.filter(itemId => itemId !== id) + } + else { + favoriteIds.value = [...favoriteIds.value, id] + } + + saveFavoriteIds(favoriteIds.value) + } + + function applyFavoritesToList(list: CaseItem[]): CaseItem[] { + return list.map(item => ({ + ...item, + favorite: favoriteIds.value.includes(item.id), + })) + } + + return { + favoriteIds, + favoriteCases, + syncFavoriteIds, + isFavorite, + toggleFavorite, + applyFavoritesToList, + } +} diff --git a/src/pages.json b/src/pages.json index 771d364..3772666 100644 --- a/src/pages.json +++ b/src/pages.json @@ -67,18 +67,54 @@ "navigationStyle": "custom" } }, + { + "path": "pages/case-library/detail/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/case-library/favorites/index", + "style": { + "navigationStyle": "custom" + } + }, { "path": "pages/message-center/index", "style": { "navigationStyle": "custom" } }, + { + "path": "pages/message-center/customer-service/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/message-center/status-notification/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/message-center/system-notification/index", + "style": { + "navigationStyle": "custom" + } + }, { "path": "pages/project-center/index", "style": { "navigationStyle": "custom" } }, + { + "path": "pages/project-center/detail/index", + "style": { + "navigationStyle": "custom" + } + }, { "path": "pages/personal-center/index", "style": { diff --git a/src/pages/case-library/components/CaseFilterPanel.vue b/src/pages/case-library/components/CaseFilterPanel.vue index 8f1cb6a..8a95a7e 100644 --- a/src/pages/case-library/components/CaseFilterPanel.vue +++ b/src/pages/case-library/components/CaseFilterPanel.vue @@ -6,7 +6,9 @@ import { CASE_FILTER_TIME_RANGES, DEFAULT_CASE_FILTER, } from '@/constants/case-library' -import type { CaseFilterValues, CaseItem } from '@/types/case-library' +import type { CaseFilterValues } from '@/types/case-library' +import type { CaseFilterTarget } from '@/utils/case-filter' +import filterIcon from '@/static/icons/icon-filter.svg' import { cloneCaseFilter, getSelectedFilterTags, @@ -16,7 +18,7 @@ import { const props = defineProps<{ visible: boolean - cases: CaseItem[] + cases: CaseFilterTarget[] value: CaseFilterValues }>() @@ -152,7 +154,7 @@ function handleConfirm() { diff --git a/src/pages/case-library/detail/index.vue b/src/pages/case-library/detail/index.vue new file mode 100644 index 0000000..0b56a02 --- /dev/null +++ b/src/pages/case-library/detail/index.vue @@ -0,0 +1,345 @@ + + + + + diff --git a/src/pages/case-library/favorites/index.vue b/src/pages/case-library/favorites/index.vue new file mode 100644 index 0000000..6b39b6d --- /dev/null +++ b/src/pages/case-library/favorites/index.vue @@ -0,0 +1,466 @@ + + + + + diff --git a/src/pages/case-library/index.vue b/src/pages/case-library/index.vue index 350fcf9..07ba4c2 100644 --- a/src/pages/case-library/index.vue +++ b/src/pages/case-library/index.vue @@ -1,6 +1,8 @@