| | |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> --> |
| | | <el-button @click="handleSubmit">提交</el-button> |
| | | <el-button @click="handleAudit">审核</el-button> |
| | | <el-button @click="handleReverseAudit">反审核</el-button> |
| | | <el-button @click="handleDelete">删除</el-button> |
| | | <el-button :loading="submitLoading" @click="handleSubmit">提交</el-button> |
| | | <el-button :loading="auditLoading" @click="handleAudit">审核</el-button> |
| | | <el-button :loading="reverseAuditLoading" @click="handleReverseAudit">反审核</el-button> |
| | | <el-button :loading="deleteLoading" @click="handleDelete">删除</el-button> |
| | | </div> |
| | | |
| | | <PIMTable |
| | |
| | | </template> |
| | | <template #action="{ row }"> |
| | | <el-button link type="primary" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button link type="primary" @click="handleProgressReport(row)">进度汇报</el-button> |
| | | <el-button link type="primary" @click="handleDiscussProgress(row)">洽谈进展</el-button> |
| | | <el-button link type="primary" :loading="progressBtnLoadingId===row.id" @click="handleProgressReport(row)">进度汇报</el-button> |
| | | <el-button link type="primary" @click="handleDetail(row)">详情</el-button> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <FormDia ref="formDiaRef" @completed="getList" /> |
| | | <ProgressReportDialog |
| | | v-model="progressReportVisible" |
| | | :project-id="progressProjectId" |
| | | :project-info="progressProjectInfo" |
| | | :plan-nodes="progressPlanNodes" |
| | | :default-plan-node-id="progressDefaultPlanNodeId" |
| | | @submitted="handleProgressSubmitted" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="ProjectManagement"> |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue' |
| | | import { useRouter } from 'vue-router' |
| | | import SearchPanel from '@/components/SearchPanel/index.vue' |
| | | import PIMTable from '@/components/PIMTable/PIMTable.vue' |
| | | import FormDia from './components/formDia.vue' |
| | | import ProgressReportDialog from '@/components/ProjectManagement/ProgressReportDialog.vue' |
| | | import { |
| | | listProject, |
| | | delProject, |
| | | submitProject, |
| | | auditProject, |
| | | reverseAuditProject |
| | | reverseAuditProject, |
| | | getProject, |
| | | saveStage |
| | | } from '@/api/projectManagement/project' |
| | | import { listPlan } from '@/api/projectManagement/projectType' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import useUserStore from '@/store/modules/user' |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | const { bill_status, project_management, plan_status } = proxy.useDict('bill_status', 'project_management', 'plan_status') |
| | | const router = useRouter() |
| | | const userStore = useUserStore() |
| | | |
| | | const loading = ref(false) |
| | | const ids = ref([]) |
| | | const tableData = ref([]) |
| | | const formDiaRef = ref() |
| | | const progressReportVisible = ref(false) |
| | | const progressProjectId = ref(undefined) |
| | | const progressProjectInfo = ref({}) |
| | | const progressPlanNodes = ref([]) |
| | | const progressDefaultPlanNodeId = ref(undefined) |
| | | const progressBtnLoadingId = ref(null) |
| | | const submitLoading = ref(false) |
| | | const auditLoading = ref(false) |
| | | const reverseAuditLoading = ref(false) |
| | | const deleteLoading = ref(false) |
| | | |
| | | const data = reactive({ |
| | | queryParams: { |
| | |
| | | formDiaRef.value?.openDialog({ operationType: 'add' }) |
| | | } |
| | | |
| | | function handleDelete() { |
| | | async function handleDelete() { |
| | | const delIds = ids.value |
| | | if (delIds.length === 0) { |
| | | ElMessage.warning('请选择要删除的数据项') |
| | | return |
| | | } |
| | | ElMessageBox.confirm('是否确认删除所选数据项?', '警告', { |
| | | try { |
| | | await ElMessageBox.confirm('是否确认删除所选数据项?', '警告', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }) |
| | | .then(() => delProject(delIds)) |
| | | .then(() => { |
| | | deleteLoading.value = true |
| | | await delProject(delIds) |
| | | getList() |
| | | ElMessage.success('删除成功') |
| | | }) |
| | | .catch(() => {}) |
| | | } catch {} finally { |
| | | deleteLoading.value = false |
| | | } |
| | | } |
| | | |
| | | function handleSubmit() { |
| | | async function handleSubmit() { |
| | | const submitIds = ids.value |
| | | if (submitIds.length === 0) { |
| | | ElMessage.warning('请选择要提交的数据项') |
| | | return |
| | | } |
| | | ElMessageBox.confirm('是否确认提交所选数据项?', '提示', { |
| | | try { |
| | | await ElMessageBox.confirm('是否确认提交所选数据项?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }) |
| | | .then(async () => { |
| | | submitLoading.value = true |
| | | await Promise.all(submitIds.map(id => submitProject({ id }))) |
| | | }) |
| | | .then(() => { |
| | | getList() |
| | | ElMessage.success('提交成功') |
| | | }) |
| | | .catch(() => {}) |
| | | } catch {} finally { |
| | | submitLoading.value = false |
| | | } |
| | | } |
| | | |
| | | function handleAudit() { |
| | | async function handleAudit() { |
| | | const auditIds = ids.value |
| | | if (auditIds.length === 0) { |
| | | ElMessage.warning('请选择要审核的数据项') |
| | | return |
| | | } |
| | | ElMessageBox.confirm('是否确认审核所选数据项?', '提示', { |
| | | try { |
| | | await ElMessageBox.confirm('是否确认审核所选数据项?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }) |
| | | .then(async () => { |
| | | auditLoading.value = true |
| | | await Promise.all(auditIds.map(id => auditProject({ id }))) |
| | | }) |
| | | .then(() => { |
| | | getList() |
| | | ElMessage.success('审核成功') |
| | | }) |
| | | .catch(() => {}) |
| | | } catch {} finally { |
| | | auditLoading.value = false |
| | | } |
| | | } |
| | | |
| | | function handleReverseAudit() { |
| | | async function handleReverseAudit() { |
| | | const reverseAuditIds = ids.value |
| | | if (reverseAuditIds.length === 0) { |
| | | ElMessage.warning('请选择要反审核的数据项') |
| | | return |
| | | } |
| | | ElMessageBox.confirm('是否确认反审核所选数据项?', '提示', { |
| | | try { |
| | | await ElMessageBox.confirm('是否确认反审核所选数据项?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }) |
| | | .then(async () => { |
| | | reverseAuditLoading.value = true |
| | | await Promise.all(reverseAuditIds.map(id => reverseAuditProject({ id }))) |
| | | }) |
| | | .then(() => { |
| | | getList() |
| | | ElMessage.success('反审核成功') |
| | | }) |
| | | .catch(() => {}) |
| | | } catch {} finally { |
| | | reverseAuditLoading.value = false |
| | | } |
| | | } |
| | | |
| | | function handleGenerateBill(command) { |
| | | ElMessage.info(`生成单据: ${command}`) |
| | | } |
| | | |
| | | function handleProgressReport(row) { |
| | | formDiaRef.value?.openDialog({ operationType: 'view', row }) |
| | | function computeDefaultPlanNodeId(stageVal, nodes) { |
| | | const list = Array.isArray(nodes) ? nodes : [] |
| | | if (list.length === 0) return undefined |
| | | const direct = list.find(n => String(n.id) === String(stageVal)) |
| | | if (direct?.id) return direct.id |
| | | const sorted = [...list].sort((a, b) => Number(a.sort ?? 0) - Number(b.sort ?? 0)) |
| | | const idx = Number(stageVal) |
| | | if (Number.isFinite(idx)) { |
| | | const byIndex = sorted[idx - 1] || sorted[idx] || sorted[0] |
| | | if (byIndex?.id) return byIndex.id |
| | | } |
| | | return sorted[0]?.id |
| | | } |
| | | |
| | | function handleDiscussProgress(row) { |
| | | formDiaRef.value?.openDialog({ operationType: 'view', row }) |
| | | async function handleProgressReport(row) { |
| | | if (!row?.id) return |
| | | try { |
| | | progressBtnLoadingId.value = row.id |
| | | const res = await getProject(row.id) |
| | | const detail = res?.data?.data ?? res?.data ?? res |
| | | const info = detail?.info || {} |
| | | progressProjectId.value = info.id |
| | | progressProjectInfo.value = info |
| | | |
| | | const planId = info.projectManagementPlanId |
| | | if (planId) { |
| | | const planRes = await listPlan({ current: 1, size: 999 }) |
| | | const records = planRes?.data?.records || planRes?.records || planRes?.rows || [] |
| | | const plan = (records || []).find(p => String(p.id) === String(planId)) || {} |
| | | progressPlanNodes.value = Array.isArray(plan?.planNodeList) ? plan.planNodeList : [] |
| | | } else { |
| | | progressPlanNodes.value = [] |
| | | } |
| | | |
| | | progressDefaultPlanNodeId.value = computeDefaultPlanNodeId(info.stage, progressPlanNodes.value) |
| | | progressReportVisible.value = true |
| | | } catch (e) { |
| | | ElMessage.error('获取项目详情失败') |
| | | } finally { |
| | | progressBtnLoadingId.value = null |
| | | } |
| | | } |
| | | |
| | | async function handleProgressSubmitted(payload) { |
| | | try { |
| | | const nodes = Array.isArray(progressPlanNodes.value) ? progressPlanNodes.value : [] |
| | | const node = nodes.find(n => String(n.id) === String(payload.planNodeId)) || {} |
| | | const description = payload.remark |
| | | ? `${payload.reportDate || ''} ${payload.remark}`.trim() |
| | | : `${payload.reportDate || ''} 进度汇报`.trim() |
| | | const req = { |
| | | id: null, |
| | | projectManagementPlanNodeId: payload.planNodeId, |
| | | projectManagementInfoId: progressProjectId.value, |
| | | description, |
| | | actualLeaderId: userStore.id || progressProjectInfo.value?.managerId, |
| | | actualLeaderName: userStore.nickName || progressProjectInfo.value?.managerName, |
| | | estimatedDuration: Number(node.estimatedDuration ?? 0) || 0, |
| | | planStartTime: payload.planStartTime || progressProjectInfo.value?.planStartTime, |
| | | planEndTime: payload.planEndTime || progressProjectInfo.value?.planEndTime, |
| | | actualStartTime: payload.actualStartTime || null, |
| | | actualEndTime: payload.actualEndTime || null, |
| | | progress: Number(payload.totalProgress ?? payload.completionProgress ?? 0) || 0, |
| | | attachmentIds: Array.isArray(payload.attachmentIds) ? payload.attachmentIds : [] |
| | | } |
| | | const res = await saveStage(req) |
| | | if (res?.code === 200) { |
| | | ElMessage.success('提交成功') |
| | | getList() |
| | | return |
| | | } |
| | | ElMessage.error(res?.msg || '提交失败') |
| | | } catch (e) { |
| | | ElMessage.error('提交失败') |
| | | } |
| | | } |
| | | |
| | | function handleDetail(row) { |
| | | formDiaRef.value?.openDialog({ operationType: 'view', row }) |
| | | if (!row?.id) return |
| | | router.push(`/projectManagement/Management/detail/${row.id}`) |
| | | } |
| | | |
| | | function handleEdit(row) { |