From 793996001157f65ad1ce4885979926b324cbea37 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 2 May 2026 23:39:44 +0800 Subject: [PATCH] feat(web): workspace selector on issue/requirement detail --- web/src/api/projects.ts | 12 ++++++- web/src/views/projects/IssueDetailView.vue | 23 +++++++++++++ .../views/projects/RequirementDetailView.vue | 33 +++++++++++++++++-- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/web/src/api/projects.ts b/web/src/api/projects.ts index 63df433..27b935a 100644 --- a/web/src/api/projects.ts +++ b/web/src/api/projects.ts @@ -25,6 +25,7 @@ export interface Requirement { phase: Phase status: Status owner_id: string + workspace_id: string | null closed_at?: string | null created_at: string updated_at: string @@ -34,6 +35,7 @@ export interface Issue { id: string project_id: string requirement_id: string | null + workspace_id: string | null number: number title: string description: string @@ -92,7 +94,13 @@ export const projectsApi = { updateRequirement: ( slug: string, number: number, - body: Partial<{ title: string; description: string; owner_id: string }>, + body: Partial<{ + title: string + description: string + owner_id: string + // 三态:未传字段 / 显式 null(detach) / ""(attach) + workspace_id: string | null + }>, ) => request(`/api/v1/projects/${enc(slug)}/requirements/${number}`, { method: 'PATCH', @@ -141,6 +149,8 @@ export const projectsApi = { description: string // 三态:未传字段 / 显式 null(detach) / number(attach/move) requirement_number: number | null + // 三态:未传字段 / 显式 null(detach) / ""(attach) + workspace_id: string | null }>, ) => request(`/api/v1/projects/${enc(slug)}/issues/${number}`, { diff --git a/web/src/views/projects/IssueDetailView.vue b/web/src/views/projects/IssueDetailView.vue index 513d4d3..0d69471 100644 --- a/web/src/views/projects/IssueDetailView.vue +++ b/web/src/views/projects/IssueDetailView.vue @@ -58,6 +58,17 @@ /> + + + + +
@@ -118,11 +129,13 @@ import { NCard, NButton, NTag, NSpin, NSelect } from 'naive-ui' import AppShell from '@/layouts/AppShell.vue' import { projectsApi } from '@/api/projects' import { useAuthStore } from '@/stores/auth' +import { useWorkspacesStore } from '@/stores/workspaces' import type { Issue, Requirement } from '@/api/projects' const route = useRoute() const router = useRouter() const auth = useAuthStore() +const wsStore = useWorkspacesStore() const slug = route.params.slug as string const number = Number(route.params.number) @@ -138,6 +151,10 @@ const requirementOptions = computed(() => requirements.value.map((r) => ({ label: `R-${r.number}: ${r.title}`, value: r.number })), ) +const workspaceOptions = computed(() => + wsStore.list.map((w) => ({ label: `${w.name} (${w.slug})`, value: w.id })), +) + const mountedRequirementNumber = computed(() => { if (!issue.value?.requirement_id) return null const req = requirements.value.find((r) => r.id === issue.value!.requirement_id) @@ -150,6 +167,7 @@ async function fetchData() { const [fetchedIssue, reqs] = await Promise.all([ projectsApi.getIssue(slug, number), projectsApi.listRequirements(slug), + wsStore.fetchByProject(slug), ]) issue.value = fetchedIssue requirements.value = reqs.items @@ -163,6 +181,11 @@ async function onMountChange(v: number | null) { issue.value = await projectsApi.updateIssue(slug, number, { requirement_number: v }) } +async function onWorkspaceChange(v: string | null) { + if (!issue.value) return + issue.value = await projectsApi.updateIssue(slug, number, { workspace_id: v }) +} + async function onClose() { toggling.value = true try { diff --git a/web/src/views/projects/RequirementDetailView.vue b/web/src/views/projects/RequirementDetailView.vue index d4cd134..f213d04 100644 --- a/web/src/views/projects/RequirementDetailView.vue +++ b/web/src/views/projects/RequirementDetailView.vue @@ -85,6 +85,17 @@

+ + + + +