新增: 三实体列表查询维度补全(status/关键词/排序/分页下沉后端)
任务/项目/灵感三实体新增 list_by_query 动态 WHERE(累积式 where_clauses
+params_vec 收口)+ order_by 白名单防注入 + limit/offset 钳制。命令层
list_{tasks,projects,ideas} 吃 Option<XxxQuery> 双参向后兼容(旧无参/单参
路径等价全量)。前端 Tasks/Ideas status/keyword 筛选下沉后端 query。
F-260621-02
This commit is contained in:
@@ -5,7 +5,7 @@ import { createTasksStore } from './project/tasks'
|
||||
import { createIdeasStore } from './project/ideas'
|
||||
import { createWorkflowStore } from './project/workflow'
|
||||
import { state, clearError } from './project/state'
|
||||
import type { DfDataChangedPayload } from '@/api/types'
|
||||
import type { DfDataChangedPayload, TaskQuery } from '@/api/types'
|
||||
|
||||
// ── barrel 组合器(零行为变更,纯重构) ──
|
||||
//
|
||||
@@ -34,10 +34,26 @@ function createStore() {
|
||||
// - 'all' : 全量拉取
|
||||
// - 具体 id : 按项目拉取
|
||||
// 由 Tasks.vue 经 setActiveTaskProject 在 onMounted/watch 更新本变量。
|
||||
//
|
||||
// F-260621-02(P1 status 下沉):新增 _activeTaskStatus 追踪当前 status 筛选,数据变更
|
||||
// 联动刷新时一并下沉到后端 query(保 B-29「store.tasks 反映当前筛选」契约,
|
||||
// 避免刷新把已选 status 冲掉)。
|
||||
let _activeTaskProject: string | undefined = undefined
|
||||
let _activeTaskStatus: string | undefined = undefined
|
||||
function setActiveTaskProject(projectKey: string | undefined) {
|
||||
_activeTaskProject = projectKey
|
||||
}
|
||||
function setActiveTaskStatus(statusKey: string | undefined) {
|
||||
_activeTaskStatus = statusKey
|
||||
}
|
||||
// 构造当前 task 视图筛选对应的 query(供数据变更 listener 复用同一筛选拉取)
|
||||
function buildActiveTaskQuery(): TaskQuery | undefined {
|
||||
if (_activeTaskProject === undefined) return undefined // 视图未挂载,不触发
|
||||
const query: TaskQuery = {}
|
||||
if (_activeTaskProject !== 'all') query.project_id = _activeTaskProject
|
||||
if (_activeTaskStatus && _activeTaskStatus !== 'all') query.status = _activeTaskStatus
|
||||
return query
|
||||
}
|
||||
|
||||
let _dataChangedUnlisten: (() => void) | null = null
|
||||
|
||||
@@ -49,9 +65,11 @@ function createStore() {
|
||||
if (entity === 'project') {
|
||||
void projectsStore.loadProjects()
|
||||
} else if (entity === 'task') {
|
||||
// 无筛选状态(undefined)时不触发,保 B-29 筛选契约;有筛选则按当前 activeProject 拉
|
||||
if (_activeTaskProject !== undefined) {
|
||||
void tasksStore.loadTasks(_activeTaskProject === 'all' ? undefined : _activeTaskProject)
|
||||
// 无筛选状态(_activeTaskProject undefined)时不触发,保 B-29 筛选契约;
|
||||
// 有筛选则按当前 activeProject + activeStatus 构造 query 下沉后端拉取
|
||||
const q = buildActiveTaskQuery()
|
||||
if (q !== undefined) {
|
||||
void tasksStore.loadTasks(q)
|
||||
}
|
||||
} else if (entity === 'idea') {
|
||||
void ideasStore.loadIdeas()
|
||||
@@ -126,6 +144,8 @@ function createStore() {
|
||||
stopDataChangedListener,
|
||||
// CR-260615-26(R-1): Tasks 视图登记当前 activeProject 筛选,供 listener 按筛选拉取
|
||||
setActiveTaskProject,
|
||||
// F-260621-02(P1 status 下沉):Tasks 视图登记当前 status 筛选,供 listener 复用同一筛选拉取
|
||||
setActiveTaskStatus,
|
||||
pendingApproval: computed(() => state.pendingApproval),
|
||||
// computed
|
||||
stats,
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import { ideaApi } from '@/api'
|
||||
import type { IdeaQuery } from '@/api/types'
|
||||
import { t } from '@/i18n/i18n-helpers'
|
||||
import { state } from './state'
|
||||
|
||||
/** 灵感 CRUD 子 store(共享全局 state) */
|
||||
export function createIdeasStore() {
|
||||
async function loadIdeas() {
|
||||
/**
|
||||
* 加载灵感列表。
|
||||
*
|
||||
* F-260621-02:status/keyword/order_by 下沉后端 WHERE,取代前端 computed filter。
|
||||
* - 传 `query` → 多条件查询(状态/关键词/排序/分页)。
|
||||
* - 不传 → 全量(created_at DESC,等价旧行为)。
|
||||
*/
|
||||
async function loadIdeas(query?: IdeaQuery) {
|
||||
try {
|
||||
state.ideas = await ideaApi.list()
|
||||
state.ideas = await ideaApi.list(query)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? t('ideas.err.loadFailed')
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { projectApi } from '@/api'
|
||||
import type { ImportProjectInput } from '@/api/project'
|
||||
import type { ImportProjectInput, ProjectQuery } from '@/api/project'
|
||||
import { t } from '@/i18n/i18n-helpers'
|
||||
import { state, clearError } from './state'
|
||||
|
||||
/** 项目 CRUD 子 store(共享全局 state) */
|
||||
export function createProjectsStore() {
|
||||
async function loadProjects() {
|
||||
/**
|
||||
* 加载未删除项目。
|
||||
* F-260621-02:可选 query 透传(关键词/排序/分页)。不传 = 当前全量行为(向后兼容)。
|
||||
*/
|
||||
async function loadProjects(query?: ProjectQuery) {
|
||||
state.loading = true
|
||||
state.error = null
|
||||
try {
|
||||
state.projects = await projectApi.list()
|
||||
state.projects = await projectApi.list(query)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? t('projects.err.loadFailed')
|
||||
} finally {
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import { taskApi } from '@/api'
|
||||
import type { TaskQuery } from '@/api/types'
|
||||
import { t } from '@/i18n/i18n-helpers'
|
||||
import { state } from './state'
|
||||
|
||||
/** 任务 CRUD 子 store(共享全局 state) */
|
||||
export function createTasksStore() {
|
||||
async function loadTasks(projectId?: string) {
|
||||
/**
|
||||
* 加载任务列表。
|
||||
*
|
||||
* **双签名向后兼容**(F-260621-02):
|
||||
* - `loadTasks(projectId?)`:旧签名,仅项目过滤(等价 `loadTasks({ project_id: projectId })`)。
|
||||
* - `loadTasks(query?)`:新签名,多条件(status/keyword/...)走后端 WHERE。
|
||||
*
|
||||
* 不传 → 全量未删任务(created_at DESC,等价改造前 list_active)。
|
||||
* status/keyword 下沉后端 WHERE(P1/P2),取代 Tasks.vue 旧的前端内存 filter。
|
||||
*/
|
||||
async function loadTasks(queryOrProjectId?: TaskQuery | string) {
|
||||
try {
|
||||
state.tasks = await taskApi.list(projectId)
|
||||
state.tasks = await taskApi.list(queryOrProjectId)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? t('tasks.err.loadFailed')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user