1.0.36 采购审批流程

dev
yinq 4 weeks ago
parent 2482fbb29f
commit 231bfead58

@ -157,6 +157,11 @@ export interface ProjectPurchaseForm extends BaseEntity {
*/
deputyId?: string | number;
/**
* ID
*/
deptId?: string | number;
/**
*
*/

@ -148,6 +148,21 @@ export interface ProjectPurchaseMaterialForm extends BaseEntity {
*/
relationMaterialId?: string | number;
/**
*
*/
relationMaterialCode?: string;
/**
*
*/
relationMaterialName?: string;
/**
*
*/
purchaseMaterialName?: string;
/**
*
*/

@ -12,14 +12,16 @@
:mode="false"
/>
<el-card shadow="never" class="mb-4" >
<el-card shadow="never" class="mb-4">
<el-form ref="projectPurchaseFormRef" :model="form" :rules="rules" label-width="120px" :disabled="isReadOnly">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目号" prop="projectCode">
<el-input v-model="form.projectCode" placeholder="请选择项目" readonly>
<template #append>
<el-button icon="Search" @click="openProjectSelect" :disabled="isReadOnly">选择</el-button>
<template #suffix>
<el-icon style="cursor: pointer" @click="openProjectSelect" :disabled="isReadOnly">
<Search />
</el-icon>
</template>
</el-input>
</el-form-item>
@ -100,7 +102,7 @@
</el-form>
</el-card>
<el-card shadow="never" >
<el-card shadow="never">
<template #header>
<div class="table-header standard">
<span class="title-dot standard-dot"></span>
@ -115,7 +117,7 @@
</el-table-column>
<el-table-column label="关联物料编号" prop="relationMaterialCode" min-width="140" show-overflow-tooltip align="center" />
<el-table-column label="关联物料名称" prop="relationMaterialName" min-width="160" show-overflow-tooltip align="center" />
<el-table-column label="采购物料名称" prop="materialName" min-width="160" show-overflow-tooltip align="center" />
<el-table-column label="采购物料名称" prop="materialName" min-width="160" show-overflow-tooltip align="center" />
<el-table-column label="规格参数" prop="specificationDescription" min-width="160" show-overflow-tooltip align="center" />
<el-table-column label="计划标识" prop="purchasePlanFlag" width="100" align="center">
<template #default="scope">
@ -130,7 +132,7 @@
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="160" show-overflow-tooltip align="center" />
<el-table-column label="操作" fixed="right" width="150" align="center" v-if="!isReadOnly">
<el-table-column label="操作" fixed="right" width="150" align="center" v-if="canEditMaterial">
<template #default="scope">
<el-button link type="warning" @click="splitMaterial(scope.row)"></el-button>
<el-button link type="primary" @click="handleEditMaterial(scope.row)"></el-button>
@ -140,7 +142,7 @@
</el-table>
</el-card>
<el-card shadow="never" >
<el-card shadow="never">
<template #header>
<div class="table-header non-standard">
<span class="title-dot non-standard-dot"></span>
@ -173,7 +175,7 @@
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="160" show-overflow-tooltip align="center" />
<el-table-column label="操作" fixed="right" width="150" align="center" v-if="!isReadOnly">
<el-table-column label="操作" fixed="right" width="150" align="center" v-if="canEditMaterial">
<template #default="scope">
<el-button link type="warning" @click="splitMaterial(scope.row)"></el-button>
<el-button link type="primary" @click="handleEditMaterial(scope.row)"></el-button>
@ -193,21 +195,21 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="materialForm.materialFlag === '1'" :span="12">
<el-form-item label="关联物料编码">
<el-input v-model="materialForm.relationMaterialCode" disabled />
</el-form-item>
</el-col>
<el-col v-if="materialForm.materialFlag === '1'" :span="12">
<el-form-item label="关联物料名称">
<el-input v-model="materialForm.relationMaterialName" disabled />
</el-form-item>
</el-col>
<el-col v-if="materialForm.materialFlag === '2'" :span="12">
<el-form-item label="关联物料名称">
<el-input v-model="materialForm.relationMaterialName" disabled />
</el-form-item>
</el-col>
<el-col v-if="materialForm.materialFlag === '1'" :span="12">
<el-form-item label="关联物料编码">
<el-input v-model="materialForm.relationMaterialCode" disabled />
</el-form-item>
</el-col>
<el-col v-if="materialForm.materialFlag === '1'" :span="12">
<el-form-item label="关联物料名称">
<el-input v-model="materialForm.relationMaterialName" disabled />
</el-form-item>
</el-col>
<el-col v-if="materialForm.materialFlag === '2'" :span="12">
<el-form-item label="关联物料名称">
<el-input v-model="materialForm.relationMaterialName" disabled />
</el-form-item>
</el-col>
<el-col v-if="materialForm.materialFlag === '1'" :span="12">
<el-form-item label="采购物料编码" prop="materialCode">
<el-input v-model="materialForm.materialCode" placeholder="请输入采购物料编码" />
@ -249,23 +251,12 @@
</el-col>
<el-col :span="12">
<el-form-item label="本次采购数量" prop="purchaseAmount">
<el-input-number
v-model="materialForm.purchaseAmount"
:min="0"
class="w-full"
placeholder="请输入数量"
:precision="2"
/>
<el-input-number v-model="materialForm.purchaseAmount" :min="0" class="w-full" placeholder="请输入数量" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="需求到货时间" prop="arrivalTime">
<el-date-picker
v-model="materialForm.arrivalTime"
type="date"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择需求到货时间"
/>
<el-date-picker v-model="materialForm.arrivalTime" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择需求到货时间" />
</el-form-item>
</el-col>
<el-col :span="24">
@ -275,7 +266,7 @@
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="materialForm.remark" type="textarea" placeholder="请输入备注" />
<el-input v-model="materialForm.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
@ -299,7 +290,13 @@ import { computed, reactive, ref, watch, getCurrentInstance, toRefs, onMounted,
import type { ComponentInternalInstance } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import type { FormInstance } from 'element-plus';
import { addProjectPurchase, getProjectPurchase, updateProjectPurchase, projectPurchaseSubmitAndFlowStart, getProjectMaterialsByProjectId } from '@/api/oa/erp/projectPurchase';
import {
addProjectPurchase,
getProjectPurchase,
updateProjectPurchase,
projectPurchaseSubmitAndFlowStart,
getProjectMaterialsByProjectId
} from '@/api/oa/erp/projectPurchase';
import type { ProjectPurchaseForm } from '@/api/oa/erp/projectPurchase/types';
import { getErpProjectPurchaseMaterialList } from '@/api/oa/erp/projectPurchaseMaterial';
import type { ProjectPurchaseMaterialVO, ProjectPurchaseMaterialForm } from '@/api/oa/erp/projectPurchaseMaterial/types';
@ -313,6 +310,7 @@ import { listUser } from '@/api/system/user';
import type { UserVO, UserQuery } from '@/api/system/user/types';
import { useUserStore } from '@/store/modules/user';
import { getBaseUnitInfoList } from '@/api/oa/base/unitInfo';
import { getInfo } from '@/api/login';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const router = useRouter();
@ -327,6 +325,10 @@ const routeParams = reactive<Record<string, any>>({});
const pageType = ref<string>((route.query.type as string) || 'add');
const isReadOnly = computed(() => pageType.value === 'view' || pageType.value === 'approval');
const userRoles = ref<string[]>([]);
const hasCgRole = computed(() => userRoles.value?.some((role) => role === 'CGJL'));
const canEditMaterial = computed(() => !isReadOnly.value || hasCgRole.value);
const pageLoading = ref(false);
const buttonLoading = ref(false);
const projectPurchaseFormRef = ref<FormInstance>();
@ -344,6 +346,7 @@ const initFormData: ProjectPurchaseForm & { projectName?: string } = {
managerId: undefined,
chargeId: undefined,
deputyId: undefined,
deptId: undefined,
reporterId: undefined,
consigneeUser: undefined,
consigneeAddress: undefined,
@ -367,10 +370,8 @@ const rules = {
const materialList = ref<ProjectPurchaseMaterialVO[]>([]);
const materialLoading = ref(false);
const disableMaterialActions = computed(() => isReadOnly.value || materialLoading.value);
// materialFlag '1'
// materialFlag = 1
const standardMaterialList = computed(() => {
return materialList.value.filter((item) => item.materialFlag === '1');
});
@ -380,7 +381,6 @@ const nonStandardMaterialList = computed(() => {
return materialList.value.filter((item) => item.materialFlag === '2');
});
const loadProjectMaterialsFromSource = async (projectId?: string | number, spareFlag?: string) => {
if (!projectId || !spareFlag) {
return;
@ -435,6 +435,7 @@ const materialDialog = reactive({
});
const materialFormRef = ref<FormInstance>();
const editingMaterialIndex = ref<number>(-1);
const initMaterialFormData: ProjectPurchaseMaterialForm = {
purchaseMaterialId: undefined,
projectPurchaseId: undefined,
@ -484,12 +485,13 @@ const resetForm = () => {
*/
const resetMaterialForm = () => {
Object.assign(materialForm.value, initMaterialFormData);
editingMaterialIndex.value = -1;
};
/**
* 根据项目采购ID加载详情
*/
const loadDetail = async (projectPurchaseId: string | number) => {
const loadDetail = async (projectPurchaseId?: string | number) => {
if (!projectPurchaseId) {
resetForm();
materialList.value = [];
@ -535,41 +537,38 @@ const loadMaterials = async () => {
/**
* 提交主表单
* @param status 提交状态draft or submit
*/
const submitForm = async (status: string, mode?: boolean) => {
const buildProjectPurchasePayload = () => {
if (!projectPurchaseFormRef.value) return;
try {
await projectPurchaseFormRef.value.validate();
} catch (error) {
return;
}
const normalizedMaterials: ProjectPurchaseMaterialForm[] = materialList.value.map((item) => {
const payloadItem: ProjectPurchaseMaterialForm = {
...item,
projectPurchaseId: form.value.projectPurchaseId
};
payloadItem.purchaseMaterialId = undefined;
return payloadItem;
});
return {
...form.value,
purchaseMaterialList: normalizedMaterials
} as ProjectPurchaseForm & {
projectName?: string;
purchaseMaterialList?: ProjectPurchaseMaterialForm[];
};
};
const submitForm = async (status: string, mode?: boolean) => {
await projectPurchaseFormRef.value.validate();
buttonLoading.value = true;
try {
const normalizedMaterials: ProjectPurchaseMaterialForm[] = materialList.value.map((item) => {
const payloadItem: ProjectPurchaseMaterialForm = {
...item,
projectPurchaseId: form.value.projectPurchaseId
};
if (typeof payloadItem.purchaseMaterialId === 'string') {
payloadItem.purchaseMaterialId = undefined;
}
return payloadItem;
});
const payload: ProjectPurchaseForm & {
projectName?: string;
purchaseMaterialList?: ProjectPurchaseMaterialForm[];
} = {
...form.value,
purchaseMaterialList: normalizedMaterials
};
const payload = buildProjectPurchasePayload();
if (status !== 'draft') {
payload.flowCode = FlowCodeEnum.PROJECT_PURCHASE_CODE;
payload.variables = {
projectPurchaseId: payload.projectPurchaseId,
projectCode: payload.projectCode,
projectName: payload.projectName
projectName: payload.projectName,
deptId: form.value.deptId
};
payload.bizExt = {
businessTitle: '项目采购审批',
@ -613,11 +612,14 @@ const submitForm = async (status: string, mode?: boolean) => {
* 编辑物料
*/
const handleEditMaterial = (row: ProjectPurchaseMaterialVO) => {
if (isReadOnly.value) {
if (!canEditMaterial.value) {
return;
}
resetMaterialForm();
Object.assign(materialForm.value, row);
editingMaterialIndex.value = materialList.value.findIndex(
(item) => item === row || (!!row.purchaseMaterialId && item.purchaseMaterialId === row.purchaseMaterialId)
);
materialDialog.title = '编辑物料';
materialDialog.visible = true;
};
@ -626,7 +628,7 @@ const handleEditMaterial = (row: ProjectPurchaseMaterialVO) => {
* 提交物料表单仅操作本地列表
*/
const submitMaterialForm = () => {
if (isReadOnly.value) {
if (!canEditMaterial.value) {
return;
}
materialFormRef.value?.validate((valid: boolean) => {
@ -637,12 +639,15 @@ const submitMaterialForm = () => {
if (index !== -1) {
Object.assign(materialList.value[index], materialForm.value);
}
} else if (editingMaterialIndex.value !== -1) {
Object.assign(materialList.value[editingMaterialIndex.value], materialForm.value);
} else {
//
materialList.value.push({ ...materialForm.value } as ProjectPurchaseMaterialVO);
}
proxy?.$modal.msgSuccess('操作成功');
materialDialog.visible = false;
editingMaterialIndex.value = -1;
});
};
@ -650,7 +655,7 @@ const submitMaterialForm = () => {
* 删除物料仅操作本地列表
*/
const handleDeleteMaterial = async (row: ProjectPurchaseMaterialVO) => {
if (isReadOnly.value) {
if (!canEditMaterial.value) {
return;
}
await proxy?.$modal.confirm(`是否确认删除物料"${row.materialName}"`);
@ -667,7 +672,7 @@ const handleDeleteMaterial = async (row: ProjectPurchaseMaterialVO) => {
* 拆分物料为计划外
*/
const splitMaterial = (row: ProjectPurchaseMaterialVO) => {
if (isReadOnly.value) {
if (!canEditMaterial.value) {
return;
}
const newItem: ProjectPurchaseMaterialVO = {
@ -716,6 +721,14 @@ const handleApprovalRecord = () => {
* 提交审批后的回调
*/
const submitCallback = async () => {
if (hasCgRole.value) {
await projectPurchaseFormRef.value?.validate();
const payload = buildProjectPurchasePayload();
if (payload?.projectPurchaseId) {
await updateProjectPurchase(payload);
Object.assign(form.value, payload);
}
}
await proxy?.$tab.closePage(route);
router.go(-1);
};
@ -739,6 +752,7 @@ const projectInfoSelectCallBack = (data: ProjectInfoVO[]) => {
form.value.chargeId = project.chargeId;
form.value.deputyId = project.deputyId;
form.value.spareFlag = project.spareFlag;
form.value.deptId = project.deptId;
loadProjectMaterialsFromSource(project.projectId as string | number, project.spareFlag);
}
};
@ -758,17 +772,14 @@ onMounted(async () => {
const type = routeParams.type as string;
pageType.value = type || 'add';
if (id && (type === 'update' || type === 'view' || type === 'approval')) {
pageLoading.value = true;
try {
await loadDetail(id);
} finally {
pageLoading.value = false;
}
} else {
resetForm();
materialList.value = [];
try {
const userInfoRes = await getInfo();
userRoles.value = userInfoRes?.data?.roles || [];
} catch (error) {
userRoles.value = [];
}
const shouldLoadDetail = !!id && (type === 'update' || type === 'view' || type === 'approval');
await loadDetail(shouldLoadDetail ? (id as string | number) : undefined);
});
});
</script>

@ -84,10 +84,10 @@
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="160" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看" placement="top">
<el-tooltip v-if="!canEdit(scope.row)" content="查看" placement="top">
<el-button link type="info" icon="View" @click="handleView(scope.row)"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-tooltip v-if="canEdit(scope.row)" content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['oa/erp:projectPurchase:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
@ -214,6 +214,10 @@ const handleAdd = () => {
});
};
const canEdit = (row?: ProjectPurchaseVO) => {
return row.projectPurchaseStatus === '1';
};
const handleUpdate = (row?: ProjectPurchaseVO) => {
const projectPurchaseId = row?.projectPurchaseId || ids.value[0];
if (!projectPurchaseId) {
@ -229,7 +233,7 @@ const handleUpdate = (row?: ProjectPurchaseVO) => {
const handleView = (row: ProjectPurchaseVO) => {
proxy?.$tab.closePage(route);
router.push({
path: '/oa/erp/projectPurchase/edit',
path: '/purchase/projectPurchase/edit',
query: { id: row.projectPurchaseId, type: 'view' }
});
};

Loading…
Cancel
Save