220 lines
6.2 KiB
TypeScript
220 lines
6.2 KiB
TypeScript
import { IconClockCircle, IconEmail, IconFile, IconHome, IconLink, IconList, IconRobot, IconUserGroup } from '@arco-design/web-react/icon'
|
|
import type {
|
|
ProjectWorkspaceDTO,
|
|
WorkspaceAISessionDTO,
|
|
WorkspaceChannelDTO,
|
|
WorkspaceCronPlanDTO,
|
|
WorkspaceInboxDTO,
|
|
WorkspaceDocumentDTO,
|
|
WorkspaceTaskDTO,
|
|
} from './projects'
|
|
import type { AISession, ChannelKey, CronJob, DocumentSummary, InboxItem, Project, ProjectChannel, ProjectWorkspace, TaskItem } from '../pages/projects/project-types'
|
|
|
|
const projectColors = ['#165DFF', '#00B42A', '#722ED1', '#FF7D00', '#14C9C9', '#F53F3F']
|
|
|
|
export function mapWorkspace(payload: ProjectWorkspaceDTO, index = 0): ProjectWorkspace {
|
|
const project: Project = {
|
|
id: payload.project.id,
|
|
name: payload.project.name,
|
|
identifier: payload.project.identifier ?? '',
|
|
icon: payload.project.icon ?? '',
|
|
background: payload.project.background ?? '',
|
|
description: payload.project.description,
|
|
short: projectIconLabel(payload.project.icon ?? '', payload.project.initials),
|
|
badge: payload.project.unreadCount,
|
|
urgent: payload.project.unreadCount > 20,
|
|
color: projectColor(payload.project.background ?? '', index),
|
|
}
|
|
|
|
return {
|
|
project,
|
|
channels: payload.channels.filter((channel) => channel.type !== 'inbox').map(mapChannel),
|
|
tags: payload.tags.map((tag) => tag.name),
|
|
recentSessions: payload.recentSessions.map(mapAISession),
|
|
inbox: payload.inbox.map(mapInbox),
|
|
tasks: payload.tasks.map(mapTask),
|
|
aiSessions: payload.aiSessions.map(mapAISession),
|
|
documents: payload.documents.map(mapDocument),
|
|
cronJobs: payload.cronPlans.map(mapCronPlan),
|
|
}
|
|
}
|
|
|
|
function projectIconLabel(icon: string, fallback: string) {
|
|
const trimmed = icon.trim()
|
|
if (!trimmed) return fallback
|
|
const chars = Array.from(trimmed)
|
|
if (chars.length <= 2) return trimmed
|
|
return chars.slice(0, 2).join('').toUpperCase()
|
|
}
|
|
|
|
function projectColor(background: string, index: number) {
|
|
const trimmed = background.trim()
|
|
if (trimmed.startsWith('#') || trimmed.startsWith('rgb') || trimmed.startsWith('hsl')) {
|
|
return trimmed
|
|
}
|
|
return projectColors[index % projectColors.length]
|
|
}
|
|
|
|
function mapChannel(channel: WorkspaceChannelDTO): ProjectChannel {
|
|
return {
|
|
id: channel.id,
|
|
key: mapChannelKey(channel.type, channel.id),
|
|
label: channelLabel(channel),
|
|
count: channel.count,
|
|
icon: channelIcon(channel),
|
|
url: channel.url,
|
|
sortOrder: channel.sortOrder,
|
|
}
|
|
}
|
|
|
|
function mapChannelKey(type: string, id = ''): ChannelKey {
|
|
switch (type) {
|
|
case 'inbox':
|
|
return 'inbox'
|
|
case 'tasks':
|
|
return 'tasks'
|
|
case 'ai_sessions':
|
|
return 'ai'
|
|
case 'documents':
|
|
return 'documents'
|
|
case 'cron':
|
|
return 'cron'
|
|
case 'overview':
|
|
return 'overview'
|
|
default:
|
|
return `custom:${id || type}`
|
|
}
|
|
}
|
|
|
|
function channelLabel(channel: WorkspaceChannelDTO) {
|
|
switch (channel.type) {
|
|
case 'overview':
|
|
return '概况'
|
|
case 'inbox':
|
|
return 'Inbox 消息流'
|
|
case 'tasks':
|
|
return '工作计划'
|
|
case 'ai_sessions':
|
|
return 'AI 会话'
|
|
case 'documents':
|
|
return '笔记资料'
|
|
case 'cron':
|
|
return '计划任务'
|
|
default:
|
|
return channel.title
|
|
}
|
|
}
|
|
|
|
function channelIcon(channel: WorkspaceChannelDTO) {
|
|
switch (channel.type) {
|
|
case 'overview':
|
|
return <IconHome />
|
|
case 'inbox':
|
|
return <IconEmail />
|
|
case 'tasks':
|
|
return <IconList />
|
|
case 'ai_sessions':
|
|
return <IconRobot />
|
|
case 'documents':
|
|
return <IconFile />
|
|
case 'cron':
|
|
return <IconClockCircle />
|
|
default:
|
|
return channel.icon === 'user' ? <IconUserGroup /> : <IconLink />
|
|
}
|
|
}
|
|
|
|
function mapInbox(item: WorkspaceInboxDTO): InboxItem {
|
|
return {
|
|
id: item.id,
|
|
title: item.title,
|
|
meta: `来源:${item.source}`,
|
|
owner: '系统',
|
|
time: formatBackendDate(item.time),
|
|
tag: item.tag || item.status,
|
|
summary: item.summary,
|
|
status: item.status,
|
|
}
|
|
}
|
|
|
|
function mapTask(task: WorkspaceTaskDTO): TaskItem {
|
|
return {
|
|
id: task.id,
|
|
title: task.title,
|
|
owner: task.owner,
|
|
progress: task.completed ? '100%' : '',
|
|
due: task.due ? formatBackendDate(task.due) : '未设置',
|
|
createdAt: formatBackendDate(task.createdAt),
|
|
completedAt: task.completedAt ? formatBackendDate(task.completedAt) : '',
|
|
duration: '',
|
|
tag: task.tag || '',
|
|
summary: task.summary,
|
|
completed: task.completed,
|
|
}
|
|
}
|
|
|
|
function formatBackendDate(value: string) {
|
|
const date = parseBackendDate(value)
|
|
if (!date) return '未知时间'
|
|
|
|
const now = new Date()
|
|
const today = startOfDay(now)
|
|
const yesterday = new Date(today)
|
|
yesterday.setDate(today.getDate() - 1)
|
|
const dateDay = startOfDay(date)
|
|
const time = `${pad(date.getHours())}:${pad(date.getMinutes())}`
|
|
|
|
if (dateDay.getTime() === today.getTime()) return `今天 ${time}`
|
|
if (dateDay.getTime() === yesterday.getTime()) return `昨天 ${time}`
|
|
return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${time}`
|
|
}
|
|
|
|
function parseBackendDate(value: string) {
|
|
if (!value) return null
|
|
const normalized = value.includes('T') ? value : `${value.replace(' ', 'T')}Z`
|
|
const date = new Date(normalized)
|
|
return Number.isNaN(date.getTime()) ? null : date
|
|
}
|
|
|
|
function startOfDay(value: Date) {
|
|
return new Date(value.getFullYear(), value.getMonth(), value.getDate())
|
|
}
|
|
|
|
function pad(value: number) {
|
|
return String(value).padStart(2, '0')
|
|
}
|
|
|
|
function mapAISession(session: WorkspaceAISessionDTO): AISession {
|
|
return {
|
|
id: session.id,
|
|
title: session.title,
|
|
summary: session.summary,
|
|
owner: 'AI',
|
|
time: formatBackendDate(session.updatedAt),
|
|
}
|
|
}
|
|
|
|
function mapDocument(document: WorkspaceDocumentDTO): DocumentSummary {
|
|
return {
|
|
id: document.id,
|
|
name: document.name,
|
|
kind: document.kind,
|
|
extension: document.extension,
|
|
mimeType: document.mimeType,
|
|
updated: formatBackendDate(document.updatedAt),
|
|
}
|
|
}
|
|
|
|
function mapCronPlan(plan: WorkspaceCronPlanDTO): CronJob {
|
|
return {
|
|
id: plan.id,
|
|
name: plan.title,
|
|
expr: plan.schedule,
|
|
status: plan.enabled ? '运行中' : '暂停',
|
|
lastRun: plan.lastResult,
|
|
nextRun: plan.nextRun ? formatBackendDate(plan.nextRun) : '暂停中',
|
|
owner: plan.owner,
|
|
enabled: plan.enabled,
|
|
}
|
|
}
|