|
|
|
|
@ -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>
|
|
|
|
|
|