From 4dfa438cbd4f3f475c97a2233688d1fe3628099c Mon Sep 17 00:00:00 2001 From: cuilei <ray_tsu1@163.com> Date: 星期六, 09 八月 2025 17:52:11 +0800 Subject: [PATCH] 生产管控 排产工单页面调整 --- src/views/mes/MesProductionWorkOrderListView.vue | 84 +++- src/views/mes/modules/MesProductionWorkOrderScheduleModal.vue | 793 +++++++++++++++++++++++++++++++++++++++++++++++++ src/views/mes/modules/MesProductionWeekCalendar.vue | 55 ++ src/views/base/ShiftManager.vue | 2 4 files changed, 904 insertions(+), 30 deletions(-) diff --git a/src/views/base/ShiftManager.vue b/src/views/base/ShiftManager.vue index 69321bc..8dec947 100644 --- a/src/views/base/ShiftManager.vue +++ b/src/views/base/ShiftManager.vue @@ -179,7 +179,7 @@ handleEdit(record) { this.$refs.modalForm.edit(record) this.$refs.modalForm.title = '缂栬緫鐝' - this.$refs.modalForm.disableSubmit = true + this.$refs.modalForm.disableSubmit = false }, handleDelete: function(record){ if(!this.url.deleteBatch){ diff --git a/src/views/mes/MesProductionWorkOrderListView.vue b/src/views/mes/MesProductionWorkOrderListView.vue index f9e9b5f..17bf9dc 100644 --- a/src/views/mes/MesProductionWorkOrderListView.vue +++ b/src/views/mes/MesProductionWorkOrderListView.vue @@ -1,5 +1,5 @@ <template> - <a-card :bordered="false" title="鎺掍骇宸ュ崟"> + <a-card :bordered="false"> <!-- 鏌ヨ鍖哄煙 --> <div class="table-page-search-wrapper"> <a-form layout="inline" @keyup.enter.native="searchQuery"> @@ -14,24 +14,33 @@ <j-input placeholder="璇疯緭鍏ョ墿鏂欑紪鍙�" v-model="queryParam.materialNumber"></j-input> </a-form-item> </a-col> - <a-col :xl="6" :lg="7" :md="8" :sm="24"> - <a-form-item label="宸ュ崟鐘舵��"> - <j-dict-select-tag dictCode="work_order_status" placeholder="璇疯緭鍏ュ伐鍗曠姸鎬�" - v-model="queryParam.workOrderStatus"></j-dict-select-tag> - </a-form-item> - </a-col> - <a-col :xl="6" :lg="7" :md="8" :sm="24"> - <a-form-item label="閲嶅彂甯冧汉"> - <j-select-user-by-dep placeholder="璇疯緭鍏ラ噸鍙戝竷浜�" - v-model="queryParam.republisher"></j-select-user-by-dep> - </a-form-item> - </a-col> + <template v-if="toggleSearchStatus"> + <a-col :xl="6" :lg="7" :md="8" :sm="24"> + <a-form-item label="宸ュ崟鐘舵��"> + <j-dict-select-tag dictCode="work_order_status" placeholder="璇疯緭鍏ュ伐鍗曠姸鎬�" + v-model="queryParam.workOrderStatus"></j-dict-select-tag> + </a-form-item> + </a-col> + <a-col :xl="6" :lg="7" :md="8" :sm="24"> + <a-form-item label="閲嶅彂甯冧汉"> + <j-select-user-by-dep placeholder="璇疯緭鍏ラ噸鍙戝竷浜�" + v-model="queryParam.republisher"></j-select-user-by-dep> + </a-form-item> + </a-col> + </template> <a-col :xl="6" :lg="7" :md="8" :sm="24"> <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons"> <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button> - <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">閲嶇疆</a-button> + <a-button type="info" @click="searchReset" icon="reload" style="margin-left: 8px">閲嶇疆</a-button> + <a @click="handleToggleSearch" style="margin-left: 8px"> + {{ toggleSearchStatus ? '鏀惰捣' : '灞曞紑' }} + <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/> + </a> </span> </a-col> + </a-row> + <a-row> + <a-button type="primary" @click="productionSchedule" icon="retweet" style="margin-bottom: 8px">鎺掍骇</a-button> </a-row> </a-form> </div> @@ -73,14 +82,22 @@ </template> <span slot="action" slot-scope="text, record"> - <a @click="handleEdit(record)">缂栬緫</a> - - <a-divider type="vertical" /> + <a @click="handleDetail(record)">璇︽儏</a> + <span v-if="record.workOrderStatus === 'PUBLISHED'"> + <a-divider type="vertical" /> + <a @click="handleRePublish(record)">閲嶅彂甯�</a> + </span> + <span v-if="record.workOrderStatus === 'NEW'"> + <a-divider type="vertical" /> + <a-popconfirm title="纭畾鍙戝竷鍚�?" @confirm="() => handlePublish(record.id)"> + <a>鍙戝竷</a> + </a-popconfirm> + <a-divider type="vertical" /> <a-dropdown> <a class="ant-dropdown-link">鏇村 <a-icon type="down" /></a> <a-menu slot="overlay"> <a-menu-item> - <a @click="handleDetail(record)">璇︽儏</a> + <a @click="handleEdit(record)">缂栬緫</a> </a-menu-item> <a-menu-item> <a-popconfirm title="纭畾鍒犻櫎鍚�?" @confirm="() => handleDelete(record.id)"> @@ -89,6 +106,8 @@ </a-menu-item> </a-menu> </a-dropdown> + </span> + </span> </a-table> </div> @@ -174,6 +193,8 @@ <mes-production-order-modal ref="MesProductionOrderModal"></mes-production-order-modal> <MesMaterialUnloadingList ref="MesMaterialUnloadingList"></MesMaterialUnloadingList> <MesMaterialTransferDetailList ref="MesMaterialTransferDetailList"></MesMaterialTransferDetailList> + <MesProductionWorkOrderScheduleModal ref="MesProductionWorkOrderScheduleModal"></MesProductionWorkOrderScheduleModal> + <MesProductionWorkOrderRepublishModal ref="MesProductionWorkOrderRepublishModal" @ok="modalFormOk"></MesProductionWorkOrderRepublishModal> </a-card> </template> @@ -186,10 +207,12 @@ import { JVxeTableModelMixin } from '@/mixins/JVxeTableModelMixin.js' import { JVXETypes } from '@/components/jeecg/JVxeTable' import { filterMultiDictText } from '@/components/dict/JDictSelectUtil' -import { getAction } from '@api/manage' +import { getAction, requestPut } from '@api/manage' import MesProductionOrderModal from '@views/mes/modules/MesProductionOrderModal.vue' import MesMaterialUnloadingList from '@views/mes/MesMaterialUnloadingList.vue' import MesMaterialTransferDetailList from '@views/mes/MesMaterialTransferDetailList.vue' +import MesProductionWorkOrderScheduleModal from '@views/mes/modules/MesProductionWorkOrderScheduleModal.vue' +import MesProductionWorkOrderRepublishModal from '@views/mes/modules/MesProductionWorkOrderRepublishModal.vue' export default { name: 'MesProductionWorkOrderList', @@ -198,7 +221,9 @@ MesProductionWorkOrderModal, MesProductionOrderModal, MesMaterialUnloadingList, - MesMaterialTransferDetailList + MesMaterialTransferDetailList, + MesProductionWorkOrderScheduleModal, + MesProductionWorkOrderRepublishModal }, data() { return { @@ -648,7 +673,8 @@ queryCompletenessCheckByWorkOrderId:'/meskittingcompletenesscheck/mesKittingCompletenessCheck/queryCompletenessCheckByWorkOrderId', queryOrderById:'/mesproductionwork/mesProductionOrder/queryById', queryUnloadingByLoadingId:'/mes/mesMaterialUnloading/queryUnloadingByLoadingId', - queryTransferDetailBy:'/mes/mesMaterialTransferDetail/queryTransferDetailBy' + queryTransferDetailBy:'/mes/mesMaterialTransferDetail/queryTransferDetailBy', + publish: '/mesproductionworkorder/mesProductionWorkOrder/publish' }, dictOptions: {}, superFieldList: [] @@ -663,6 +689,22 @@ } }, methods: { + productionSchedule() { + this.$refs.MesProductionWorkOrderScheduleModal.scheduleOpen() + }, + handlePublish(id) { + requestPut(this.url.publish, null, { ids: id }).then((res) => { + if (res.success) { + this.$message.success(res.message) + this.loadData() + } else { + this.$message.warning(res.message) + } + }) + }, + handleRePublish(record) { + this.$refs.MesProductionWorkOrderRepublishModal.add(record) + }, async handleTransferDetail(row){ console.log('row---->',row) const transferDetailResult = await getAction(this.url.queryTransferDetailBy,{'requestId':row.id}) diff --git a/src/views/mes/modules/MesProductionWeekCalendar.vue b/src/views/mes/modules/MesProductionWeekCalendar.vue index 46c0716..d902bae 100644 --- a/src/views/mes/modules/MesProductionWeekCalendar.vue +++ b/src/views/mes/modules/MesProductionWeekCalendar.vue @@ -1,11 +1,11 @@ <!-- src/views/mes/modules/MesProductionWeekCalendar.vue --> <template> <div class="week-calendar"> - <div class="calendar-header"> - <a-button icon="left" @click="prevWeek" size="small" /> + <div v-if="showHeader" class="calendar-header"> + <a-button v-if="showNavigation" icon="left" @click="prevWeek" size="small" /> <span class="current-week-range">{{ weekRangeText }}</span> - <a-button icon="right" @click="nextWeek" size="small" /> - <a-button @click="goToToday" size="small" style="margin-left: 8px">浠婂ぉ</a-button> + <a-button v-if="showNavigation" icon="right" @click="nextWeek" size="small" /> + <a-button v-if="showTodayButton" @click="goToToday" size="small" style="margin-left: 8px">浠婂ぉ</a-button> </div> <div class="calendar-grid"> @@ -14,11 +14,16 @@ v-for="(day, index) in weekDays" :key="index" class="header-cell" + :class="{ 'first-day-highlight': showFirstDayHighlight && index === 0 }" > <div class="day-name">{{ day.format('ddd') }}</div> <div class="day-number" - :class="{ today: isToday(day), selected: isSelected(day) }" + :class="{ + 'highlight': showTodayHighlight && isToday(day), + today: isToday(day), + selected: isSelected(day) + }" @click="selectDay(day)" > {{ day.date() }} @@ -31,7 +36,12 @@ v-for="(day, index) in weekDays" :key="index" class="day-cell" - :class="{ today: isToday(day), selected: isSelected(day) }" + :class="{ + 'highlight': showTodayHighlight && isToday(day), + 'first-day-highlight': showFirstDayHighlight && index === 0, + today: isToday(day), + selected: isSelected(day) + }" @click="selectDay(day)" > <div class="cell-content"> @@ -64,6 +74,31 @@ startDate: { type: [Object, String, Date], default: null + }, + // 鏄惁鏄剧ず澶撮儴瀵艰埅 + showHeader: { + type: Boolean, + default: true + }, + // 鏄惁鏄剧ず瀵艰埅鎸夐挳锛堝墠鍚庣炕椤碉級 + showNavigation: { + type: Boolean, + default: true + }, + // 鏄惁鏄剧ず浠婂ぉ鎸夐挳 + showTodayButton: { + type: Boolean, + default: true + }, + // 鏄惁楂樹寒褰撳ぉ + showTodayHighlight: { + type: Boolean, + default: true + }, + // 鏄惁楂樹寒鏈懆绗竴澶� + showFirstDayHighlight: { + type: Boolean, + default: true } }, data() { @@ -179,6 +214,10 @@ border-right: none; } +.header-cell.first-day-highlight { + background-color: #ffffff; /* 閲嶇疆绗竴澶╃殑鑳屾櫙鑹� */ +} + .day-name { font-size: 12px; color: #666; @@ -196,7 +235,7 @@ border-radius: 50%; } -.day-number.today { +.day-number.today.highlight { background-color: #1890ff; color: white; } @@ -222,7 +261,7 @@ border-right: none; } -.day-cell.today { +.day-cell.today.highlight { background-color: #e6f7ff; } diff --git a/src/views/mes/modules/MesProductionWorkOrderScheduleModal.vue b/src/views/mes/modules/MesProductionWorkOrderScheduleModal.vue new file mode 100644 index 0000000..8a0a54a --- /dev/null +++ b/src/views/mes/modules/MesProductionWorkOrderScheduleModal.vue @@ -0,0 +1,793 @@ +<template> + <j-modal + :title="title" + :width="width" + :visible="visible" + :fullscreen="true" + switchFullscreen + @ok="handleOk" + :okButtonProps="{ class:{'jee-hidden': disableSubmit} }" + @cancel="handleCancel" + cancelText="鍏抽棴"> + + <a-row :gutter="{ xs: 4, sm: 8, md: 16}"> + <a-col :span="12"> + <a-card :bordered="false"> + <!-- 鏌ヨ鍖哄煙 --> + <div class="table-page-search-wrapper"> + <a-form layout="inline" @keyup.enter.native="searchQuery"> + <a-row :gutter="12"> + <a-col :span="7"> + <a-form-item label="浜х嚎" :label-col="{span: 6}" :wrapper-col="{span: 18}"> + <j-tree-select dict="base_factory,factory_name,id" pid-field="parent_id" + v-model="queryParam.factoryId" style="width: 100%"></j-tree-select> + </a-form-item> + </a-col> + <a-col :span="9"> + <a-form-item label="鏃ユ湡" :label-col="{span: 4}" :wrapper-col="{span: 20}"> + <a-range-picker + style="width: 100%" + @change="dateRangeChange" + :value="dateRange" + :disabledDate="disabledDate" + @openChange="onOpenChange" + /> + </a-form-item> + </a-col> + <a-col :span="8"> + <span style="float: left;overflow: hidden;white-space: nowrap;" class="table-page-search-submitButtons"> + <a-button type="primary" @click="searchQuery" icon="search">鏌ヨ</a-button> + <a-button type="info" @click="searchReset" icon="reload" style="margin-left: 8px">閲嶇疆</a-button> + </span> + </a-col> + </a-row> + <a-row :gutter="12" style="margin-top: 8px;"> + <a-col :span="24"> + <a-button type="primary" @click="generatePlan" icon="retweet">鐢熸垚鎺掍骇璁″垝</a-button> + </a-col> + </a-row> + </a-form> + </div> + + <div class="table-operator"> + <a-dropdown v-if="selectedRowKeys.length > 0"> + <a-menu slot="overlay"> + <a-menu-item key="1" @click="batchDel"> + <a-icon type="delete" /> + 鍒犻櫎 + </a-menu-item> + </a-menu> + <a-button style="margin-left: 8px"> 鎵归噺鎿嶄綔 + <a-icon type="down" /> + </a-button> + </a-dropdown> + </div> +<!-- <div>--> +<!-- <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">--> +<!-- <i class="anticon anticon-info-circle ant-alert-icon"></i> 宸查�夋嫨 <a--> +<!-- style="font-weight: 600">{{ selectedRowKeys.length }}</a>椤�--> +<!-- <a style="margin-left: 24px" @click="onClearSelected">娓呯┖</a>--> +<!-- </div>--> + + <vxe-table + ref="table" + border + show-overflow + show-header-overflow + :scroll-x="{enabled: true}" + :data="dataSource" + :edit-config="{trigger: 'click', mode: 'cell', activeMethod: isRowEditable}" + :edit-rules="editRules" + > +<!-- <vxe-table-column type="checkbox" width="40" fixed="left"></vxe-table-column>--> + <vxe-table-column type="seq" width="40" /> + <vxe-table-column width="100" title="宸ュ崟鍙�" field="workOrderCode"> + <template #default="{ row }"> + <span v-if="row.workOrderCode">{{ row.workOrderCode }}</span> + <span v-else class="placeholder-text">绯荤粺鑷姩鐢熸垚</span> + </template> + </vxe-table-column> + <vxe-table-column + title="鐗╂枡缂栧彿" + field="materialNumber" + width="120" + :edit-render="{name: '$select', options: materialOptions, events: {change: handleMaterialChange}}"> + <template #default="{ row }"> + <span v-if="row.materialNumber">{{ row.materialNumber }}</span> + <span v-else class="placeholder-text">璇烽�夋嫨鐗╂枡缂栧彿</span> + </template> + </vxe-table-column> + <vxe-table-column title="鐗╂枡鍚嶇О" field="materialName" width="100"> + <template #default="{ row }"> + <span v-if="row.materialName">{{ row.materialName }}</span> + <span v-else class="placeholder-text">鐗╂枡鍚嶇О鑷姩濉厖</span> + </template> + </vxe-table-column> + <vxe-table-column title="鐝粍id" :visible="false" field="groupId"></vxe-table-column> + <vxe-table-column + title="鐝" + width="100" + field="shiftId" + :edit-render="{name: '$select', options: shiftOptions, events: {change: handleShiftChange}}"> + <template #default="{ row }"> + <span v-if="row.shiftId">{{ row.shiftName || row.shiftId_dictText }}</span> + <span v-else class="placeholder-text">璇烽�夋嫨鐝</span> + </template> + </vxe-table-column> + <vxe-table-column + title="鎺掍骇鏃ユ湡" + field="workOrderDate" + width="120" + :edit-render="{name: '$select', options: workOrderDateOptions, events: {change: handleWorkOrderDateChange}}"> + <template #default="{ row }"> + <span v-if="row.workOrderDate">{{ row.workOrderDate }}</span> + <span v-else class="placeholder-text">璇烽�夋嫨鎺掍骇鏃ユ湡</span> + </template> + </vxe-table-column> + <vxe-table-column + title="璁″垝鐢熶骇鏁伴噺" + field="planQuantity" + width="100" + :edit-render="{name: '$input'}"> + <template #default="{ row }"> + <span v-if="row.planQuantity">{{ row.planQuantity }}</span> + <span v-else class="placeholder-text">璇峰~鍐欒鍒掔敓浜ф暟閲�</span> + </template> + </vxe-table-column> + <vxe-table-column title="" width="40" fixed="right"> + <template #default="{ row }"> + <span v-if="row.workOrderStatus === 'NEW' || !row.workOrderStatus"> + <i class="vxe-icon--remove" @click="handleRemove(row)"></i> + </span> + </template> + </vxe-table-column> + </vxe-table> + <a-button + :disabled="addScheduleFlag" + style="width: 100%; margin-top: 16px; margin-bottom: 8px" + type="dashed" + icon="plus" + @click="addSchedulePlan" + >鏂板鎺掍骇璁″垝 + </a-button> +<!-- <vxe-pager--> +<!-- :current-page="pagination.current"--> +<!-- :page-size="pagination.pageSize"--> +<!-- :total="pagination.total"--> +<!-- :layouts="['PrevPage', 'JumpNumber', 'NextPage', 'FullJump', 'Sizes', 'Total']"--> +<!-- @page-change="handlePageChange">--> +<!-- </vxe-pager>--> + </div> + </a-card> + </a-col> + <a-col :span="12"> + <a-card :bordered="false"> + <MesProductionWeekCalendar + ref="weekCalendar" + :start-date="calendarStartDate" + :show-navigation="false" + :show-today-button="false" + :show-today-highlight="false" + :show-first-day-highlight="false" + @select="onDateSelect" + @change="onCalendarChange" + > + <template #dateCell="{ date, isSelected, isToday }"> + <div class="custom-date-content"> + <div + v-for="(workOrder, index) in getWorkOrdersForDate(date)" + :key="workOrder.id" + class="work-order-item" + :class="getColorClass(index)" + > + <span class="work-order-shift">{{ workOrder.shiftCode }}</span> + <span class="work-order-material">{{ workOrder.materialName }}</span> + <span class="work-order-quantity">{{ workOrder.planQuantity }}</span> + </div> + </div> + </template> + </MesProductionWeekCalendar> + </a-card> + </a-col> + </a-row> + + </j-modal> + + +</template> + +<script> + +import '@/assets/less/TableExpand.less' +import MesProductionWeekCalendar from '@views/mes/modules/MesProductionWeekCalendar.vue' +import moment from 'moment' +import { getAction, postAction, requestPut } from '@api/manage' +import { ajaxGetDictItems } from '@api/api' + +export default { + name: 'MesProductionWorkOrderScheduleModal', + components: { + MesProductionWeekCalendar + }, + data() { + return { + title: '鎺掍骇绠$悊椤甸潰', + width: 600, + visible: false, + disableSubmit: false, + addScheduleFlag: false, + queryParam: {}, + dataSource: [], + shiftOptions: [], + groupShiftMap: {}, + materialOptions: [], + materNumberNameMap: {}, + workOrderDateOptions: [], + selectedRowKeys: [], + selectionRows: [], + /* 鍒嗛〉鍙傛暟 */ + pagination: { + current: 1, + pageSize: 10, + total: 0 + }, + // 琛ㄥご + url: { + list: '/mesproductionworkorder/mesProductionWorkOrder/list', + delete: '/mesproductionworkorder/mesProductionWorkOrder/delete', + deleteBatch: '/mesproductionworkorder/mesProductionWorkOrder/deleteBatch', + exportXlsUrl: '/mesproductionworkorder/mesProductionWorkOrder/exportXls', + importExcelUrl: 'mesproductionworkorder/mesProductionWorkOrder/importExcel', + listProductionLinesOption: '/base/factory/queryIdTree', + queryShiftGroupByFactoryId: '/base/shiftGroup/queryShiftGroupByFactoryId', + queryFactoryById: '/base/factory/queryById', + schedule: '/mesproductionworkorder/mesProductionWorkOrder/schedule', + addSchedulePlan: '/mesproductionworkorder/mesProductionWorkOrder/addSchedulePlan' + }, + editRules: { + materialNumber: [ + { required: true, message: '鐗╂枡缂栧彿蹇呴』閫夋嫨' } + ], + shiftId: [ + { required: true, message: '鐝蹇呴』閫夋嫨' } + ], + workOrderDate: [ + { required: true, message: '鎺掍骇鏃ユ湡蹇呴』閫夋嫨' } + ], + planQuantity: [ + { required: true, message: '璁″垝鐢熶骇鏁伴噺涓哄繀濉�' } + ] + }, + dictOptions: {}, + superFieldList: [], + // 鐢ㄤ簬婕旂ず鐨勫伐鍗曟暟鎹� + workOrdersByDate: {}, + // 鏃ュ巻璧峰鏃ユ湡 + calendarStartDate: moment().startOf('week'), // 榛樿鏄剧ず褰撳墠鍛ㄧ殑鍛ㄤ竴 + productionLineData: [], + dateRange: [], + tempStartDate: null, // 涓存椂瀛樺偍寮�濮嬫棩鏈� + hoveredDate: null // 瀛樺偍榧犳爣鎮仠鐨勬棩鏈� + } + }, + created() { + }, + watch: { + dataSource: { + handler() { + // 浣跨敤 nextTick 纭繚鍦� DOM 鏇存柊鍚庡啀鏇存柊鏃ュ巻 + this.$nextTick(() => { + this.updateCalendarWorkOrders() + }) + }, + deep: true + } + }, + computed: { + importExcelUrl: function() { + return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}` + } + }, + methods: { + isRowEditable({row, rowIndex}) { + return row.workOrderStatus === 'NEW' || !row.workOrderStatus + }, + getColorClass(index) { + return index % 2 === 0 ? 'blue-item' : 'red-item'; + }, + scheduleOpen() { + this.visible = true + }, + close() { + this.$emit('close') + this.visible = false + }, + handleOk() { + // 琛ㄦ牸鍏ㄨ〃鏍¢獙 + this.$refs.table.validate((valid) => { + if (valid) { + this.$message.error("璇峰畬鎴愭墍鏈夊繀濉俊鎭悗鍐嶆彁浜わ紒") + } else { + let tableData = this.$refs.table.getTableData().fullData + postAction(this.url.addSchedulePlan, tableData).then(res=> { + if (res.success) { + this.$message.success(res.message) + this.submitCallback() + } else { + this.$message.warning(res.message) + } + }) + } + }) + }, + submitCallback() { + this.$emit('ok') + this.queryParam = {} + this.dateRange = [] + this.workOrdersByDate = {} + this.dataSource = [] + this.visible = false + }, + handleCancel() { + this.queryParam = {} + this.dateRange = [] + this.workOrdersByDate = {} + this.dataSource = [] + this.pagination.current = 1 + this.pagination.pageSize = 10 + this.pagination.total = 0 + this.close() + }, + onClearSelected() { + this.selectedRowKeys = [] + this.selectionRows = [] + }, + loadData(arg) { + return new Promise((resolve, reject) => { + //鍔犺浇鏁版嵁 鑻ヤ紶鍏ュ弬鏁�1鍒欏姞杞界涓�椤电殑鍐呭 + if (arg === 1) { + this.pagination.current = 1 + } + var params = Object.assign({}, this.queryParam, { + pageNo: this.pagination.current, + pageSize: this.pagination.pageSize + }) + console.log('params', params) + if (!params) { + reject(new Error('鏌ヨ鍙傛暟鏃犳晥')) + return false + } + this.loading = true + getAction(this.url.list, params).then((res) => { + if (res.success) { + this.dataSource = res.result.records || res.result + if (res.result.total) { + this.pagination.total = res.result.total + } else { + this.pagination.total = 0 + } + resolve(res) + } else { + this.$message.warning(res.message) + reject(new Error(res.message)) + } + }).catch(error => { + reject(error) + }).finally(() => { + this.loading = false + }) + }) + }, + handlePageChange({ currentPage, pageSize }) { + this.pagination.current = currentPage + this.pagination.pageSize = pageSize + this.loadData() + }, + searchQuery() { + if (!this.queryParam.factoryId || this.dateRange.length === 0) { + this.$message.warning('璇烽�夋嫨浜х嚎鍙婃帓浜ф棩鏈熻寖鍥达紒') + return + } + this.queryParam = Object.assign(this.queryParam, this.dateRange) + this.loadData(1).then(() => { + this.initTableData(null, this.dateRange) + // 璁剧疆鏃ュ巻鏄剧ず涓烘煡璇㈡棩鏈熻寖鍥村唴鐨勭涓�鍛� + if (this.dateRange[0]) { + this.calendarStartDate = this.dateRange[0].clone().startOf('week'); + } + }) + }, + searchReset() { + this.queryParam = {} + this.dateRange = [] + this.workOrdersByDate = {} + this.dataSource = [] + this.pagination.total = 0 + }, + // 鐢熸垚宸ュ崟鍙风殑鏂规硶 + generateWorkOrderCode(row) { + // 鑾峰彇鍚勪釜瀛楁鐨勫�� + const factoryCode = row.factoryCode || ''; + const materialNumber = row.materialNumber || ''; + const workDate = row.workOrderDate || ''; + const shiftCode = row.shiftCode || ''; + + let formattedDate = workDate; + if (workDate && workDate.length >= 10) { + // 濡傛灉鏄畬鏁存棩鏈熸牸寮忥紝鎻愬彇 YYYY-MM-DD 閮ㄥ垎 + formattedDate = workDate.substring(0, 10).replace(/-/g, ''); + } + return `${factoryCode}${materialNumber}${formattedDate}${shiftCode}`; + }, + updateWorkOrderCode(row) { + row.workOrderCode = this.generateWorkOrderCode(row); + }, + // 鏍煎紡鍖栨棩鏈熶负 YYYY-MM-DD + formatDate(date) { + 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}`; + }, + // 鐢熸垚鏃ユ湡鑼冨洿鏁扮粍 + generateDateRangeOptions(startDate, endDate) { + const dateOptions = []; + const start = new Date(startDate); + const end = new Date(endDate); + + // 璁剧疆鏃堕棿涓烘瘡澶╃殑0鐐� + start.setHours(0, 0, 0, 0); + end.setHours(0, 0, 0, 0); + + // 鐢熸垚鏃ユ湡鑼冨洿鍐呯殑鎵�鏈夋棩鏈� + for (let date = new Date(start); date <= end; date.setDate(date.getDate() + 1)) { + const formattedDate = this.formatDate(date); + dateOptions.push({ + value: formattedDate, + label: formattedDate + }); + } + return dateOptions; + }, + initDictSelectOptions(record) { + return new Promise((resolve) => { + // 骞惰鎵ц澶氫釜寮傛璇锋眰 + const promises = []; + + let factoryId + if (record && record.length > 0) { + factoryId = record[0].factoryId + } else { + factoryId = this.queryParam.factoryId + } + + const shiftGroupPromise = getAction(this.url.queryShiftGroupByFactoryId, { factoryId: factoryId }).then(res => { + if (res.success) { + this.shiftOptions = res.result.map(item => { + return { + value: item.shiftId, + label: item.shiftId_dictText + } + }) + this.groupShiftMap = res.result.reduce((map, item) => { + map[item.shiftId] = { + groupId: item.id, + shiftCode: item.shiftCode_dictText, + shiftName: item.shiftId_dictText + } + return map + }, {}) + } + }).catch(() => { + }); + promises.push(shiftGroupPromise); + + const materialNumberPromise = ajaxGetDictItems("lsw_material,material_name,material_number,del_flag!='1' order by material_number asc", null).then(res => { + if (res.success) { + this.materialOptions = res.result.map(item => { + return { + value: item.value, + label: item.value + } + }); + this.materNumberNameMap = res.result.reduce((map, item) => { + map[item.value] = item.text + return map + }, {}) + } + }).catch(() => { + }); + promises.push(materialNumberPromise); + + // 绛夊緟鎵�鏈夎姹傚畬鎴� + Promise.all(promises).then(() => { + resolve(); + }); + }) + }, + generatePlan() { + if (!this.queryParam.factoryId || this.dateRange.length === 0) { + this.$message.warning('璇烽�夋嫨浜х嚎鍙婃帓浜ф棩鏈熻寖鍥达紒') + return + } + getAction(this.url.schedule, { + factoryId: this.queryParam.factoryId, + startDate: this.dateRange[0].format('YYYY-MM-DD'), + endDate: this.dateRange[1].format('YYYY-MM-DD') + }).then(res => { + if (res.success) { + const record = res.result + this.initTableData(record, this.dateRange) + // 璁剧疆鏃ュ巻鏄剧ず涓虹敓鎴愯鍒掓棩鏈熻寖鍥村唴鐨勭涓�鍛� + if (this.dateRange[0]) { + this.calendarStartDate = this.dateRange[0].clone().startOf('week'); + } + } + }) + }, + initTableData(record, dateRange) { + // 鍏堝姞杞藉瓧鍏告暟鎹紝鍐嶅垵濮嬪寲琛ㄥ崟 + this.initDictSelectOptions(record).then(() => { + this.$nextTick(() => { + // 鏍规嵁鏃ユ湡鑼冨洿鐢熸垚鎺掍骇鏃ユ湡閫夐」 + if (dateRange && dateRange.length === 2) { + this.workOrderDateOptions = this.generateDateRangeOptions(dateRange[0], dateRange[1]); + } + + // 涓烘瘡鏉¤褰曠敓鎴愬伐鍗曞彿 + if (record && record.length > 0) { + record.forEach(row => { + if (!row.workOrderCode) { + this.updateWorkOrderCode(row); + } + }); + this.dataSource.push(...record) + } + this.pagination.total = this.dataSource.length + this.$nextTick(() => { + if (this.$refs.table && this.dataSource.length > 0) { + // 婵�娲荤涓�琛岃繘鍏ョ紪杈戠姸鎬� + this.$refs.table.setActiveRow(this.dataSource[0]) + } + }) + }); + }) + }, + handleWorkOrderDateChange($event, value) { + $event.row.workOrderDate = value.value; + this.updateWorkOrderCode($event.row) + }, + handleMaterialChange($event, value) { + const key = value.value + if (key && this.materNumberNameMap[key]) { + $event.row.materialName = this.materNumberNameMap[key] + } else { + $event.row.materialName = ''; + } + // 鏇存柊鐗╂枡缂栧彿 + $event.row.materialNumber = key; + // 閲嶆柊鐢熸垚宸ュ崟鍙� + this.updateWorkOrderCode($event.row); + }, + handleShiftChange($event, value) { + const key = value.value + // 浠� groupShiftMap 涓幏鍙栧搴旂殑鐝粍id + if (key && this.groupShiftMap[key]) { + // 鏇存柊褰撳墠琛岀殑鐝粍id銆佺彮娆$紪鐮侊紙鎷兼帴宸ュ崟鍙风敤锛夊瓧娈� + $event.row.groupId = this.groupShiftMap[key].groupId + $event.row.shiftCode = this.groupShiftMap[key].shiftCode + $event.row.shiftName = this.groupShiftMap[key].shiftName + } else { + // 濡傛灉娌℃湁鍖归厤鐨勭彮缁勶紝鍒欐竻绌� + $event.row.groupId = '' + $event.row.shiftCode = '' + $event.row.shiftName = '' + } + // 閲嶆柊鐢熸垚宸ュ崟鍙� + this.updateWorkOrderCode($event.row); + }, + async addSchedulePlan() { + if (!this.queryParam.factoryId || this.dateRange.length === 0) { + this.$message.warning('璇峰厛閫夋嫨浜х嚎鍙婃帓浜ф棩鏈熻寖鍥达紒') + return + } + let factoryCode = '' + if (this.dataSource.length === 0) { + const res = await getAction(this.url.queryFactoryById, {id: this.queryParam.factoryId}) + if (res.success) { + factoryCode = res.result.factoryCode + } + } else { + factoryCode = this.dataSource[0].factoryCode + } + // 鍒涘缓鏂拌鏁版嵁 + const newRow = { + workOrderCode: factoryCode, + materialNumber: '', + materialName: '', + factoryId: this.dataSource.length > 0 ? this.dataSource[0].factoryId : this.queryParam.factoryId, + factoryCode: factoryCode, + groupId: '', + shiftId: '', + shiftCode: '', + shiftName: '', + workOrderDate: '', + planQuantity: '' + } + this.initDictSelectOptions(null).then(() => { + // 鏍规嵁鏃ユ湡鑼冨洿鐢熸垚鎺掍骇鏃ユ湡閫夐」 + if (this.dateRange && this.dateRange.length === 2) { + this.workOrderDateOptions = this.generateDateRangeOptions(this.dateRange[0], this.dateRange[1]); + } + this.dataSource.push(newRow) + this.pagination.total += 1 + // 婵�娲绘柊澧炵殑琛岃繘鍏ョ紪杈戠姸鎬� + this.$nextTick(() => { + if (this.$refs.table) { + this.$refs.table.setActiveRow(newRow) + } + }) + }) + }, + handleRemove(row) { + let table = this.$refs.table + this.$confirm({ + title: '鎻愮ず', + content: '纭瑕佸垹闄ゅ悧锛�', + okText: '纭畾', + cancelText: '鍙栨秷', + onOk: () => { + const index = this.dataSource.indexOf(row) + if (index > -1) { + this.dataSource.splice(index, 1) + this.pagination.total -= 1 + } + // 鍒犻櫎琛� + table.remove(row) + } + }) + }, + onOpenChange(open) { + if (!open) { + // 鍏抽棴閫夋嫨鍣ㄦ椂閲嶇疆鐘舵�� + this.tempStartDate = null + this.hoveredDate = null + } + }, + disabledDate(current) { + // 濡傛灉鏈変复鏃跺紑濮嬫棩鏈燂紝鍒欓檺鍒剁粨鏉熸棩鏈熻寖鍥� + if (this.tempStartDate) { + const startDate = this.tempStartDate.clone().startOf('day') + const maxDate = startDate.clone().add(6, 'days').endOf('day') // 7澶╁寘鎷捣濮嬫棩 + const minDate = startDate.clone().subtract(6, 'days').startOf('day') // 涔熷彲浠ュ悜鍓嶉��6澶� + // 绂佺敤瓒呭嚭7澶╄寖鍥寸殑鏃ユ湡 + return current && (current < minDate || current > maxDate) + } + // 榛樿涓嶇鐢� + return false + }, + dateRangeChange(dates, dateStrings) { + this.dateRange = dates + if (dates && dates.length > 0) { + if (dates.length === 1) { + // 閫夋嫨浜嗗紑濮嬫棩鏈燂紝淇濆瓨鍒颁复鏃跺彉閲� + this.tempStartDate = dates[0] + this.hoveredDate = dates[0] + } else if (dates.length === 2) { + // 閫夋嫨浜嗙粨鏉熸棩鏈燂紝楠岃瘉鑼冨洿 + const startDate = dates[0] + const endDate = dates[1] + const diffDays = endDate.diff(startDate, 'days') + 1 + + if (diffDays > 7) { + this.$message.warning('鏃ユ湡鑼冨洿涓嶈兘瓒呰繃7澶�') + // 鑷姩璋冩暣涓�7澶╄寖鍥� + const adjustedEndDate = startDate.clone().add(6, 'days') + this.dateRange = [startDate, adjustedEndDate] + this.queryParam.startDate = startDate.format('YYYY-MM-DD') + this.queryParam.endDate = adjustedEndDate.format('YYYY-MM-DD') + } else { + this.queryParam.startDate = dateStrings[0] + this.queryParam.endDate = dateStrings[1] + } + // 閲嶇疆涓存椂鐘舵�� + this.tempStartDate = null + this.hoveredDate = null + } + + // 鏇存柊鏃ュ巻鏄剧ず涓洪�変腑鏃ユ湡鎵�鍦ㄥ懆 + if (dates[0]) { + this.calendarStartDate = dates[0].clone().startOf('week'); + } + } else { + // 娓呴櫎浜嗛�夋嫨 + this.queryParam.startDate = null + this.queryParam.endDate = null + this.tempStartDate = null + this.hoveredDate = null + // 閲嶇疆鏃ュ巻涓哄綋鍓嶅懆 + this.calendarStartDate = moment().startOf('week'); + } + }, + // 澶勭悊鏃ユ湡閫夋嫨浜嬩欢 - 鏇存柊鏃ュ巻鏄剧ず涓洪�変腑鏃ユ湡鎵�鍦ㄥ懆 + onDateSelect(date) { + console.log('Selected date:', date.format('YYYY-MM-DD')) + // 鏇存柊鏃ュ巻鏄剧ず涓洪�変腑鏃ユ湡鎵�鍦ㄥ懆 + this.calendarStartDate = date.clone().startOf('week'); + }, + + // 澶勭悊鏃ュ巻鍛ㄥ彉鍖栦簨浠� + onCalendarChange(date) { + console.log('Calendar week changed:', date.format('YYYY-MM-DD')) + // 鏃ュ巻鍛ㄥ彉鍖栨椂鏇存柊 startDate + this.calendarStartDate = date.clone().startOf('week'); + }, + // 鏇存柊鏃ュ巻涓殑宸ュ崟鏁版嵁 + updateCalendarWorkOrders() { + const workOrdersByDate = {} + this.dataSource.forEach(workOrder => { + const workOrderDate = workOrder.workOrderDate + if (workOrderDate) { + if (!workOrdersByDate[workOrderDate]) { + workOrdersByDate[workOrderDate] = [] + } + workOrdersByDate[workOrderDate].push({ + id: workOrder.id, + shiftCode: workOrder.shiftCode || '', + materialName: workOrder.materialName || '', + planQuantity: workOrder.planQuantity || 0 + }) + } + }) + this.workOrdersByDate = workOrdersByDate + }, + // 鑾峰彇鎸囧畾鏃ユ湡鐨勫伐鍗� + getWorkOrdersForDate(date) { + const dateStr = date.format('YYYY-MM-DD') + return this.workOrdersByDate[dateStr] || [] + } + } +} +</script> +<style scoped> +@import '~@assets/less/common.less'; + +.placeholder-text { + font-style: italic; + color: #999; +} + +.work-order-item { + font-size: 12px; + padding: 2px 4px; + margin-bottom: 2px; + background-color: #f0f0f0; + border-radius: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.work-order-item.blue-item { + background-color: #e6f7ff; + border-left: 2px solid #1890ff; +} + +.work-order-item.red-item { + background-color: #fff1f0; + border-left: 2px solid #f5222d; +} + +.work-order-shift { + font-weight: bold; + margin-right: 4px; +} + +.work-order-material { + margin-right: 4px; +} + +.work-order-quantity { + float: right; +} +</style> \ No newline at end of file -- Gitblit v1.9.3