<template>
|
<div class="app-container">
|
<div class="search_form">
|
<div>
|
<el-form :model="searchForm"
|
:inline="true">
|
<el-form-item label="申请单号:">
|
<el-input v-model="searchForm.applicationNo"
|
placeholder="请输入"
|
clearable
|
:prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="项目名称:">
|
<el-input v-model="searchForm.projectName"
|
placeholder="请输入"
|
clearable
|
:prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="供应商:">
|
<el-select v-model="searchForm.supplierId"
|
placeholder="请选择"
|
filterable
|
clearable
|
style="width: 240px"
|
@change="handleQuery">
|
<el-option v-for="item in supplierOptions"
|
:key="item.id"
|
:label="item.supplierName"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="状态:">
|
<el-select v-model="searchForm.status"
|
placeholder="请选择"
|
clearable
|
style="width: 160px"
|
@change="handleQuery">
|
<el-option label="草稿"
|
:value="0" />
|
<el-option label="已生成订单"
|
:value="1" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="申请日期:">
|
<el-date-picker v-model="searchForm.applyDate"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="daterange"
|
placeholder="请选择"
|
clearable
|
@change="changeDaterange" />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary"
|
@click="handleQuery"> 搜索 </el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
</div>
|
<div class="table_list">
|
<div style="display: flex;justify-content: flex-end;margin-bottom: 20px;">
|
<el-button type="primary"
|
@click="openForm('add')">新增申请单</el-button>
|
<el-button type="danger"
|
plain
|
@click="handleDelete()">删除</el-button>
|
</div>
|
<el-table :data="tableData"
|
border
|
v-loading="tableLoading"
|
@selection-change="handleSelectionChange"
|
:row-key="(row) => row.id"
|
show-summary
|
:summary-method="summarizeMainTable"
|
height="calc(100vh - 21.5em)">
|
<el-table-column align="center"
|
type="selection"
|
width="55"
|
:selectable="row => row.status === 0" />
|
<el-table-column align="center"
|
label="序号"
|
type="index"
|
width="60" />
|
<el-table-column label="申请单号"
|
prop="applicationNo"
|
width="170"
|
show-overflow-tooltip />
|
<el-table-column label="供应商名称"
|
prop="supplierName"
|
width="200"
|
show-overflow-tooltip />
|
<el-table-column label="项目名称"
|
prop="projectName"
|
width="280"
|
show-overflow-tooltip />
|
<el-table-column label="销售合同号"
|
prop="salesContractNo"
|
width="170"
|
show-overflow-tooltip />
|
<el-table-column label="申请人"
|
prop="applicantName"
|
width="100"
|
show-overflow-tooltip />
|
<el-table-column label="申请日期"
|
prop="applyDate"
|
width="110"
|
show-overflow-tooltip />
|
<el-table-column label="期望到货日期"
|
prop="expectedArrivalDate"
|
width="130"
|
show-overflow-tooltip />
|
<el-table-column label="合同金额(元)"
|
prop="contractAmount"
|
width="140"
|
show-overflow-tooltip
|
:formatter="formattedNumber" />
|
<el-table-column label="付款方式"
|
prop="paymentMethod"
|
width="100"
|
show-overflow-tooltip />
|
<el-table-column label="状态"
|
prop="status"
|
width="110"
|
align="center">
|
<template #default="scope">
|
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'"
|
size="small">
|
{{ statusText[scope.row.status] || '--' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="备注"
|
prop="remarks"
|
width="200"
|
show-overflow-tooltip />
|
<el-table-column fixed="right"
|
label="操作"
|
width="200"
|
align="center">
|
<template #default="scope">
|
<template v-if="scope.row.status === 0">
|
<el-button link
|
type="primary"
|
@click="openForm('edit', scope.row)">编辑</el-button>
|
<el-button link
|
type="primary"
|
@click="handleConvert(scope.row)">转订单</el-button>
|
<el-button link
|
type="danger"
|
@click="handleDelete(scope.row)">删除</el-button>
|
</template>
|
<el-button v-else
|
link
|
type="primary"
|
@click="openForm('detail', scope.row)">查看</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination v-show="total > 0"
|
:total="total"
|
layout="total, sizes, prev, pager, next, jumper"
|
:page="page.current"
|
:limit="page.size"
|
@pagination="paginationChange" />
|
</div>
|
<FormDialog v-model="dialogFormVisible"
|
:title="dialogTitle"
|
:width="'70%'"
|
:operation-type="operationType"
|
@close="closeDia"
|
@confirm="submitForm"
|
@cancel="closeDia">
|
<el-form :model="form"
|
:disabled="isDetail"
|
label-width="140px"
|
label-position="top"
|
:rules="rules"
|
ref="formRef">
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="申请单号:"
|
prop="applicationNo">
|
<el-input v-model="form.applicationNo"
|
placeholder="保存后自动生成"
|
disabled />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="申请日期:"
|
prop="applyDate">
|
<el-date-picker style="width: 100%"
|
v-model="form.applyDate"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="date"
|
placeholder="请选择"
|
clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="供应商名称:"
|
prop="supplierId">
|
<el-select v-model="form.supplierId"
|
placeholder="请选择"
|
filterable
|
clearable
|
style="width: 100%">
|
<el-option v-for="item in supplierList"
|
:key="item.id"
|
:label="item.supplierName"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="项目名称"
|
prop="projectName">
|
<el-input v-model="form.projectName"
|
placeholder="请输入"
|
clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="销售合同号:"
|
prop="salesLedgerId">
|
<el-select v-model="form.salesLedgerId"
|
placeholder="请选择"
|
filterable
|
clearable
|
style="width: 100%"
|
@change="salesLedgerChange">
|
<el-option v-for="item in salesContractList"
|
:key="item.id"
|
:label="item.salesContractNo"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="申请人:"
|
prop="applicantId">
|
<el-select v-model="form.applicantId"
|
placeholder="不选则默认为当前登录用户"
|
filterable
|
clearable
|
style="width: 100%">
|
<el-option v-for="item in userList"
|
:key="item.userId"
|
:label="item.nickName"
|
:value="item.userId" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="期望到货日期:"
|
prop="expectedArrivalDate">
|
<el-date-picker style="width: 100%"
|
v-model="form.expectedArrivalDate"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="date"
|
placeholder="请选择"
|
clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="合同金额(元):"
|
prop="contractAmount">
|
<el-input-number v-model="form.contractAmount"
|
:precision="2"
|
:step="0.1"
|
:min="0"
|
placeholder="请输入"
|
style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="付款方式:"
|
prop="paymentMethod">
|
<el-input v-model="form.paymentMethod"
|
placeholder="请输入"
|
clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row>
|
<el-form-item label="产品信息:">
|
<el-button v-if="!isDetail"
|
type="primary"
|
@click="openProductForm('add')">添加</el-button>
|
<el-button v-if="!isDetail"
|
plain
|
type="danger"
|
@click="deleteProduct">删除</el-button>
|
</el-form-item>
|
</el-row>
|
<el-table :data="productData"
|
border
|
@selection-change="productSelected"
|
show-summary
|
:summary-method="summarizeProTable">
|
<el-table-column align="center"
|
type="selection"
|
width="55"
|
:selectable="() => !isDetail" />
|
<el-table-column align="center"
|
label="序号"
|
type="index"
|
width="60" />
|
<el-table-column label="产品大类"
|
prop="productCategory"
|
show-overflow-tooltip />
|
<el-table-column label="规格型号"
|
prop="specificationModel"
|
show-overflow-tooltip />
|
<el-table-column label="单位"
|
prop="unit"
|
width="70" />
|
<el-table-column label="数量"
|
prop="quantity"
|
width="80" />
|
<el-table-column label="税率(%)"
|
prop="taxRate"
|
width="80" />
|
<el-table-column label="含税单价(元)"
|
prop="taxInclusiveUnitPrice"
|
width="120"
|
:formatter="formattedNumber" />
|
<el-table-column label="含税总价(元)"
|
prop="taxInclusiveTotalPrice"
|
width="120"
|
:formatter="formattedNumber" />
|
<el-table-column label="不含税总价(元)"
|
prop="taxExclusiveTotalPrice"
|
width="130"
|
:formatter="formattedNumber" />
|
<el-table-column label="发票类型"
|
prop="invoiceType"
|
width="110"
|
show-overflow-tooltip />
|
<el-table-column label="是否质检"
|
prop="isChecked"
|
width="90">
|
<template #default="scope">
|
<el-tag :type="scope.row.isChecked ? 'success' : 'info'"
|
size="small">
|
{{ scope.row.isChecked ? '是' : '否' }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="备注"
|
prop="remark"
|
show-overflow-tooltip />
|
<el-table-column v-if="!isDetail"
|
fixed="right"
|
label="操作"
|
width="80"
|
align="center">
|
<template #default="scope">
|
<el-button link
|
type="primary"
|
@click="openProductForm('edit', scope.row, scope.$index)">编辑
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="备注:"
|
prop="remarks">
|
<el-input v-model="form.remarks"
|
placeholder="请输入"
|
clearable
|
type="textarea"
|
:rows="2" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
</FormDialog>
|
<FormDialog v-model="productFormVisible"
|
:title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
|
:width="'40%'"
|
:operation-type="productOperationType"
|
@close="closeProductDia"
|
@confirm="submitProduct"
|
@cancel="closeProductDia">
|
<el-form :model="productForm"
|
label-width="140px"
|
label-position="top"
|
:rules="productRules"
|
ref="productFormRef">
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="产品大类:"
|
prop="productId">
|
<el-tree-select v-model="productForm.productId"
|
placeholder="请选择"
|
clearable
|
filterable
|
check-strictly
|
@change="getModels"
|
:data="productOptions"
|
:render-after-expand="false"
|
style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="规格型号:"
|
prop="productModelId">
|
<el-select v-model="productForm.productModelId"
|
placeholder="请选择"
|
filterable
|
clearable
|
style="width: 100%"
|
@change="getProductModel">
|
<el-option v-for="item in modelOptions"
|
:key="item.id"
|
:label="item.model"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="单位:"
|
prop="unit">
|
<el-input v-model="productForm.unit"
|
placeholder="请输入"
|
clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="税率(%):"
|
prop="taxRate">
|
<el-select v-model="productForm.taxRate"
|
placeholder="请选择"
|
clearable
|
style="width: 100%"
|
@change="calcTotals">
|
<el-option v-for="dict in tax_rate"
|
:key="dict.value"
|
:label="dict.label"
|
:value="dict.value" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="含税单价(元):"
|
prop="taxInclusiveUnitPrice">
|
<el-input-number v-model="productForm.taxInclusiveUnitPrice"
|
:precision="2"
|
:step="0.1"
|
:min="0"
|
style="width: 100%"
|
@change="calcTotals" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="数量:"
|
prop="quantity">
|
<el-input-number v-model="productForm.quantity"
|
:precision="2"
|
:step="0.1"
|
:min="0"
|
placeholder="请输入"
|
style="width: 100%"
|
@change="calcTotals" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="含税总价(元):"
|
prop="taxInclusiveTotalPrice">
|
<el-input-number v-model="productForm.taxInclusiveTotalPrice"
|
:precision="2"
|
disabled
|
style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="不含税总价(元):"
|
prop="taxExclusiveTotalPrice">
|
<el-input-number v-model="productForm.taxExclusiveTotalPrice"
|
:precision="2"
|
disabled
|
style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="发票类型:"
|
prop="invoiceType">
|
<el-select v-model="productForm.invoiceType"
|
placeholder="请选择"
|
clearable
|
style="width: 100%">
|
<el-option label="增普票"
|
value="增普票" />
|
<el-option label="增专票"
|
value="增专票" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="是否质检:"
|
prop="isChecked">
|
<el-radio-group v-model="productForm.isChecked">
|
<el-radio label="是"
|
:value="true" />
|
<el-radio label="否"
|
:value="false" />
|
</el-radio-group>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="备注:"
|
prop="remark">
|
<el-input v-model="productForm.remark"
|
placeholder="请输入"
|
clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
</FormDialog>
|
</div>
|
</template>
|
|
<script setup>
|
import FormDialog from "@/components/Dialog/FormDialog.vue";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import {
|
ref,
|
reactive,
|
toRefs,
|
computed,
|
getCurrentInstance,
|
nextTick,
|
onMounted,
|
} from "vue";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
import { Search } from "@element-plus/icons-vue";
|
import dayjs from "dayjs";
|
import router from "@/router";
|
import usePermissionStore from "@/store/modules/permission";
|
import {
|
applicationList,
|
getApplicationById,
|
addApplication,
|
editApplication,
|
delApplication,
|
convertToOrder,
|
} from "@/api/procurementManagement/purchaseApplication.js";
|
import {
|
getSalesNo,
|
getOptions,
|
} from "@/api/procurementManagement/procurementLedger.js";
|
import { modelList, productTreeList } from "@/api/basicData/product.js";
|
import { userListNoPage } from "@/api/system/user.js";
|
|
const { proxy } = getCurrentInstance();
|
const { tax_rate } = proxy.useDict("tax_rate");
|
const permissionStore = usePermissionStore();
|
|
const statusText = {
|
0: "草稿",
|
1: "已生成订单",
|
};
|
|
const tableData = ref([]);
|
const productData = ref([]);
|
const selectedRows = ref([]);
|
const productSelectedRows = ref([]);
|
const supplierOptions = ref([]);
|
const supplierList = ref([]);
|
const salesContractList = ref([]);
|
const userList = ref([]);
|
const productOptions = ref([]);
|
const modelOptions = ref([]);
|
const tableLoading = ref(false);
|
const dialogFormVisible = ref(false);
|
const productFormVisible = ref(false);
|
const operationType = ref("");
|
const productOperationType = ref("");
|
const productOperationIndex = ref("");
|
const currentId = ref("");
|
const total = ref(0);
|
const page = reactive({ current: 1, size: 10 });
|
|
const isDetail = computed(() => operationType.value === "detail");
|
const dialogTitle = computed(() => {
|
if (operationType.value === "add") return "新增采购申请";
|
if (operationType.value === "edit") return "编辑采购申请";
|
return "采购申请详情";
|
});
|
|
const searchForm = reactive({
|
applicationNo: "",
|
projectName: "",
|
supplierId: "",
|
status: "",
|
applyDate: null,
|
startDate: undefined,
|
endDate: undefined,
|
});
|
|
const data = reactive({
|
form: {
|
id: "",
|
applicationNo: "",
|
supplierId: "",
|
projectName: "",
|
salesContractNo: "",
|
salesLedgerId: "",
|
applicantId: "",
|
applyDate: "",
|
expectedArrivalDate: "",
|
contractAmount: "",
|
paymentMethod: "",
|
remarks: "",
|
},
|
rules: {
|
applyDate: [{ required: true, message: "请选择", trigger: "change" }],
|
},
|
});
|
const { form, rules } = toRefs(data);
|
|
const productFormData = reactive({
|
productForm: {
|
productId: "",
|
productCategory: "",
|
productModelId: "",
|
specificationModel: "",
|
unit: "",
|
quantity: "",
|
taxRate: "",
|
taxInclusiveUnitPrice: "",
|
taxInclusiveTotalPrice: "",
|
taxExclusiveTotalPrice: "",
|
invoiceType: "",
|
isChecked: false,
|
remark: "",
|
},
|
productRules: {
|
productId: [{ required: true, message: "请选择", trigger: "change" }],
|
productModelId: [{ required: true, message: "请选择", trigger: "change" }],
|
unit: [{ required: true, message: "请输入", trigger: "blur" }],
|
quantity: [{ required: true, message: "请输入", trigger: "blur" }],
|
taxRate: [{ required: true, message: "请选择", trigger: "change" }],
|
taxInclusiveUnitPrice: [
|
{ required: true, message: "请输入", trigger: "blur" },
|
],
|
},
|
});
|
const { productForm, productRules } = toRefs(productFormData);
|
|
const formattedNumber = (row, column, cellValue) => {
|
if (cellValue === null || cellValue === undefined || cellValue === "") {
|
return "--";
|
}
|
return Number(cellValue).toFixed(2);
|
};
|
|
const changeDaterange = value => {
|
if (value) {
|
searchForm.startDate = dayjs(value[0]).format("YYYY-MM-DD");
|
searchForm.endDate = dayjs(value[1]).format("YYYY-MM-DD");
|
} else {
|
searchForm.startDate = undefined;
|
searchForm.endDate = undefined;
|
}
|
handleQuery();
|
};
|
|
const handleQuery = () => {
|
page.current = 1;
|
getList();
|
};
|
|
const paginationChange = obj => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
|
const getList = () => {
|
tableLoading.value = true;
|
const { applyDate, ...rest } = searchForm;
|
applicationList({ ...rest, pageNum: page.current, pageSize: page.size })
|
.then(res => {
|
const rows = res.rows || res.data?.rows || res.data?.records || [];
|
tableData.value = rows;
|
total.value = res.total ?? res.data?.total ?? 0;
|
})
|
.catch(() => {
|
tableData.value = [];
|
total.value = 0;
|
})
|
.finally(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
const handleSelectionChange = selection => {
|
selectedRows.value = selection;
|
};
|
|
const productSelected = selection => {
|
productSelectedRows.value = selection;
|
};
|
|
const summarizeMainTable = param => {
|
return proxy.summarizeTable(param, ["contractAmount"]);
|
};
|
|
const summarizeProTable = param => {
|
return proxy.summarizeTable(param, [
|
"taxInclusiveUnitPrice",
|
"taxInclusiveTotalPrice",
|
"taxExclusiveTotalPrice",
|
]);
|
};
|
|
// 供应商下拉:筛选用全量,表单仅可选白名单供应商(与采购台账一致)
|
const getSupplierOptions = async () => {
|
const res = await getOptions();
|
const list = res.data || [];
|
supplierOptions.value = list;
|
supplierList.value = list.filter(item => item.isWhite === 0);
|
};
|
|
const getSalesContractList = async () => {
|
const res = await getSalesNo();
|
salesContractList.value = Array.isArray(res) ? res : res?.data || [];
|
};
|
|
const getUserList = async () => {
|
const res = await userListNoPage();
|
userList.value = res.data || [];
|
};
|
|
const getProductOptions = async () => {
|
const res = await productTreeList();
|
productOptions.value = convertIdToValue(res || []);
|
};
|
|
function convertIdToValue(list) {
|
return list.map(item => {
|
const { id, children, ...rest } = item;
|
const newItem = { ...rest, value: id };
|
if (children && children.length > 0) {
|
newItem.children = convertIdToValue(children);
|
}
|
return newItem;
|
});
|
}
|
|
const findNodeLabelById = (nodes, value) => {
|
for (const node of nodes) {
|
if (node.value === value) {
|
return node.label;
|
}
|
if (node.children && node.children.length > 0) {
|
const found = findNodeLabelById(node.children, value);
|
if (found) return found;
|
}
|
}
|
return "";
|
};
|
|
const findNodeValueByLabel = (nodes, label) => {
|
for (const node of nodes) {
|
if (node.label === label) {
|
return node.value;
|
}
|
if (node.children && node.children.length > 0) {
|
const found = findNodeValueByLabel(node.children, label);
|
if (found) return found;
|
}
|
}
|
return "";
|
};
|
|
const getModels = value => {
|
if (!value) {
|
productForm.value.productCategory = "";
|
modelOptions.value = [];
|
return Promise.resolve([]);
|
}
|
productForm.value.productCategory = findNodeLabelById(
|
productOptions.value,
|
value
|
);
|
return modelList({ id: value }).then(res => {
|
modelOptions.value = res || [];
|
return res;
|
});
|
};
|
|
const getProductModel = value => {
|
const matched = modelOptions.value.find(item => item.id === value);
|
if (matched) {
|
productForm.value.specificationModel = matched.model;
|
productForm.value.unit = matched.unit;
|
} else {
|
productForm.value.specificationModel = "";
|
productForm.value.unit = "";
|
}
|
};
|
|
// 含税总价 = 含税单价 × 数量;不含税总价由含税总价与税率反算
|
const calcTotals = () => {
|
const { taxInclusiveUnitPrice, quantity, taxRate } = productForm.value;
|
if (!taxInclusiveUnitPrice && taxInclusiveUnitPrice !== 0) return;
|
if (!quantity && quantity !== 0) return;
|
productForm.value.taxInclusiveTotalPrice =
|
proxy.calculateTaxIncludeTotalPrice(taxInclusiveUnitPrice, quantity);
|
if (taxRate) {
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
productForm.value.taxInclusiveTotalPrice,
|
taxRate
|
);
|
}
|
};
|
|
const openProductForm = async (type, row, index) => {
|
productOperationType.value = type;
|
productOperationIndex.value = index;
|
productForm.value = {};
|
proxy.resetForm("productFormRef");
|
productFormVisible.value = true;
|
|
if (productOptions.value.length === 0) {
|
await getProductOptions();
|
}
|
await nextTick();
|
|
if (type === "add") {
|
productForm.value.isChecked = false;
|
return;
|
}
|
|
productForm.value = { ...row };
|
if (!productForm.value.productId && productForm.value.productCategory) {
|
productForm.value.productId = findNodeValueByLabel(
|
productOptions.value,
|
productForm.value.productCategory
|
);
|
}
|
if (productForm.value.productId) {
|
await getModels(productForm.value.productId);
|
await nextTick();
|
if (productForm.value.productModelId) {
|
getProductModel(productForm.value.productModelId);
|
}
|
}
|
};
|
|
const submitProduct = () => {
|
proxy.$refs["productFormRef"].validate(valid => {
|
if (!valid) return;
|
if (productOperationType.value === "add") {
|
productData.value.push({ ...productForm.value });
|
} else {
|
productData.value[productOperationIndex.value] = {
|
...productForm.value,
|
};
|
}
|
closeProductDia();
|
});
|
};
|
|
const deleteProduct = () => {
|
if (productSelectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
productData.value = productData.value.filter(
|
item => !productSelectedRows.value.includes(item)
|
);
|
productSelectedRows.value = [];
|
};
|
|
const closeProductDia = () => {
|
proxy.resetForm("productFormRef");
|
productFormVisible.value = false;
|
};
|
|
const salesLedgerChange = value => {
|
const matched = salesContractList.value.find(item => item.id === value);
|
form.value.salesContractNo = matched ? matched.salesContractNo : "";
|
};
|
|
const openForm = async (type, row) => {
|
operationType.value = type;
|
currentId.value = row?.id || "";
|
proxy.resetForm("formRef");
|
form.value = {
|
id: "",
|
applicationNo: "",
|
supplierId: "",
|
projectName: "",
|
salesContractNo: "",
|
salesLedgerId: "",
|
applicantId: "",
|
applyDate: dayjs().format("YYYY-MM-DD"),
|
expectedArrivalDate: "",
|
contractAmount: "",
|
paymentMethod: "",
|
remarks: "",
|
};
|
productData.value = [];
|
productSelectedRows.value = [];
|
|
try {
|
await Promise.all([
|
getSupplierOptions(),
|
getSalesContractList(),
|
getUserList(),
|
getProductOptions(),
|
]);
|
} catch (error) {
|
proxy.$modal.msgError("加载基础数据失败");
|
return;
|
}
|
|
if (type === "add") {
|
dialogFormVisible.value = true;
|
return;
|
}
|
|
try {
|
const res = await getApplicationById({ id: row.id });
|
form.value = { ...(res.data || {}), id: row.id };
|
productData.value = res.data?.productData || [];
|
} catch (error) {
|
proxy.$modal.msgError("加载采购申请详情失败");
|
return;
|
}
|
dialogFormVisible.value = true;
|
};
|
|
const closeDia = () => {
|
proxy.resetForm("formRef");
|
dialogFormVisible.value = false;
|
};
|
|
// 只提交后端允许的字段,自动字段(单号、状态、租户等)一律不传
|
const buildPayload = () => {
|
const payload = {
|
supplierId: form.value.supplierId || null,
|
projectName: form.value.projectName,
|
salesContractNo: form.value.salesContractNo,
|
salesLedgerId: form.value.salesLedgerId || null,
|
applyDate: form.value.applyDate,
|
expectedArrivalDate: form.value.expectedArrivalDate || null,
|
contractAmount:
|
form.value.contractAmount === "" ? null : form.value.contractAmount,
|
paymentMethod: form.value.paymentMethod,
|
remarks: form.value.remarks,
|
productData: productData.value.map(
|
({ id, purchaseApplicationId, ...rest }) => rest
|
),
|
};
|
// 申请人留空表示由后端取当前登录用户
|
if (form.value.applicantId) {
|
payload.applicantId = form.value.applicantId;
|
}
|
return payload;
|
};
|
|
const submitForm = () => {
|
proxy.$refs["formRef"].validate(async valid => {
|
if (!valid) return;
|
const payload = buildPayload();
|
try {
|
if (operationType.value === "add") {
|
await addApplication(payload);
|
} else {
|
await editApplication({ id: currentId.value, ...payload });
|
}
|
proxy.$modal.msgSuccess("保存成功");
|
closeDia();
|
getList();
|
} catch (error) {
|
// 错误信息由 request 拦截器统一提示
|
}
|
});
|
};
|
|
const handleDelete = row => {
|
let ids = [];
|
if (row) {
|
ids = [row.id];
|
} else if (selectedRows.value.length > 0) {
|
ids = selectedRows.value.map(item => item.id);
|
} else {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(async () => {
|
await delApplication(ids);
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
})
|
.catch(() => {});
|
};
|
|
const handleConvert = row => {
|
ElMessageBox.confirm(
|
`确认将申请单「${row.applicationNo}」转为采购订单吗?转订单后将自动提交采购审批。`,
|
"转订单",
|
{
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
}
|
)
|
.then(async () => {
|
const res = await convertToOrder(row.id);
|
getList();
|
ElMessageBox.confirm(
|
`转订单成功,已生成采购台账(id:${res.data})。是否前往采购台账查看?`,
|
"提示",
|
{
|
confirmButtonText: "前往查看",
|
cancelButtonText: "留在本页",
|
type: "success",
|
}
|
)
|
.then(() => {
|
const path = findLedgerPath(permissionStore.sidebarRouters);
|
if (path) {
|
router.push(path);
|
} else {
|
ElMessage.info("请前往「采购台账」查看生成的订单");
|
}
|
})
|
.catch(() => {});
|
})
|
.catch(() => {});
|
};
|
|
// 从侧边栏菜单中定位采购台账路由,找不到时不跳转仅提示
|
const findLedgerPath = (routes, prefix = "") => {
|
for (const route of routes || []) {
|
const fullPath = String(route.path || "").startsWith("/")
|
? route.path
|
: `${prefix}/${route.path || ""}`;
|
if (route.meta?.title === "采购台账") {
|
return fullPath;
|
}
|
const found = findLedgerPath(route.children, fullPath);
|
if (found) return found;
|
}
|
return "";
|
};
|
|
onMounted(() => {
|
getList();
|
getSupplierOptions();
|
});
|
</script>
|