|
|
<template>
|
|
|
<div class="p-2" v-loading="pageLoading">
|
|
|
<approvalButton
|
|
|
class="mb-4"
|
|
|
@submitForm="submitForm"
|
|
|
@approvalVerifyOpen="approvalVerifyOpen"
|
|
|
@handleApprovalRecord="handleApprovalRecord"
|
|
|
:buttonLoading="buttonLoading"
|
|
|
:id="form.projectPurchaseId as any"
|
|
|
:status="form.flowStatus as any"
|
|
|
:pageType="pageType"
|
|
|
:mode="false"
|
|
|
/>
|
|
|
|
|
|
<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 #suffix>
|
|
|
<el-icon style="cursor: pointer" @click="openProjectSelect" :disabled="isReadOnly">
|
|
|
<Search />
|
|
|
</el-icon>
|
|
|
</template>
|
|
|
</el-input>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="采购编号" prop="purchaseCode">
|
|
|
<el-input v-model="form.purchaseCode" placeholder="自动生成" disabled />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="项目名称" prop="projectName">
|
|
|
<el-input v-model="form.projectName" placeholder="请选择项目后自动填充" disabled />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="项目经理" prop="managerId">
|
|
|
<el-select v-model="form.managerId" placeholder="请选择项目后自动填充" disabled>
|
|
|
<el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="部门负责人" prop="chargeId">
|
|
|
<el-select v-model="form.chargeId" placeholder="请选择项目后自动填充" disabled>
|
|
|
<el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="分管副总" prop="deputyId">
|
|
|
<el-select v-model="form.deputyId" placeholder="请选择项目后自动填充" disabled>
|
|
|
<el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="提报人" prop="reporterId">
|
|
|
<el-input v-model="reporterName" placeholder="当前登录用户" disabled />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="收货人" prop="consigneeUser">
|
|
|
<el-select v-model="form.consigneeUser" placeholder="请选择收货人" clearable filterable :disabled="isReadOnly">
|
|
|
<el-option v-for="user in userList" :key="user.nickName" :label="user.nickName" :value="user.nickName" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="收货地址" prop="consigneeAddress">
|
|
|
<el-input type="textarea" v-model="form.consigneeAddress" placeholder="请输入收货地址" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="联系方式" prop="consigneeContact">
|
|
|
<el-input v-model="form.consigneeContact" placeholder="请输入收货人联系方式" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="是否备件类" prop="spareFlag">
|
|
|
<el-radio-group v-model="form.spareFlag" disabled>
|
|
|
<el-radio v-for="dict in spare_flag" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="24">
|
|
|
<el-form-item label="项目采购状态" prop="projectPurchaseStatus">
|
|
|
<el-radio-group v-model="form.projectPurchaseStatus" disabled>
|
|
|
<el-radio v-for="dict in project_purchase_status" :key="dict.value" :label="dict.value">{{ dict.label }} </el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="24">
|
|
|
<el-form-item label="备注" prop="remark">
|
|
|
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</el-form>
|
|
|
</el-card>
|
|
|
|
|
|
<el-card shadow="never">
|
|
|
<template #header>
|
|
|
<div class="table-header standard">
|
|
|
<div class="title-wrapper">
|
|
|
<span class="title-dot standard-dot"></span>
|
|
|
<span class="title-text">标准物料</span>
|
|
|
</div>
|
|
|
<el-button v-if="canEditMaterial" type="primary" icon="Plus" size="small" @click="handleAddMaterial('1')">新增</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
<el-table v-loading="materialLoading" :data="standardMaterialList" border :row-class-name="getRowClassName">
|
|
|
<el-table-column label="序号" width="70" align="center">
|
|
|
<template #default="scope">
|
|
|
{{ scope.$index + 1 }}
|
|
|
</template>
|
|
|
</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="specificationDescription" min-width="160" show-overflow-tooltip align="center" />
|
|
|
<el-table-column label="计划标识" prop="purchasePlanFlag" width="100" align="center">
|
|
|
<template #default="scope">
|
|
|
<dict-tag :options="purchase_plan_flag" :value="scope.row.purchasePlanFlag" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="需采购数量" prop="needPurchaseAmount" width="120" align="center" />
|
|
|
<el-table-column label="本次采购数量" prop="purchaseAmount" width="140" align="center" />
|
|
|
<el-table-column label="需求到货时间" prop="arrivalTime" width="180" align="center">
|
|
|
<template #default="scope">
|
|
|
<span>{{ proxy?.parseTime?.(scope.row.arrivalTime, '{y}-{m}-{d}') || scope.row.arrivalTime }}</span>
|
|
|
</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="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>
|
|
|
<el-button link type="danger" @click="handleDeleteMaterial(scope.row)">删除</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
</el-card>
|
|
|
|
|
|
<el-card shadow="never">
|
|
|
<template #header>
|
|
|
<div class="table-header non-standard">
|
|
|
<div class="title-wrapper">
|
|
|
<span class="title-dot non-standard-dot"></span>
|
|
|
<span class="title-text">非标准物料</span>
|
|
|
</div>
|
|
|
<el-button v-if="canEditMaterial" type="primary" icon="Plus" size="small" @click="handleAddMaterial('2')">新增</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
<el-table v-loading="materialLoading" :data="nonStandardMaterialList" border :row-class-name="getRowClassName">
|
|
|
<el-table-column label="序号" width="70" align="center">
|
|
|
<template #default="scope">
|
|
|
{{ scope.$index + 1 }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="关联物料名称" prop="relationMaterialName" min-width="160" show-overflow-tooltip align="center" />
|
|
|
<el-table-column label="采购物料名称" min-width="160" show-overflow-tooltip align="center">
|
|
|
<template #default="scope">
|
|
|
<span>{{ scope.row.purchaseMaterialName || scope.row.materialName }}</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<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">
|
|
|
<dict-tag :options="purchase_plan_flag" :value="scope.row.purchasePlanFlag" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="需采购数量" prop="needPurchaseAmount" width="120" align="center" />
|
|
|
<el-table-column label="本次采购数量" prop="purchaseAmount" width="140" align="center" />
|
|
|
<el-table-column label="需求到货时间" prop="arrivalTime" width="180" align="center">
|
|
|
<template #default="scope">
|
|
|
<span>{{ proxy?.parseTime?.(scope.row.arrivalTime, '{y}-{m}-{d}') || scope.row.arrivalTime }}</span>
|
|
|
</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="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>
|
|
|
<el-button link type="danger" @click="handleDeleteMaterial(scope.row)">删除</el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
</el-card>
|
|
|
|
|
|
<el-dialog :title="materialDialog.title" v-model="materialDialog.visible" width="800px" append-to-body>
|
|
|
<el-form ref="materialFormRef" :model="materialForm" :rules="materialRules" label-width="120px">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="计划标识" prop="purchasePlanFlag">
|
|
|
<el-radio-group v-model="materialForm.purchasePlanFlag">
|
|
|
<el-radio v-for="dict in purchase_plan_flag" :key="dict.value" :label="dict.value">{{ dict.label }} </el-radio>
|
|
|
</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="采购物料编码" prop="materialCode">
|
|
|
<el-input v-model="materialForm.materialCode" placeholder="请选择采购标准物料" readonly>
|
|
|
<template #suffix>
|
|
|
<el-icon
|
|
|
style="cursor: pointer"
|
|
|
:disabled="!canEditMaterial"
|
|
|
@click="openMaterialSelect"
|
|
|
>
|
|
|
<Search />
|
|
|
</el-icon>
|
|
|
</template>
|
|
|
</el-input>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="采购物料名称" prop="materialName">
|
|
|
<el-input v-model="materialForm.materialName" placeholder="请输入采购物料名称" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<!-- <el-col :span="12">-->
|
|
|
<!-- <el-form-item label="物料ID" prop="materialId">-->
|
|
|
<!-- <el-input v-model="materialForm.materialId" placeholder="请输入物料ID" />-->
|
|
|
<!-- </el-form-item>-->
|
|
|
<!-- </el-col>-->
|
|
|
<!-- <el-col :span="12">-->
|
|
|
<!-- <el-form-item label="销售物料ID" prop="relationMaterialId">-->
|
|
|
<!-- <el-input v-model="materialForm.relationMaterialId" placeholder="请输入销售物料ID" />-->
|
|
|
<!-- </el-form-item>-->
|
|
|
<!-- </el-col>-->
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="单位" prop="unitId">
|
|
|
<el-select v-model="materialForm.unitId" placeholder="请选择单位" clearable filterable>
|
|
|
<el-option v-for="item in unitInfoList" :key="item.unitId" :label="item.unitName" :value="item.unitId" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="需采购数量" prop="needPurchaseAmount">
|
|
|
<el-input-number
|
|
|
v-model="materialForm.needPurchaseAmount"
|
|
|
:min="0"
|
|
|
class="w-full"
|
|
|
placeholder="请输入数量"
|
|
|
:precision="2"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</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-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-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="24">
|
|
|
<el-form-item label="详细参数" prop="specificationDescription">
|
|
|
<el-input v-model="materialForm.specificationDescription" type="textarea" placeholder="请输入详细参数" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="24">
|
|
|
<el-form-item label="备注" prop="remark">
|
|
|
<el-input v-model="materialForm.remark" type="textarea" placeholder="请输入备注" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</el-form>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
<el-button type="primary" :loading="materialLoading" @click="submitMaterialForm">确 定</el-button>
|
|
|
<el-button @click="materialDialog.visible = false">取 消</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
|
|
|
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
|
|
<approvalRecord ref="approvalRecordRef" />
|
|
|
<ProjectSelect ref="projectSelectRef" :multiple="false" @confirm-call-back="projectInfoSelectCallBack" />
|
|
|
<MaterialSelect ref="materialSelectRef" :multiple="false" @confirm-call-back="materialSelectCallBack" />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup name="ProjectPurchaseEdit" lang="ts">
|
|
|
import { computed, reactive, ref, watch, getCurrentInstance, toRefs, onMounted, nextTick } from 'vue';
|
|
|
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 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';
|
|
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
|
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
|
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
|
|
import ProjectSelect from '@/components/ProjectSelect/index.vue';
|
|
|
import MaterialSelect from '@/components/MaterialSelect/index.vue';
|
|
|
import { FlowCodeEnum } from '@/enums/OAEnum';
|
|
|
import type { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
|
|
|
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';
|
|
|
import type { MaterialInfoVO } from '@/api/oa/base/materialInfo/types';
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
const router = useRouter();
|
|
|
const route = useRoute();
|
|
|
const userStore = useUserStore();
|
|
|
|
|
|
const { active_flag, project_purchase_status, spare_flag, purchase_plan_flag, material_flag } = toRefs<any>(
|
|
|
proxy?.useDict('active_flag', 'project_purchase_status', 'spare_flag', 'purchase_plan_flag', 'material_flag')
|
|
|
);
|
|
|
|
|
|
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>();
|
|
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
|
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
|
|
const projectSelectRef = ref<InstanceType<typeof ProjectSelect>>();
|
|
|
const materialSelectRef = ref<InstanceType<typeof MaterialSelect>>();
|
|
|
const taskVariables = ref<Record<string, any>>({});
|
|
|
|
|
|
const initFormData: ProjectPurchaseForm & { projectName?: string } = {
|
|
|
projectPurchaseId: undefined,
|
|
|
projectId: undefined,
|
|
|
projectCode: undefined,
|
|
|
purchaseCode: undefined,
|
|
|
projectName: undefined,
|
|
|
managerId: undefined,
|
|
|
chargeId: undefined,
|
|
|
deputyId: undefined,
|
|
|
deptId: undefined,
|
|
|
reporterId: undefined,
|
|
|
consigneeUser: undefined,
|
|
|
consigneeAddress: undefined,
|
|
|
consigneeContact: undefined,
|
|
|
projectPurchaseStatus: undefined,
|
|
|
flowStatus: undefined,
|
|
|
sortOrder: undefined,
|
|
|
relationId: undefined,
|
|
|
remark: undefined,
|
|
|
spareFlag: undefined,
|
|
|
activeFlag: undefined
|
|
|
};
|
|
|
|
|
|
const form = ref<ProjectPurchaseForm & { projectName?: string }>({ ...initFormData });
|
|
|
|
|
|
const rules = {
|
|
|
projectCode: [{ required: true, message: '项目号不能为空', trigger: 'blur' }],
|
|
|
consigneeUser: [{ required: true, message: '收货人不能为空', trigger: 'blur' }],
|
|
|
consigneeAddress: [{ required: true, message: '收货地址不能为空', trigger: 'blur' }]
|
|
|
};
|
|
|
|
|
|
const materialList = ref<ProjectPurchaseMaterialVO[]>([]);
|
|
|
const materialLoading = ref(false);
|
|
|
|
|
|
// 标准物料列表(materialFlag 为 '1')
|
|
|
const standardMaterialList = computed(() => {
|
|
|
return materialList.value.filter((item) => item.materialFlag === '1');
|
|
|
});
|
|
|
|
|
|
// 非标准物料列表(materialFlag 为 '2')
|
|
|
const nonStandardMaterialList = computed(() => {
|
|
|
return materialList.value.filter((item) => item.materialFlag === '2');
|
|
|
});
|
|
|
|
|
|
const loadProjectMaterialsFromSource = async (projectId?: string | number, spareFlag?: string) => {
|
|
|
if (!projectId || !spareFlag) {
|
|
|
return;
|
|
|
}
|
|
|
materialLoading.value = true;
|
|
|
try {
|
|
|
const res = await getProjectMaterialsByProjectId(projectId, spareFlag);
|
|
|
let data = res?.data || [];
|
|
|
data = data.map((item, index) => ({
|
|
|
...item,
|
|
|
purchasePlanFlag: '1',
|
|
|
serialNumber: index + 1 // 加序号
|
|
|
}));
|
|
|
materialList.value = data;
|
|
|
} finally {
|
|
|
materialLoading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 获取行类名,计划外的行显示黄色背景
|
|
|
const getRowClassName = ({ row }: { row: ProjectPurchaseMaterialVO }) => {
|
|
|
// 计划外通常是 '2' 或 '否',根据实际字典值调整
|
|
|
if (row.purchasePlanFlag === '2' || row.purchasePlanFlag === '否' || row.purchasePlanFlag === '计划外') {
|
|
|
return 'plan-out-row';
|
|
|
}
|
|
|
return '';
|
|
|
};
|
|
|
|
|
|
const openMaterialSelect = () => {
|
|
|
if (!canEditMaterial.value) {
|
|
|
return;
|
|
|
}
|
|
|
materialSelectRef.value?.open();
|
|
|
};
|
|
|
|
|
|
const materialSelectCallBack = (data: MaterialInfoVO[]) => {
|
|
|
if (!data?.length) {
|
|
|
return;
|
|
|
}
|
|
|
const material = data[0];
|
|
|
materialForm.value.materialId = material.materialId;
|
|
|
materialForm.value.materialCode = material.materialCode;
|
|
|
materialForm.value.materialName = material.materialName;
|
|
|
materialForm.value.purchaseMaterialName = material.materialName;
|
|
|
// materialForm.value.relationMaterialCode = material.materialCode;
|
|
|
// materialForm.value.relationMaterialName = material.materialName;
|
|
|
};
|
|
|
|
|
|
// 用户列表
|
|
|
const userList = ref<UserVO[]>([]);
|
|
|
const getUserList = async () => {
|
|
|
const params: UserQuery = { pageNum: 1, pageSize: 9999 };
|
|
|
const res = await listUser(params);
|
|
|
userList.value = res.rows || [];
|
|
|
};
|
|
|
|
|
|
// 单位列表
|
|
|
const unitInfoList = ref<any[]>([]);
|
|
|
const getUnitInfoListSelect = async () => {
|
|
|
const res = await getBaseUnitInfoList(null);
|
|
|
unitInfoList.value = res.data || [];
|
|
|
};
|
|
|
|
|
|
// 提报人名称(当前登录用户)
|
|
|
const reporterName = computed(() => {
|
|
|
return userStore.nickname || '';
|
|
|
});
|
|
|
|
|
|
const materialDialog = reactive({
|
|
|
visible: false,
|
|
|
title: ''
|
|
|
});
|
|
|
|
|
|
const materialFormRef = ref<FormInstance>();
|
|
|
const editingMaterialIndex = ref<number>(-1);
|
|
|
const initMaterialFormData: ProjectPurchaseMaterialForm = {
|
|
|
purchaseMaterialId: undefined,
|
|
|
projectPurchaseId: undefined,
|
|
|
relationDetailsId: undefined,
|
|
|
spareFlag: undefined,
|
|
|
purchasePlanFlag: undefined,
|
|
|
materialFlag: undefined,
|
|
|
materialId: undefined,
|
|
|
relationMaterialId: undefined,
|
|
|
relationMaterialCode: undefined,
|
|
|
relationMaterialName: undefined,
|
|
|
materialCode: undefined,
|
|
|
materialName: undefined,
|
|
|
purchaseMaterialName: undefined,
|
|
|
specificationDescription: undefined,
|
|
|
unitId: undefined,
|
|
|
needPurchaseAmount: undefined,
|
|
|
purchaseAmount: undefined,
|
|
|
arrivalTime: undefined,
|
|
|
serialNumber: undefined,
|
|
|
remark: undefined,
|
|
|
activeFlag: undefined
|
|
|
};
|
|
|
|
|
|
const materialForm = ref<ProjectPurchaseMaterialForm>({ ...initMaterialFormData });
|
|
|
|
|
|
const materialRules = {
|
|
|
materialName: [{ required: true, message: '采购物料名称不能为空', trigger: 'blur' }],
|
|
|
purchaseAmount: [{ required: true, message: '采购数量不能为空', trigger: 'blur' }]
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 重置主表表单
|
|
|
*/
|
|
|
const resetForm = () => {
|
|
|
Object.assign(form.value, initFormData);
|
|
|
form.value.projectPurchaseStatus = '1';
|
|
|
form.value.flowStatus = 'draft';
|
|
|
// 自动填充当前登录用户为提报人
|
|
|
if (userStore.userId) {
|
|
|
form.value.reporterId = userStore.userId;
|
|
|
}
|
|
|
if (!form.value.activeFlag && active_flag.value?.length) {
|
|
|
form.value.activeFlag = active_flag.value[0].value;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 重置物料表单
|
|
|
*/
|
|
|
const resetMaterialForm = () => {
|
|
|
Object.assign(materialForm.value, initMaterialFormData);
|
|
|
editingMaterialIndex.value = -1;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 根据项目采购ID加载详情
|
|
|
*/
|
|
|
const loadDetail = async (projectPurchaseId?: string | number) => {
|
|
|
if (!projectPurchaseId) {
|
|
|
resetForm();
|
|
|
materialList.value = [];
|
|
|
return;
|
|
|
}
|
|
|
try {
|
|
|
resetForm();
|
|
|
const res = await getProjectPurchase(projectPurchaseId);
|
|
|
Object.assign(form.value, res?.data || {});
|
|
|
if (!form.value.projectPurchaseStatus) {
|
|
|
form.value.projectPurchaseStatus = '1';
|
|
|
}
|
|
|
if (!form.value.flowStatus) {
|
|
|
form.value.flowStatus = 'draft';
|
|
|
}
|
|
|
// 确保用户列表已加载,然后根据收货人名称查找对应的用户ID
|
|
|
if (userList.value.length === 0) {
|
|
|
await getUserList();
|
|
|
}
|
|
|
materialList.value = res?.data.purchaseMaterialList || [];
|
|
|
} finally {
|
|
|
pageLoading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 提交主表单
|
|
|
*/
|
|
|
const buildProjectPurchasePayload = () => {
|
|
|
if (!projectPurchaseFormRef.value) 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 payload = buildProjectPurchasePayload();
|
|
|
if (status !== 'draft') {
|
|
|
payload.flowCode = FlowCodeEnum.PROJECT_PURCHASE_CODE;
|
|
|
payload.variables = {
|
|
|
projectPurchaseId: payload.projectPurchaseId,
|
|
|
projectCode: payload.projectCode,
|
|
|
projectName: payload.projectName,
|
|
|
deptId: form.value.deptId
|
|
|
};
|
|
|
payload.bizExt = {
|
|
|
businessTitle: '项目采购审批',
|
|
|
businessCode: payload.projectCode
|
|
|
};
|
|
|
payload.projectPurchaseStatus = '2';
|
|
|
payload.flowStatus = 'waiting';
|
|
|
const res: any = await projectPurchaseSubmitAndFlowStart(payload);
|
|
|
if (res?.data) {
|
|
|
Object.assign(form.value, res.data);
|
|
|
} else {
|
|
|
Object.assign(form.value, payload);
|
|
|
}
|
|
|
proxy?.$modal.msgSuccess('操作成功');
|
|
|
proxy?.$tab.closePage();
|
|
|
router.go(-1);
|
|
|
} else {
|
|
|
payload.projectPurchaseStatus = '1';
|
|
|
payload.flowStatus = 'draft';
|
|
|
if (payload.projectPurchaseId) {
|
|
|
await updateProjectPurchase(payload);
|
|
|
} else {
|
|
|
const res: any = await addProjectPurchase(payload);
|
|
|
const newId = res?.data?.projectPurchaseId ?? res?.data ?? res?.msg;
|
|
|
if (newId) {
|
|
|
payload.projectPurchaseId = newId;
|
|
|
form.value.projectPurchaseId = newId as any;
|
|
|
}
|
|
|
}
|
|
|
Object.assign(form.value, payload);
|
|
|
proxy?.$modal.msgSuccess('暂存成功');
|
|
|
proxy?.$tab.closePage();
|
|
|
router.go(-1);
|
|
|
}
|
|
|
} finally {
|
|
|
buttonLoading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 编辑物料
|
|
|
*/
|
|
|
const handleEditMaterial = (row: ProjectPurchaseMaterialVO) => {
|
|
|
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;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 新增物料
|
|
|
*/
|
|
|
const handleAddMaterial = (materialFlag) => {
|
|
|
if (!canEditMaterial.value) {
|
|
|
return;
|
|
|
}
|
|
|
resetMaterialForm();
|
|
|
materialForm.value.materialFlag = materialFlag;
|
|
|
materialForm.value.purchasePlanFlag = '2';
|
|
|
materialForm.value.projectPurchaseId = form.value.projectPurchaseId;
|
|
|
materialDialog.title = materialFlag === '1' ? '新增标准物料' : '新增非标准物料';
|
|
|
materialDialog.visible = true;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 提交物料表单(仅操作本地列表)
|
|
|
*/
|
|
|
const submitMaterialForm = () => {
|
|
|
if (!canEditMaterial.value) {
|
|
|
return;
|
|
|
}
|
|
|
materialFormRef.value?.validate((valid: boolean) => {
|
|
|
if (!valid) return;
|
|
|
if (materialForm.value.purchaseMaterialId) {
|
|
|
// 编辑:更新列表中的物料
|
|
|
const index = materialList.value.findIndex((item) => item.purchaseMaterialId === materialForm.value.purchaseMaterialId);
|
|
|
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;
|
|
|
});
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 删除物料(仅操作本地列表)
|
|
|
*/
|
|
|
const handleDeleteMaterial = async (row: ProjectPurchaseMaterialVO) => {
|
|
|
if (!canEditMaterial.value) {
|
|
|
return;
|
|
|
}
|
|
|
await proxy?.$modal.confirm(`是否确认删除物料"${row.materialName}"?`);
|
|
|
const index = materialList.value.findIndex(
|
|
|
(item) => (row.purchaseMaterialId && item.purchaseMaterialId === row.purchaseMaterialId) || (!row.purchaseMaterialId && item === row)
|
|
|
);
|
|
|
if (index !== -1) {
|
|
|
materialList.value.splice(index, 1);
|
|
|
proxy?.$modal.msgSuccess('删除成功');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 拆分物料为计划外
|
|
|
*/
|
|
|
const splitMaterial = (row: ProjectPurchaseMaterialVO) => {
|
|
|
if (!canEditMaterial.value) {
|
|
|
return;
|
|
|
}
|
|
|
const newItem: ProjectPurchaseMaterialVO = {
|
|
|
...row,
|
|
|
purchaseMaterialId: `split-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`,
|
|
|
projectPurchaseId: form.value.projectPurchaseId ?? row.projectPurchaseId,
|
|
|
purchasePlanFlag: '2',
|
|
|
needPurchaseAmount: row.needPurchaseAmount,
|
|
|
purchaseAmount: row.purchaseAmount,
|
|
|
serialNumber: (materialList.value?.length || 0) + 1
|
|
|
} as ProjectPurchaseMaterialVO;
|
|
|
const index = materialList.value.indexOf(row);
|
|
|
if (index >= 0) {
|
|
|
materialList.value.splice(index + 1, 0, newItem);
|
|
|
} else {
|
|
|
materialList.value.push(newItem);
|
|
|
}
|
|
|
proxy?.$modal?.msgSuccess('拆分成功');
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 打开审批弹窗
|
|
|
*/
|
|
|
const approvalVerifyOpen = async () => {
|
|
|
taskVariables.value = {
|
|
|
projectPurchaseId: form.value.projectPurchaseId,
|
|
|
projectCode: form.value.projectCode,
|
|
|
projectName: form.value.projectName
|
|
|
};
|
|
|
const taskId = (routeParams.taskId as string) || (route.query.taskId as string);
|
|
|
if (taskId) {
|
|
|
await submitVerifyRef.value?.openDialog(taskId);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 查看审批记录
|
|
|
*/
|
|
|
const handleApprovalRecord = () => {
|
|
|
if (form.value.projectPurchaseId) {
|
|
|
approvalRecordRef.value?.init(form.value.projectPurchaseId);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 提交审批后的回调
|
|
|
*/
|
|
|
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);
|
|
|
};
|
|
|
|
|
|
// 打开项目选择框
|
|
|
const openProjectSelect = () => {
|
|
|
if (isReadOnly.value) {
|
|
|
return;
|
|
|
}
|
|
|
projectSelectRef.value?.open();
|
|
|
};
|
|
|
|
|
|
// 项目选择回调,自动填充项目相关信息
|
|
|
const projectInfoSelectCallBack = (data: ProjectInfoVO[]) => {
|
|
|
if (data && data.length > 0) {
|
|
|
const project = data[0];
|
|
|
form.value.projectId = project.projectId;
|
|
|
form.value.projectCode = project.projectCode;
|
|
|
form.value.projectName = project.projectName;
|
|
|
form.value.managerId = project.managerId;
|
|
|
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);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 初始化调用
|
|
|
const loadSelectOptions = () => {
|
|
|
getUserList();
|
|
|
getUnitInfoListSelect();
|
|
|
};
|
|
|
|
|
|
onMounted(async () => {
|
|
|
nextTick(async () => {
|
|
|
// 获取路由参数
|
|
|
Object.assign(routeParams, route.query);
|
|
|
// pageLoading.value = true;
|
|
|
loadSelectOptions();
|
|
|
const id = routeParams.id as string | number;
|
|
|
const type = routeParams.type as string;
|
|
|
pageType.value = type || 'add';
|
|
|
|
|
|
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);
|
|
|
pageLoading.value = false;
|
|
|
});
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
:deep(.plan-out-row) {
|
|
|
background-color: #e9d571 !important;
|
|
|
}
|
|
|
|
|
|
:deep(.plan-out-row:hover) {
|
|
|
background-color: #d8bb3a !important;
|
|
|
}
|
|
|
|
|
|
.table-header {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
font-weight: 600;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
|
|
|
.title-wrapper {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 8px;
|
|
|
}
|
|
|
|
|
|
.title-dot {
|
|
|
width: 8px;
|
|
|
height: 24px;
|
|
|
border-radius: 4px;
|
|
|
margin-right: 8px;
|
|
|
display: inline-block;
|
|
|
}
|
|
|
|
|
|
.standard-dot {
|
|
|
background-color: #409eff;
|
|
|
}
|
|
|
|
|
|
.non-standard-dot {
|
|
|
background-color: #f56c6c;
|
|
|
}
|
|
|
|
|
|
.title-text {
|
|
|
color: #333;
|
|
|
}
|
|
|
</style>
|