ids, Boolean isValid) {
+ if (isValid) {
+ // TODO: 可以添加业务校验,例如检查是否被日历班次配置使用
+ }
+ return baseMapper.deleteBatchIds(ids) > 0;
+ }
+}
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsAutoScheduleMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsAutoScheduleMapper.xml
new file mode 100644
index 00000000..c9722545
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsAutoScheduleMapper.xml
@@ -0,0 +1,230 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DELETE FROM wms_schedule_operation
+ WHERE plan_id = #{planId}
+ AND locked_flag = 0
+
+
+
+
+
+
+
+ INSERT INTO wms_schedule_operation
+ (
+ plan_id,
+ detail_id,
+ order_id,
+ order_detail_id,
+ product_id,
+ process_id,
+ line_id,
+ sequence_no,
+ plan_qty,
+ start_time,
+ end_time,
+ setup_minutes,
+ status,
+ locked_flag,
+ remark,
+ create_by,
+ update_by
+ )
+ VALUES
+ (
+ #{planId},
+ #{detailId},
+ #{orderId},
+ #{orderDetailId},
+ #{productId},
+ #{processId},
+ #{lineId},
+ #{sequenceNo},
+ #{planQty},
+ #{startTime},
+ #{endTime},
+ #{setupMinutes},
+ #{status},
+ #{lockedFlag},
+ #{remark},
+ #{createBy},
+ #{updateBy}
+ )
+
+
+
+ INSERT INTO wms_schedule_change_log
+ (
+ operation_id,
+ change_type,
+ before_value,
+ after_value,
+ change_reason,
+ change_by
+ )
+ VALUES
+ (
+ #{operationId},
+ #{changeType},
+ #{beforeValue},
+ #{afterValue},
+ #{changeReason},
+ #{changeBy}
+ )
+
+
+
+ UPDATE wms_schedule_plan
+ SET status = #{status},
+ update_by = #{updateBy},
+ update_time = CURRENT_TIMESTAMP
+ WHERE plan_id = #{planId}
+ AND del_flag = 0
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsCalendarMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsCalendarMapper.xml
new file mode 100644
index 00000000..d4ef045b
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsCalendarMapper.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT calendar_id, calendar_date, calendar_type, factory_code, remark,
+ create_by, create_time, update_by, update_time
+ FROM wms_calendar
+
+
+
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsCalendarShiftMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsCalendarShiftMapper.xml
new file mode 100644
index 00000000..7a2303b7
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsCalendarShiftMapper.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsGanttMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsGanttMapper.xml
new file mode 100644
index 00000000..49af8740
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsGanttMapper.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsLineCapabilityMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsLineCapabilityMapper.xml
new file mode 100644
index 00000000..197d5939
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsLineCapabilityMapper.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsLockMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsLockMapper.xml
new file mode 100644
index 00000000..6065f119
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsLockMapper.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+ INSERT INTO wms_schedule_lock
+ (
+ lock_type,
+ plan_id,
+ line_id,
+ operation_id,
+ lock_start_time,
+ lock_end_time,
+ lock_reason,
+ status,
+ create_by,
+ update_by
+ )
+ VALUES
+ (
+ #{lockType},
+ #{planId},
+ #{lineId},
+ #{operationId},
+ #{lockStartTime},
+ #{lockEndTime},
+ #{lockReason},
+ #{status},
+ #{createBy},
+ #{updateBy}
+ )
+
+
+
+ UPDATE wms_schedule_lock
+ SET status = #{status},
+ update_by = #{updateBy},
+ update_time = CURRENT_TIMESTAMP
+ WHERE lock_id = #{lockId}
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsOperationMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsOperationMapper.xml
new file mode 100644
index 00000000..d789d205
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsOperationMapper.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UPDATE wms_schedule_operation
+ SET line_id = #{lineId},
+ start_time = #{startTime},
+ end_time = #{endTime},
+ update_by = #{updateBy},
+ update_time = CURRENT_TIMESTAMP
+ WHERE operation_id = #{operationId}
+
+
+
+ INSERT INTO wms_schedule_change_log
+ (
+ operation_id,
+ change_type,
+ before_value,
+ after_value,
+ change_reason,
+ change_by
+ )
+ VALUES
+ (
+ #{operationId},
+ #{changeType},
+ #{beforeValue},
+ #{afterValue},
+ #{changeReason},
+ #{changeBy}
+ )
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsPlanMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsPlanMapper.xml
new file mode 100644
index 00000000..9263861b
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsPlanMapper.xml
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO wms_order
+ (
+ order_code,
+ customer_id,
+ customer_name,
+ sales_manager,
+ order_status,
+ remark,
+ tax_amount,
+ no_tax_amount,
+ del_flag,
+ create_by,
+ update_by
+ )
+ VALUES
+ (
+ #{orderCode},
+ #{customerId},
+ #{customerName},
+ #{salesManager},
+ #{orderStatus},
+ #{remark},
+ #{taxAmount},
+ #{noTaxAmount},
+ 0,
+ #{createBy},
+ #{updateBy}
+ )
+
+
+
+ INSERT INTO wms_order_detail
+ (
+ order_id,
+ product_id,
+ quantity,
+ unit,
+ remark,
+ tax_price,
+ no_tax_price,
+ group_id,
+ del_flag,
+ create_by,
+ update_by
+ )
+ VALUES
+ (
+ #{orderId},
+ #{productId},
+ #{quantity},
+ #{unit},
+ #{remark},
+ #{taxPrice},
+ #{noTaxPrice},
+ #{groupId},
+ IFNULL(#{delFlag}, 0),
+ #{createBy},
+ #{updateBy}
+ )
+
+
+
+
+
+ INSERT INTO wms_schedule_plan
+ (
+ plan_code,
+ version,
+ order_id,
+ status,
+ remark,
+ del_flag,
+ create_by,
+ update_by,
+ priority,
+ start_date,
+ end_date
+ )
+ VALUES
+ (
+ #{planCode},
+ #{version},
+ #{orderId},
+ #{status},
+ #{remark},
+ #{delFlag},
+ #{createBy},
+ #{updateBy},
+ #{priority},
+ #{startDate},
+ #{endDate}
+ )
+
+
+
+ INSERT INTO wms_schedule_plan_detail
+ (
+ plan_id,
+ line_id,
+ task_id,
+ product_id,
+ quantity,
+ start_date,
+ end_date,
+ remark,
+ del_flag,
+ create_by,
+ update_by
+ )
+ VALUES
+ (
+ #{planId},
+ #{lineId},
+ #{taskId},
+ #{productId},
+ #{quantity},
+ #{startDate},
+ #{endDate},
+ #{remark},
+ #{delFlag},
+ #{createBy},
+ #{updateBy}
+ )
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsScheduleSheetMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsScheduleSheetMapper.xml
new file mode 100644
index 00000000..482f3d06
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsScheduleSheetMapper.xml
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+ UPDATE wms_schedule_operation_coil
+ SET del_flag = 1,
+ update_by = #{updateBy},
+ update_time = CURRENT_TIMESTAMP
+ WHERE operation_id = #{operationId}
+ AND del_flag = 0
+
+
+
+ INSERT INTO wms_schedule_operation_coil
+ (
+ operation_id,
+ coil_id,
+ create_by,
+ update_by,
+ del_flag
+ )
+ VALUES
+ (
+ #{operationId},
+ #{coilId},
+ #{createBy},
+ #{createBy},
+ 0
+ )
+
+
+
+ UPDATE wms_schedule_operation
+ SET remark = #{remarkJson},
+ update_by = #{updateBy},
+ update_time = CURRENT_TIMESTAMP
+ WHERE operation_id = #{operationId}
+
+
+
+
diff --git a/klp-da/src/main/resources/mapper/da/aps/ApsShiftTemplateMapper.xml b/klp-da/src/main/resources/mapper/da/aps/ApsShiftTemplateMapper.xml
new file mode 100644
index 00000000..9c24f0c0
--- /dev/null
+++ b/klp-da/src/main/resources/mapper/da/aps/ApsShiftTemplateMapper.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
diff --git a/klp-ui/src/api/aps/aps.js b/klp-ui/src/api/aps/aps.js
new file mode 100644
index 00000000..74354cf5
--- /dev/null
+++ b/klp-ui/src/api/aps/aps.js
@@ -0,0 +1,344 @@
+import request from '@/utils/request'
+
+// CRM 订单转换为库存订单
+export function convertFromCrm(data) {
+ return request({
+ url: '/aps/order/convert-from-crm',
+ method: 'post',
+ data
+ })
+}
+
+// 查询 CRM 订单明细
+export function listCrmOrderItems(query) {
+ return request({
+ url: '/crm/orderItem/list',
+ method: 'get',
+ params: query
+ })
+}
+
+// 产品直排转换为库存订单(单产品)
+export function convertFromProduct(data) {
+ return request({
+ url: '/aps/order/convert-from-product',
+ method: 'post',
+ data
+ })
+}
+
+// 产品直排转换为库存订单(多产品)
+export function convertFromProducts(data) {
+ return request({
+ url: '/aps/order/convert-from-products',
+ method: 'post',
+ data
+ })
+}
+
+// 创建排产计划
+export function createPlan(data) {
+ return request({
+ url: '/aps/plan/create',
+ method: 'post',
+ data
+ })
+}
+
+// 自动排程
+export function autoSchedule(data) {
+ return request({
+ url: '/aps/plan/auto-schedule',
+ method: 'post',
+ data
+ })
+}
+
+// 发布计划
+export function publishPlan(planId) {
+ return request({
+ url: `/aps/plan/publish/${planId}`,
+ method: 'post'
+ })
+}
+
+// 甘特查询
+export function fetchGantt(params) {
+ return request({
+ url: '/aps/gantt',
+ method: 'get',
+ params
+ })
+}
+
+// 工厂日历聚合(后端计算)
+export function fetchFactoryCalendar(params) {
+ return request({
+ url: '/aps/factory-calendar',
+ method: 'get',
+ params
+ })
+}
+
+// 单工序重排
+export function rescheduleOperation(data) {
+ return request({
+ url: '/aps/operation/reschedule',
+ method: 'post',
+ data
+ })
+}
+
+// 创建锁定
+export function createLock(data) {
+ return request({
+ url: '/aps/lock',
+ method: 'post',
+ data
+ })
+}
+
+// 解除锁定
+export function releaseLock(lockId) {
+ return request({
+ url: `/aps/lock/release/${lockId}`,
+ method: 'post'
+ })
+}
+
+/**
+ * 统一排产表(按模板/机组导出与展示)
+ * 说明:
+ * - templateKey: cold_rolling / acid_pickling / slitting / galvanizing
+ * - 后端建议返回:{ header: {...}, rows: [...], summary: {...} }
+ */
+export function fetchScheduleSheet(params) {
+ return request({
+ url: '/aps/schedule-sheet',
+ method: 'get',
+ params,
+ timeout: 120000
+ })
+}
+
+export function exportScheduleSheet(params) {
+ return request({
+ url: '/aps/schedule-sheet/export',
+ method: 'get',
+ params,
+ responseType: 'blob',
+ timeout: 120000
+ })
+}
+
+export function saveScheduleSheetSupplement(data) {
+ return request({
+ url: '/aps/schedule-sheet/supplement/save',
+ method: 'post',
+ data,
+ timeout: 120000
+ })
+}
+
+// ========== 基础数据管理 ==========
+
+// 工厂日历
+export function listCalendar(query) {
+ return request({
+ url: '/aps/calendar/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function getCalendar(calendarId) {
+ return request({
+ url: '/aps/calendar/' + calendarId,
+ method: 'get'
+ })
+}
+
+export function addCalendar(data) {
+ return request({
+ url: '/aps/calendar',
+ method: 'post',
+ data
+ })
+}
+
+export function updateCalendar(data) {
+ return request({
+ url: '/aps/calendar',
+ method: 'put',
+ data
+ })
+}
+
+export function delCalendar(calendarIds) {
+ return request({
+ url: '/aps/calendar/' + calendarIds,
+ method: 'delete'
+ })
+}
+
+export function exportCalendar(query) {
+ return request({
+ url: '/aps/calendar/export',
+ method: 'post',
+ params: query,
+ responseType: 'blob'
+ })
+}
+
+// 班次模板
+export function listShiftTemplate(query) {
+ return request({
+ url: '/aps/shift-template/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function getShiftTemplate(shiftId) {
+ return request({
+ url: '/aps/shift-template/' + shiftId,
+ method: 'get'
+ })
+}
+
+export function addShiftTemplate(data) {
+ return request({
+ url: '/aps/shift-template',
+ method: 'post',
+ data
+ })
+}
+
+export function updateShiftTemplate(data) {
+ return request({
+ url: '/aps/shift-template',
+ method: 'put',
+ data
+ })
+}
+
+export function delShiftTemplate(shiftIds) {
+ return request({
+ url: '/aps/shift-template/' + shiftIds,
+ method: 'delete'
+ })
+}
+
+export function exportShiftTemplate(query) {
+ return request({
+ url: '/aps/shift-template/export',
+ method: 'post',
+ params: query,
+ responseType: 'blob'
+ })
+}
+
+// 日历班次配置
+export function listCalendarShift(query) {
+ return request({
+ url: '/aps/calendar-shift/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function getCalendarShift(configId) {
+ return request({
+ url: '/aps/calendar-shift/' + configId,
+ method: 'get'
+ })
+}
+
+export function addCalendarShift(data) {
+ return request({
+ url: '/aps/calendar-shift',
+ method: 'post',
+ data
+ })
+}
+
+export function updateCalendarShift(data) {
+ return request({
+ url: '/aps/calendar-shift',
+ method: 'put',
+ data
+ })
+}
+
+export function delCalendarShift(configIds) {
+ return request({
+ url: '/aps/calendar-shift/' + configIds,
+ method: 'delete'
+ })
+}
+
+export function exportCalendarShift(query) {
+ return request({
+ url: '/aps/calendar-shift/export',
+ method: 'post',
+ params: query,
+ responseType: 'blob'
+ })
+}
+
+export function generateCalendarShiftWorkdayYear(year, overwriteExisting = false) {
+ return request({
+ url: `/aps/calendar-shift/generate-workday-year/${year}`,
+ method: 'post',
+ params: { overwriteExisting },
+ timeout: 600000
+ })
+}
+
+// 产线能力
+export function listLineCapability(query) {
+ return request({
+ url: '/aps/line-capability/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function getLineCapability(capabilityId) {
+ return request({
+ url: '/aps/line-capability/' + capabilityId,
+ method: 'get'
+ })
+}
+
+export function addLineCapability(data) {
+ return request({
+ url: '/aps/line-capability',
+ method: 'post',
+ data
+ })
+}
+
+export function updateLineCapability(data) {
+ return request({
+ url: '/aps/line-capability',
+ method: 'put',
+ data
+ })
+}
+
+export function delLineCapability(capabilityIds) {
+ return request({
+ url: '/aps/line-capability/' + capabilityIds,
+ method: 'delete'
+ })
+}
+
+export function exportLineCapability(query) {
+ return request({
+ url: '/aps/line-capability/export',
+ method: 'post',
+ params: query,
+ responseType: 'blob'
+ })
+}
diff --git a/klp-ui/src/api/wms/coil.js b/klp-ui/src/api/wms/coil.js
index 82d278a7..559bc4ba 100644
--- a/klp-ui/src/api/wms/coil.js
+++ b/klp-ui/src/api/wms/coil.js
@@ -9,6 +9,14 @@ export function listMaterialCoil(query) {
})
}
+export function getMaterialCoilLocationGrid(query) {
+ return request({
+ url: '/wms/materialCoil/locationGrid',
+ method: 'get',
+ params: query
+ })
+}
+
export function exportMaterialCoil(query) {
return request({
url: '/wms/materialCoil/export',
diff --git a/klp-ui/src/router/index.js b/klp-ui/src/router/index.js
index 60f82715..a7cc2ad5 100644
--- a/klp-ui/src/router/index.js
+++ b/klp-ui/src/router/index.js
@@ -100,6 +100,31 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' }
}
]
+ },
+ {
+ path: '/aps',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: 'lineCapability',
+ component: () => import('@/views/aps/lineCapability/index'),
+ name: 'ApsLineCapability',
+ meta: { title: '产线能力' }
+ },
+ {
+ path: 'processManage',
+ component: () => import('@/views/aps/processManage/index'),
+ name: 'ApsProcessManage',
+ meta: { title: '工序管理' }
+ },
+ {
+ path: 'factory-calendar',
+ component: () => import('@/views/aps/factoryCalendar'),
+ name: 'ApsFactoryCalendarPage',
+ meta: { title: '工厂总日历' }
+ }
+ ]
}
]
diff --git a/klp-ui/src/views/aps/calendar/index.vue b/klp-ui/src/views/aps/calendar/index.vue
new file mode 100644
index 00000000..71de900b
--- /dev/null
+++ b/klp-ui/src/views/aps/calendar/index.vue
@@ -0,0 +1,512 @@
+
+
+
+
+
+
工厂日历排产看板
+
同一日期聚合展示全部产线×班次,悬浮查看完整任务信息,支持快速编辑日历
+
+
+ 上一段
+ 下一段
+ 近30天
+ 前后30天
+ 回到今天
+
+
+
+
+
+
+ 刷新
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+
+
+ 日历图例:
+ 工作日
+ 休息日
+
+
+
+
+
+
+
+
{{ date }}
+
+
+
+
+
+ {{ shortText(slot.lineName, 6) }}
+ {{ shortText(slot.shiftName, 4) }}
+
+
+
+ {{ shortText(taskDisplayName(slot.tasks[0]), 14) }}
+
+ 无任务
+ +{{ slot.tasks.length - 1 }}
+
+
编辑
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 工作日
+ 停用/休息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/aps/calendarShift/index.vue b/klp-ui/src/views/aps/calendarShift/index.vue
new file mode 100644
index 00000000..f50730a0
--- /dev/null
+++ b/klp-ui/src/views/aps/calendarShift/index.vue
@@ -0,0 +1,343 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+ 一键生成全年工作日
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 停用
+ 启用
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/aps/factoryCalendar.vue b/klp-ui/src/views/aps/factoryCalendar.vue
new file mode 100644
index 00000000..5aceb418
--- /dev/null
+++ b/klp-ui/src/views/aps/factoryCalendar.vue
@@ -0,0 +1,583 @@
+
+
+
+
+
+
+
任务总数
+
{{ overview.taskCount }}
+
+
+
活跃产线
+
{{ overview.activeLineCount }} / {{ overview.totalLineCount }}
+
+
+
排产总工时
+
{{ overview.totalHours }}
+
+
+
峰值日
+
{{ overview.peakDayText }}
+
+
+
最忙产线
+
{{ overview.busiestLineText }}
+
+
+
最忙产线-班组
+
{{ overview.busiestLineShiftText }}
+
+
+
+
+
+
+
+
+
+ {{ w }}
+
+
+
+
{{ cell.day }}
+
+ {{ getLineDay(line.lineId, cell.date).taskCount }} 单
+
+ {{ shortTaskWithShift(t) }}
+
+ +{{ getLineDay(line.lineId, cell.date).taskCount - 3 }}
+
+
+
+
+
+
+
+
+
+
+
+
产线-班组日历
+
+ 工作日
+ 休息日
+
+
+
+
+
+
+ {{ w }}
+
+
+
+
{{ cell.day }}
+
+ {{ getLineShiftDay(item.lineId, item.shiftId, cell.date).taskCount }} 单
+
+ {{ shortTask(t) }}
+
+ +{{ getLineShiftDay(item.lineId, item.shiftId, cell.date).taskCount - 3 }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/aps/index.vue b/klp-ui/src/views/aps/index.vue
new file mode 100644
index 00000000..c64b739b
--- /dev/null
+++ b/klp-ui/src/views/aps/index.vue
@@ -0,0 +1,1580 @@
+
+
+
+
+
+
+
+
+
+
+
+ 产品直排
+ 库存订单排产
+
+
+
+
+ 选择
+
+
+
+
+
+
+ 选择
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+
+
+
+
+
+
+
+ 新建
+ 生产中
+ 已完成
+ {{ scope.row.orderStatus }}
+
+
+
+
+ 选择
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+
+
+
+ 批量加入清单
+ 已选 {{ selectedProductRows.length }} 条
+
+
+
+
+
+
+ {{ scope.row.material || '-' }}
+
+
+
+ {{ scope.row.unit || '-' }}
+
+
+
+ 选择
+
+
+
+
+
+
+
+
+
+ 手动排产步骤:1)选择目标产线;2)选择目标时间范围;3)填写调整原因并确认。
+
+
+
+ {{ rescheduleDialog.meta.lineName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 工序
+ 产线时间窗
+
+
+
+ {{ form.planId || '-' }}
+
+
+ {{ lockDialog.meta.lineName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 确定要解除该工序/时间窗的锁定吗?
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/aps/lineCapability/index.vue b/klp-ui/src/views/aps/lineCapability/index.vue
new file mode 100644
index 00000000..23687c43
--- /dev/null
+++ b/klp-ui/src/views/aps/lineCapability/index.vue
@@ -0,0 +1,486 @@
+
+
+
+
+
+
+ 平均每小时产能
{{ avgCapacityText }}
+
+
+
+ 产线管理
+
+
+
+
+
+
+
+ 新增产线
+ 刷新
+
+
+
+
+
+
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+ 产线能力设置
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新增能力
+ 查询
+ 重置
+
+
+
+
+
+
+
+ {{ formatProduct(scope.row) }}
+
+
+ {{ formatProcess(scope.row) }}
+
+
+
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择
+ 清空
+
+
+
+ 选择
+ 清空
+
+
+
+
+ 启用停用
+
+
+
+
+
+
+
+
+ 搜索
+
+
+
+
+
+
+
+ 选择
+
+
+
+
+
+
+
+
+ 搜索
+
+
+
+
+
+
+ 选择
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/aps/processManage/index.vue b/klp-ui/src/views/aps/processManage/index.vue
new file mode 100644
index 00000000..d3f108ff
--- /dev/null
+++ b/klp-ui/src/views/aps/processManage/index.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/klp-ui/src/views/aps/sheet.vue b/klp-ui/src/views/aps/sheet.vue
new file mode 100644
index 00000000..62fff6e4
--- /dev/null
+++ b/klp-ui/src/views/aps/sheet.vue
@@ -0,0 +1,756 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.rawCoilNos || '选择原料钢卷' }}
+
+
+
+
+
+
+
+
+ {{ scope.row[col.prop] == null || scope.row[col.prop] === '' ? '-' : scope.row[col.prop] }}
+
+
+
+
+
+
+ 合计:
+ {{ summaryText }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/aps/sheets/SheetColumns.vue b/klp-ui/src/views/aps/sheets/SheetColumns.vue
new file mode 100644
index 00000000..e78fa79c
--- /dev/null
+++ b/klp-ui/src/views/aps/sheets/SheetColumns.vue
@@ -0,0 +1,43 @@
+
+
diff --git a/klp-ui/src/views/aps/sheets/templates.js b/klp-ui/src/views/aps/sheets/templates.js
new file mode 100644
index 00000000..1e4ed4df
--- /dev/null
+++ b/klp-ui/src/views/aps/sheets/templates.js
@@ -0,0 +1,42 @@
+/**
+ * 统一排产表:模板配置
+ *
+ * 设计目标:
+ * - 用同一套 UI 渲染不同机组的“排产表样式”(多级表头/字段差异)
+ * - 后端返回统一的 rowModel(行数据)后,前端仅做字段映射和展示
+ *
+ * 约定:
+ * - columns 支持多级:{ label, children } 或叶子列 { label, prop, width, minWidth, fixed, align }
+ * - summary:用于底部合计显示(哪些字段求和)
+ */
+
+export const APS_SHEET_TEMPLATES = [
+ {
+ key: 'unified',
+ name: '统一排产表',
+ columns: [
+ { label: '产线', prop: 'lineName', minWidth: 120 },
+ { label: '计划号', prop: 'planCode', minWidth: 140 },
+ { label: '订单号', prop: 'orderCode', minWidth: 140 },
+ { label: '客户', prop: 'customerName', minWidth: 140 },
+ { label: '业务员', prop: 'salesman', width: 100 },
+ { label: '产品', prop: 'productName', minWidth: 140 },
+ { label: '原料钢卷', prop: 'rawMaterialId', minWidth: 220 },
+ { label: '原料卷号', prop: 'rawCoilNos', minWidth: 220 },
+ { label: '钢卷位置', prop: 'rawLocation', minWidth: 140 },
+ { label: '包装要求', prop: 'rawPackaging', minWidth: 140 },
+ { label: '切边要求', prop: 'rawEdgeReq', minWidth: 120 },
+ { label: '镀层种类', prop: 'rawCoatingType', width: 110 },
+ { label: '原料净重', prop: 'rawNetWeight', width: 110, align: 'right' },
+ { label: '计划数量', prop: 'planQty', width: 100, align: 'right' },
+ { label: '开始时间', prop: 'startTime', width: 170 },
+ { label: '结束时间', prop: 'endTime', width: 170 }
+ ],
+ summary: { sumFields: ['planQty', 'rawNetWeight'] }
+ }
+]
+
+export function getTemplateByKey(key) {
+ return APS_SHEET_TEMPLATES.find(t => t.key === key) || APS_SHEET_TEMPLATES[0]
+}
+
diff --git a/klp-ui/src/views/aps/shiftTemplate/index.vue b/klp-ui/src/views/aps/shiftTemplate/index.vue
new file mode 100644
index 00000000..b6c41f9e
--- /dev/null
+++ b/klp-ui/src/views/aps/shiftTemplate/index.vue
@@ -0,0 +1,252 @@
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 不跨天
+ 跨天
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/klp-ui/src/views/wms/order/panels/orderPage.vue b/klp-ui/src/views/wms/order/panels/orderPage.vue
index 661522ce..90591994 100644
--- a/klp-ui/src/views/wms/order/panels/orderPage.vue
+++ b/klp-ui/src/views/wms/order/panels/orderPage.vue
@@ -40,12 +40,34 @@
-
+
-
-
+
+
+ 排产
+
+
@@ -64,6 +86,23 @@
+
+
@@ -460,6 +499,34 @@ export default {
}).catch(() => {
this.$modal.msgError("转化失败");
});
+ },
+
+ /** 跳转到 APS 排产中心,携带当前订单标识 */
+ goApsSchedule(row) {
+ if (!row || !row.orderId) {
+ this.$modal.msgWarning("当前订单数据异常,无法进入排产");
+ return;
+ }
+ this.$router
+ .push({
+ path: "/aps/index",
+ query: { orderId: row.orderId, orderCode: row.orderCode }
+ })
+ .catch(() => {});
+ },
+
+ /** 从订单详情一键排产并查看结果 */
+ goApsOneKeySchedule() {
+ if (!this.form || !this.form.orderId) {
+ this.$modal.msgWarning("请先选择需要排产的订单");
+ return;
+ }
+ this.$router
+ .push({
+ path: "/aps/index",
+ query: { orderId: this.form.orderId, orderCode: this.form.orderCode, autoOneKey: "1" }
+ })
+ .catch(() => {});
}
}
};
@@ -485,6 +552,17 @@ export default {
margin-bottom: 16px;
}
+.order-detail-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 8px;
+}
+.order-detail-title {
+ font-weight: 600;
+ font-size: 14px;
+}
+
::v-deep .el-input-group__append,
::v-deep .el-input-group__prepend {
width: 20px !important;
diff --git a/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java b/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java
index 6df85839..6607302e 100644
--- a/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java
+++ b/klp-wms/src/main/java/com/klp/controller/WmsMaterialCoilController.java
@@ -5,9 +5,9 @@ import java.util.Map;
import java.util.Arrays;
import java.util.stream.Collectors;
-import com.klp.common.core.domain.AjaxResult;
import com.klp.domain.vo.WmsMaterialCoilExportVo;
import com.klp.domain.vo.WmsMaterialCoilDeliveryExportVo;
+import com.klp.domain.vo.WmsMaterialCoilLocationGridVo;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
@@ -50,6 +50,20 @@ public class WmsMaterialCoilController extends BaseController {
return iWmsMaterialCoilService.queryPageList(bo, pageQuery);
}
+ /**
+ * 原料钢卷库位分布查询(先库位,再钢卷映射)
+ */
+ @GetMapping("/locationGrid")
+ public R locationGrid(
+ @RequestParam @NotNull(message = "库区ID不能为空") Long actualWarehouseId,
+ @RequestParam(required = false, defaultValue = "raw_material") String itemType,
+ @RequestParam(required = false) String enterCoilNo,
+ @RequestParam(required = false) String currentCoilNo,
+ @RequestParam(required = false) String manufacturer
+ ) {
+ return R.ok(iWmsMaterialCoilService.queryLocationGrid(actualWarehouseId, itemType, enterCoilNo, currentCoilNo, manufacturer));
+ }
+
/**
* 导出钢卷物料表列表(完整字段版本)
*/
diff --git a/klp-wms/src/main/java/com/klp/domain/vo/WmsMaterialCoilLocationGridVo.java b/klp-wms/src/main/java/com/klp/domain/vo/WmsMaterialCoilLocationGridVo.java
new file mode 100644
index 00000000..f223db52
--- /dev/null
+++ b/klp-wms/src/main/java/com/klp/domain/vo/WmsMaterialCoilLocationGridVo.java
@@ -0,0 +1,21 @@
+package com.klp.domain.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 原料钢卷库位分布响应
+ */
+@Data
+public class WmsMaterialCoilLocationGridVo {
+
+ /** 库位列表(用于绘制库位网格) */
+ private List warehouses;
+
+ /** 钢卷列表(用于映射到库位) */
+ private List coils;
+
+ /** 钢卷总数 */
+ private Integer total;
+}
diff --git a/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java b/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java
index 758ed2a9..1381e453 100644
--- a/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java
+++ b/klp-wms/src/main/java/com/klp/service/IWmsMaterialCoilService.java
@@ -1,6 +1,7 @@
package com.klp.service;
import com.klp.domain.vo.WmsMaterialCoilDeliveryExportVo;
+import com.klp.domain.vo.WmsMaterialCoilLocationGridVo;
import com.klp.domain.vo.WmsMaterialCoilVo;
import com.klp.domain.bo.WmsMaterialCoilBo;
import com.klp.common.core.page.TableDataInfo;
@@ -215,15 +216,16 @@ public interface IWmsMaterialCoilService {
Map cancelSpecialSplit(@NotNull(message = "待操作记录ID不能为空") Long pendingActionId);
- /**
- * 钢卷退货操作
- * 将钢卷退货到退货仓,创建新钢卷记录,将原钢卷设置为历史钢卷
- *
- * @param coilId 原钢卷ID
- * @return 退货后的新钢卷信息
- */
-WmsMaterialCoilVo returnCoil(@NotNull(message = "钢卷ID不能为空") Long coilId);
-
List getCoilTrimStatistics();
+ WmsMaterialCoilVo returnCoil(@NotNull(message = "钢卷ID不能为空") Long coilId);
+
+ /**
+ * 原料钢卷库位分布查询:先返回库位,再返回该库位下钢卷
+ */
+ WmsMaterialCoilLocationGridVo queryLocationGrid(Long actualWarehouseId,
+ String itemType,
+ String enterCoilNo,
+ String currentCoilNo,
+ String manufacturer);
}
diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java
index 1bed0abc..f2eff18c 100644
--- a/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java
+++ b/klp-wms/src/main/java/com/klp/service/impl/WmsMaterialCoilServiceImpl.java
@@ -856,6 +856,39 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
}
}
+ @Override
+ public WmsMaterialCoilLocationGridVo queryLocationGrid(Long actualWarehouseId,
+ String itemType,
+ String enterCoilNo,
+ String currentCoilNo,
+ String manufacturer) {
+ WmsMaterialCoilLocationGridVo result = new WmsMaterialCoilLocationGridVo();
+ if (actualWarehouseId == null) {
+ result.setWarehouses(Collections.emptyList());
+ result.setCoils(Collections.emptyList());
+ result.setTotal(0);
+ return result;
+ }
+
+ WmsActualWarehouseBo warehouseBo = new WmsActualWarehouseBo();
+ warehouseBo.setParentId(actualWarehouseId);
+ List warehouses = actualWarehouseService.queryList(warehouseBo);
+
+ WmsMaterialCoilBo coilBo = new WmsMaterialCoilBo();
+ coilBo.setActualWarehouseId(actualWarehouseId);
+ coilBo.setItemType(StringUtils.isBlank(itemType) ? "raw_material" : itemType);
+ coilBo.setEnterCoilNo(enterCoilNo);
+ coilBo.setCurrentCoilNo(currentCoilNo);
+ coilBo.setItemManufacturer(manufacturer);
+ coilBo.setDataType(1);
+ List coils = this.queryList(coilBo);
+
+ result.setWarehouses(warehouses);
+ result.setCoils(coils);
+ result.setTotal(coils.size());
+ return result;
+ }
+
/**
* 查询钢卷物料表列表
*/
diff --git a/script/sql/mysql/klp-oa.sql b/script/sql/mysql/klp-oa.sql
index 92ce4633..7876079f 100644
--- a/script/sql/mysql/klp-oa.sql
+++ b/script/sql/mysql/klp-oa.sql
@@ -4342,4 +4342,191 @@ CREATE TABLE `xxl_job_user` (
UNIQUE INDEX `i_username`(`username` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
+-- =============================
+-- APS 排产补充表(wms_*)
+-- =============================
+
+-- 1) 工厂日历
+DROP TABLE IF EXISTS `wms_calendar`;
+CREATE TABLE `wms_calendar` (
+ `calendar_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `calendar_date` date NOT NULL COMMENT '日期',
+ `calendar_type` tinyint NOT NULL DEFAULT 1 COMMENT '日历类型:1工作日 2周末 3法定假日 4停机日',
+ `factory_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'DEFAULT' COMMENT '工厂编码',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
+ PRIMARY KEY (`calendar_id`) USING BTREE,
+ UNIQUE KEY `uk_calendar_date_factory` (`calendar_date`,`factory_code`) USING BTREE,
+ KEY `idx_calendar_type` (`calendar_type`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='工厂日历' ROW_FORMAT=Dynamic;
+
+-- 2) 班次模板
+DROP TABLE IF EXISTS `wms_shift_template`;
+CREATE TABLE `wms_shift_template` (
+ `shift_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `shift_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '班次编码',
+ `shift_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '班次名称',
+ `start_time` time NOT NULL COMMENT '开始时间',
+ `end_time` time NOT NULL COMMENT '结束时间',
+ `cross_day` tinyint NOT NULL DEFAULT 0 COMMENT '是否跨天:0否 1是',
+ `efficiency_rate` decimal(6,4) NOT NULL DEFAULT 1.0000 COMMENT '班次效率系数',
+ `is_enabled` tinyint NOT NULL DEFAULT 1 COMMENT '是否启用:0否 1是',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
+ PRIMARY KEY (`shift_id`) USING BTREE,
+ UNIQUE KEY `uk_shift_code` (`shift_code`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='班次模板' ROW_FORMAT=Dynamic;
+
+-- 3) 日历班次配置(某天 + 某产线 + 某班次)
+DROP TABLE IF EXISTS `wms_calendar_shift`;
+CREATE TABLE `wms_calendar_shift` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `calendar_date` date NOT NULL COMMENT '日期',
+ `line_id` bigint NOT NULL COMMENT '产线ID',
+ `shift_id` bigint NOT NULL COMMENT '班次ID',
+ `planned_hours` decimal(8,2) NOT NULL DEFAULT 8.00 COMMENT '计划工时',
+ `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1可排产 2停机',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
+ PRIMARY KEY (`id`) USING BTREE,
+ UNIQUE KEY `uk_calendar_shift` (`calendar_date`,`line_id`,`shift_id`) USING BTREE,
+ KEY `idx_cs_line_date` (`line_id`,`calendar_date`) USING BTREE,
+ KEY `idx_cs_shift` (`shift_id`) USING BTREE,
+ CONSTRAINT `fk_cs_line` FOREIGN KEY (`line_id`) REFERENCES `wms_production_line` (`line_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_cs_shift` FOREIGN KEY (`shift_id`) REFERENCES `wms_shift_template` (`shift_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='日历班次配置' ROW_FORMAT=Dynamic;
+
+-- 4) 产线能力(支持产品维度 / 工序维度)
+DROP TABLE IF EXISTS `wms_line_capability`;
+CREATE TABLE `wms_line_capability` (
+ `capability_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `line_id` bigint NOT NULL COMMENT '产线ID',
+ `product_id` bigint DEFAULT NULL COMMENT '产品ID,可空(按工序维度时可空)',
+ `process_id` bigint DEFAULT NULL COMMENT '工序ID,可空(按产品维度时可空)',
+ `capacity_per_hour` decimal(18,4) NOT NULL COMMENT '每小时产能',
+ `setup_minutes` int NOT NULL DEFAULT 0 COMMENT '换型准备时间(分钟)',
+ `priority` int NOT NULL DEFAULT 100 COMMENT '优先级(越小越优先)',
+ `is_enabled` tinyint NOT NULL DEFAULT 1 COMMENT '是否启用:0否 1是',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
+ PRIMARY KEY (`capability_id`) USING BTREE,
+ UNIQUE KEY `uk_line_prod_proc` (`line_id`,`product_id`,`process_id`) USING BTREE,
+ KEY `idx_lc_line` (`line_id`) USING BTREE,
+ KEY `idx_lc_product` (`product_id`) USING BTREE,
+ KEY `idx_lc_process` (`process_id`) USING BTREE,
+ CONSTRAINT `fk_lc_line` FOREIGN KEY (`line_id`) REFERENCES `wms_production_line` (`line_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_lc_product` FOREIGN KEY (`product_id`) REFERENCES `wms_product` (`product_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_lc_process` FOREIGN KEY (`process_id`) REFERENCES `wms_processe` (`process_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='产线能力(产品/工序可生产关系)' ROW_FORMAT=Dynamic;
+
+-- 5) 工序级排程记录(核心)
+DROP TABLE IF EXISTS `wms_schedule_operation`;
+CREATE TABLE `wms_schedule_operation` (
+ `operation_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `plan_id` bigint NOT NULL COMMENT '排产计划ID',
+ `detail_id` bigint DEFAULT NULL COMMENT '排产明细ID',
+ `order_id` bigint NOT NULL COMMENT '订单ID',
+ `order_detail_id` bigint NOT NULL COMMENT '订单明细ID',
+ `product_id` bigint NOT NULL COMMENT '产品ID',
+ `process_id` bigint NOT NULL COMMENT '工序ID',
+ `line_id` bigint NOT NULL COMMENT '产线ID',
+ `sequence_no` int NOT NULL COMMENT '工序顺序',
+ `plan_qty` decimal(18,4) NOT NULL COMMENT '计划数量',
+ `start_time` datetime NOT NULL COMMENT '计划开始时间',
+ `end_time` datetime NOT NULL COMMENT '计划结束时间',
+ `setup_minutes` int NOT NULL DEFAULT 0 COMMENT '换型时长',
+ `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态:0待执行 1执行中 2已完成 3已锁定 4取消',
+ `locked_flag` tinyint NOT NULL DEFAULT 0 COMMENT '是否锁定:0否 1是',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
+ PRIMARY KEY (`operation_id`) USING BTREE,
+ KEY `idx_so_plan` (`plan_id`) USING BTREE,
+ KEY `idx_so_line_time` (`line_id`,`start_time`,`end_time`) USING BTREE,
+ KEY `idx_so_order_detail` (`order_detail_id`) USING BTREE,
+ KEY `idx_so_process` (`process_id`) USING BTREE,
+ CONSTRAINT `fk_so_plan` FOREIGN KEY (`plan_id`) REFERENCES `wms_schedule_plan` (`plan_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_so_detail` FOREIGN KEY (`detail_id`) REFERENCES `wms_schedule_plan_detail` (`detail_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_so_order` FOREIGN KEY (`order_id`) REFERENCES `wms_order` (`order_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_so_order_detail` FOREIGN KEY (`order_detail_id`) REFERENCES `wms_order_detail` (`detail_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_so_product` FOREIGN KEY (`product_id`) REFERENCES `wms_product` (`product_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_so_process` FOREIGN KEY (`process_id`) REFERENCES `wms_processe` (`process_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_so_line` FOREIGN KEY (`line_id`) REFERENCES `wms_production_line` (`line_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='工序级排产记录' ROW_FORMAT=Dynamic;
+
+-- 5b) 工序级排程-钢卷关系
+DROP TABLE IF EXISTS `wms_schedule_operation_coil`;
+CREATE TABLE `wms_schedule_operation_coil` (
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `operation_id` bigint NOT NULL COMMENT '工序排程ID(关联 wms_schedule_operation.operation_id)',
+ `coil_id` bigint NOT NULL COMMENT '钢卷ID(关联 wms_material_coil.coil_id)',
+ `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
+ `del_flag` tinyint(1) NOT NULL DEFAULT 0 COMMENT '删除标志(0=正常,1=已删除)',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `idx_soc_operation` (`operation_id`) USING BTREE,
+ KEY `idx_soc_coil` (`coil_id`) USING BTREE,
+ CONSTRAINT `fk_soc_operation` FOREIGN KEY (`operation_id`) REFERENCES `wms_schedule_operation` (`operation_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_soc_coil` FOREIGN KEY (`coil_id`) REFERENCES `wms_material_coil` (`coil_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='工序排程钢卷关系表' ROW_FORMAT=Dynamic;
+
+-- 6) 排产锁定(冻结机制)
+DROP TABLE IF EXISTS `wms_schedule_lock`;
+CREATE TABLE `wms_schedule_lock` (
+ `lock_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `lock_type` tinyint NOT NULL COMMENT '锁定类型:1计划 2产线+时间窗 3工序记录',
+ `plan_id` bigint DEFAULT NULL COMMENT '计划ID',
+ `line_id` bigint DEFAULT NULL COMMENT '产线ID',
+ `operation_id` bigint DEFAULT NULL COMMENT '工序排程ID',
+ `lock_start_time` datetime DEFAULT NULL COMMENT '锁定开始时间',
+ `lock_end_time` datetime DEFAULT NULL COMMENT '锁定结束时间',
+ `lock_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '锁定原因',
+ `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1生效 0失效',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人',
+ PRIMARY KEY (`lock_id`) USING BTREE,
+ KEY `idx_sl_plan` (`plan_id`) USING BTREE,
+ KEY `idx_sl_line_time` (`line_id`,`lock_start_time`,`lock_end_time`) USING BTREE,
+ KEY `idx_sl_operation` (`operation_id`) USING BTREE,
+ CONSTRAINT `fk_sl_plan` FOREIGN KEY (`plan_id`) REFERENCES `wms_schedule_plan` (`plan_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_sl_line` FOREIGN KEY (`line_id`) REFERENCES `wms_production_line` (`line_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
+ CONSTRAINT `fk_sl_operation` FOREIGN KEY (`operation_id`) REFERENCES `wms_schedule_operation` (`operation_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='排产锁定表' ROW_FORMAT=Dynamic;
+
+-- 7) 排程变更日志
+DROP TABLE IF EXISTS `wms_schedule_change_log`;
+CREATE TABLE `wms_schedule_change_log` (
+ `log_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `operation_id` bigint NOT NULL COMMENT '工序排程ID',
+ `change_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '变更类型:CREATE/UPDATE/DELETE/RESCHEDULE/LOCK/UNLOCK',
+ `before_value` json DEFAULT NULL COMMENT '变更前快照',
+ `after_value` json DEFAULT NULL COMMENT '变更后快照',
+ `change_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '变更原因',
+ `change_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '变更时间',
+ `change_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '变更人',
+ PRIMARY KEY (`log_id`) USING BTREE,
+ KEY `idx_scl_operation` (`operation_id`) USING BTREE,
+ KEY `idx_scl_time` (`change_time`) USING BTREE,
+ CONSTRAINT `fk_scl_operation` FOREIGN KEY (`operation_id`) REFERENCES `wms_schedule_operation` (`operation_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='排产变更日志' ROW_FORMAT=Dynamic;
+
SET FOREIGN_KEY_CHECKS = 1;