| | |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form-item label="客户名称:"> |
| | | <el-input v-model="searchForm.customerName" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <!-- 简化版搜索条件 --> |
| | | <el-form-item label="产品名称:"> |
| | | <el-input v-model="searchForm.productName" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品规格:"> |
| | | <el-input v-model="searchForm.model" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="物料编码:"> |
| | | <el-input v-model="searchForm.materialCode" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="申请单编号:"> |
| | | <el-input v-model="searchForm.applyNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | |
| | | </el-form-item> |
| | | <el-form-item label="下发状态:"> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="请选择状态" |
| | | placeholder="请选择状态" |
| | | clearable |
| | | filterable |
| | | style="width: 100px"> |
| | |
| | | value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <!-- 展开版搜索条件 --> |
| | | <template v-if="searchFormExpanded"> |
| | | <el-form-item label="客户名称:"> |
| | | <el-input v-model="searchForm.customerName" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品规格:"> |
| | | <el-input v-model="searchForm.model" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="物料编码:"> |
| | | <el-input v-model="searchForm.materialCode" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="申请单编号:"> |
| | | <el-input v-model="searchForm.applyNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | </template> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">搜索</el-button> |
| | |
| | | <div> |
| | | </div> |
| | | </div> |
| | | <div class="search-header"> |
| | | <el-button type="text" |
| | | @click="toggleSearchForm"> |
| | | <el-icon> |
| | | <ArrowUp v-if="searchFormExpanded" /> |
| | | <ArrowDown v-else /> |
| | | </el-icon> |
| | | {{ searchFormExpanded ? '收起搜索条件' : '展开搜索条件' }} |
| | | </el-button> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | |
| | | :selectable="isSelectable" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="pagination"> |
| | | <template #quantity="{ row }"> |
| | | {{ row.quantity || '-' }}<span style="color:rgb(63, 95, 211)"> 块</span> |
| | | </template> |
| | | <template #volume="{ row }"> |
| | | {{ row.volume || '-' }}<span style="color:rgba(12, 46, 40, 0.76)"> 方</span> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <!-- 合并下发弹窗 --> |
| | | <el-dialog v-model="isShowNewModal" |
| | | destroy-on-close |
| | | title="合并下发" |
| | | width="600px"> |
| | | <el-form :model="mergeForm" |
| | |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 追踪进度弹窗 --> |
| | | <el-dialog v-model="showTrackProgressDialog" |
| | | :title="`追踪进度 - ${trackProgressForm.materialCode || ''}`" |
| | | width="600px"> |
| | | <el-form :model="trackProgressForm" |
| | | label-width="120px"> |
| | | <el-form-item label="物料编码"> |
| | | <el-input v-model="trackProgressForm.materialCode" |
| | | disabled /> |
| | | </el-form-item> |
| | | <el-form-item label="当前状态"> |
| | | <el-select v-model="trackProgressForm.currentStatus" |
| | | placeholder="请选择状态"> |
| | | <el-option label="待处理" |
| | | value="pending" /> |
| | | <el-option label="进行中" |
| | | value="processing" /> |
| | | <el-option label="已完成" |
| | | value="completed" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="完成进度"> |
| | | <el-progress :percentage="trackProgressForm.completionRate" |
| | | :status="trackProgressForm.completionRate === 100 ? 'success' : ''" /> |
| | | </el-form-item> |
| | | <el-form-item label="进度详情"> |
| | | <el-table :data="trackProgressForm.progressDetails" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="step" |
| | | label="步骤" |
| | | align="center" |
| | | width="100" /> |
| | | <el-table-column prop="status" |
| | | label="状态" |
| | | align="center" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'completed' ? 'success' : scope.row.status === 'processing' ? 'warning' : 'info'"> |
| | | {{ scope.row.status === 'completed' ? '已完成' : scope.row.status === 'processing' ? '进行中' : '待开始' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="startTime" |
| | | label="开始时间" |
| | | align="center" |
| | | width="180" /> |
| | | <el-table-column prop="endTime" |
| | | label="结束时间" |
| | | align="center" |
| | | width="180" /> |
| | | </el-table> |
| | | </el-form-item> |
| | | <el-form-item label="备注"> |
| | | <el-input v-model="trackProgressForm.remark" |
| | | type="textarea" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="showTrackProgressDialog = false">关闭</el-button> |
| | | <el-button type="primary" |
| | | @click="handleUpdateProgress">更新进度</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- 导入弹窗 --> |
| | | <ImportDialog ref="importDialogRef" |
| | | v-model="importDialogVisible" |
| | |
| | | @close="handleImportClose" /> |
| | | <!-- 新增/编辑弹窗 --> |
| | | <el-dialog v-model="dialogVisible" |
| | | destroy-on-close |
| | | :title="operationType === 'add' ? '新增生产计划' : '编辑生产计划'" |
| | | width="600px"> |
| | | <el-form ref="formRef" |
| | |
| | | <script setup> |
| | | import { onMounted, ref, reactive, getCurrentInstance, toRefs } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { ArrowUp, ArrowDown } from "@element-plus/icons-vue"; |
| | | import dayjs from "dayjs"; |
| | | import ImportDialog from "@/components/Dialog/ImportDialog.vue"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import { useDict } from "@/utils/dict"; |
| | | import { useRouter } from "vue-router"; |
| | | import { |
| | | productionPlanListPage, |
| | | loadProdData, |
| | |
| | | } from "@/api/basicData/newProduct.js"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const router = useRouter(); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | |
| | | { |
| | | label: "块数", |
| | | prop: "quantity", |
| | | formatData: cell => (cell ? `${cell}块` : ""), |
| | | align: "right", |
| | | dataType: "slot", |
| | | slot: "quantity", |
| | | }, |
| | | { |
| | | label: "方数", |
| | | prop: "volume", |
| | | width: "150px", |
| | | align: "right", |
| | | dataType: "slot", |
| | | slot: "volume", |
| | | className: "volume-cell", |
| | | formatData: cell => (cell ? `${cell}方` : ""), |
| | | }, |
| | | { |
| | | label: "下发状态", |
| | |
| | | strength: "", |
| | | }); |
| | | |
| | | // 追踪进度弹窗控制 |
| | | const showTrackProgressDialog = ref(false); |
| | | // 追踪进度表单数据 |
| | | const trackProgressForm = reactive({ |
| | | materialCode: "", |
| | | currentStatus: "", |
| | | completionRate: 0, |
| | | progressDetails: [], |
| | | remark: "", |
| | | }); |
| | | |
| | | // 导入相关 |
| | | const importDialogRef = ref(null); |
| | | const importDialogVisible = ref(false); |
| | |
| | | |
| | | // 处理追踪进度按钮点击 |
| | | const handleTrackProgress = row => { |
| | | // 设置表单数据 |
| | | trackProgressForm.materialCode = row.materialCode; |
| | | trackProgressForm.currentStatus = row.status; |
| | | |
| | | // 生成模拟进度数据 |
| | | trackProgressForm.progressDetails = generateProgressDetails(row.status); |
| | | |
| | | // 计算完成率 |
| | | trackProgressForm.completionRate = calculateCompletionRate( |
| | | trackProgressForm.progressDetails |
| | | ); |
| | | trackProgressForm.remark = ""; |
| | | |
| | | // 打开弹窗 |
| | | showTrackProgressDialog.value = true; |
| | | // 跳转到追踪进度页面 |
| | | router.push({ |
| | | path: "/productionPlan/trackProgress", |
| | | query: { |
| | | row: encodeURIComponent(JSON.stringify(row)), |
| | | }, |
| | | }); |
| | | }; |
| | | const onBlur = value => { |
| | | // 限制四位小数 |
| | |
| | | } |
| | | }; |
| | | |
| | | // 生成模拟进度详情数据 |
| | | const generateProgressDetails = status => { |
| | | const details = [ |
| | | { |
| | | step: "计划确认", |
| | | status: "completed", |
| | | startTime: "2026-03-01 09:00:00", |
| | | endTime: "2026-03-01 10:00:00", |
| | | }, |
| | | { |
| | | step: "物料准备", |
| | | status: |
| | | status === "completed" |
| | | ? "completed" |
| | | : status === "processing" |
| | | ? "completed" |
| | | : "pending", |
| | | startTime: |
| | | status === "completed" || status === "processing" |
| | | ? "2026-03-01 10:30:00" |
| | | : "", |
| | | endTime: |
| | | status === "completed" || status === "processing" |
| | | ? "2026-03-02 16:00:00" |
| | | : "", |
| | | }, |
| | | { |
| | | step: "生产加工", |
| | | status: |
| | | status === "completed" |
| | | ? "completed" |
| | | : status === "processing" |
| | | ? "processing" |
| | | : "pending", |
| | | startTime: |
| | | status === "completed" || status === "processing" |
| | | ? "2026-03-03 08:00:00" |
| | | : "", |
| | | endTime: status === "completed" ? "2026-03-08 17:00:00" : "", |
| | | }, |
| | | { |
| | | step: "质量检验", |
| | | status: status === "completed" ? "completed" : "pending", |
| | | startTime: status === "completed" ? "2026-03-09 09:00:00" : "", |
| | | endTime: status === "completed" ? "2026-03-09 15:00:00" : "", |
| | | }, |
| | | { |
| | | step: "入库", |
| | | status: status === "completed" ? "completed" : "pending", |
| | | startTime: status === "completed" ? "2026-03-10 10:00:00" : "", |
| | | endTime: status === "completed" ? "2026-03-10 11:00:00" : "", |
| | | }, |
| | | ]; |
| | | return details; |
| | | }; |
| | | |
| | | // 计算完成率 |
| | | const calculateCompletionRate = details => { |
| | | const completedSteps = details.filter( |
| | | step => step.status === "completed" |
| | | ).length; |
| | | return Math.round((completedSteps / details.length) * 100); |
| | | }; |
| | | |
| | | // 处理进度更新 |
| | | const handleUpdateProgress = () => { |
| | | // 这里可以添加更新进度的逻辑 |
| | | ElMessage.success("进度更新成功"); |
| | | showTrackProgressDialog.value = false; |
| | | }; |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", |
| | |
| | | applyNo: "", |
| | | dateRange: [], |
| | | }, |
| | | searchFormExpanded: false, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const { searchForm, searchFormExpanded } = toRefs(data); |
| | | |
| | | // 切换搜索表单展开/收起状态 |
| | | const toggleSearchForm = () => { |
| | | data.searchFormExpanded = !data.searchFormExpanded; |
| | | }; |
| | | |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | |
| | | sum + |
| | | (row.volume == null |
| | | ? 0 |
| | | : (Number(row.volume) - Number(row.assignedQuantity)).toFixed(4)) |
| | | : Number(Number(row.volume) - Number(row.assignedQuantity).toFixed(4))) |
| | | ); |
| | | }, 0); |
| | | sumAssignedQuantity.value = totalAssignedQuantity; |
| | |
| | | } |
| | | |
| | | console.log(mergeForm, "mergeForm"); |
| | | const strengthItem = block_strength.value.find(item => item.id === mergeForm.strength); |
| | | const strengthItem = block_strength.value.find( |
| | | item => item.id === mergeForm.strength |
| | | ); |
| | | const payload = { |
| | | ...mergeForm, |
| | | strength: strengthItem ? strengthItem.label : mergeForm.strength |
| | | strength: strengthItem ? strengthItem.label : mergeForm.strength, |
| | | }; |
| | | productionPlanCombine(payload) |
| | | .then(res => { |
| | |
| | | } |
| | | |
| | | .search_form { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | // margin-bottom: 24px; |
| | | padding: 20px; |
| | | background-color: #ffffff; |
| | | border-radius: 6px; |
| | |
| | | } |
| | | } |
| | | |
| | | .search-header { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | // margin-bottom: 5px; |
| | | // padding-bottom: 5px; |
| | | position: relative; |
| | | bottom: 35px; |
| | | // border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .search-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | |
| | | .search-header .el-button { |
| | | color: #606266; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .search-header .el-button:hover { |
| | | color: #409eff; |
| | | } |
| | | |
| | | .search-header .el-icon { |
| | | margin-right: 4px; |
| | | } |
| | | |
| | | .table_list { |
| | | // margin-bottom: 24px; |
| | | background-color: #ffffff; |
| | |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | overflow: hidden; |
| | | height: calc(100vh - 250px); |
| | | margin-top: 0px !important; |
| | | } |
| | | |
| | | :deep(.el-table) { |