feat(项目看板): 新增项目综合看板功能

新增项目综合看板功能,聚合展示项目、任务、进度主表和步骤数据
- 新增后端聚合接口 GET /oa/project/dashboard/{projectId}
- 新增前端看板页面,包含项目列表、任务表格和进度导图
- 优化思维导图组件,支持看板模式下的紧凑展示
- 新增进度明细表格视图和状态图例
- 实现任务与进度步骤的关联展示
- 添加项目模糊搜索功能
This commit is contained in:
2026-04-15 17:19:56 +08:00
parent 5d4794c9bd
commit 50f3f15f48
24 changed files with 1623 additions and 115 deletions

View File

@@ -0,0 +1,121 @@
import { listProject, getProjectDashboard } from '@/api/oa/project'
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function retry (fn, times, delayMs) {
let lastErr
for (let i = 0; i < times; i++) {
try {
return await fn()
} catch (e) {
lastErr = e
if (i < times - 1) {
await sleep(delayMs)
}
}
}
throw lastErr
}
const state = {
currentProjectId: '',
projectQuery: {
pageNum: 1,
pageSize: 10,
keyword: ''
},
projectList: [],
projectTotal: 0,
projectDetail: null,
taskList: [],
scheduleList: [],
stepList: [],
taskQuery: {
pageNum: 1,
pageSize: 10,
projectCode: '',
taskKeyword: ''
},
loading: false
}
const mutations = {
SET_LOADING (state, val) {
state.loading = !!val
},
SET_CURRENT_PROJECT (state, projectId) {
state.currentProjectId = projectId || ''
},
SET_PROJECT_QUERY (state, payload) {
state.projectQuery = { ...state.projectQuery, ...(payload || {}) }
},
SET_PROJECT_LIST (state, payload) {
state.projectList = payload.rows || []
state.projectTotal = payload.total || 0
},
SET_DASHBOARD (state, payload) {
const p = payload || {}
state.projectDetail = p.project || null
state.taskList = p.tasks || []
state.scheduleList = p.schedules || []
state.stepList = p.steps || []
},
CLEAR_RIGHT (state) {
state.projectDetail = null
state.taskList = []
state.scheduleList = []
state.stepList = []
},
SET_TASK_QUERY (state, payload) {
state.taskQuery = { ...state.taskQuery, ...(payload || {}) }
}
}
const actions = {
async fetchProjectList ({ commit, state }, payload) {
const merged = { ...state.projectQuery, ...(payload || {}) }
const query = {
pageNum: merged.pageNum,
pageSize: merged.pageSize,
keyword: (merged.keyword != null ? String(merged.keyword) : '').trim()
}
commit('SET_PROJECT_QUERY', query)
commit('SET_LOADING', true)
try {
const res = await retry(() => listProject(query), 2, 600)
commit('SET_PROJECT_LIST', { rows: res.rows || [], total: res.total || 0 })
return res
} finally {
commit('SET_LOADING', false)
}
},
async selectProject ({ commit }, projectId) {
commit('SET_CURRENT_PROJECT', projectId)
if (!projectId) {
commit('CLEAR_RIGHT')
return
}
const res = await retry(() => getProjectDashboard(projectId), 2, 600)
const data = res.data || {}
commit('SET_DASHBOARD', data)
return res
}
}
export default {
namespaced: true,
state,
mutations,
actions
}