| | |
| | | slot: "inboundDate", |
| | | }, |
| | | { label: "产品名称", prop: "productName", minWidth: "140" }, |
| | | { label: "产品规格", prop: "specificationModel", minWidth: "140" }, |
| | | { label: "规格型号", prop: "specificationModel", minWidth: "140" }, |
| | | { |
| | | label: "金额", |
| | | prop: "inboundAmount", |
| | |
| | | <template> |
| | | <!-- 销售出库 --> |
| | | <!-- 销售出库 --> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form :model="filters" |
| | | :inline="true"> |
| | | <el-form-item label="出库单号:"> |
| | | <el-input v-model="filters.outboundBatches" placeholder="请输入出库单号" clearable style="width: 200px;" /> |
| | | <el-input v-model="filters.outboundBatches" |
| | | placeholder="请输入出库单号" |
| | | clearable |
| | | style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="客户名称:"> |
| | | <el-input v-model="filters.customerName" placeholder="请输入客户名称" clearable style="width: 200px;" /> |
| | | <el-input v-model="filters.customerName" |
| | | placeholder="请输入客户名称" |
| | | clearable |
| | | style="width: 200px;" /> |
| | | </el-form-item> |
| | | <el-form-item label="出库日期:"> |
| | | <el-date-picker |
| | | v-model="filters.dateRange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | clearable |
| | | /> |
| | | <el-date-picker v-model="filters.dateRange" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | clearable /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="onSearch">搜索</el-button> |
| | | <el-button type="primary" |
| | | @click="onSearch">搜索</el-button> |
| | | <el-button @click="resetFilters">重置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button @click="handleOut" icon="Download">导出</el-button> |
| | | <el-button @click="handleOut" |
| | | icon="Download">导出</el-button> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :tableLoading="tableLoading" |
| | | :page="{ |
| | | <PIMTable rowKey="id" |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :tableLoading="tableLoading" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @pagination="changePage" |
| | | /> |
| | | @pagination="changePage" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { listPageAccountSales } from "@/api/financialManagement/accountSales"; |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { listPageAccountSales } from "@/api/financialManagement/accountSales"; |
| | | |
| | | defineOptions({ |
| | | name: "销售出库", |
| | | }); |
| | | defineOptions({ |
| | | name: "销售出库", |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const filters = reactive({ |
| | | outboundBatches: "", |
| | | customerName: "", |
| | | dateRange: [], |
| | | }); |
| | | const filters = reactive({ |
| | | outboundBatches: "", |
| | | customerName: "", |
| | | dateRange: [], |
| | | }); |
| | | |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | }); |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | }); |
| | | |
| | | const columns = [ |
| | | { label: "出库单号", prop: "outboundBatches", minWidth: "150" }, |
| | | { label: "客户名称", prop: "customerName", minWidth: "180" }, |
| | | { label: "出库日期", prop: "shippingDate", width: "170" }, |
| | | { label: "产品名称", prop: "productName", minWidth: "140" }, |
| | | { label: "产品规格", prop: "specificationModel", minWidth: "140" }, |
| | | { |
| | | label: "金额", |
| | | prop: "outboundAmount", |
| | | minWidth: "120", |
| | | align: "right", |
| | | formatData: (val) => (val === null || val === undefined || val === "" ? "" : Number(val).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })), |
| | | }, |
| | | { label: "发货编号", prop: "shippingNo", minWidth: "140" }, |
| | | { label: "销售订单号", prop: "salesContractNo", minWidth: "150" }, |
| | | ]; |
| | | const columns = [ |
| | | { label: "出库单号", prop: "outboundBatches", minWidth: "150" }, |
| | | { label: "客户名称", prop: "customerName", minWidth: "180" }, |
| | | { label: "出库日期", prop: "shippingDate", width: "170" }, |
| | | { label: "产品名称", prop: "productName", minWidth: "140" }, |
| | | { label: "规格型号", prop: "specificationModel", minWidth: "140" }, |
| | | { |
| | | label: "金额", |
| | | prop: "outboundAmount", |
| | | minWidth: "120", |
| | | align: "right", |
| | | formatData: val => |
| | | val === null || val === undefined || val === "" |
| | | ? "" |
| | | : Number(val).toLocaleString("zh-CN", { |
| | | minimumFractionDigits: 2, |
| | | maximumFractionDigits: 2, |
| | | }), |
| | | }, |
| | | { label: "发货编号", prop: "shippingNo", minWidth: "140" }, |
| | | { label: "销售订单号", prop: "salesContractNo", minWidth: "150" }, |
| | | ]; |
| | | |
| | | const dataList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const dataList = ref([]); |
| | | const tableLoading = ref(false); |
| | | |
| | | function buildFilterParams() { |
| | | const params = { |
| | | outboundBatches: filters.outboundBatches || undefined, |
| | | customerName: filters.customerName || undefined, |
| | | }; |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | params.startDate = filters.dateRange[0]; |
| | | params.endDate = filters.dateRange[1]; |
| | | function buildFilterParams() { |
| | | const params = { |
| | | outboundBatches: filters.outboundBatches || undefined, |
| | | customerName: filters.customerName || undefined, |
| | | }; |
| | | if (filters.dateRange && filters.dateRange.length === 2) { |
| | | params.startDate = filters.dateRange[0]; |
| | | params.endDate = filters.dateRange[1]; |
| | | } |
| | | return params; |
| | | } |
| | | return params; |
| | | } |
| | | |
| | | const onSearch = () => { |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | const onSearch = () => { |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const getTableData = () => { |
| | | tableLoading.value = true; |
| | | listPageAccountSales({ |
| | | ...buildFilterParams(), |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | }) |
| | | .then((res) => { |
| | | const ok = res.code === 200 || res.code === 0; |
| | | if (ok && res.data) { |
| | | pagination.total = res.data.total ?? 0; |
| | | dataList.value = res.data.records ?? []; |
| | | } else { |
| | | ElMessage.error(res.msg || "查询失败"); |
| | | const getTableData = () => { |
| | | tableLoading.value = true; |
| | | listPageAccountSales({ |
| | | ...buildFilterParams(), |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | }) |
| | | .then(res => { |
| | | const ok = res.code === 200 || res.code === 0; |
| | | if (ok && res.data) { |
| | | pagination.total = res.data.total ?? 0; |
| | | dataList.value = res.data.records ?? []; |
| | | } else { |
| | | ElMessage.error(res.msg || "查询失败"); |
| | | dataList.value = []; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | dataList.value = []; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | dataList.value = []; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const resetFilters = () => { |
| | | filters.outboundBatches = ""; |
| | | filters.customerName = ""; |
| | | filters.dateRange = []; |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | const resetFilters = () => { |
| | | filters.outboundBatches = ""; |
| | | filters.customerName = ""; |
| | | filters.dateRange = []; |
| | | pagination.currentPage = 1; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | getTableData(); |
| | | }; |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | proxy.download( |
| | | "/accountSales/exportAccountSalesOutbound", |
| | | buildFilterParams(), |
| | | `销售出库_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | const handleOut = () => { |
| | | proxy.download( |
| | | "/accountSales/exportAccountSalesOutbound", |
| | | buildFilterParams(), |
| | | `销售出库_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 15px; |
| | | } |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 15px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div> |
| | | <div class="search_form" style="margin-bottom: 10px"> |
| | | <el-form |
| | | ref="searchFormRef" |
| | | :model="searchForm" |
| | | class="demo-form-inline" |
| | | > |
| | | <div class="search_form" |
| | | style="margin-bottom: 10px"> |
| | | <el-form ref="searchFormRef" |
| | | :model="searchForm" |
| | | class="demo-form-inline"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="4"> |
| | | <el-form-item label="出库日期" prop="timeStr"> |
| | | <el-form-item label="出库日期" |
| | | prop="timeStr"> |
| | | <el-date-picker v-model="searchForm.timeStr" |
| | | type="date" |
| | | placeholder="请选择日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="产品大类" prop="productName"> |
| | | <el-form-item label="产品大类" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="4"> |
| | | <el-form-item label="产品规格" prop="model"> |
| | | <el-form-item label="规格型号" |
| | | prop="model"> |
| | | <el-input v-model="searchForm.model" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="批号" prop="batchNo"> |
| | | <el-form-item label="批号" |
| | | prop="batchNo"> |
| | | <el-input v-model="searchForm.batchNo" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="来源" prop="recordType"> |
| | | <el-select |
| | | v-model="searchForm.recordType" |
| | | style="width: 240px" |
| | | placeholder="请选择" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in stockRecordTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | <el-form-item label="来源" |
| | | prop="recordType"> |
| | | <el-select v-model="searchForm.recordType" |
| | | style="width: 240px" |
| | | placeholder="请选择" |
| | | clearable> |
| | | <el-option v-for="item in stockRecordTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- 按钮 --> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getList"> |
| | | <el-button type="primary" |
| | | @click="getList"> |
| | | 搜索 |
| | | </el-button> |
| | | |
| | | <el-button @click="resetSearch"> |
| | | 重置 |
| | | </el-button> |
| | |
| | | </el-form> |
| | | </div> |
| | | <div class="actions"> |
| | | <el-button type="primary" @click="handleBatchApprove">审批</el-button> |
| | | <el-button type="primary" |
| | | @click="handleBatchApprove">审批</el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">删除</el-button> |
| | | <el-button type="primary" plain @click="handlePrint">打印</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">删除</el-button> |
| | | <el-button type="primary" |
| | | plain |
| | | @click="handlePrint">打印</el-button> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row) => row.id" |
| | | style="width: 100%" |
| | | height="calc(100vh - 18.5em)" |
| | | > |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column |
| | | label="出库批次" |
| | | prop="outboundBatches" |
| | | min-width="100" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="出库日期" |
| | | prop="createTime" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="产品大类" |
| | | prop="productName" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="规格型号" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="批号" prop="batchNo" show-overflow-tooltip /> |
| | | <el-table-column label="单位" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="出库数量" |
| | | prop="stockOutNum" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="出库人" prop="createBy" show-overflow-tooltip /> |
| | | <el-table-column label="来源" prop="recordType" show-overflow-tooltip> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row) => row.id" |
| | | style="width: 100%" |
| | | height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" /> |
| | | <el-table-column align="center" |
| | | label="序号" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="出库批次" |
| | | prop="outboundBatches" |
| | | min-width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="出库日期" |
| | | prop="createTime" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="产品大类" |
| | | prop="productName" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="规格型号" |
| | | prop="model" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="批号" |
| | | prop="batchNo" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="单位" |
| | | prop="unit" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="出库数量" |
| | | prop="stockOutNum" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="出库人" |
| | | prop="createBy" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="来源" |
| | | prop="recordType" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ getRecordType(scope.row.recordType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="审批状态" |
| | | prop="approvalStatus" |
| | | show-overflow-tooltip |
| | | > |
| | | <el-table-column label="审批状态" |
| | | prop="approvalStatus" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag |
| | | :type="getApprovalStatusTagType(scope.row.approvalStatus)" |
| | | size="small" |
| | | > |
| | | <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | {{ getApprovalStatusLabel(scope.row.approvalStatus) }} |
| | | </el-tag> |
| | | </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" |
| | | /> |
| | | <pagination v-show="total > 0" |
| | | :total="total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | @pagination="paginationChange" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import { |
| | | getStockOutPage, |
| | | delPendingStockOut, |
| | | batchApproveStockOutRecords, |
| | | } from "@/api/inventoryManagement/stockOut.js"; |
| | | import { |
| | | findAllQualifiedStockOutRecordTypeOptions, |
| | | findAllUnQualifiedStockOutRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import { |
| | | getStockOutPage, |
| | | delPendingStockOut, |
| | | batchApproveStockOutRecords, |
| | | } from "@/api/inventoryManagement/stockOut.js"; |
| | | import { |
| | | findAllQualifiedStockOutRecordTypeOptions, |
| | | findAllUnQualifiedStockOutRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | // 来源类型选项 |
| | | const stockRecordTypeOptions = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | // 来源类型选项 |
| | | const stockRecordTypeOptions = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | |
| | | const props = defineProps({ |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: "0", |
| | | }, |
| | | topParentProductId: { |
| | | type: [String, Number], |
| | | default: undefined, |
| | | }, |
| | | }); |
| | | const props = defineProps({ |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: "0", |
| | | }, |
| | | topParentProductId: { |
| | | type: [String, Number], |
| | | default: undefined, |
| | | }, |
| | | }); |
| | | |
| | | // 打印相关 |
| | | const printPreviewVisible = ref(false); |
| | | const printData = ref([]); |
| | | // 打印相关 |
| | | const printPreviewVisible = ref(false); |
| | | const printData = ref([]); |
| | | |
| | | // 用户信息表单弹框数据 |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | timeStr: "", |
| | | recordType: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | // 用户信息表单弹框数据 |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | timeStr: "", |
| | | recordType: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const searchFormRef = ref(null); |
| | | const searchFormRef = ref(null); |
| | | |
| | | const resetSearch = () => { |
| | | searchFormRef.value?.resetFields(); |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | const resetSearch = () => { |
| | | searchFormRef.value?.resetFields(); |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const paginationChange = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockOutPage({ |
| | | ...searchForm.value, |
| | | ...page, |
| | | topParentProductId: props.topParentProductId, |
| | | }) |
| | | .then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | tableData.value.map((item) => { |
| | | item.children = []; |
| | | }); |
| | | total.value = res.data.total; |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockOutPage({ |
| | | ...searchForm.value, |
| | | ...page, |
| | | topParentProductId: props.topParentProductId, |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | tableData.value.map(item => { |
| | | item.children = []; |
| | | }); |
| | | total.value = res.data.total; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const getRecordType = (recordType) => { |
| | | return ( |
| | | stockRecordTypeOptions.value.find((item) => item.value === recordType) |
| | | ?.label || "" |
| | | ); |
| | | }; |
| | | const getRecordType = recordType => { |
| | | return ( |
| | | stockRecordTypeOptions.value.find(item => item.value === recordType) |
| | | ?.label || "" |
| | | ); |
| | | }; |
| | | |
| | | const approvalStatusLabelMap = { |
| | | 0: "待审批", |
| | | 1: "通过", |
| | | 2: "驳回", |
| | | 3: "待确认", |
| | | pending: "待审批", |
| | | approved: "通过", |
| | | rejected: "驳回", |
| | | PENDING: "待审批", |
| | | APPROVED: "通过", |
| | | REJECTED: "驳回", |
| | | }; |
| | | const approvalStatusLabelMap = { |
| | | 0: "待审批", |
| | | 1: "通过", |
| | | 2: "驳回", |
| | | 3: "待确认", |
| | | pending: "待审批", |
| | | approved: "通过", |
| | | rejected: "驳回", |
| | | PENDING: "待审批", |
| | | APPROVED: "通过", |
| | | REJECTED: "驳回", |
| | | }; |
| | | |
| | | const getApprovalStatusLabel = (status) => { |
| | | if (status === null || status === undefined || status === "") { |
| | | return "待审批"; |
| | | } |
| | | return approvalStatusLabelMap[status] || "待审批"; |
| | | }; |
| | | const getApprovalStatusLabel = status => { |
| | | if (status === null || status === undefined || status === "") { |
| | | return "待审批"; |
| | | } |
| | | return approvalStatusLabelMap[status] || "待审批"; |
| | | }; |
| | | |
| | | // 通过/驳回固定色;其余(含待审批、空值、未映射但文案为待审批)统一用 warning 预警色 |
| | | const getApprovalStatusTagType = (status) => { |
| | | if ( |
| | | status === 1 || |
| | | status === "1" || |
| | | status === "approved" || |
| | | status === "APPROVED" |
| | | ) |
| | | return "success"; |
| | | if ( |
| | | status === 2 || |
| | | status === "2" || |
| | | status === "rejected" || |
| | | status === "REJECTED" |
| | | ) |
| | | return "danger"; |
| | | return "warning"; |
| | | }; |
| | | // 通过/驳回固定色;其余(含待审批、空值、未映射但文案为待审批)统一用 warning 预警色 |
| | | const getApprovalStatusTagType = status => { |
| | | if ( |
| | | status === 1 || |
| | | status === "1" || |
| | | status === "approved" || |
| | | status === "APPROVED" |
| | | ) |
| | | return "success"; |
| | | if ( |
| | | status === 2 || |
| | | status === "2" || |
| | | status === "rejected" || |
| | | status === "REJECTED" |
| | | ) |
| | | return "danger"; |
| | | return "warning"; |
| | | }; |
| | | |
| | | // 获取来源类型选项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === "0") { |
| | | findAllQualifiedStockOutRecordTypeOptions().then((res) => { |
| | | // 获取来源类型选项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === "0") { |
| | | findAllQualifiedStockOutRecordTypeOptions().then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }); |
| | | return; |
| | | } |
| | | findAllUnQualifiedStockOutRecordTypeOptions().then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }); |
| | | return; |
| | | } |
| | | findAllUnQualifiedStockOutRecordTypeOptions().then((res) => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | // 表格选择数据 |
| | | const handleSelectionChange = (selection) => { |
| | | // 过滤掉子数据 |
| | | selectedRows.value = selection.filter((item) => item.id); |
| | | console.log("selection", selectedRows.value); |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | // 表格选择数据 |
| | | const handleSelectionChange = selection => { |
| | | // 过滤掉子数据 |
| | | selectedRows.value = selection.filter(item => item.id); |
| | | console.log("selection", selectedRows.value); |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | const handleBatchApprove = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请选择数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map((item) => item.id); |
| | | ElMessageBox.confirm("请选择审批结果", "审批", { |
| | | confirmButtonText: "通过", |
| | | cancelButtonText: "驳回", |
| | | type: "warning", |
| | | distinguishCancelAndClose: true, |
| | | }) |
| | | .then(() => { |
| | | batchApproveStockOutRecords({ ids, approvalStatus: 1 }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("审批通过成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("审批通过失败"); |
| | | }); |
| | | const handleBatchApprove = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请选择数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("请选择审批结果", "审批", { |
| | | confirmButtonText: "通过", |
| | | cancelButtonText: "驳回", |
| | | type: "warning", |
| | | distinguishCancelAndClose: true, |
| | | }) |
| | | .catch((action) => { |
| | | if (action === "cancel") { |
| | | batchApproveStockOutRecords({ ids, approvalStatus: 2 }) |
| | | .then(() => { |
| | | batchApproveStockOutRecords({ ids, approvalStatus: 1 }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("审批驳回成功"); |
| | | proxy.$modal.msgSuccess("审批通过成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("审批驳回失败"); |
| | | proxy.$modal.msgError("审批通过失败"); |
| | | }); |
| | | return; |
| | | } |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | |
| | | // 导出 |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download( |
| | | "/stockOutRecord/exportStockOutRecord", |
| | | { type: props.type }, |
| | | props.type === "0" ? "合格出库台账.xlsx" : "不合格出库台账.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | |
| | | // 删除 |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("请选择数据"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delPendingStockOut(ids).then((res) => { |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | getList(); |
| | | }) |
| | | .catch(action => { |
| | | if (action === "cancel") { |
| | | batchApproveStockOutRecords({ ids, approvalStatus: 2 }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("审批驳回成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("审批驳回失败"); |
| | | }); |
| | | return; |
| | | } |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | |
| | | // 导出 |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | .then(() => { |
| | | proxy.download( |
| | | "/stockOutRecord/exportStockOutRecord", |
| | | { type: props.type }, |
| | | props.type === "0" ? "合格出库台账.xlsx" : "不合格出库台账.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | |
| | | // 打印功能 |
| | | const handlePrint = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请选择要打印的数据"); |
| | | return; |
| | | } |
| | | printData.value = [...selectedRows.value]; |
| | | console.log("打印数据:", printData.value); |
| | | printPreviewVisible.value = true; |
| | | }; |
| | | // 删除 |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("请选择数据"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delPendingStockOut(ids).then(res => { |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | |
| | | // 执行打印 |
| | | const executePrint = () => { |
| | | console.log("开始执行打印,数据条数:", printData.value.length); |
| | | console.log("打印数据:", printData.value); |
| | | // 打印功能 |
| | | const handlePrint = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请选择要打印的数据"); |
| | | return; |
| | | } |
| | | printData.value = [...selectedRows.value]; |
| | | console.log("打印数据:", printData.value); |
| | | printPreviewVisible.value = true; |
| | | }; |
| | | |
| | | // 创建一个新的打印窗口 |
| | | const printWindow = window.open("", "_blank", "width=800,height=600"); |
| | | // 执行打印 |
| | | const executePrint = () => { |
| | | console.log("开始执行打印,数据条数:", printData.value.length); |
| | | console.log("打印数据:", printData.value); |
| | | |
| | | // 构建打印内容 |
| | | let printContent = ` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>打印预览</title> |
| | | <style> |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | font-family: "SimSun", serif; |
| | | background: white; |
| | | } |
| | | .print-page { |
| | | width: 200mm; |
| | | height: 75mm; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | background: white; |
| | | box-sizing: border-box; |
| | | page-break-after: always; |
| | | page-break-inside: avoid; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-size: 12px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | color: #000; |
| | | } |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .info-row { |
| | | line-height: 20px; |
| | | } |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 12px; |
| | | } |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .table-section { |
| | | margin-bottom: 40px; |
| | | // flex: 0.6; |
| | | } |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | } |
| | | .product-table th, .product-table td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | text-align: center; |
| | | font-size: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | .product-table th { |
| | | font-weight: bold; |
| | | } |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | | .footer-section { |
| | | margin-top: auto; |
| | | } |
| | | .footer-row { |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 22px; |
| | | justify-content: space-between; |
| | | } |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | } |
| | | .footer-item .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .footer-item .value { |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .address-item .address-value { |
| | | min-width: 200px; |
| | | } |
| | | @media print { |
| | | // 创建一个新的打印窗口 |
| | | const printWindow = window.open("", "_blank", "width=800,height=600"); |
| | | |
| | | // 构建打印内容 |
| | | let printContent = ` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>打印预览</title> |
| | | <style> |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | font-family: "SimSun", serif; |
| | | background: white; |
| | | } |
| | | .print-page { |
| | | margin: 0; |
| | | padding: 10mm; |
| | | /* padding-left: 20mm; */ |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | } |
| | | .print-page { |
| | | width: 200mm; |
| | | height: 75mm; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | background: white; |
| | | box-sizing: border-box; |
| | | page-break-after: always; |
| | | page-break-inside: avoid; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | `; |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-size: 12px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | color: #000; |
| | | } |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .info-row { |
| | | line-height: 20px; |
| | | } |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 12px; |
| | | } |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .table-section { |
| | | margin-bottom: 40px; |
| | | // flex: 0.6; |
| | | } |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | } |
| | | .product-table th, .product-table td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | text-align: center; |
| | | font-size: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | .product-table th { |
| | | font-weight: bold; |
| | | } |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | | .footer-section { |
| | | margin-top: auto; |
| | | } |
| | | .footer-row { |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 22px; |
| | | justify-content: space-between; |
| | | } |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | } |
| | | .footer-item .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .footer-item .value { |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .address-item .address-value { |
| | | min-width: 200px; |
| | | } |
| | | @media print { |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | .print-page { |
| | | margin: 0; |
| | | padding: 10mm; |
| | | /* padding-left: 20mm; */ |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | `; |
| | | |
| | | // 为每条数据生成打印页面 |
| | | printData.value.forEach((item, index) => { |
| | | printContent += ` |
| | | <div class="print-page"> |
| | | <div class="delivery-note"> |
| | | <div class="header"> |
| | | <div class="document-title">零售发货单</div> |
| | | </div> |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row"> |
| | | <div> |
| | | <span class="label">发货日期:</span> |
| | | <span class="value">${formatDate(item.createTime)}</span> |
| | | // 为每条数据生成打印页面 |
| | | printData.value.forEach((item, index) => { |
| | | printContent += ` |
| | | <div class="print-page"> |
| | | <div class="delivery-note"> |
| | | <div class="header"> |
| | | <div class="document-title">零售发货单</div> |
| | | </div> |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row"> |
| | | <div> |
| | | <span class="label">发货日期:</span> |
| | | <span class="value">${formatDate(item.createTime)}</span> |
| | | </div> |
| | | <div> |
| | | <span class="label">客户名称:</span> |
| | | <span class="value">${item.supplierName}</span> |
| | | </div> |
| | | </div> |
| | | <div> |
| | | <span class="label">客户名称:</span> |
| | | <span class="value">${item.supplierName}</span> |
| | | <div class="info-row"> |
| | | <span class="label">单号:</span> |
| | | <span class="value">${item.code || ""}</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <span class="label">单号:</span> |
| | | <span class="value">${item.code || ""}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="table-section"> |
| | | <table class="product-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>产品名称</th> |
| | | <th>规格型号</th> |
| | | <th>单位</th> |
| | | <th>单价</th> |
| | | <th>零售数量</th> |
| | | <th>零售金额</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>${item.productName || "砂灰砖"}</td> |
| | | <td>${item.model || "标准"}</td> |
| | | <td>${item.unit || "块"}</td> |
| | | <td>${item.taxInclusiveUnitPrice || "0"}</td> |
| | | <td>${item.inboundNum || "2000"}</td> |
| | | <td>${item.taxInclusiveTotalPrice || "0"}</td> |
| | | </tr> |
| | | </tbody> |
| | | <tfoot> |
| | | <tr> |
| | | <td class="label">合计</td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value">${item.inboundNum || "2000"}</td> |
| | | <td class="total-value">${ |
| | | item.taxInclusiveTotalPrice || "0" |
| | | }</td> |
| | | </tr> |
| | | </tfoot> |
| | | </table> |
| | | </div> |
| | | |
| | | <div class="footer-section"> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">收货电话:</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">收货人:</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item address-item"> |
| | | <span class="label">收货地址:</span> |
| | | <span class="value address-value"></span> |
| | | </div> |
| | | <div class="table-section"> |
| | | <table class="product-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>产品名称</th> |
| | | <th>规格型号</th> |
| | | <th>单位</th> |
| | | <th>单价</th> |
| | | <th>零售数量</th> |
| | | <th>零售金额</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>${item.productName || "砂灰砖"}</td> |
| | | <td>${item.model || "标准"}</td> |
| | | <td>${item.unit || "块"}</td> |
| | | <td>${item.taxInclusiveUnitPrice || "0"}</td> |
| | | <td>${item.inboundNum || "2000"}</td> |
| | | <td>${item.taxInclusiveTotalPrice || "0"}</td> |
| | | </tr> |
| | | </tbody> |
| | | <tfoot> |
| | | <tr> |
| | | <td class="label">合计</td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value">${item.inboundNum || "2000"}</td> |
| | | <td class="total-value">${ |
| | | item.taxInclusiveTotalPrice || "0" |
| | | }</td> |
| | | </tr> |
| | | </tfoot> |
| | | </table> |
| | | </div> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">操作员:</span> |
| | | <span class="value">${userStore.nickName || "撕开前"}</span> |
| | | |
| | | <div class="footer-section"> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">收货电话:</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">收货人:</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item address-item"> |
| | | <span class="label">收货地址:</span> |
| | | <span class="value address-value"></span> |
| | | </div> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">打印日期:</span> |
| | | <span class="value">${formatDateTime(new Date())}</span> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">操作员:</span> |
| | | <span class="value">${userStore.nickName || "撕开前"}</span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">打印日期:</span> |
| | | <span class="value">${formatDateTime(new Date())}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | `; |
| | | }); |
| | | |
| | | printContent += ` |
| | | </body> |
| | | </html> |
| | | `; |
| | | |
| | | // 写入内容到新窗口 |
| | | printWindow.document.write(printContent); |
| | | printWindow.document.close(); |
| | | |
| | | // 等待内容加载完成后打印 |
| | | printWindow.onload = () => { |
| | | setTimeout(() => { |
| | | printWindow.print(); |
| | | printWindow.close(); |
| | | printPreviewVisible.value = false; |
| | | }, 500); |
| | | }; |
| | | }; |
| | | |
| | | // 格式化日期 |
| | | const formatDate = dateString => { |
| | | if (!dateString) return getCurrentDate(); |
| | | const date = new Date(dateString); |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(date.getDate()).padStart(2, "0"); |
| | | return `${year}/${month}/${day}`; |
| | | }; |
| | | |
| | | // 格式化日期时间 |
| | | const formatDateTime = date => { |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(date.getDate()).padStart(2, "0"); |
| | | const hours = String(date.getHours()).padStart(2, "0"); |
| | | const minutes = String(date.getMinutes()).padStart(2, "0"); |
| | | const seconds = String(date.getSeconds()).padStart(2, "0"); |
| | | return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`; |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | fetchStockRecordTypeOptions(); |
| | | }); |
| | | |
| | | printContent += ` |
| | | </body> |
| | | </html> |
| | | `; |
| | | |
| | | // 写入内容到新窗口 |
| | | printWindow.document.write(printContent); |
| | | printWindow.document.close(); |
| | | |
| | | // 等待内容加载完成后打印 |
| | | printWindow.onload = () => { |
| | | setTimeout(() => { |
| | | printWindow.print(); |
| | | printWindow.close(); |
| | | printPreviewVisible.value = false; |
| | | }, 500); |
| | | }; |
| | | }; |
| | | |
| | | // 格式化日期 |
| | | const formatDate = (dateString) => { |
| | | if (!dateString) return getCurrentDate(); |
| | | const date = new Date(dateString); |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(date.getDate()).padStart(2, "0"); |
| | | return `${year}/${month}/${day}`; |
| | | }; |
| | | |
| | | // 格式化日期时间 |
| | | const formatDateTime = (date) => { |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(date.getDate()).padStart(2, "0"); |
| | | const hours = String(date.getHours()).padStart(2, "0"); |
| | | const minutes = String(date.getMinutes()).padStart(2, "0"); |
| | | const seconds = String(date.getSeconds()).padStart(2, "0"); |
| | | return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`; |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | fetchStockRecordTypeOptions(); |
| | | }); |
| | | |
| | | watch( |
| | | () => props.topParentProductId, |
| | | () => { |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | ); |
| | | watch( |
| | | () => props.topParentProductId, |
| | | () => { |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | ); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .print-preview-dialog { |
| | | .el-dialog__body { |
| | | padding: 0; |
| | | max-height: 80vh; |
| | | overflow-y: auto; |
| | | } |
| | | } |
| | | |
| | | .print-preview-container { |
| | | .print-preview-header { |
| | | padding: 15px; |
| | | border-bottom: 1px solid #e4e7ed; |
| | | text-align: center; |
| | | |
| | | .el-button { |
| | | margin: 0 10px; |
| | | .print-preview-dialog { |
| | | .el-dialog__body { |
| | | padding: 0; |
| | | max-height: 80vh; |
| | | overflow-y: auto; |
| | | } |
| | | } |
| | | |
| | | .print-preview-content { |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | | min-height: 400px; |
| | | } |
| | | } |
| | | |
| | | .print-page { |
| | | width: 220mm; |
| | | height: 90mm; |
| | | padding: 10mm; |
| | | margin: 0 auto; |
| | | background: white; |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
| | | margin-bottom: 10px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-family: "SimSun", serif; |
| | | font-size: 10px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .info-row { |
| | | line-height: 20px; |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .table-section { |
| | | margin-bottom: 4px; |
| | | flex: 1; |
| | | |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | |
| | | th, |
| | | td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | .print-preview-container { |
| | | .print-preview-header { |
| | | padding: 15px; |
| | | border-bottom: 1px solid #e4e7ed; |
| | | text-align: center; |
| | | font-size: 14px; |
| | | line-height: 1.4; |
| | | |
| | | .el-button { |
| | | margin: 0 10px; |
| | | } |
| | | } |
| | | |
| | | th { |
| | | .print-preview-content { |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | | min-height: 400px; |
| | | } |
| | | } |
| | | |
| | | .print-page { |
| | | width: 220mm; |
| | | height: 90mm; |
| | | padding: 10mm; |
| | | margin: 0 auto; |
| | | background: white; |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
| | | margin-bottom: 10px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-family: "SimSun", serif; |
| | | font-size: 10px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .total-label { |
| | | text-align: right; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .total-value { |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .footer-section { |
| | | .footer-row { |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | .info-row { |
| | | line-height: 20px; |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | width: 60px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | &.address-item { |
| | | .address-value { |
| | | min-width: 200px; |
| | | .table-section { |
| | | margin-bottom: 4px; |
| | | flex: 1; |
| | | |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | |
| | | th, |
| | | td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | text-align: center; |
| | | font-size: 14px; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | th { |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .total-label { |
| | | text-align: right; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .footer-section { |
| | | .footer-row { |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 20px; |
| | | justify-content: space-between; |
| | | |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .value { |
| | | min-width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | &.address-item { |
| | | .address-value { |
| | | min-width: 200px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @media print { |
| | | .app-container { |
| | | display: none; |
| | | @media print { |
| | | .app-container { |
| | | display: none; |
| | | } |
| | | |
| | | .print-page { |
| | | box-shadow: none; |
| | | margin: 0; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | |
| | | .print-page { |
| | | box-shadow: none; |
| | | margin: 0; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | .actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-bottom: 10px; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-bottom: 10px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div> |
| | | <div class="search_form" style="margin-bottom: 10px;"> |
| | | <el-form |
| | | ref="searchFormRef" |
| | | :model="searchForm" |
| | | class="demo-form-inline" |
| | | > |
| | | <div class="search_form" |
| | | style="margin-bottom: 10px;"> |
| | | <el-form ref="searchFormRef" |
| | | :model="searchForm" |
| | | class="demo-form-inline"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="4"> |
| | | <el-form-item label="入库日期" prop="timeStr"> |
| | | <el-form-item label="入库日期" |
| | | prop="timeStr"> |
| | | <el-date-picker v-model="searchForm.timeStr" |
| | | type="date" |
| | | placeholder="请选择日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="产品大类" prop="productName"> |
| | | <el-form-item label="产品大类" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="4"> |
| | | <el-form-item label="产品规格" prop="model"> |
| | | <el-form-item label="规格型号" |
| | | prop="model"> |
| | | <el-input v-model="searchForm.model" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="批号" prop="batchNo"> |
| | | <el-form-item label="批号" |
| | | prop="batchNo"> |
| | | <el-input v-model="searchForm.batchNo" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="来源" prop="recordType"> |
| | | <el-form-item label="来源" |
| | | prop="recordType"> |
| | | <el-select v-model="searchForm.recordType" |
| | | style="width: 240px" |
| | | placeholder="请选择" |
| | |
| | | <el-option v-for="item in stockRecordTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value"/> |
| | | :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- 按钮 --> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getList"> |
| | | <el-button type="primary" |
| | | @click="getList"> |
| | | 搜索 |
| | | </el-button> |
| | | |
| | | <el-button @click="resetSearch"> |
| | | 重置 |
| | | </el-button> |
| | |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | :selectable="isRowSelectable" |
| | | width="55"/> |
| | | width="55" /> |
| | | <el-table-column align="center" |
| | | label="序号" |
| | | type="index" |
| | | width="60"/> |
| | | width="60" /> |
| | | <el-table-column label="入库批次" |
| | | prop="inboundBatches" |
| | | width="200" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="入库时间" |
| | | prop="createTime" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="产品大类" |
| | | prop="productName" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="规格型号" |
| | | prop="model" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="批号" |
| | | prop="batchNo" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="单位" |
| | | prop="unit" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="入库数量" |
| | | prop="stockInNum" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="入库人" |
| | | prop="createBy" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="来源" |
| | | prop="recordType" |
| | | show-overflow-tooltip> |
| | |
| | | {{ getRecordType(scope.row.recordType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | v-if="showSourceOrderNoColumn" |
| | | label="源单号" |
| | | width="150" |
| | | prop="sourceOrderNo" |
| | | show-overflow-tooltip> |
| | | <el-table-column v-if="showSourceOrderNoColumn" |
| | | label="源单号" |
| | | width="150" |
| | | prop="sourceOrderNo" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ formatSourceOrderNo(scope.row?.sourceOrderNo) }} |
| | | </template> |
| | |
| | | prop="approvalStatus" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" size="small"> |
| | | <el-tag :type="getApprovalStatusTagType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | {{ getApprovalStatusLabel(scope.row.approvalStatus) }} |
| | | </el-tag> |
| | | </template> |
| | |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | @pagination="pageProductChange"/> |
| | | @pagination="pageProductChange" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | ref, |
| | | reactive, |
| | | toRefs, |
| | | computed, |
| | | onMounted, |
| | | getCurrentInstance, |
| | | } from "vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import { |
| | | getStockInRecordListPage, |
| | | batchDeletePendingStockInRecords, |
| | | batchApproveStockInRecords, |
| | | batchUnapproveStockInRecords, |
| | | } from "@/api/inventoryManagement/stockInRecord.js"; |
| | | import { |
| | | findAllQualifiedStockInRecordTypeOptions, |
| | | // findAllUnQualifiedStockInRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | ref, |
| | | reactive, |
| | | toRefs, |
| | | computed, |
| | | onMounted, |
| | | getCurrentInstance, |
| | | } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | | getStockInRecordListPage, |
| | | batchDeletePendingStockInRecords, |
| | | batchApproveStockInRecords, |
| | | batchUnapproveStockInRecords, |
| | | } from "@/api/inventoryManagement/stockInRecord.js"; |
| | | import { |
| | | findAllQualifiedStockInRecordTypeOptions, |
| | | // findAllUnQualifiedStockInRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | |
| | | const {proxy} = getCurrentInstance(); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | const props = defineProps({ |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: '0' |
| | | }, |
| | | topParentProductId: { |
| | | type: [String, Number], |
| | | default: undefined |
| | | } |
| | | }) |
| | | const props = defineProps({ |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: "0", |
| | | }, |
| | | topParentProductId: { |
| | | type: [String, Number], |
| | | default: undefined, |
| | | }, |
| | | }); |
| | | |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | // 来源类型选项 |
| | | const stockRecordTypeOptions = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | }); |
| | | const total = ref(0); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | // 来源类型选项 |
| | | const stockRecordTypeOptions = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 10, |
| | | }); |
| | | const total = ref(0); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: "", |
| | | batchNo: "", |
| | | model: "", |
| | | timeStr: "", |
| | | recordType: "", |
| | | }, |
| | | }); |
| | | const {searchForm} = toRefs(data); |
| | | const searchFormRef = ref(null); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: "", |
| | | batchNo: "", |
| | | model: "", |
| | | timeStr: "", |
| | | recordType: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const searchFormRef = ref(null); |
| | | |
| | | const resetSearch = () => { |
| | | searchFormRef.value?.resetFields(); |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | const resetSearch = () => { |
| | | searchFormRef.value?.resetFields(); |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const getRecordType = (recordType) => { |
| | | return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || '' |
| | | } |
| | | const getRecordType = recordType => { |
| | | return ( |
| | | stockRecordTypeOptions.value.find(item => item.value === recordType) |
| | | ?.label || "" |
| | | ); |
| | | }; |
| | | |
| | | const approvalStatusLabelMap = { |
| | | 0: "待审批", |
| | | 1: "通过", |
| | | 2: "驳回", |
| | | pending: "待审批", |
| | | approved: "通过", |
| | | rejected: "驳回", |
| | | PENDING: "待审批", |
| | | APPROVED: "通过", |
| | | REJECTED: "驳回", |
| | | }; |
| | | approvalStatusLabelMap[3] = "待确认"; |
| | | const approvalStatusLabelMap = { |
| | | 0: "待审批", |
| | | 1: "通过", |
| | | 2: "驳回", |
| | | pending: "待审批", |
| | | approved: "通过", |
| | | rejected: "驳回", |
| | | PENDING: "待审批", |
| | | APPROVED: "通过", |
| | | REJECTED: "驳回", |
| | | }; |
| | | approvalStatusLabelMap[3] = "待确认"; |
| | | |
| | | const getApprovalStatusLabel = (status) => { |
| | | if (status === null || status === undefined || status === "") { |
| | | return "待审批"; |
| | | } |
| | | return approvalStatusLabelMap[status] || "待审批"; |
| | | }; |
| | | const getApprovalStatusLabel = status => { |
| | | if (status === null || status === undefined || status === "") { |
| | | return "待审批"; |
| | | } |
| | | return approvalStatusLabelMap[status] || "待审批"; |
| | | }; |
| | | |
| | | // 通过/驳回固定色;其余(含待审批、空值、未映射但文案为待审批)统一用 warning 预警色 |
| | | const getApprovalStatusTagType = (status) => { |
| | | if (status === 1 || status === "1" || status === "approved" || status === "APPROVED") return "success"; |
| | | if (status === 2 || status === "2" || status === "rejected" || status === "REJECTED") return "danger"; |
| | | return "warning"; |
| | | }; |
| | | // 通过/驳回固定色;其余(含待审批、空值、未映射但文案为待审批)统一用 warning 预警色 |
| | | const getApprovalStatusTagType = status => { |
| | | if ( |
| | | status === 1 || |
| | | status === "1" || |
| | | status === "approved" || |
| | | status === "APPROVED" |
| | | ) |
| | | return "success"; |
| | | if ( |
| | | status === 2 || |
| | | status === "2" || |
| | | status === "rejected" || |
| | | status === "REJECTED" |
| | | ) |
| | | return "danger"; |
| | | return "warning"; |
| | | }; |
| | | |
| | | const isPendingApproval = status => { |
| | | return status === 0 || status === "0" || status === "pending" || status === "PENDING" || status === null || status === undefined || status === ""; |
| | | }; |
| | | const isPendingApproval = status => { |
| | | return ( |
| | | status === 0 || |
| | | status === "0" || |
| | | status === "pending" || |
| | | status === "PENDING" || |
| | | status === null || |
| | | status === undefined || |
| | | status === "" |
| | | ); |
| | | }; |
| | | |
| | | const isRejectedApproval = status => { |
| | | return status === 2 || status === "2" || status === "rejected" || status === "REJECTED"; |
| | | }; |
| | | const isRejectedApproval = status => { |
| | | return ( |
| | | status === 2 || |
| | | status === "2" || |
| | | status === "rejected" || |
| | | status === "REJECTED" |
| | | ); |
| | | }; |
| | | |
| | | const isRowSelectable = row => { |
| | | return isPendingApproval(row?.approvalStatus) || isRejectedApproval(row?.approvalStatus); |
| | | }; |
| | | const isRowSelectable = row => { |
| | | return ( |
| | | isPendingApproval(row?.approvalStatus) || |
| | | isRejectedApproval(row?.approvalStatus) |
| | | ); |
| | | }; |
| | | |
| | | const canBatchApprove = computed(() => { |
| | | return selectedRows.value.length > 0 |
| | | && selectedRows.value.every(row => isPendingApproval(row.approvalStatus)); |
| | | }); |
| | | const canBatchApprove = computed(() => { |
| | | return ( |
| | | selectedRows.value.length > 0 && |
| | | selectedRows.value.every(row => isPendingApproval(row.approvalStatus)) |
| | | ); |
| | | }); |
| | | |
| | | const canReverseApprove = computed(() => { |
| | | return selectedRows.value.length > 0 |
| | | && selectedRows.value.every(row => isRejectedApproval(row.approvalStatus)); |
| | | }); |
| | | const canReverseApprove = computed(() => { |
| | | return ( |
| | | selectedRows.value.length > 0 && |
| | | selectedRows.value.every(row => isRejectedApproval(row.approvalStatus)) |
| | | ); |
| | | }); |
| | | |
| | | const canDelete = computed(() => canBatchApprove.value); |
| | | const showSourceOrderNoColumn = computed(() => { |
| | | const topParentProductId = Number(props.topParentProductId); |
| | | return topParentProductId === 276 || topParentProductId === 278; |
| | | }); |
| | | const canDelete = computed(() => canBatchApprove.value); |
| | | const showSourceOrderNoColumn = computed(() => { |
| | | const topParentProductId = Number(props.topParentProductId); |
| | | return topParentProductId === 276 || topParentProductId === 278; |
| | | }); |
| | | |
| | | const formatSourceOrderNo = (value) => { |
| | | const text = String(value ?? "").trim(); |
| | | return text || "--"; |
| | | }; |
| | | const formatSourceOrderNo = value => { |
| | | const text = String(value ?? "").trim(); |
| | | return text || "--"; |
| | | }; |
| | | |
| | | const pageProductChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const pageProductChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockInRecordListPage(Object.assign({}, {...searchForm.value, ...page, topParentProductId: props.topParentProductId})) |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockInRecordListPage( |
| | | Object.assign( |
| | | {}, |
| | | { |
| | | ...searchForm.value, |
| | | ...page, |
| | | topParentProductId: props.topParentProductId, |
| | | } |
| | | ) |
| | | ) |
| | | .then(res => { |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total || 0; |
| | | }).finally(() => { |
| | | tableLoading.value = false; |
| | | }) |
| | | }; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // 获取来源类型选项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === '0') { |
| | | findAllQualifiedStockInRecordTypeOptions() |
| | | .then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }) |
| | | return |
| | | } |
| | | // findAllUnQualifiedStockInRecordTypeOptions() |
| | | // .then(res => { |
| | | // stockRecordTypeOptions.value = res.data; |
| | | // }) |
| | | } |
| | | // 获取来源类型选项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === "0") { |
| | | findAllQualifiedStockInRecordTypeOptions().then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }); |
| | | return; |
| | | } |
| | | // findAllUnQualifiedStockInRecordTypeOptions() |
| | | // .then(res => { |
| | | // stockRecordTypeOptions.value = res.data; |
| | | // }) |
| | | }; |
| | | |
| | | // 表格选择数据 |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection.filter(item => item.id && isRowSelectable(item)); |
| | | }; |
| | | // 表格选择数据 |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection.filter( |
| | | item => item.id && isRowSelectable(item) |
| | | ); |
| | | }; |
| | | |
| | | const expandedRowKeys = ref([]); |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | const handleReverseApprove = () => { |
| | | if (!canReverseApprove.value) { |
| | | proxy.$modal.msgWarning("请选择已驳回的数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("反审后记录将恢复为待审批状态,是否确认反审?", "反审", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | const handleReverseApprove = () => { |
| | | if (!canReverseApprove.value) { |
| | | proxy.$modal.msgWarning("请选择已驳回的数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("反审后记录将恢复为待审批状态,是否确认反审?", "反审", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | batchUnapproveStockInRecords({ids}) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("反审成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("反审失败"); |
| | | }); |
| | | batchUnapproveStockInRecords({ ids }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("反审成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("反审失败"); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | const handleBatchApprove = () => { |
| | | if (!canBatchApprove.value) { |
| | | proxy.$modal.msgWarning("请选择待审批的数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("请选择审批结果", "审批", { |
| | | confirmButtonText: "通过", |
| | | cancelButtonText: "驳回", |
| | | type: "warning", |
| | | distinguishCancelAndClose: true, |
| | | }) |
| | | const handleBatchApprove = () => { |
| | | if (!canBatchApprove.value) { |
| | | proxy.$modal.msgWarning("请选择待审批的数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | ElMessageBox.confirm("请选择审批结果", "审批", { |
| | | confirmButtonText: "通过", |
| | | cancelButtonText: "驳回", |
| | | type: "warning", |
| | | distinguishCancelAndClose: true, |
| | | }) |
| | | .then(() => { |
| | | batchApproveStockInRecords({ids, approvalStatus: 1}) |
| | | batchApproveStockInRecords({ ids, approvalStatus: 1 }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("审批通过成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("审批通过失败"); |
| | | }); |
| | | }) |
| | | .catch(action => { |
| | | if (action === "cancel") { |
| | | batchApproveStockInRecords({ ids, approvalStatus: 2 }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("审批通过成功"); |
| | | proxy.$modal.msgSuccess("审批驳回成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("审批通过失败"); |
| | | proxy.$modal.msgError("审批驳回失败"); |
| | | }); |
| | | }) |
| | | .catch((action) => { |
| | | if (action === "cancel") { |
| | | batchApproveStockInRecords({ids, approvalStatus: 2}) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("审批驳回成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("审批驳回失败"); |
| | | }); |
| | | return; |
| | | } |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | // 导出 |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | // 导出 |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | // 根据不同的 tab 类型调用不同的导出接口 |
| | | proxy.download("/stockInRecord/exportStockInRecord", {type: props.type}, props.type === '0' ? "合格入库.xlsx" : "不合格入库.xlsx"); |
| | | proxy.download( |
| | | "/stockInRecord/exportStockInRecord", |
| | | { type: props.type }, |
| | | props.type === "0" ? "合格入库.xlsx" : "不合格入库.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | // 删除 |
| | | const handleDelete = () => { |
| | | if (!canDelete.value) { |
| | | proxy.$modal.msgWarning("请选择待审批的数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | // 删除 |
| | | const handleDelete = () => { |
| | | if (!canDelete.value) { |
| | | proxy.$modal.msgWarning("请选择待审批的数据"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | batchDeletePendingStockInRecords(ids) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("删除失败"); |
| | | }); |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("删除失败"); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | fetchStockRecordTypeOptions(); |
| | | }); |
| | | |
| | | watch( |
| | | () => props.topParentProductId, |
| | | () => { |
| | | page.current = 1; |
| | | onMounted(() => { |
| | | getList(); |
| | | } |
| | | ); |
| | | fetchStockRecordTypeOptions(); |
| | | }); |
| | | |
| | | watch( |
| | | () => props.topParentProductId, |
| | | () => { |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | ); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-bottom: 10px; |
| | | } |
| | | .actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-bottom: 10px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div> |
| | | <div class="search_form mb10"> |
| | | <el-form |
| | | ref="searchFormRef" |
| | | :model="searchForm" |
| | | class="demo-form-inline" |
| | | > |
| | | <el-form ref="searchFormRef" |
| | | :model="searchForm" |
| | | class="demo-form-inline"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="4"> |
| | | <el-form-item label="产品大类" prop="productName"> |
| | | <el-form-item label="产品大类" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="4"> |
| | | <el-form-item label="产品规格" prop="model"> |
| | | <el-form-item label="规格型号" |
| | | prop="model"> |
| | | <el-input v-model="searchForm.model" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="批号" prop="batchNo"> |
| | | <el-form-item label="批号" |
| | | prop="batchNo"> |
| | | <el-input v-model="searchForm.batchNo" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- 按钮 --> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getList"> |
| | | <el-button type="primary" |
| | | @click="getList"> |
| | | 搜索 |
| | | </el-button> |
| | | |
| | | <el-button @click="resetSearch"> |
| | | 重置 |
| | | </el-button> |
| | |
| | | </el-row> |
| | | </el-form> |
| | | <div> |
| | | <el-button type="primary" @click="isShowNewModal = true" |
| | | >新增库存</el-button |
| | | > |
| | | <el-button |
| | | type="info" |
| | | plain |
| | | icon="Upload" |
| | | @click="isShowImportModal = true" |
| | | > |
| | | <el-button type="primary" |
| | | @click="isShowNewModal = true">新增库存</el-button> |
| | | <el-button type="info" |
| | | plain |
| | | icon="Upload" |
| | | @click="isShowImportModal = true"> |
| | | 导入库存 |
| | | </el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row, index) => index" |
| | | style="width: 100%" |
| | | :row-class-name="tableRowClassName" |
| | | height="calc(100vh - 18.5em)" |
| | | > |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column |
| | | label="产品名称" |
| | | prop="productName" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="规格型号" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="单位" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="批号" prop="batchNo" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="合格库存数量" |
| | | prop="qualifiedQuantity" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="不合格库存数量" |
| | | prop="unQualifiedQuantity" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="合格冻结数量" |
| | | prop="qualifiedLockedQuantity" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="不合格冻结数量" |
| | | prop="unQualifiedLockedQuantity" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="库存预警数量" |
| | | prop="warnNum" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="备注" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column |
| | | label="最近更新时间" |
| | | prop="updateTime" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | fixed="right" |
| | | label="操作" |
| | | min-width="80" |
| | | align="center" |
| | | > |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row, index) => index" |
| | | style="width: 100%" |
| | | :row-class-name="tableRowClassName" |
| | | height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" /> |
| | | <el-table-column align="center" |
| | | label="序号" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="产品名称" |
| | | prop="productName" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="规格型号" |
| | | prop="model" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="单位" |
| | | prop="unit" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="批号" |
| | | prop="batchNo" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="合格库存数量" |
| | | prop="qualifiedQuantity" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="不合格库存数量" |
| | | prop="unQualifiedQuantity" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="合格冻结数量" |
| | | prop="qualifiedLockedQuantity" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="不合格冻结数量" |
| | | prop="unQualifiedLockedQuantity" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="库存预警数量" |
| | | prop="warnNum" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="备注" |
| | | prop="remark" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" |
| | | prop="updateTime" |
| | | show-overflow-tooltip /> |
| | | <el-table-column fixed="right" |
| | | label="操作" |
| | | min-width="80" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | @click="showDetailModal(scope.row)" |
| | | >详情</el-button |
| | | > |
| | | <el-button link |
| | | type="primary" |
| | | @click="showDetailModal(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" |
| | | /> |
| | | <pagination v-show="total > 0" |
| | | :total="total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | @pagination="paginationChange" /> |
| | | </div> |
| | | <batch-no-qty-detail |
| | | v-if="isShowDetailModal" |
| | | v-model:visible="isShowDetailModal" |
| | | :record="record" |
| | | @subtract="handleDetailSubtract" |
| | | @frozen="handleDetailFrozen" |
| | | @thaw="handleDetailThaw" |
| | | /> |
| | | <new-stock-inventory |
| | | v-if="isShowNewModal" |
| | | v-model:visible="isShowNewModal" |
| | | :top-product-parent-id="props.productId" |
| | | @completed="handleQuery" |
| | | /> |
| | | |
| | | <subtract-stock-inventory |
| | | v-if="isShowSubtractModal" |
| | | v-model:visible="isShowSubtractModal" |
| | | :record="record" |
| | | :type="record.stockType" |
| | | @completed="handleQuery" |
| | | /> |
| | | <batch-no-qty-detail v-if="isShowDetailModal" |
| | | v-model:visible="isShowDetailModal" |
| | | :record="record" |
| | | @subtract="handleDetailSubtract" |
| | | @frozen="handleDetailFrozen" |
| | | @thaw="handleDetailThaw" /> |
| | | <new-stock-inventory v-if="isShowNewModal" |
| | | v-model:visible="isShowNewModal" |
| | | :top-product-parent-id="props.productId" |
| | | @completed="handleQuery" /> |
| | | <subtract-stock-inventory v-if="isShowSubtractModal" |
| | | v-model:visible="isShowSubtractModal" |
| | | :record="record" |
| | | :type="record.stockType" |
| | | @completed="handleQuery" /> |
| | | <!-- 导入库存--> |
| | | <import-stock-inventory |
| | | v-if="isShowImportModal" |
| | | v-model:visible="isShowImportModal" |
| | | type="qualified" |
| | | @uploadSuccess="handleQuery" |
| | | /> |
| | | <import-stock-inventory v-if="isShowImportModal" |
| | | v-model:visible="isShowImportModal" |
| | | type="qualified" |
| | | @uploadSuccess="handleQuery" /> |
| | | <!-- 冻结/解冻库存--> |
| | | <frozen-and-thaw-stock-inventory |
| | | v-if="isShowFrozenAndThawModal" |
| | | v-model:visible="isShowFrozenAndThawModal" |
| | | :record="record" |
| | | :operation-type="operationType" |
| | | :type="record.stockType" |
| | | @completed="handleQuery" |
| | | /> |
| | | <frozen-and-thaw-stock-inventory v-if="isShowFrozenAndThawModal" |
| | | v-model:visible="isShowFrozenAndThawModal" |
| | | :record="record" |
| | | :operation-type="operationType" |
| | | :type="record.stockType" |
| | | @completed="handleQuery" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { getStockInventoryListPageCombined } from "@/api/inventoryManagement/stockInventory.js"; |
| | | const props = defineProps({ |
| | | productId: { |
| | | type: Number, |
| | | required: true, |
| | | default: 0, |
| | | }, |
| | | }); |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { getStockInventoryListPageCombined } from "@/api/inventoryManagement/stockInventory.js"; |
| | | const props = defineProps({ |
| | | productId: { |
| | | type: Number, |
| | | required: true, |
| | | default: 0, |
| | | }, |
| | | }); |
| | | |
| | | const NewStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/New.vue") |
| | | ); |
| | | const SubtractStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/Subtract.vue") |
| | | ); |
| | | const ImportStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/Import.vue") |
| | | ); |
| | | const FrozenAndThawStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue") |
| | | ); |
| | | const BatchNoQtyDetail = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const record = ref({}); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | // 是否显示新增弹框 |
| | | const isShowNewModal = ref(false); |
| | | // 是否显示领用弹框 |
| | | const isShowSubtractModal = ref(false); |
| | | // 是否显示冻结/解冻弹框 |
| | | const isShowFrozenAndThawModal = ref(false); |
| | | // 是否显示详情弹框 |
| | | const isShowDetailModal = ref(false); |
| | | // 操作类型 |
| | | const operationType = ref("frozen"); |
| | | // 是否显示导入弹框 |
| | | const isShowImportModal = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: "", |
| | | model: "", |
| | | batchNo: "", |
| | | topParentProductId: props.productId, |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const searchFormRef = ref(null); |
| | | const NewStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/New.vue") |
| | | ); |
| | | const SubtractStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/Subtract.vue") |
| | | ); |
| | | const ImportStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/Import.vue") |
| | | ); |
| | | const FrozenAndThawStockInventory = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue") |
| | | ); |
| | | const BatchNoQtyDetail = defineAsyncComponent(() => |
| | | import("@/views/inventoryManagement/stockManagement/BatchNoQtyDetail.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const record = ref({}); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | // 是否显示新增弹框 |
| | | const isShowNewModal = ref(false); |
| | | // 是否显示领用弹框 |
| | | const isShowSubtractModal = ref(false); |
| | | // 是否显示冻结/解冻弹框 |
| | | const isShowFrozenAndThawModal = ref(false); |
| | | // 是否显示详情弹框 |
| | | const isShowDetailModal = ref(false); |
| | | // 操作类型 |
| | | const operationType = ref("frozen"); |
| | | // 是否显示导入弹框 |
| | | const isShowImportModal = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: "", |
| | | model: "", |
| | | batchNo: "", |
| | | topParentProductId: props.productId, |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const searchFormRef = ref(null); |
| | | |
| | | const resetSearch = () => { |
| | | searchFormRef.value?.resetFields(); |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | const resetSearch = () => { |
| | | searchFormRef.value?.resetFields(); |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const paginationChange = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockInventoryListPageCombined({ ...searchForm.value, ...page }) |
| | | .then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | // 数据加载完成后检查库存 |
| | | // checkStockAndCreatePurchase(); |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getStockInventoryListPageCombined({ ...searchForm.value, ...page }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | // 数据加载完成后检查库存 |
| | | // checkStockAndCreatePurchase(); |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleFileSuccess = response => { |
| | | const { code, msg } = response; |
| | | if (code == 200) { |
| | | ElMessage({ message: "导入成功", type: "success" }); |
| | | upload.open = false; |
| | | emits("uploadSuccess"); |
| | | } else { |
| | | ElMessage({ message: msg, type: "error" }); |
| | | } |
| | | }; |
| | | |
| | | // 点击领用 |
| | | const showSubtractModal = row => { |
| | | record.value = row; |
| | | isShowSubtractModal.value = true; |
| | | }; |
| | | |
| | | // 点击详情 |
| | | const showDetailModal = row => { |
| | | if (!row?.productId || !row?.productModelId) { |
| | | proxy.$modal.msgError("当前数据缺少产品ID或规格型号ID"); |
| | | return; |
| | | } |
| | | record.value = row; |
| | | isShowDetailModal.value = true; |
| | | }; |
| | | |
| | | const handleDetailSubtract = row => { |
| | | isShowDetailModal.value = false; |
| | | showSubtractModal(row); |
| | | }; |
| | | |
| | | const handleDetailFrozen = row => { |
| | | isShowDetailModal.value = false; |
| | | showFrozenModal(row); |
| | | }; |
| | | |
| | | const handleDetailThaw = row => { |
| | | isShowDetailModal.value = false; |
| | | showThawModal(row); |
| | | }; |
| | | |
| | | // 点击冻结 |
| | | const showFrozenModal = row => { |
| | | record.value = row; |
| | | isShowFrozenAndThawModal.value = true; |
| | | operationType.value = "frozen"; |
| | | }; |
| | | |
| | | // 点击解冻 |
| | | const showThawModal = row => { |
| | | record.value = row; |
| | | isShowFrozenAndThawModal.value = true; |
| | | operationType.value = "thaw"; |
| | | }; |
| | | |
| | | // 表格选择数据 |
| | | const handleSelectionChange = selection => { |
| | | // 过滤掉子数据 |
| | | selectedRows.value = selection.filter(item => item.id); |
| | | console.log("selection", selectedRows.value); |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | // 表格行类名 |
| | | const tableRowClassName = ({ row }) => { |
| | | const stock = Number(row?.qualifiedUnLockedQuantity ?? 0); |
| | | const warn = Number(row?.warnNum ?? 0); |
| | | if (!Number.isFinite(stock) || !Number.isFinite(warn)) { |
| | | return ""; |
| | | } |
| | | return stock < warn ? "row-low-stock" : ""; |
| | | }; |
| | | |
| | | // 导出 |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | .then(() => { |
| | | proxy.download( |
| | | "/stockInventory/exportStockInventory", |
| | | { topParentProductId: props.productId }, |
| | | "库存信息.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | |
| | | const handleFileSuccess = (response) => { |
| | | const { code, msg } = response; |
| | | if (code == 200) { |
| | | ElMessage({ message: "导入成功", type: "success" }); |
| | | upload.open = false; |
| | | emits("uploadSuccess"); |
| | | } else { |
| | | ElMessage({ message: msg, type: "error" }); |
| | | } |
| | | }; |
| | | |
| | | // 点击领用 |
| | | const showSubtractModal = (row) => { |
| | | record.value = row; |
| | | isShowSubtractModal.value = true; |
| | | }; |
| | | |
| | | // 点击详情 |
| | | const showDetailModal = (row) => { |
| | | if (!row?.productId || !row?.productModelId) { |
| | | proxy.$modal.msgError("当前数据缺少产品ID或规格型号ID"); |
| | | return; |
| | | } |
| | | record.value = row; |
| | | isShowDetailModal.value = true; |
| | | }; |
| | | |
| | | const handleDetailSubtract = (row) => { |
| | | isShowDetailModal.value = false; |
| | | showSubtractModal(row); |
| | | }; |
| | | |
| | | const handleDetailFrozen = (row) => { |
| | | isShowDetailModal.value = false; |
| | | showFrozenModal(row); |
| | | }; |
| | | |
| | | const handleDetailThaw = (row) => { |
| | | isShowDetailModal.value = false; |
| | | showThawModal(row); |
| | | }; |
| | | |
| | | // 点击冻结 |
| | | const showFrozenModal = (row) => { |
| | | record.value = row; |
| | | isShowFrozenAndThawModal.value = true; |
| | | operationType.value = "frozen"; |
| | | }; |
| | | |
| | | // 点击解冻 |
| | | const showThawModal = (row) => { |
| | | record.value = row; |
| | | isShowFrozenAndThawModal.value = true; |
| | | operationType.value = "thaw"; |
| | | }; |
| | | |
| | | // 表格选择数据 |
| | | const handleSelectionChange = (selection) => { |
| | | // 过滤掉子数据 |
| | | selectedRows.value = selection.filter((item) => item.id); |
| | | console.log("selection", selectedRows.value); |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | // 表格行类名 |
| | | const tableRowClassName = ({ row }) => { |
| | | const stock = Number(row?.qualifiedUnLockedQuantity ?? 0); |
| | | const warn = Number(row?.warnNum ?? 0); |
| | | if (!Number.isFinite(stock) || !Number.isFinite(warn)) { |
| | | return ""; |
| | | } |
| | | return stock < warn ? "row-low-stock" : ""; |
| | | }; |
| | | |
| | | // 导出 |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download( |
| | | "/stockInventory/exportStockInventory", |
| | | { topParentProductId: props.productId }, |
| | | "库存信息.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | | } |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | | } |
| | | |
| | | :deep(.row-low-stock:hover > td) { |
| | | background-color: #fcd4d4; |
| | | } |
| | | :deep(.row-low-stock:hover > td) { |
| | | background-color: #fcd4d4; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- 搜索区域 --> |
| | | <el-card class="search-card" shadow="never"> |
| | | <el-form :model="searchForm" :inline="true" class="search-form"> |
| | | <el-card class="search-card" |
| | | shadow="never"> |
| | | <el-form :model="searchForm" |
| | | :inline="true" |
| | | class="search-form"> |
| | | <el-form-item label="计划名称"> |
| | | <el-input v-model="searchForm.planName" placeholder="请输入计划名称" clearable /> |
| | | <el-input v-model="searchForm.planName" |
| | | placeholder="请输入计划名称" |
| | | clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="状态"> |
| | | <el-select v-model="searchForm.status" placeholder="请选择状态" clearable style="width: 150px"> |
| | | <el-option label="启用" value="active" /> |
| | | <el-option label="禁用" value="disabled" /> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="请选择状态" |
| | | clearable |
| | | style="width: 150px"> |
| | | <el-option label="启用" |
| | | value="active" /> |
| | | <el-option label="禁用" |
| | | value="disabled" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleSearch"> |
| | | <el-icon><Search /></el-icon> |
| | | <el-button type="primary" |
| | | @click="handleSearch"> |
| | | <el-icon> |
| | | <Search /> |
| | | </el-icon> |
| | | 搜索 |
| | | </el-button> |
| | | <el-button @click="handleReset"> |
| | | <el-icon><Refresh /></el-icon> |
| | | <el-icon> |
| | | <Refresh /> |
| | | </el-icon> |
| | | 重置 |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <el-card class="table-card" shadow="never"> |
| | | <el-card class="table-card" |
| | | shadow="never"> |
| | | <div class="table-header"> |
| | | <div class="table-title">采购计划列表</div> |
| | | <div class="table-actions"> |
| | | <el-button type="primary" @click="handleAdd"> |
| | | <el-icon><Plus /></el-icon> |
| | | <el-button type="primary" |
| | | @click="handleAdd"> |
| | | <el-icon> |
| | | <Plus /> |
| | | </el-icon> |
| | | 新增计划 |
| | | </el-button> |
| | | <el-button type="info" @click="handleExport"> |
| | | <el-icon><Download /></el-icon> |
| | | <el-button type="info" |
| | | @click="handleExport"> |
| | | <el-icon> |
| | | <Download /> |
| | | </el-icon> |
| | | 导出 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 数据表格 --> |
| | | <el-table |
| | | v-loading="loading" |
| | | :data="tableData" |
| | | stripe |
| | | border |
| | | style="width: 100%" |
| | | > |
| | | <el-table-column prop="planName" label="计划名称" min-width="150" /> |
| | | <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip /> |
| | | <el-table-column prop="formula" label="计算公式" min-width="200" show-overflow-tooltip> |
| | | <el-table v-loading="loading" |
| | | :data="tableData" |
| | | stripe |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="planName" |
| | | label="计划名称" |
| | | min-width="150" /> |
| | | <el-table-column prop="description" |
| | | label="描述" |
| | | min-width="200" |
| | | show-overflow-tooltip /> |
| | | <el-table-column prop="formula" |
| | | label="计算公式" |
| | | min-width="200" |
| | | show-overflow-tooltip> |
| | | <template #default="{ row }"> |
| | | <el-tag type="info" size="small">{{ row.formula }}</el-tag> |
| | | <el-tag type="info" |
| | | size="small">{{ row.formula }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="状态" width="80" align="center"> |
| | | <el-table-column prop="status" |
| | | label="状态" |
| | | width="80" |
| | | align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.status === 'active' ? 'success' : 'info'" size="small"> |
| | | <el-tag :type="row.status === 'active' ? 'success' : 'info'" |
| | | size="small"> |
| | | {{ row.status === 'active' ? '启用' : '禁用' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="updateTime" label="最后计算时间" width="160" /> |
| | | <el-table-column label="操作" width="200" fixed="right" align="center"> |
| | | <el-table-column prop="updateTime" |
| | | label="最后计算时间" |
| | | width="160" /> |
| | | <el-table-column label="操作" |
| | | width="200" |
| | | fixed="right" |
| | | align="center"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" link @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="success" link @click="handleCalculate(row)">计算</el-button> |
| | | <el-button type="danger" link @click="handleDelete(row)">删除</el-button> |
| | | <el-button type="primary" |
| | | link |
| | | @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="success" |
| | | link |
| | | @click="handleCalculate(row)">计算</el-button> |
| | | <el-button type="danger" |
| | | link |
| | | @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- 分页 --> |
| | | <div class="pagination-container"> |
| | | <el-pagination |
| | | v-model:current-page="pagination.current" |
| | | v-model:page-size="pagination.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | <el-pagination v-model:current-page="pagination.current" |
| | | v-model:page-size="pagination.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" /> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 新增/编辑对话框 --> |
| | | <FormDialog |
| | | v-model="dialogVisible" |
| | | :title="dialogType === 'add' ? '新增采购计划' : '编辑采购计划'" |
| | | :width="'1000px'" |
| | | :operation-type="dialogType" |
| | | :close-on-click-modal="false" |
| | | @close="dialogVisible = false" |
| | | @confirm="handleSubmit" |
| | | @cancel="dialogVisible = false" |
| | | > |
| | | <FormDialog v-model="dialogVisible" |
| | | :title="dialogType === 'add' ? '新增采购计划' : '编辑采购计划'" |
| | | :width="'1000px'" |
| | | :operation-type="dialogType" |
| | | :close-on-click-modal="false" |
| | | @close="dialogVisible = false" |
| | | @confirm="handleSubmit" |
| | | @cancel="dialogVisible = false"> |
| | | <div class="form-container"> |
| | | <!-- 基本信息 --> |
| | | <div class="form-section"> |
| | | <div class="section-title">基本信息</div> |
| | | <el-form |
| | | ref="formRef" |
| | | :model="formData" |
| | | :rules="formRules" |
| | | label-width="120px" |
| | | > |
| | | <el-form ref="formRef" |
| | | :model="formData" |
| | | :rules="formRules" |
| | | label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="编码" prop="code"> |
| | | <el-input v-model="formData.code" placeholder="系统自动生成" disabled /> |
| | | <el-form-item label="编码" |
| | | prop="code"> |
| | | <el-input v-model="formData.code" |
| | | placeholder="系统自动生成" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="名称" prop="planName" required> |
| | | <el-input v-model="formData.planName" placeholder="请输入计划名称" /> |
| | | <el-form-item label="名称" |
| | | prop="planName" |
| | | required> |
| | | <el-input v-model="formData.planName" |
| | | placeholder="请输入计划名称" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-form-item label="描述" prop="description"> |
| | | <el-input |
| | | v-model="formData.description" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请输入计划描述" |
| | | /> |
| | | <el-form-item label="描述" |
| | | prop="description"> |
| | | <el-input v-model="formData.description" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请输入计划描述" /> |
| | | </el-form-item> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="状态" prop="status"> |
| | | <el-select v-model="formData.status" placeholder="请选择状态" style="width: 100%"> |
| | | <el-option label="启用" value="active" /> |
| | | <el-option label="禁用" value="disabled" /> |
| | | <el-form-item label="状态" |
| | | prop="status"> |
| | | <el-select v-model="formData.status" |
| | | placeholder="请选择状态" |
| | | style="width: 100%"> |
| | | <el-option label="启用" |
| | | value="active" /> |
| | | <el-option label="禁用" |
| | | value="disabled" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </el-row> |
| | | </el-form> |
| | | </div> |
| | | |
| | | <!-- 计算参数 --> |
| | | <div class="form-section"> |
| | | <div class="section-title">计算参数</div> |
| | | <el-tabs v-model="activeTab" class="param-tabs"> |
| | | <el-tab-pane label="需求参数" name="demand"> |
| | | <el-tabs v-model="activeTab" |
| | | class="param-tabs"> |
| | | <el-tab-pane label="需求参数" |
| | | name="demand"> |
| | | <div class="checkbox-group"> |
| | | <el-checkbox v-model="formData.considerExistingStock">考虑现有库存</el-checkbox> |
| | | <el-checkbox v-model="formData.warehouseControl">仓库运行MRP的控制</el-checkbox> |
| | |
| | | <el-checkbox v-model="formData.negativeStockAsDemand">负库存作为需求</el-checkbox> |
| | | </div> |
| | | </el-tab-pane> |
| | | <el-tab-pane label="计算参数" name="calculation"> |
| | | <el-tab-pane label="计算参数" |
| | | name="calculation"> |
| | | <div class="checkbox-group"> |
| | | <el-checkbox v-model="formData.considerExistingStock">考虑现有库存</el-checkbox> |
| | | <el-checkbox v-model="formData.warehouseControl">仓库运行MRP的控制</el-checkbox> |
| | |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | |
| | | <!-- 汇总合并选项 --> |
| | | <div class="form-section"> |
| | | <div class="section-title">汇总合并选项</div> |
| | |
| | | <el-checkbox v-model="formData.summaryDemandDate">需求日期</el-checkbox> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 计算公式 --> |
| | | <div class="form-section"> |
| | | <div class="section-title">计算公式</div> |
| | | <div class="formula-input-section"> |
| | | <el-form-item label="计算公式" prop="formula" required> |
| | | <el-input |
| | | v-model="formData.formula" |
| | | placeholder="例如: 预计出库数量 - 现有库存 + 安全库存 - 预计入库数量" |
| | | @input="validateFormula" |
| | | /> |
| | | <el-form-item label="计算公式" |
| | | prop="formula" |
| | | required> |
| | | <el-input v-model="formData.formula" |
| | | placeholder="例如: 预计出库数量 - 现有库存 + 安全库存 - 预计入库数量" |
| | | @input="validateFormula" /> |
| | | </el-form-item> |
| | | <div class="formula-help"> |
| | | <el-text type="info" size="small"> |
| | | <el-text type="info" |
| | | size="small"> |
| | | 支持变量:预计出库数量、现有库存、安全库存、预计入库数量 |
| | | </el-text> |
| | | </div> |
| | |
| | | </div> |
| | | </div> |
| | | </FormDialog> |
| | | |
| | | <!-- 产品选择对话框 --> |
| | | <FormDialog |
| | | v-model="productSelectDialogVisible" |
| | | title="选择产品" |
| | | :width="'800px'" |
| | | :close-on-click-modal="false" |
| | | @close="productSelectDialogVisible = false" |
| | | @confirm="handleConfirmProductSelection" |
| | | @cancel="productSelectDialogVisible = false" |
| | | > |
| | | <FormDialog v-model="productSelectDialogVisible" |
| | | title="选择产品" |
| | | :width="'800px'" |
| | | :close-on-click-modal="false" |
| | | @close="productSelectDialogVisible = false" |
| | | @confirm="handleConfirmProductSelection" |
| | | @cancel="productSelectDialogVisible = false"> |
| | | <div class="product-select"> |
| | | <el-alert |
| | | title="请选择要计算的产品" |
| | | type="info" |
| | | :closable="false" |
| | | show-icon |
| | | > |
| | | <el-alert title="请选择要计算的产品" |
| | | type="info" |
| | | :closable="false" |
| | | show-icon> |
| | | <template #default> |
| | | <p>选择产品后,系统将根据当前计算公式和产品库存情况进行计算。</p> |
| | | </template> |
| | | </el-alert> |
| | | |
| | | <el-table |
| | | v-loading="productLoading" |
| | | :data="productList" |
| | | @selection-change="handleProductSelectionChange" |
| | | stripe |
| | | border |
| | | style="width: 100%; margin-top: 20px;" |
| | | > |
| | | <el-table-column type="selection" width="55" /> |
| | | <el-table-column prop="productCategory" label="产品大类" min-width="150" /> |
| | | <el-table-column prop="specificationModel" label="产品规格" width="120" /> |
| | | <el-table-column prop="inboundNum0" label="现有库存" width="100" align="right" /> |
| | | <el-table-column prop="inboundNum" label="安全库存" width="100" align="right" /> |
| | | <el-table-column prop="inboundNum" label="预计出库" width="100" align="right" /> |
| | | <el-table-column prop="inboundNum0" label="预计入库" width="100" align="right" /> |
| | | <el-table v-loading="productLoading" |
| | | :data="productList" |
| | | @selection-change="handleProductSelectionChange" |
| | | stripe |
| | | border |
| | | style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column type="selection" |
| | | width="55" /> |
| | | <el-table-column prop="productCategory" |
| | | label="产品大类" |
| | | min-width="150" /> |
| | | <el-table-column prop="specificationModel" |
| | | label="规格型号" |
| | | width="120" /> |
| | | <el-table-column prop="inboundNum0" |
| | | label="现有库存" |
| | | width="100" |
| | | align="right" /> |
| | | <el-table-column prop="inboundNum" |
| | | label="安全库存" |
| | | width="100" |
| | | align="right" /> |
| | | <el-table-column prop="inboundNum" |
| | | label="预计出库" |
| | | width="100" |
| | | align="right" /> |
| | | <el-table-column prop="inboundNum0" |
| | | label="预计入库" |
| | | width="100" |
| | | align="right" /> |
| | | </el-table> |
| | | </div> |
| | | </FormDialog> |
| | | |
| | | <!-- 计算结果对话框 --> |
| | | <FormDialog |
| | | v-model="calculateDialogVisible" |
| | | title="采购计算结果" |
| | | :width="'1000px'" |
| | | :close-on-click-modal="false" |
| | | @close="calculateDialogVisible = false" |
| | | @confirm="handleCreatePurchaseOrder" |
| | | @cancel="calculateDialogVisible = false" |
| | | > |
| | | <FormDialog v-model="calculateDialogVisible" |
| | | title="采购计算结果" |
| | | :width="'1000px'" |
| | | :close-on-click-modal="false" |
| | | @close="calculateDialogVisible = false" |
| | | @confirm="handleCreatePurchaseOrder" |
| | | @cancel="calculateDialogVisible = false"> |
| | | <div class="calculate-result"> |
| | | <el-alert |
| | | title="计算结果" |
| | | type="success" |
| | | :closable="false" |
| | | show-icon |
| | | > |
| | | <el-alert title="计算结果" |
| | | type="success" |
| | | :closable="false" |
| | | show-icon> |
| | | <template #default> |
| | | <p>基于当前配置的计算公式和库存情况,系统已计算出各产品的采购需求。</p> |
| | | </template> |
| | | </el-alert> |
| | | |
| | | <el-table :data="calculateResult" stripe border style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="productCategory" label="产品大类" min-width="150" /> |
| | | <el-table-column prop="specificationModel" label="产品规格" width="120" /> |
| | | <el-table-column prop="inboundNum0" label="现有库存" width="100" align="right" /> |
| | | <el-table-column prop="inboundNum" label="安全库存" width="100" align="right" /> |
| | | <el-table-column prop="inboundNum" label="预计出库数量" width="120" align="right" /> |
| | | <el-table-column prop="inboundNum0" label="预计入库数量" width="120" align="right" /> |
| | | <el-table-column prop="weeklyNetDemand" label="按周净需求" width="120" align="right"> |
| | | <el-table :data="calculateResult" |
| | | stripe |
| | | border |
| | | style="width: 100%; margin-top: 20px;"> |
| | | <el-table-column prop="productCategory" |
| | | label="产品大类" |
| | | min-width="150" /> |
| | | <el-table-column prop="specificationModel" |
| | | label="规格型号" |
| | | width="120" /> |
| | | <el-table-column prop="inboundNum0" |
| | | label="现有库存" |
| | | width="100" |
| | | align="right" /> |
| | | <el-table-column prop="inboundNum" |
| | | label="安全库存" |
| | | width="100" |
| | | align="right" /> |
| | | <el-table-column prop="inboundNum" |
| | | label="预计出库数量" |
| | | width="120" |
| | | align="right" /> |
| | | <el-table-column prop="inboundNum0" |
| | | label="预计入库数量" |
| | | width="120" |
| | | align="right" /> |
| | | <el-table-column prop="weeklyNetDemand" |
| | | label="按周净需求" |
| | | width="120" |
| | | align="right"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.weeklyNetDemand > 0 ? 'warning' : 'success'" size="small"> |
| | | <el-tag :type="row.weeklyNetDemand > 0 ? 'warning' : 'success'" |
| | | size="small"> |
| | | {{ row.weeklyNetDemand }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="suggestedPurchase" label="建议采购" width="100" align="right"> |
| | | <el-table-column prop="suggestedPurchase" |
| | | label="建议采购" |
| | | width="100" |
| | | align="right"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.suggestedPurchase > 0 ? 'danger' : 'success'" size="small"> |
| | | <el-tag :type="row.suggestedPurchase > 0 ? 'danger' : 'success'" |
| | | size="small"> |
| | | {{ row.suggestedPurchase }} |
| | | </el-tag> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import {ref, reactive, onMounted, getCurrentInstance} from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Search, Refresh, Plus, Download } from '@element-plus/icons-vue' |
| | | import {listPage,add,update,del,listPageCopy} from "@/api/procurementManagement/procurementPlan.js" |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { ref, reactive, onMounted, getCurrentInstance } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Search, Refresh, Plus, Download } from "@element-plus/icons-vue"; |
| | | import { |
| | | listPage, |
| | | add, |
| | | update, |
| | | del, |
| | | listPageCopy, |
| | | } from "@/api/procurementManagement/procurementPlan.js"; |
| | | |
| | | // 响应式数据 |
| | | const loading = ref(false) |
| | | const submitLoading = ref(false) |
| | | const dialogVisible = ref(false) |
| | | const productSelectDialogVisible = ref(false) |
| | | const calculateDialogVisible = ref(false) |
| | | const dialogType = ref('add') |
| | | const productLoading = ref(false) |
| | | const selectedProducts = ref([]) |
| | | const currentPlan = ref(null) |
| | | // 响应式数据 |
| | | const loading = ref(false); |
| | | const submitLoading = ref(false); |
| | | const dialogVisible = ref(false); |
| | | const productSelectDialogVisible = ref(false); |
| | | const calculateDialogVisible = ref(false); |
| | | const dialogType = ref("add"); |
| | | const productLoading = ref(false); |
| | | const selectedProducts = ref([]); |
| | | const currentPlan = ref(null); |
| | | |
| | | // 搜索表单 |
| | | const searchForm = reactive({ |
| | | planName: '', |
| | | status: '' |
| | | }) |
| | | // 搜索表单 |
| | | const searchForm = reactive({ |
| | | planName: "", |
| | | status: "", |
| | | }); |
| | | |
| | | // 分页数据 |
| | | const pagination = reactive({ |
| | | current: 1, |
| | | size: 20 |
| | | }) |
| | | // 分页数据 |
| | | const pagination = reactive({ |
| | | current: 1, |
| | | size: 20, |
| | | }); |
| | | |
| | | // 表单数据 |
| | | const formData = reactive({ |
| | | code: '', |
| | | planName: '', |
| | | description: '', |
| | | status: '', |
| | | isSystemPreset: false, |
| | | formula: '', |
| | | // 计算参数 |
| | | considerExistingStock: false, |
| | | warehouseControl: false, |
| | | calculateTotalDemand: false, |
| | | considerSafetyStock: false, |
| | | considerLockedStock: false, |
| | | notConsiderMaterialAux: false, |
| | | negativeStockAsDemand: false, |
| | | // 汇总合并选项 |
| | | summaryMaterial: false, |
| | | summaryAuxAttributes: false, |
| | | summaryDemandDate: false |
| | | }) |
| | | |
| | | // 当前激活的标签页 |
| | | const activeTab = ref('demand') |
| | | |
| | | // 表单验证规则 |
| | | const formRules = { |
| | | planName: [ |
| | | { required: true, message: '请输入计划名称', trigger: 'blur' } |
| | | ], |
| | | status: [ |
| | | { required: true, message: '请选择状态', trigger: 'change' } |
| | | ], |
| | | formula: [ |
| | | { required: true, message: '请输入计算公式', trigger: 'blur' } |
| | | ] |
| | | } |
| | | |
| | | // 表格数据 |
| | | const tableData = ref([]) |
| | | |
| | | // 产品列表数据 |
| | | const productList = ref([ |
| | | { |
| | | id: 4, |
| | | productName: '产品D', |
| | | productCode: 'PD004', |
| | | existingStock: 90, |
| | | safetyStock: 40, |
| | | expectedOutbound: 160, |
| | | expectedInbound: 35 |
| | | } |
| | | ]) |
| | | |
| | | // 计算结果数据 |
| | | const calculateResult = ref([ |
| | | { |
| | | productName: '产品A', |
| | | existingStock: 100, |
| | | safetyStock: 50, |
| | | expectedOutbound: 200, |
| | | expectedInbound: 30, |
| | | weeklyNetDemand: 120, |
| | | suggestedPurchase: 150 |
| | | }, |
| | | { |
| | | productName: '产品B', |
| | | existingStock: 80, |
| | | safetyStock: 30, |
| | | expectedOutbound: 150, |
| | | expectedInbound: 20, |
| | | weeklyNetDemand: 100, |
| | | suggestedPurchase: 120 |
| | | } |
| | | ]) |
| | | const total = ref(0) |
| | | // 方法 |
| | | const handleSearch = () => { |
| | | pagination.current = 1 |
| | | loadData() |
| | | } |
| | | |
| | | const handleReset = () => { |
| | | Object.assign(searchForm, { |
| | | planName: '', |
| | | status: '' |
| | | }) |
| | | handleSearch() |
| | | } |
| | | |
| | | const loadData = () => { |
| | | loading.value = true |
| | | listPage({...searchForm,...pagination}).then(res => { |
| | | if(res.code === 200){ |
| | | tableData.value = res.data.records |
| | | total.value = res.data.total |
| | | loading.value = false |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const handleAdd = () => { |
| | | dialogType.value = 'add' |
| | | resetForm() |
| | | // 自动生成编码 |
| | | formData.code = 'CGJH' + String(Date.now()).slice(-4) |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | const handleEdit = (row) => { |
| | | dialogType.value = 'edit' |
| | | Object.assign(formData, row) |
| | | dialogVisible.value = true |
| | | } |
| | | |
| | | const handleDelete = async (row) => { |
| | | try { |
| | | await ElMessageBox.confirm('确定要删除这个采购计划吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }) |
| | | let ids = [row.id] |
| | | del(ids).then(res =>{ |
| | | if(res.code === 200){ |
| | | ElMessage.success('删除成功') |
| | | loadData() |
| | | } |
| | | }) |
| | | } catch { |
| | | // 用户取消删除 |
| | | } |
| | | } |
| | | |
| | | const handleSubmit = async () => { |
| | | try { |
| | | // 表单验证 |
| | | if (!formData.planName || !formData.formula) { |
| | | ElMessage.error('请填写必填项') |
| | | return |
| | | } |
| | | |
| | | submitLoading.value = true |
| | | |
| | | if (dialogType.value === 'add') { |
| | | add(formData).then(res => { |
| | | if(res.code === 200){ |
| | | ElMessage.success('新增成功') |
| | | dialogVisible.value = false |
| | | loadData() |
| | | } |
| | | }) |
| | | } else { |
| | | // 编辑 |
| | | update(formData).then(res => { |
| | | if(res.code === 200){ |
| | | ElMessage.success('编辑成功') |
| | | dialogVisible.value = false |
| | | loadData() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | |
| | | } catch (error) { |
| | | ElMessage.error('操作失败') |
| | | } finally { |
| | | submitLoading.value = false |
| | | } |
| | | } |
| | | |
| | | const resetForm = () => { |
| | | Object.assign(formData, { |
| | | code: '', |
| | | planName: '', |
| | | description: '', |
| | | status: '', |
| | | // 表单数据 |
| | | const formData = reactive({ |
| | | code: "", |
| | | planName: "", |
| | | description: "", |
| | | status: "", |
| | | isSystemPreset: false, |
| | | formula: '预计出库数量 - 现有库存 + 安全库存 - 预计入库数量', |
| | | formula: "", |
| | | // 计算参数 |
| | | considerExistingStock: false, |
| | | warehouseControl: false, |
| | |
| | | // 汇总合并选项 |
| | | summaryMaterial: false, |
| | | summaryAuxAttributes: false, |
| | | summaryDemandDate: false |
| | | }) |
| | | activeTab.value = 'demand' |
| | | } |
| | | summaryDemandDate: false, |
| | | }); |
| | | |
| | | const validateFormula = () => { |
| | | // 简单的公式验证 |
| | | const formula = formData.formula |
| | | if (formula && !/^[a-zA-Z\u4e00-\u9fa5\s\*\+\-\/\(\)\d\.]+$/.test(formula)) { |
| | | ElMessage.warning('公式格式可能不正确,请检查') |
| | | } |
| | | } |
| | | // 当前激活的标签页 |
| | | const activeTab = ref("demand"); |
| | | |
| | | const handleCalculate = (row) => { |
| | | currentPlan.value = row |
| | | productSelectDialogVisible.value = true |
| | | loadProductList() |
| | | } |
| | | // 表单验证规则 |
| | | const formRules = { |
| | | planName: [{ required: true, message: "请输入计划名称", trigger: "blur" }], |
| | | status: [{ required: true, message: "请选择状态", trigger: "change" }], |
| | | formula: [{ required: true, message: "请输入计算公式", trigger: "blur" }], |
| | | }; |
| | | |
| | | const loadProductList = () => { |
| | | productLoading.value = true |
| | | // 模拟加载产品数据 |
| | | listPageCopy({size:-1}).then(res => { |
| | | if(res.code === 200){ |
| | | productList.value = res.data.records |
| | | productLoading.value = false |
| | | // 表格数据 |
| | | const tableData = ref([]); |
| | | |
| | | // 产品列表数据 |
| | | const productList = ref([ |
| | | { |
| | | id: 4, |
| | | productName: "产品D", |
| | | productCode: "PD004", |
| | | existingStock: 90, |
| | | safetyStock: 40, |
| | | expectedOutbound: 160, |
| | | expectedInbound: 35, |
| | | }, |
| | | ]); |
| | | |
| | | // 计算结果数据 |
| | | const calculateResult = ref([ |
| | | { |
| | | productName: "产品A", |
| | | existingStock: 100, |
| | | safetyStock: 50, |
| | | expectedOutbound: 200, |
| | | expectedInbound: 30, |
| | | weeklyNetDemand: 120, |
| | | suggestedPurchase: 150, |
| | | }, |
| | | { |
| | | productName: "产品B", |
| | | existingStock: 80, |
| | | safetyStock: 30, |
| | | expectedOutbound: 150, |
| | | expectedInbound: 20, |
| | | weeklyNetDemand: 100, |
| | | suggestedPurchase: 120, |
| | | }, |
| | | ]); |
| | | const total = ref(0); |
| | | // 方法 |
| | | const handleSearch = () => { |
| | | pagination.current = 1; |
| | | loadData(); |
| | | }; |
| | | |
| | | const handleReset = () => { |
| | | Object.assign(searchForm, { |
| | | planName: "", |
| | | status: "", |
| | | }); |
| | | handleSearch(); |
| | | }; |
| | | |
| | | const loadData = () => { |
| | | loading.value = true; |
| | | listPage({ ...searchForm, ...pagination }).then(res => { |
| | | if (res.code === 200) { |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleAdd = () => { |
| | | dialogType.value = "add"; |
| | | resetForm(); |
| | | // 自动生成编码 |
| | | formData.code = "CGJH" + String(Date.now()).slice(-4); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleEdit = row => { |
| | | dialogType.value = "edit"; |
| | | Object.assign(formData, row); |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleDelete = async row => { |
| | | try { |
| | | await ElMessageBox.confirm("确定要删除这个采购计划吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }); |
| | | let ids = [row.id]; |
| | | del(ids).then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success("删除成功"); |
| | | loadData(); |
| | | } |
| | | }); |
| | | } catch { |
| | | // 用户取消删除 |
| | | } |
| | | }) |
| | | } |
| | | }; |
| | | |
| | | const handleProductSelectionChange = (selection) => { |
| | | selectedProducts.value = selection |
| | | } |
| | | const handleSubmit = async () => { |
| | | try { |
| | | // 表单验证 |
| | | if (!formData.planName || !formData.formula) { |
| | | ElMessage.error("请填写必填项"); |
| | | return; |
| | | } |
| | | |
| | | const handleConfirmProductSelection = () => { |
| | | if (selectedProducts.value.length === 0) { |
| | | ElMessage.warning('请选择要计算的产品') |
| | | return |
| | | } |
| | | |
| | | ElMessage.success(`正在计算 ${currentPlan.value.planName} 的采购需求...`) |
| | | productSelectDialogVisible.value = false |
| | | |
| | | // 根据选择的产品和计算公式进行计算 |
| | | calculateWithSelectedProducts() |
| | | } |
| | | submitLoading.value = true; |
| | | |
| | | const calculateWithSelectedProducts = () => { |
| | | // 模拟计算过程 |
| | | // 根据选择的产品更新计算结果 |
| | | const result = selectedProducts.value.map(product => { |
| | | // 这里应该根据实际的计算公式进行计算 |
| | | // 示例:预计出库数量 - 现有库存 + 安全库存 - 预计入库数量 |
| | | const weeklyNetDemand = product.inboundNum - product.inboundNum0 + product.inboundNum - product.inboundNum0 |
| | | const suggestedPurchase = Math.max(0, weeklyNetDemand) |
| | | |
| | | return { |
| | | productCategory: product.productCategory, |
| | | specificationModel: product.specificationModel, |
| | | inboundNum0: product.inboundNum0, |
| | | inboundNum: product.inboundNum, |
| | | weeklyNetDemand: weeklyNetDemand, |
| | | suggestedPurchase: suggestedPurchase |
| | | if (dialogType.value === "add") { |
| | | add(formData).then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success("新增成功"); |
| | | dialogVisible.value = false; |
| | | loadData(); |
| | | } |
| | | }); |
| | | } else { |
| | | // 编辑 |
| | | update(formData).then(res => { |
| | | if (res.code === 200) { |
| | | ElMessage.success("编辑成功"); |
| | | dialogVisible.value = false; |
| | | loadData(); |
| | | } |
| | | }); |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error("操作失败"); |
| | | } finally { |
| | | submitLoading.value = false; |
| | | } |
| | | }) |
| | | }; |
| | | |
| | | calculateResult.value = result |
| | | calculateDialogVisible.value = true |
| | | } |
| | | const resetForm = () => { |
| | | Object.assign(formData, { |
| | | code: "", |
| | | planName: "", |
| | | description: "", |
| | | status: "", |
| | | isSystemPreset: false, |
| | | formula: "预计出库数量 - 现有库存 + 安全库存 - 预计入库数量", |
| | | // 计算参数 |
| | | considerExistingStock: false, |
| | | warehouseControl: false, |
| | | calculateTotalDemand: false, |
| | | considerSafetyStock: false, |
| | | considerLockedStock: false, |
| | | notConsiderMaterialAux: false, |
| | | negativeStockAsDemand: false, |
| | | // 汇总合并选项 |
| | | summaryMaterial: false, |
| | | summaryAuxAttributes: false, |
| | | summaryDemandDate: false, |
| | | }); |
| | | activeTab.value = "demand"; |
| | | }; |
| | | |
| | | const validateFormula = () => { |
| | | // 简单的公式验证 |
| | | const formula = formData.formula; |
| | | if (formula && !/^[a-zA-Z\u4e00-\u9fa5\s\*\+\-\/\(\)\d\.]+$/.test(formula)) { |
| | | ElMessage.warning("公式格式可能不正确,请检查"); |
| | | } |
| | | }; |
| | | |
| | | const handleCreatePurchaseOrder = () => { |
| | | calculateDialogVisible.value = false |
| | | } |
| | | const { proxy } = getCurrentInstance(); |
| | | const handleExport = () => { |
| | | ElMessageBox.confirm("内容将被导出,是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | const handleCalculate = row => { |
| | | currentPlan.value = row; |
| | | productSelectDialogVisible.value = true; |
| | | loadProductList(); |
| | | }; |
| | | |
| | | const loadProductList = () => { |
| | | productLoading.value = true; |
| | | // 模拟加载产品数据 |
| | | listPageCopy({ size: -1 }).then(res => { |
| | | if (res.code === 200) { |
| | | productList.value = res.data.records; |
| | | productLoading.value = false; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleProductSelectionChange = selection => { |
| | | selectedProducts.value = selection; |
| | | }; |
| | | |
| | | const handleConfirmProductSelection = () => { |
| | | if (selectedProducts.value.length === 0) { |
| | | ElMessage.warning("请选择要计算的产品"); |
| | | return; |
| | | } |
| | | |
| | | ElMessage.success(`正在计算 ${currentPlan.value.planName} 的采购需求...`); |
| | | productSelectDialogVisible.value = false; |
| | | |
| | | // 根据选择的产品和计算公式进行计算 |
| | | calculateWithSelectedProducts(); |
| | | }; |
| | | |
| | | const calculateWithSelectedProducts = () => { |
| | | // 模拟计算过程 |
| | | // 根据选择的产品更新计算结果 |
| | | const result = selectedProducts.value.map(product => { |
| | | // 这里应该根据实际的计算公式进行计算 |
| | | // 示例:预计出库数量 - 现有库存 + 安全库存 - 预计入库数量 |
| | | const weeklyNetDemand = |
| | | product.inboundNum - |
| | | product.inboundNum0 + |
| | | product.inboundNum - |
| | | product.inboundNum0; |
| | | const suggestedPurchase = Math.max(0, weeklyNetDemand); |
| | | |
| | | return { |
| | | productCategory: product.productCategory, |
| | | specificationModel: product.specificationModel, |
| | | inboundNum0: product.inboundNum0, |
| | | inboundNum: product.inboundNum, |
| | | weeklyNetDemand: weeklyNetDemand, |
| | | suggestedPurchase: suggestedPurchase, |
| | | }; |
| | | }); |
| | | |
| | | calculateResult.value = result; |
| | | calculateDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleCreatePurchaseOrder = () => { |
| | | calculateDialogVisible.value = false; |
| | | }; |
| | | const { proxy } = getCurrentInstance(); |
| | | const handleExport = () => { |
| | | ElMessageBox.confirm("内容将被导出,是否确认导出?", "导出", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/procurementPlan/export", {}, "采购计划.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已取消"); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const handleSizeChange = size => { |
| | | pagination.size = size; |
| | | loadData(); |
| | | }; |
| | | |
| | | const handleSizeChange = (size) => { |
| | | pagination.size = size |
| | | loadData() |
| | | } |
| | | const handleCurrentChange = current => { |
| | | pagination.current = current; |
| | | loadData(); |
| | | }; |
| | | |
| | | const handleCurrentChange = (current) => { |
| | | pagination.current = current |
| | | loadData() |
| | | } |
| | | |
| | | // 生命周期 |
| | | onMounted(() => { |
| | | loadData() |
| | | }) |
| | | // 生命周期 |
| | | onMounted(() => { |
| | | loadData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .page-header { |
| | | margin-bottom: 20px; |
| | | } |
| | | .page-header { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .page-header h2 { |
| | | margin: 0 0 8px 0; |
| | | color: #303133; |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | } |
| | | .page-header h2 { |
| | | margin: 0 0 8px 0; |
| | | color: #303133; |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .page-header p { |
| | | margin: 0; |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | .page-header p { |
| | | margin: 0; |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .search-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .search-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .search-form { |
| | | margin-bottom: 0; |
| | | } |
| | | .search-form { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .table-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .table-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .table-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | .table-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .table-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | .table-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | |
| | | .table-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | .table-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .pagination-container { |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: end; |
| | | } |
| | | .pagination-container { |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: end; |
| | | } |
| | | |
| | | .form-container { |
| | | padding: 0 20px; |
| | | } |
| | | .form-container { |
| | | padding: 0 20px; |
| | | } |
| | | |
| | | .formula-help { |
| | | margin-top: 5px; |
| | | } |
| | | .formula-help { |
| | | margin-top: 5px; |
| | | } |
| | | |
| | | .calculate-result { |
| | | padding: 20px 0; |
| | | } |
| | | .calculate-result { |
| | | padding: 20px 0; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | |
| | | :deep(.el-card__body) { |
| | | padding: 20px; |
| | | } |
| | | :deep(.el-card__body) { |
| | | padding: 20px; |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | font-size: 14px; |
| | | } |
| | | :deep(.el-table) { |
| | | font-size: 14px; |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | font-weight: 500; |
| | | } |
| | | :deep(.el-form-item__label) { |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .form-container { |
| | | padding: 0; |
| | | } |
| | | .form-container { |
| | | padding: 0; |
| | | } |
| | | |
| | | .form-section { |
| | | margin-bottom: 24px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | } |
| | | .form-section { |
| | | margin-bottom: 24px; |
| | | border: 1px solid #e4e7ed; |
| | | border-radius: 6px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .section-title { |
| | | background-color: #f5f7fa; |
| | | padding: 12px 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #e4e7ed; |
| | | } |
| | | .section-title { |
| | | background-color: #f5f7fa; |
| | | padding: 12px 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | border-bottom: 1px solid #e4e7ed; |
| | | } |
| | | |
| | | .form-section .el-form { |
| | | padding: 20px; |
| | | } |
| | | .form-section .el-form { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .param-tabs { |
| | | padding: 20px; |
| | | } |
| | | .param-tabs { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .param-tabs :deep(.el-tabs__header) { |
| | | margin-bottom: 20px; |
| | | } |
| | | .param-tabs :deep(.el-tabs__header) { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .param-tabs :deep(.el-tabs__item.is-active) { |
| | | color: #f56c6c; |
| | | border-bottom-color: #f56c6c; |
| | | } |
| | | .param-tabs :deep(.el-tabs__item.is-active) { |
| | | color: #f56c6c; |
| | | border-bottom-color: #f56c6c; |
| | | } |
| | | |
| | | .checkbox-group { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | } |
| | | .checkbox-group { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .checkbox-group .el-checkbox { |
| | | margin-right: 0; |
| | | margin-bottom: 8px; |
| | | } |
| | | .checkbox-group .el-checkbox { |
| | | margin-right: 0; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .formula-input-section { |
| | | padding: 20px; |
| | | } |
| | | .formula-input-section { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .formula-input-section .el-form-item { |
| | | margin-bottom: 12px; |
| | | } |
| | | .formula-input-section .el-form-item { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .formula-help { |
| | | text-align: center; |
| | | margin-top: 8px; |
| | | } |
| | | .formula-help { |
| | | text-align: center; |
| | | margin-top: 8px; |
| | | } |
| | | </style> |
| | |
| | | border> |
| | | <el-descriptions-item label="生产订单号">{{ rowData.productionOrderDto?.npsNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产品名称">{{ rowData.productionOrderDto?.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产品规格">{{ rowData.productionOrderDto?.model || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="规格型号">{{ rowData.productionOrderDto?.model || '-' }}</el-descriptions-item> |
| | | <!-- <el-descriptions-item label="物料编码">{{ rowData.productionOrderDto?.materialCode || '-' }}</el-descriptions-item> --> |
| | | <el-descriptions-item label="计划数量">{{ rowData.productionOrderDto?.quantity || 0 }} <span class="unit">{{ rowData.productionOrderDto?.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="当前状态"> |
| | |
| | | <span class="info-value">{{ transferCardRowData.productName }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="info-label">产品规格</span> |
| | | <span class="info-label">规格型号</span> |
| | | <span class="info-value">{{ transferCardRowData.model }}</span> |
| | | </div> |
| | | <!-- <div class="info-item"> |
| | |
| | | <span class="info-value">{{ transferCardRowData.productName }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="info-label">产品规格</span> |
| | | <span class="info-label">规格型号</span> |
| | | <span class="info-value">{{ transferCardRowData.model }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品规格:" |
| | | <el-form-item label="规格型号:" |
| | | prop="model"> |
| | | <el-input v-model="searchForm.model" |
| | | placeholder="请输入" |
| | |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col> |
| | | <el-form-item label="产品规格"> |
| | | <el-form-item label="规格型号"> |
| | | <div class="info-display">{{ mergeForm.model || '-' }}</div> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | @change="handleProductChange" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品规格" |
| | | <el-form-item label="规格型号" |
| | | prop="productModelId"> |
| | | <el-select v-model="form.productModelId" |
| | | @change="handleChangeSpecification" |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: "产品规格", |
| | | label: "规格型号", |
| | | prop: "model", |
| | | width: "150px", |
| | | className: "spec-cell", |
| | |
| | | const rules = reactive({ |
| | | productId: [{ required: true, message: "请选择产品", trigger: "change" }], |
| | | productModelId: [ |
| | | { required: true, message: "请选择产品规格", trigger: "change" }, |
| | | { required: true, message: "请选择规格型号", trigger: "change" }, |
| | | ], |
| | | qtyRequired: [{ required: true, message: "请输入数量", trigger: "blur" }], |
| | | requiredDate: [ |
| | |
| | | }); |
| | | }; |
| | | |
| | | // 选中的产品规格ID |
| | | // 选中的规格型号ID |
| | | const selectedProductModelId = ref(""); |
| | | |
| | | // 表格选择数据 |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | // 如果有选中的行,记录第一个选中行的产品规格ID |
| | | // 如果有选中的行,记录第一个选中行的规格型号ID |
| | | if (selection.length > 0) { |
| | | selectedProductModelId.value = selection[0].productModelId; |
| | | } else { |
| | | // 如果没有选中的行,清空产品规格ID |
| | | // 如果没有选中的行,清空规格型号ID |
| | | selectedProductModelId.value = ""; |
| | | } |
| | | }; |
| | |
| | | if (!selectedProductModelId.value) { |
| | | return true; |
| | | } |
| | | // 如果有选中的行,只有产品规格ID相同的行才可选择 |
| | | // 如果有选中的行,只有规格型号ID相同的行才可选择 |
| | | return row.productModelId === selectedProductModelId.value; |
| | | }; |
| | | // 拉取数据按钮操作 |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> |
| | | <el-form-item label="产品名称" prop="productName"> |
| | | <el-input |
| | | v-model="queryParams.productName" |
| | | placeholder="请输入产品名称" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | /> |
| | | <el-form :model="queryParams" |
| | | ref="queryForm" |
| | | :inline="true" |
| | | v-show="showSearch" |
| | | label-width="68px"> |
| | | <el-form-item label="产品名称" |
| | | prop="productName"> |
| | | <el-input v-model="queryParams.productName" |
| | | placeholder="请输入产品名称" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="批次号" prop="batchNumber"> |
| | | <el-input |
| | | v-model="queryParams.batchNumber" |
| | | placeholder="请输入批次号" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | /> |
| | | <el-form-item label="批次号" |
| | | prop="batchNumber"> |
| | | <el-input v-model="queryParams.batchNumber" |
| | | placeholder="请输入批次号" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="退回日期" prop="returnDate"> |
| | | <el-date-picker |
| | | clearable |
| | | v-model="queryParams.returnDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择退回日期"> |
| | | <el-form-item label="退回日期" |
| | | prop="returnDate"> |
| | | <el-date-picker clearable |
| | | v-model="queryParams.returnDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择退回日期"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">重置</el-button> |
| | | <el-button type="primary" |
| | | icon="Search" |
| | | @click="handleQuery">搜索</el-button> |
| | | <el-button icon="Refresh" |
| | | @click="resetQuery">重置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-row :gutter="10" |
| | | class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | icon="Plus" |
| | | @click="handleAdd" |
| | | >新增</el-button> |
| | | <el-button type="primary" |
| | | plain |
| | | icon="Plus" |
| | | @click="handleAdd">新增</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="success" |
| | | plain |
| | | icon="Edit" |
| | | :disabled="single" |
| | | @click="handleUpdate" |
| | | >修改</el-button> |
| | | <el-button type="success" |
| | | plain |
| | | icon="Edit" |
| | | :disabled="single" |
| | | @click="handleUpdate">修改</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="danger" |
| | | plain |
| | | icon="Delete" |
| | | :disabled="multiple" |
| | | @click="handleDelete" |
| | | >删除</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | icon="Delete" |
| | | :disabled="multiple" |
| | | @click="handleDelete">删除</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="warning" |
| | | plain |
| | | icon="Download" |
| | | @click="handleExport" |
| | | >导出</el-button> |
| | | <el-button type="warning" |
| | | plain |
| | | icon="Download" |
| | | @click="handleExport">导出</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | <right-toolbar v-model:showSearch="showSearch" |
| | | @queryTable="getList"></right-toolbar> |
| | | </el-row> |
| | | |
| | | <el-table v-loading="loading" :data="nearExpiryReturnList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="序号" type="index" width="50" align="center" /> |
| | | <el-table-column label="产品名称" prop="productName" /> |
| | | <el-table-column label="产品规格" prop="productSpec" /> |
| | | <el-table-column label="批次号" prop="batchNumber" /> |
| | | <el-table-column label="生产日期" prop="productionDate" align="center"> |
| | | <el-table v-loading="loading" |
| | | :data="nearExpiryReturnList" |
| | | @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" |
| | | width="55" |
| | | align="center" /> |
| | | <el-table-column label="序号" |
| | | type="index" |
| | | width="50" |
| | | align="center" /> |
| | | <el-table-column label="产品名称" |
| | | prop="productName" /> |
| | | <el-table-column label="规格型号" |
| | | prop="productSpec" /> |
| | | <el-table-column label="批次号" |
| | | prop="batchNumber" /> |
| | | <el-table-column label="生产日期" |
| | | prop="productionDate" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.productionDate, '{y}-{m}-{d}') }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="到期日期" prop="expiryDate" align="center"> |
| | | <el-table-column label="到期日期" |
| | | prop="expiryDate" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.expiryDate, '{y}-{m}-{d}') }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="退回数量" prop="returnQuantity" /> |
| | | <el-table-column label="退回原因" prop="returnReason" /> |
| | | <el-table-column label="退回日期" prop="returnDate" align="center"> |
| | | <el-table-column label="退回数量" |
| | | prop="returnQuantity" /> |
| | | <el-table-column label="退回原因" |
| | | prop="returnReason" /> |
| | | <el-table-column label="退回日期" |
| | | prop="returnDate" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.returnDate, '{y}-{m}-{d}') }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="处理状态" prop="status" align="center"> |
| | | <el-table-column label="处理状态" |
| | | prop="status" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <dict-tag :options="statusOptions" :value="scope.row.status"/> |
| | | <dict-tag :options="statusOptions" |
| | | :value="scope.row.status" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| | | <el-table-column label="操作" |
| | | align="center" |
| | | class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-button size="mini" type="text" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button> |
| | | <el-button size="mini" type="text" icon="Delete" @click="handleDelete(scope.row)">删除</el-button> |
| | | <el-button size="mini" |
| | | type="text" |
| | | icon="Edit" |
| | | @click="handleUpdate(scope.row)">修改</el-button> |
| | | <el-button size="mini" |
| | | type="text" |
| | | icon="Delete" |
| | | @click="handleDelete(scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination |
| | | v-show="total>0" |
| | | :total="total" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | |
| | | <pagination v-show="total>0" |
| | | :total="total" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" /> |
| | | <!-- 添加或修改临期退回台账对话框 --> |
| | | <el-dialog :title="title" v-model="open" width="800px" append-to-body> |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="100px"> |
| | | <el-dialog :title="title" |
| | | v-model="open" |
| | | width="800px" |
| | | append-to-body> |
| | | <el-form ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="产品名称" prop="productName"> |
| | | <el-input v-model="form.productName" placeholder="请输入产品名称" /> |
| | | <el-form-item label="产品名称" |
| | | prop="productName"> |
| | | <el-input v-model="form.productName" |
| | | placeholder="请输入产品名称" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="产品规格" prop="productSpec"> |
| | | <el-input v-model="form.productSpec" placeholder="请输入产品规格" /> |
| | | <el-form-item label="规格型号" |
| | | prop="productSpec"> |
| | | <el-input v-model="form.productSpec" |
| | | placeholder="请输入规格型号" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="批次号" prop="batchNumber"> |
| | | <el-input v-model="form.batchNumber" placeholder="请输入批次号" /> |
| | | <el-form-item label="批次号" |
| | | prop="batchNumber"> |
| | | <el-input v-model="form.batchNumber" |
| | | placeholder="请输入批次号" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="退回数量" prop="returnQuantity"> |
| | | <el-input-number v-model="form.returnQuantity" controls-position="right" :min="1" /> |
| | | <el-form-item label="退回数量" |
| | | prop="returnQuantity"> |
| | | <el-input-number v-model="form.returnQuantity" |
| | | controls-position="right" |
| | | :min="1" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="生产日期" prop="productionDate"> |
| | | <el-date-picker |
| | | clearable |
| | | v-model="form.productionDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择生产日期"> |
| | | <el-form-item label="生产日期" |
| | | prop="productionDate"> |
| | | <el-date-picker clearable |
| | | v-model="form.productionDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择生产日期"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="到期日期" prop="expiryDate"> |
| | | <el-date-picker |
| | | clearable |
| | | v-model="form.expiryDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择到期日期"> |
| | | <el-form-item label="到期日期" |
| | | prop="expiryDate"> |
| | | <el-date-picker clearable |
| | | v-model="form.expiryDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择到期日期"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="退回日期" prop="returnDate"> |
| | | <el-date-picker |
| | | clearable |
| | | v-model="form.returnDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择退回日期"> |
| | | <el-form-item label="退回日期" |
| | | prop="returnDate"> |
| | | <el-date-picker clearable |
| | | v-model="form.returnDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择退回日期"> |
| | | </el-date-picker> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="处理状态" prop="status"> |
| | | <el-select v-model="form.status" placeholder="请选择处理状态"> |
| | | <el-option |
| | | v-for="dict in statusOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | ></el-option> |
| | | <el-form-item label="处理状态" |
| | | prop="status"> |
| | | <el-select v-model="form.status" |
| | | placeholder="请选择处理状态"> |
| | | <el-option v-for="dict in statusOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="退回原因" prop="returnReason"> |
| | | <el-input v-model="form.returnReason" type="textarea" placeholder="请输入退回原因" /> |
| | | <el-form-item label="退回原因" |
| | | prop="returnReason"> |
| | | <el-input v-model="form.returnReason" |
| | | type="textarea" |
| | | placeholder="请输入退回原因" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="备注" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" /> |
| | | <el-form-item label="备注" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | placeholder="请输入备注" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确 定</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm">确 定</el-button> |
| | | <el-button @click="cancel">取 消</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup name="NearExpiryReturn"> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | // API接口已移除,不再调用后端接口 |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | // API接口已移除,不再调用后端接口 |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const { parseTime } = proxy; |
| | | const { proxy } = getCurrentInstance(); |
| | | const { parseTime } = proxy; |
| | | |
| | | const nearExpiryReturnList = ref([]); |
| | | const open = ref(false); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const ids = ref([]); |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const total = ref(0); |
| | | const title = ref(""); |
| | | const nearExpiryReturnList = ref([]); |
| | | const open = ref(false); |
| | | const loading = ref(true); |
| | | const showSearch = ref(true); |
| | | const ids = ref([]); |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const total = ref(0); |
| | | const title = ref(""); |
| | | |
| | | // 状态字典 |
| | | const statusOptions = ref([ |
| | | { label: "待处理", value: "0" }, |
| | | { label: "处理中", value: "1" }, |
| | | { label: "已完成", value: "2" } |
| | | ]); |
| | | // 状态字典 |
| | | const statusOptions = ref([ |
| | | { label: "待处理", value: "0" }, |
| | | { label: "处理中", value: "1" }, |
| | | { label: "已完成", value: "2" }, |
| | | ]); |
| | | |
| | | const data = reactive({ |
| | | form: {}, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | productName: null, |
| | | batchNumber: null, |
| | | returnDate: null |
| | | }, |
| | | rules: { |
| | | productName: [ |
| | | { required: true, message: "产品名称不能为空", trigger: "blur" } |
| | | ], |
| | | productSpec: [ |
| | | { required: true, message: "产品规格不能为空", trigger: "blur" } |
| | | ], |
| | | batchNumber: [ |
| | | { required: true, message: "批次号不能为空", trigger: "blur" } |
| | | ], |
| | | returnQuantity: [ |
| | | { required: true, message: "退回数量不能为空", trigger: "blur" } |
| | | ], |
| | | productionDate: [ |
| | | { required: true, message: "生产日期不能为空", trigger: "blur" } |
| | | ], |
| | | expiryDate: [ |
| | | { required: true, message: "到期日期不能为空", trigger: "blur" } |
| | | ], |
| | | returnDate: [ |
| | | { required: true, message: "退回日期不能为空", trigger: "blur" } |
| | | ], |
| | | returnReason: [ |
| | | { required: true, message: "退回原因不能为空", trigger: "blur" } |
| | | ], |
| | | status: [ |
| | | { required: true, message: "处理状态不能为空", trigger: "change" } |
| | | ] |
| | | } |
| | | }); |
| | | |
| | | const { queryParams, form, rules } = toRefs(data); |
| | | |
| | | /** 查询临期退回台账列表 */ |
| | | function getList() { |
| | | loading.value = true; |
| | | // 不调用接口,返回空数据 |
| | | nearExpiryReturnList.value = []; |
| | | total.value = 0; |
| | | loading.value = false; |
| | | } |
| | | |
| | | // 取消按钮 |
| | | function cancel() { |
| | | open.value = false; |
| | | reset(); |
| | | } |
| | | |
| | | // 表单重置 |
| | | function reset() { |
| | | form.value = { |
| | | id: null, |
| | | productName: null, |
| | | productSpec: null, |
| | | batchNumber: null, |
| | | productionDate: null, |
| | | expiryDate: null, |
| | | returnQuantity: null, |
| | | returnReason: null, |
| | | returnDate: null, |
| | | status: null, |
| | | remark: null |
| | | }; |
| | | proxy.resetForm("formRef"); |
| | | } |
| | | |
| | | /** 搜索按钮操作 */ |
| | | function handleQuery() { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | |
| | | /** 重置按钮操作 */ |
| | | function resetQuery() { |
| | | proxy.resetForm("queryForm"); |
| | | handleQuery(); |
| | | } |
| | | |
| | | // 多选框选中数据 |
| | | function handleSelectionChange(selection) { |
| | | ids.value = selection.map(item => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | |
| | | /** 新增按钮操作 */ |
| | | function handleAdd() { |
| | | reset(); |
| | | open.value = true; |
| | | title.value = "添加临期退回台账"; |
| | | } |
| | | |
| | | /** 修改按钮操作 */ |
| | | function handleUpdate(row) { |
| | | reset(); |
| | | // 不调用接口,直接使用传入的数据 |
| | | if (row) { |
| | | form.value = { ...row }; |
| | | open.value = true; |
| | | title.value = "修改临期退回台账"; |
| | | } |
| | | } |
| | | |
| | | /** 提交按钮 */ |
| | | function submitForm() { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | // 不调用接口,只显示成功提示 |
| | | if (form.value.id != null) { |
| | | proxy.$modal.msgSuccess("修改成功"); |
| | | } else { |
| | | proxy.$modal.msgSuccess("新增成功"); |
| | | } |
| | | open.value = false; |
| | | getList(); |
| | | } |
| | | const data = reactive({ |
| | | form: {}, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | productName: null, |
| | | batchNumber: null, |
| | | returnDate: null, |
| | | }, |
| | | rules: { |
| | | productName: [ |
| | | { required: true, message: "产品名称不能为空", trigger: "blur" }, |
| | | ], |
| | | productSpec: [ |
| | | { required: true, message: "规格型号不能为空", trigger: "blur" }, |
| | | ], |
| | | batchNumber: [ |
| | | { required: true, message: "批次号不能为空", trigger: "blur" }, |
| | | ], |
| | | returnQuantity: [ |
| | | { required: true, message: "退回数量不能为空", trigger: "blur" }, |
| | | ], |
| | | productionDate: [ |
| | | { required: true, message: "生产日期不能为空", trigger: "blur" }, |
| | | ], |
| | | expiryDate: [ |
| | | { required: true, message: "到期日期不能为空", trigger: "blur" }, |
| | | ], |
| | | returnDate: [ |
| | | { required: true, message: "退回日期不能为空", trigger: "blur" }, |
| | | ], |
| | | returnReason: [ |
| | | { required: true, message: "退回原因不能为空", trigger: "blur" }, |
| | | ], |
| | | status: [ |
| | | { required: true, message: "处理状态不能为空", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | } |
| | | |
| | | /** 删除按钮操作 */ |
| | | function handleDelete(row) { |
| | | const deleteIds = row.id || ids.value; |
| | | ElMessageBox.confirm('是否确认删除临期退回台账编号为"' + deleteIds + '"的数据项?', "警告", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning" |
| | | }).then(function() { |
| | | // 不调用接口,只显示成功提示 |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | const { queryParams, form, rules } = toRefs(data); |
| | | |
| | | /** 查询临期退回台账列表 */ |
| | | function getList() { |
| | | loading.value = true; |
| | | // 不调用接口,返回空数据 |
| | | nearExpiryReturnList.value = []; |
| | | total.value = 0; |
| | | loading.value = false; |
| | | } |
| | | |
| | | // 取消按钮 |
| | | function cancel() { |
| | | open.value = false; |
| | | reset(); |
| | | } |
| | | |
| | | // 表单重置 |
| | | function reset() { |
| | | form.value = { |
| | | id: null, |
| | | productName: null, |
| | | productSpec: null, |
| | | batchNumber: null, |
| | | productionDate: null, |
| | | expiryDate: null, |
| | | returnQuantity: null, |
| | | returnReason: null, |
| | | returnDate: null, |
| | | status: null, |
| | | remark: null, |
| | | }; |
| | | proxy.resetForm("formRef"); |
| | | } |
| | | |
| | | /** 搜索按钮操作 */ |
| | | function handleQuery() { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | }).catch(() => {}); |
| | | } |
| | | } |
| | | |
| | | /** 导出按钮操作 */ |
| | | function handleExport() { |
| | | // 不调用接口,只显示提示 |
| | | proxy.$modal.msgSuccess("导出功能暂未实现"); |
| | | } |
| | | /** 重置按钮操作 */ |
| | | function resetQuery() { |
| | | proxy.resetForm("queryForm"); |
| | | handleQuery(); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | // 多选框选中数据 |
| | | function handleSelectionChange(selection) { |
| | | ids.value = selection.map(item => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | |
| | | /** 新增按钮操作 */ |
| | | function handleAdd() { |
| | | reset(); |
| | | open.value = true; |
| | | title.value = "添加临期退回台账"; |
| | | } |
| | | |
| | | /** 修改按钮操作 */ |
| | | function handleUpdate(row) { |
| | | reset(); |
| | | // 不调用接口,直接使用传入的数据 |
| | | if (row) { |
| | | form.value = { ...row }; |
| | | open.value = true; |
| | | title.value = "修改临期退回台账"; |
| | | } |
| | | } |
| | | |
| | | /** 提交按钮 */ |
| | | function submitForm() { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | // 不调用接口,只显示成功提示 |
| | | if (form.value.id != null) { |
| | | proxy.$modal.msgSuccess("修改成功"); |
| | | } else { |
| | | proxy.$modal.msgSuccess("新增成功"); |
| | | } |
| | | open.value = false; |
| | | getList(); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** 删除按钮操作 */ |
| | | function handleDelete(row) { |
| | | const deleteIds = row.id || ids.value; |
| | | ElMessageBox.confirm( |
| | | '是否确认删除临期退回台账编号为"' + deleteIds + '"的数据项?', |
| | | "警告", |
| | | { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(function () { |
| | | // 不调用接口,只显示成功提示 |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | getList(); |
| | | }) |
| | | .catch(() => {}); |
| | | } |
| | | |
| | | /** 导出按钮操作 */ |
| | | function handleExport() { |
| | | // 不调用接口,只显示提示 |
| | | proxy.$modal.msgSuccess("导出功能暂未实现"); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |