feat(erpProjectPlan): 添加项目计划甘特图和计划变更按钮

- 在项目计划编辑页面添加实际开始和结束时间字段
- 引入项目信息类型定义并优化项目选择逻辑
- 新增项目计划甘特图展示页面路由配置
- 添加项目变更编辑页面路由配置
- 扩展项目计划列表操作列,新增计划变更和甘特图按钮
- 实现项目计划变更和甘特图跳转逻辑
- 调整操作列宽度以适应新增按钮
- 优化 handleProjectChange 方法支持部分字段同步控制
dev
zangch@mesnac.com 1 month ago
parent fa01567268
commit 3f0abdc86a

@ -115,7 +115,20 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/oa/erp/erpProjectPlan/edit.vue'),
name: 'ErpProjectPlanView',
meta: { title: '项目计划查看', activeMenu: '/oa/erp/erpProjectPlan' }
}
},
{
path: 'erpProjectPlan/gantt/:projectPlanId',
component: () => import('@/views/oa/erp/erpProjectPlan/gantt.vue'),
name: 'ErpProjectPlanGantt',
meta: { title: '项目计划甘特图', activeMenu: '/oa/erp/erpProjectPlan' }
},
{
path: 'erpProjectChange/edit/:projectChangeId',
component: () => import('@/views/oa/erp/erpProjectChange/edit.vue'),
name: 'ErpProjectChangeEdit',
meta: { title: '项目变更编辑', activeMenu: '/oa/erp/erpProjectPlan' }
},
]
},
{
@ -128,7 +141,13 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/oa/crm/crmQuoteInfo/edit.vue'),
name: 'crmQuoteInfoEdit',
meta: { title: '报价单编辑', activeMenu: '/oa/crm/crmQuoteInfo' }
}
},
{
path: 'crmQuoteInfo/view/:quoteId',
component: () => import('@/views/oa/crm/crmQuoteInfo/edit.vue'),
name: 'crmQuoteInfoView',
meta: { title: '报价单查看', activeMenu: '/oa/crm/crmQuoteInfo' }
},
]
},
{

@ -140,11 +140,33 @@
<el-input-number v-model="scope.row.delayDay" :min="0" :step="1" controls-position="right" style="width: 100%" :disabled="!canEditLimited" @change="recalcReceivableDate(scope.row)"/>
</template>
</el-table-column>
<el-table-column label="应收款日期" width="160" align="center">
<!-- <el-table-column label="应收款日期" width="160" align="center">
<template #default="scope">
<el-date-picker v-model="scope.row.receivableDate" type="date" value-format="YYYY-MM-DD" placeholder="自动计算" style="width: 100%" disabled/>
</template>
</el-table-column>
</el-table-column>-->
<el-table-column label="实际开始" min-width="140">
<template #default="scope">
<el-date-picker
v-model="scope.row.realStartTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 100%"
/>
</template>
</el-table-column>
<el-table-column label="实际结束" min-width="140">
<template #default="scope">
<el-date-picker
v-model="scope.row.realEndTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 100%"
/>
</template>
</el-table-column>
<el-table-column label="进度备注" width="200" align="center">
<template #default="scope">
<el-input v-model="scope.row.scheduleRemark" placeholder="请输入进度备注" :disabled="!canEditLimited"/>
@ -174,6 +196,7 @@ import { getErpProjectPlan, addErpProjectPlan, updateErpProjectPlan, projectPlan
import { ErpProjectPlanForm } from '@/api/oa/erp/erpProjectPlan/types';
import { listUser } from '@/api/system/user';
import { getErpProjectInfoList } from '@/api/oa/erp/projectInfo';
import type { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
import SubmitVerify from '@/components/Process/submitVerify.vue';
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
import { useUserStore } from '@/store/modules/user';
@ -284,7 +307,7 @@ const buttonLoading = ref(false);
const draftLoading = ref(false);
const submitLoading = ref(false);
const currentAction = ref<'draft' | 'submit' | null>(null);
const projectInfoList = ref<any[]>([]);
const projectInfoList = ref<Partial<ProjectInfoVO>[]>([]);
const userList = ref<any[]>([]);
const selectedProjectCode = ref<string>(''); //
const baseDataLoaded = ref(false);
@ -321,7 +344,7 @@ const resetForm = () => {
/** 获取项目列表 */
const getProjectInfoList = async () => {
const res = await getErpProjectInfoList({});
projectInfoList.value = res.data;
projectInfoList.value = (res.data || []) as Partial<ProjectInfoVO>[];
};
/** 获取用户列表 */
@ -370,20 +393,44 @@ const handleDeleteStage = (index: number) => {
form.value.planStageList?.splice(index, 1);
};
/** 处理项目选择变化,自动填充项目经理、部门负责人和项目编号 */
const handleProjectChange = (projectId: number) => {
if (!projectId) {
form.value.managerId = undefined;
form.value.chargeId = undefined;
interface ProjectSyncOptions {
syncManagerAndCharge?: boolean;
syncPaymentMethod?: boolean;
}
/** 处理项目选择变化,自动填充项目经理、部门负责人、付款方式和项目编号 */
const handleProjectChange = (
projectId?: string | number,
{ syncManagerAndCharge = true, syncPaymentMethod = true }: ProjectSyncOptions = {}
) => {
const isEmptySelection = projectId === undefined || projectId === null || projectId === '';
if (isEmptySelection) {
if (syncManagerAndCharge) {
form.value.managerId = undefined;
form.value.chargeId = undefined;
}
if (syncPaymentMethod) {
form.value.paymentMethod = undefined;
}
selectedProjectCode.value = '';
return;
}
const project = projectInfoList.value.find(p => p.projectId === projectId);
if (project) {
form.value.managerId = project.managerId;
form.value.chargeId = project.chargeId;
selectedProjectCode.value = project.projectCode || '';
const project = projectInfoList.value.find(item => String(item.projectId) === String(projectId));
if (!project) {
return;
}
if (syncManagerAndCharge) {
form.value.managerId = project.managerId ?? undefined;
form.value.chargeId = project.chargeId ?? undefined;
}
if (syncPaymentMethod) {
form.value.paymentMethod = (project.paymentMethod as string) ?? undefined;
}
selectedProjectCode.value = (project.projectCode as string) || '';
};
@ -562,6 +609,12 @@ const loadFormData = async () => {
if (!form.value.planStageList) {
form.value.planStageList = [];
}
if (form.value.projectId) {
handleProjectChange(form.value.projectId, {
syncManagerAndCharge: false,
syncPaymentMethod: false
});
}
} else {
resetForm();
form.value.flowStatus = 'draft';

@ -75,7 +75,7 @@
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" fixed="right" class-name="small-padding fixed-width">
<el-table-column label="操作" align="center" width="200" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看" placement="top" v-if="scope.row.projectPlanStatus !== '1'">
<el-button link type="info" icon="DocumentChecked" @click="handleView(scope.row)" v-hasPermi="['oa/erp:erpProjectPlan:query']"></el-button>
@ -86,9 +86,15 @@
<el-tooltip content="维护进度" placement="top" v-if="scope.row.projectPlanStatus === '3' || scope.row.flowStatus === 'finish'">
<el-button link type="primary" icon="EditPen" @click="handleProgress(scope.row)" v-hasPermi="['oa/erp:erpProjectPlan:edit']"></el-button>
</el-tooltip>
<el-tooltip content="计划变更" placement="top" v-if="scope.row.projectPlanStatus === '3' || scope.row.flowStatus === 'finish'">
<el-button link type="warning" icon="Operation" @click="handlePlanChange(scope.row)" v-hasPermi="['oa/erp:erpProjectChange:add']"></el-button>
</el-tooltip>
<el-tooltip content="审批记录" placement="top" v-if="scope.row.projectPlanStatus === '2' || scope.row.projectPlanStatus === '3'">
<el-button link type="info" icon="View" @click="handleApprovalRecord(scope.row)"></el-button>
</el-tooltip>
<el-tooltip content="甘特图" placement="top" v-if="scope.row.projectPlanId">
<el-button link type="primary" icon="Histogram" @click="handleGantt(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
@ -372,6 +378,21 @@
approvalRecordRef.value?.init(row.projectPlanId);
}
/** 项目计划变更按钮操作 */
const handlePlanChange = (row: ErpProjectPlanVO) => {
// ID
router.push(`/oa/erp/erpProjectChange/edit/0?projectId=${row.projectId}`);
}
/** 甘特图按钮 */
const handleGantt = (row: ErpProjectPlanVO) => {
if (!row.projectPlanId) {
proxy?.$modal.msgWarning('请先保存项目计划信息');
return;
}
router.push(`/oa/erp/erpProjectPlan/gantt/${row.projectPlanId}`);
}
/** 修改按钮操作(保留用于对话框形式) */
const handleUpdate = async (row?: ErpProjectPlanVO) => {
reset();

Loading…
Cancel
Save