|
|
|
|
@ -17,8 +17,14 @@
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
<el-form-item label="项目号">
|
|
|
|
|
<el-input v-model="searchForm.projectCode" placeholder="请选择项目" readonly @click="showProjectSelectDialog" suffix-icon="Search">
|
|
|
|
|
</el-input>
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="searchForm.projectCode"
|
|
|
|
|
:placeholder="isTopFormReadonly ? '' : '请选择项目'"
|
|
|
|
|
:disabled="isTopFormReadonly"
|
|
|
|
|
:readonly="!isTopFormReadonly"
|
|
|
|
|
:suffix-icon="isTopFormReadonly ? undefined : 'Search'"
|
|
|
|
|
@click="onProjectCodeInputClick"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
@ -35,7 +41,7 @@
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="6">
|
|
|
|
|
<el-form-item label="申请说明">
|
|
|
|
|
<el-input v-model="searchForm.remark" type="textarea" placeholder="请输入申请说明" />
|
|
|
|
|
<el-input v-model="searchForm.remark" type="textarea" placeholder="请输入申请说明" :disabled="isTopFormReadonly" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
@ -51,7 +57,7 @@
|
|
|
|
|
|
|
|
|
|
<!-- 中间标签页区域 -->
|
|
|
|
|
<!-- 研发项目预算 -->
|
|
|
|
|
<el-card class="mb-6" v-if="searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION">
|
|
|
|
|
<el-card class="mb-6" v-if="isRdBudgetCategory(searchForm.projectCategory)">
|
|
|
|
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
|
|
|
<el-tab-pane label="预算编制标准说明" name="budgetDefinition">
|
|
|
|
|
<RdBudgetDefinition ref="rdBudgetDefinitionRef" :projectId="searchForm.projectId" />
|
|
|
|
|
@ -90,7 +96,7 @@
|
|
|
|
|
<el-card
|
|
|
|
|
class="mb-6"
|
|
|
|
|
shadow="never"
|
|
|
|
|
v-if="searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART"
|
|
|
|
|
v-if="isMarketBudgetCategory(searchForm.projectCategory)"
|
|
|
|
|
>
|
|
|
|
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
|
|
|
<el-tab-pane label="预算表" name="budget">
|
|
|
|
|
@ -186,7 +192,7 @@
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts" name="BudgetInfoEdit">
|
|
|
|
|
import { ref, reactive } from 'vue';
|
|
|
|
|
import { ref, reactive, computed } from 'vue';
|
|
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
|
|
import {
|
|
|
|
|
listProjectInfo,
|
|
|
|
|
@ -201,6 +207,7 @@ import { getUserList } from '@/api/system/user';
|
|
|
|
|
|
|
|
|
|
import { deepEqualArrays } from '@/utils/objHandle';
|
|
|
|
|
import { cloneDeep } from 'lodash-es';
|
|
|
|
|
import { ProjectCategoryEnum } from '@/enums/OAEnum';
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
@ -278,12 +285,21 @@ const oriRdBudgetExpertMeetingCostList = ref<rdBudgetTechCostVO[]>([]); //专家
|
|
|
|
|
const oriRdBudgetExpertCommCostList = ref<rdBudgetTechCostVO[]>([]); //专家咨询通讯形式
|
|
|
|
|
const oriRdBudgetOtherCostList = ref<rdBudgetOtherCostVO[]>([]); //其他费用
|
|
|
|
|
|
|
|
|
|
const PROJECT_CATEGORY = reactive({
|
|
|
|
|
MARKET: '1', //销售(实施、物流)
|
|
|
|
|
MARKET_PART: '2', //销售(备件)
|
|
|
|
|
RD: '3', //研发
|
|
|
|
|
PRE_PRODUCTION: '4' //预投
|
|
|
|
|
});
|
|
|
|
|
/** 研发 / 预投(与字典 project_category、OAEnum 一致) */
|
|
|
|
|
function isRdBudgetCategory(category: string | number | undefined | null): boolean {
|
|
|
|
|
const c = category === undefined || category === null ? '' : String(category);
|
|
|
|
|
return c === ProjectCategoryEnum.RD || c === ProjectCategoryEnum.PRE_INVEST;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 销售实施、物流、备件(与列表页 index 及 OAEnum 一致;含类别 0,避免选「实施」项目后无表单) */
|
|
|
|
|
function isMarketBudgetCategory(category: string | number | undefined | null): boolean {
|
|
|
|
|
const c = category === undefined || category === null ? '' : String(category);
|
|
|
|
|
return (
|
|
|
|
|
c === ProjectCategoryEnum.SALE_IMPLEMENT ||
|
|
|
|
|
c === ProjectCategoryEnum.SALE_LOGISTICS ||
|
|
|
|
|
c === ProjectCategoryEnum.SALE_SPARE
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const BUSINESS_STATUS = reactive({
|
|
|
|
|
DRAFT: '1', //暂存
|
|
|
|
|
@ -322,19 +338,22 @@ const searchForm = reactive({
|
|
|
|
|
watch(
|
|
|
|
|
() => searchForm.projectCategory,
|
|
|
|
|
(newCategory) => {
|
|
|
|
|
if (newCategory === PROJECT_CATEGORY.RD || newCategory === PROJECT_CATEGORY.PRE_PRODUCTION) {
|
|
|
|
|
if (isRdBudgetCategory(newCategory as string)) {
|
|
|
|
|
activeTab.value = 'budgetTable';
|
|
|
|
|
} else if (newCategory === PROJECT_CATEGORY.MARKET || newCategory === PROJECT_CATEGORY.MARKET_PART) {
|
|
|
|
|
} else if (isMarketBudgetCategory(newCategory as string)) {
|
|
|
|
|
activeTab.value = 'budget';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 项目信息
|
|
|
|
|
const projectInfo = reactive<ProjectInfoVO>({
|
|
|
|
|
const projectInfo = reactive<Partial<ProjectInfoVO>>({
|
|
|
|
|
projectId: undefined,
|
|
|
|
|
projectName: '',
|
|
|
|
|
projectCode: '',
|
|
|
|
|
projectCategory: ''
|
|
|
|
|
projectCategory: '',
|
|
|
|
|
managerId: undefined,
|
|
|
|
|
amount: undefined
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 研发预算成本数据
|
|
|
|
|
@ -412,7 +431,6 @@ const resetQuery = () => {
|
|
|
|
|
const getProjectList = async () => {
|
|
|
|
|
projectLoading.value = true;
|
|
|
|
|
const res = await listProjectInfo(queryParams.value);
|
|
|
|
|
console.log(searchForm);
|
|
|
|
|
projectList.value = res.rows;
|
|
|
|
|
projectTotal.value = res.total;
|
|
|
|
|
projectLoading.value = false;
|
|
|
|
|
@ -422,9 +440,9 @@ const getProjectList = async () => {
|
|
|
|
|
const handleTabClick = (tab: any) => {
|
|
|
|
|
activeTab.value = tab.paneName;
|
|
|
|
|
if ((budgetId.value && routeParams.value.type === 'update') || !budgetId.value) {
|
|
|
|
|
if (searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION) {
|
|
|
|
|
if (isRdBudgetCategory(searchForm.projectCategory)) {
|
|
|
|
|
updateRdBudgetTable();
|
|
|
|
|
} else if (searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART) {
|
|
|
|
|
} else if (isMarketBudgetCategory(searchForm.projectCategory)) {
|
|
|
|
|
updateBudgetTable();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -459,6 +477,8 @@ const confirmProjectSelection = () => {
|
|
|
|
|
projectInfo.projectName = selectedProject.value.projectName;
|
|
|
|
|
projectInfo.projectCode = selectedProject.value.projectCode;
|
|
|
|
|
projectInfo.projectCategory = selectedProject.value.projectCategory;
|
|
|
|
|
projectInfo.managerId = selectedProject.value.managerId;
|
|
|
|
|
projectInfo.amount = selectedProject.value.amount;
|
|
|
|
|
|
|
|
|
|
projectSelectDialogVisible.value = false;
|
|
|
|
|
// ElMessage.success('项目选择成功');
|
|
|
|
|
@ -536,8 +556,8 @@ const handleSave = async (status: string, mode: boolean) => {
|
|
|
|
|
try {
|
|
|
|
|
buttonLoading.value = true;
|
|
|
|
|
|
|
|
|
|
const isRdProject = [PROJECT_CATEGORY.RD, PROJECT_CATEGORY.PRE_PRODUCTION].includes(searchForm.projectCategory);
|
|
|
|
|
const isMarketProject = [PROJECT_CATEGORY.MARKET, PROJECT_CATEGORY.MARKET_PART].includes(searchForm.projectCategory);
|
|
|
|
|
const isRdProject = isRdBudgetCategory(searchForm.projectCategory);
|
|
|
|
|
const isMarketProject = isMarketBudgetCategory(searchForm.projectCategory);
|
|
|
|
|
|
|
|
|
|
let budgetForm: budgetInfoForm = {};
|
|
|
|
|
|
|
|
|
|
@ -767,6 +787,17 @@ const handleClose = () => {
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const budgetId = ref();
|
|
|
|
|
|
|
|
|
|
/** 查看、审批:顶部基础信息只读(与 route.query.type 一致) */
|
|
|
|
|
const isTopFormReadonly = computed(() => {
|
|
|
|
|
const t = route.query.type as string | undefined;
|
|
|
|
|
return t === 'view' || t === 'approval';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const onProjectCodeInputClick = () => {
|
|
|
|
|
if (isTopFormReadonly.value) return;
|
|
|
|
|
showProjectSelectDialog();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
// 定义不同类型的主键字段映射
|
|
|
|
|
const PRIMARY_KEY_MAP = {
|
|
|
|
|
@ -817,9 +848,10 @@ async function loadBudgetData() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleAddMode() {
|
|
|
|
|
searchForm.projectCategory = routeParams.value.projectCategory;
|
|
|
|
|
queryParams.value.projectCategory = searchForm.projectCategory;
|
|
|
|
|
if (isRdOrPreProductionCategory()) {
|
|
|
|
|
const raw = routeParams.value.projectCategory;
|
|
|
|
|
searchForm.projectCategory = raw === undefined || raw === null || raw === '' ? '' : String(raw);
|
|
|
|
|
queryParams.value.projectCategory = searchForm.projectCategory || undefined;
|
|
|
|
|
if (isRdBudgetCategory(searchForm.projectCategory)) {
|
|
|
|
|
const rdBudgetDefinitionListData = await getRdBudgetDefinitionList();
|
|
|
|
|
if (rdBudgetDefinitionRef.value.budgetDefinitionData) {
|
|
|
|
|
rdBudgetDefinitionRef.value.budgetDefinitionData = rdBudgetDefinitionListData.data;
|
|
|
|
|
@ -838,9 +870,9 @@ async function handleLoadMode() {
|
|
|
|
|
searchForm.budgetVersion = (searchForm.budgetVersion || 0) + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isRdOrPreProductionCategory()) {
|
|
|
|
|
if (isRdBudgetCategory(searchForm.projectCategory)) {
|
|
|
|
|
await handleRdOrPreProductionData(res.data);
|
|
|
|
|
} else if (isMarketCategory()) {
|
|
|
|
|
} else if (isMarketBudgetCategory(searchForm.projectCategory)) {
|
|
|
|
|
await handleMarketCategoryData(res.data);
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
@ -848,14 +880,6 @@ async function handleLoadMode() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isRdOrPreProductionCategory(): boolean {
|
|
|
|
|
return searchForm.projectCategory === PROJECT_CATEGORY.RD || searchForm.projectCategory === PROJECT_CATEGORY.PRE_PRODUCTION;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isMarketCategory(): boolean {
|
|
|
|
|
return searchForm.projectCategory === PROJECT_CATEGORY.MARKET || searchForm.projectCategory === PROJECT_CATEGORY.MARKET_PART;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleRdOrPreProductionData(data: any) {
|
|
|
|
|
const isChangeType = routeParams.value.changeFlag === '1';
|
|
|
|
|
|
|
|
|
|
@ -1146,6 +1170,7 @@ import { rdBudgetOtherCostVO } from '@/api/oa/erp/budgetInfo/rd/rdBudgetOtherCos
|
|
|
|
|
import { UserVO } from '@/api/system/user/types';
|
|
|
|
|
// 路由参数
|
|
|
|
|
const routeParams = ref<Record<string, any>>({});
|
|
|
|
|
|
|
|
|
|
// 审批相关组件引用
|
|
|
|
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
|
|
|
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
|
|
|
|
|