Merge branch 'master' of http://119.91.43.128:3001/sheng/mes-ui-d2
This commit is contained in:
94
docs/迁移任务列表.md
Normal file
94
docs/迁移任务列表.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# MES V2 迁移任务列表
|
||||
|
||||
> 根据 `后台Webman界面截图对照表.md` 生成。状态以当前 V2 项目中已落地的页面目录为准。
|
||||
|
||||
- 总功能数:79
|
||||
- 已迁移:20
|
||||
- 未迁移:59
|
||||
|
||||
| 状态 | 一级模块 | 二级模块 | 三级模块 | 功能说明 | V2 目标路径 |
|
||||
|:---:|---|---|---|---|---|
|
||||
| ✅ | 系统设置 (System Administration) | 用户管理 (User Management) | 角色 (Role) | 设置用户组并分配权限(增删改查用户组,并实现权限分配功能) | `src/views/system-administration/user-management/role/` |
|
||||
| ✅ | 系统设置 (System Administration) | 用户管理 (User Management) | 用户 (User) | 管理用户账号并绑定对应角色 | `src/views/system-administration/user-management/user/` |
|
||||
| ✅ | 系统设置 (System Administration) | 菜单管理 (Menu Management) | 菜单配置 (Menu Configuration) | 系统菜单配置 | `src/views/system-administration/menu-management/menu-configuration/` |
|
||||
| ✅ | 系统设置 (System Administration) | 系统助手 (System Utilities) | 操作日志 (Operation Logs) | 系统操作日志 | `src/views/system-administration/system-utilities/operation-logs/` |
|
||||
| ✅ | 系统设置 (System Administration) | 系统助手 (System Utilities) | 接口日志 (API Logs) | 与设备对接流程交互日志(支持按 IP 和接口名称查询) | `src/views/system-administration/system-utilities/api-logs/` |
|
||||
| ⬜ | 系统设置 (System Administration) | 系统监控 (System Monitoring) | 监控设置 (Monitoring Configuration) | 系统监控配置 | 待确认 |
|
||||
| ✅ | 生产配置 (Production Master Data) | 工厂模型 (Factory Model) | 产线设置 (Production Line) | 管理产线(支持增删改查) | `src/views/production-master-data/factory-model/production-line/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 工厂模型 (Factory Model) | 工厂区域 (Factory Area) | 管理工厂区域(支持增删改查) | `src/views/production-master-data/factory-model/factory-area/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 工艺模型 (Process Model) | 工艺流程类别 (Process Category) | 工艺流程类别的增删改查 | `src/views/production-master-data/process-model/process-category/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 工艺模型 (Process Model) | 工序单元 (Process Step) | 配置工序单元(节点),支持参数预设 | `src/views/production-master-data/process-model/process-step/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 工艺模型 (Process Model) | 工艺流程 (Process Routing) | 设置生产工艺流程并管理流程卡 | `src/views/production-master-data/process-model/process-routing/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 产品管理 (Product Management) | 产品列表 (Product List) | 产品管理(增删改查) | `src/views/production-master-data/product-management/product-list/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 产品管理 (Product Management) | 不良管理 (Defect Management) | 不良代码及描述管理,支持批量导入 | `src/views/production-master-data/product-model/product-ng-info/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 物料模型 (Material Model) | 物料类别列表 (Material Category) | 区分原材料和半成品 | `src/views/production-master-data/material-model/material-category/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | 物料模型 (Material Model) | 物料信息管理 (Material Master) | 维护物料编码、名称、规格等属性 | `src/views/production-master-data/material-model/material-master/` |
|
||||
| ⬜ | 生产配置 (Production Master Data) | 物料模型 (Material Model) | BOM物料清单 (Bill of Materials) | 产品BOM管理 | 待确认 |
|
||||
| ✅ | 生产配置 (Production Master Data) | 物料模型 (Material Model) | 计量单位 (Unit of Measure) | 计量单位配置与管理 | `src/views/production-master-data/material-model/material-unit/` |
|
||||
| ✅ | 生产配置 (Production Master Data) | SPC采集模型 (SPC Configuration) | SPC采集配置 (Data Collection Configuration) | 配置SPC采集参数 | `src/views/production-master-data/spc-configuration/data-collection-configuration/` |
|
||||
| ⬜ | 生产配置 (Production Master Data) | 班组模型 (Team Model) | 班组管理 (Team Management) | 管理生产班组 | 待确认 |
|
||||
| ⬜ | 生产配置 (Production Master Data) | 班组模型 (Team Model) | 班次管理 (Shift Management) | 管理生产班次 | 待确认 |
|
||||
| ⬜ | 生产配置 (Production Master Data) | 班组模型 (Team Model) | 排班日历 (Scheduling Calendar) | 查看排班日历 | 待确认 |
|
||||
| ✅ | 设备模型 (Equipment Management) | 设备类别 (Equipment Category) | 设备类别 (Equipment Category) | 管理设备类别 | `src/views/equipment-management/equipment-model/equipment-category/` |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备信息 (Equipment Management) | 设备信息 (Equipment Registry) | 管理设备信息 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备点检 (Inspection Management) | 设备点检项目 (Inspection Items) | 点检项目管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备点检 (Inspection Management) | 设备点检记录 (Inspection Records) | 点检记录管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备点检 (Inspection Management) | 设备点检日志 (Inspection Logs) | 点检日志查询 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备保养 (Maintenance Management) | 设备保养项目 (Maintenance Items) | 保养项目管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备保养 (Maintenance Management) | 设备保养详情 (Maintenance Details) | 保养详情管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备保养 (Maintenance Management) | 设备保养日志 (Maintenance Logs) | 保养日志查询 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备维修 (Repair Management) | 设备维修管理 (Repair Management) | 维修管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备维修 (Repair Management) | 设备维修日志 (Repair Logs) | 维修日志查询 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备损耗品 (Consumables Management) | 设备损耗品类别 (Consumables Category) | 损耗品分类管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备损耗品 (Consumables Management) | 设备损耗品项目 (Consumables Items) | 损耗品项目管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备损耗品 (Consumables Management) | 设备损耗品寿命管理 (Consumables Lifecycle Management) | 寿命管理 | 待确认 |
|
||||
| ⬜ | 设备模型 (Equipment Management) | 设备损耗品 (Consumables Management) | 设备损耗品更换日志 (Replacement Logs) | 更换记录查询 | 待确认 |
|
||||
| ✅ | 计划与生产 (Planning & Production) | 生产批次管理 (Batch Management) | 批次列表 (Batch List) | 批次管理 | `src/views/planning-production/batch-management/batch-list/` |
|
||||
| ✅ | 计划与生产 (Planning & Production) | 生产批次管理 (Batch Management) | 批次托盘 (Tray Tracking) | 托盘跟踪与操作 | `src/views/planning-production/batch-management/tray-tracking/` |
|
||||
| ✅ | 计划与生产 (Planning & Production) | 生产批次管理 (Batch Management) | 生产批次不良报表 (Batch Defect Report) | 不良报表 | `src/views/planning-production/batch-management/batch-defect-report/` |
|
||||
| ⬜ | 计划与生产 (Planning & Production) | 预警中心 (Alert Center) | 预警中心 (Alert Center) | 预警中心 | 待确认 |
|
||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 物料监控 (Material Monitoring) | 物料监控 | 待确认 |
|
||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 电池复投管理 (Rework Management) | 返工管理 | 待确认 |
|
||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 托盘管理 (Tray Management) | 托盘管理 | 待确认 |
|
||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 托盘登录 (Tray Registration) | 托盘登记 | 待确认 |
|
||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 设备监控 (Equipment Monitoring) | 设备监控 | 待确认 |
|
||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 电池工序管理 (Process Execution) | 工序管理 | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 过程控制 (Process Control) | 检验类别管理 (Inspection Type Management) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 过程控制 (Process Control) | 首巡检项目配置 (First Article Inspection Configuration) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 过程控制 (Process Control) | 首巡检录入 (First Article Inspection Records) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 过程控制 (Process Control) | 首巡检报表 (First Article Inspection Reports) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 检验控制 (Inspection Management) | 检验单管理 (Inspection Orders) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 检验控制 (Inspection Management) | 检验标准 (Inspection Standards) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 检验控制 (Inspection Management) | 接收质量限 (AQL Standards) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 检验控制 (Inspection Management) | 检测方案维护 (Inspection Plans) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 检验控制 (Inspection Management) | 检验项目 (Inspection Items) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | 检验控制 (Inspection Management) | 抽样方案配置 (Sampling Plans) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC统计过程控制 (SPC Control) | SPC渲染条件配置 (SPC Configuration) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | XBar-R (XBar-R Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | XBar-S (XBar-S Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | I-MR (I-MR Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | Levey-Jennings (Levey-Jennings Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | EWMA (EWMA Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | CUSUM (CUSUM Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | MA (Moving Average Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | MAMR (Moving Average MR Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | MAMS (Moving Average S Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计量型报表 (SPC Variable Charts) | CPK (Process Capability Index) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计数型报表 (SPC Attribute Charts) | DPMO (DPMO) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计数型报表 (SPC Attribute Charts) | PChart (P Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计数型报表 (SPC Attribute Charts) | NPChart (NP Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计数型报表 (SPC Attribute Charts) | CChart (C Chart) | | 待确认 |
|
||||
| ⬜ | 质量管理 (Quality Management) | SPC计数型报表 (SPC Attribute Charts) | UChart (U Chart) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 基础追溯 (Traceability) | 反向追溯 (Backward Traceability) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 基础追溯 (Traceability) | 正向追溯 (Forward Traceability) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 基础追溯 (Traceability) | 电池曲线 (Battery Curve) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 基础追溯 (Traceability) | 托盘追溯 (Tray Traceability) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 基础追溯 (Traceability) | 电池追溯 (Battery Traceability) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 生产报表 (Production Reports) | 设备履历报表 (Equipment History Report) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 生产报表 (Production Reports) | 电池详情报表 (Battery Detail Report) | | 待确认 |
|
||||
| ⬜ | 数据中台 (Data Platform) | 相关性分析 (Correlation Analysis) | 鹰眼 (Hawkeye) | | 待确认 |
|
||||
|
||||
## 状态说明
|
||||
|
||||
- ✅:V2 项目中已存在对应页面,或本轮已完成转换并通过构建验证。
|
||||
- ⬜:尚未确认/尚未转换到 V2 页面目录。
|
||||
27
src/api/planning-production/batch-defect-report.js
Normal file
27
src/api/planning-production/batch-defect-report.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { request } from '@/api/_service'
|
||||
|
||||
const BASE = 'planning_production/production_batch_management/report/'
|
||||
|
||||
function apiParams (method, data = {}) {
|
||||
return {
|
||||
method,
|
||||
platform: 'background',
|
||||
...data
|
||||
}
|
||||
}
|
||||
|
||||
export function getBatchDefectReport (data) {
|
||||
return request({
|
||||
url: BASE + 'bad',
|
||||
method: 'get',
|
||||
params: apiParams('planning_production_production_batch_management_batch_bad', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function exportBatchDefectReport (data) {
|
||||
return request({
|
||||
url: BASE + 'export',
|
||||
method: 'get',
|
||||
params: apiParams('planning_production_production_batch_management_batch_export', data)
|
||||
})
|
||||
}
|
||||
59
src/api/planning-production/batch-list.js
Normal file
59
src/api/planning-production/batch-list.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import { request } from '@/api/_service'
|
||||
|
||||
const BASE = 'planning_production/production_batch_management/batch/'
|
||||
|
||||
function apiParams (method, data = {}) {
|
||||
return {
|
||||
method: `planning_production_production_batch_management_batch_${method}`,
|
||||
platform: 'background',
|
||||
...data
|
||||
}
|
||||
}
|
||||
|
||||
export function getBatchAll (data) {
|
||||
return request({
|
||||
url: BASE + 'all',
|
||||
method: 'get',
|
||||
params: apiParams('all', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function getBatchList (data) {
|
||||
return request({
|
||||
url: BASE + 'list',
|
||||
method: 'get',
|
||||
params: apiParams('list', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function createBatch (data) {
|
||||
return request({
|
||||
url: BASE + 'create',
|
||||
method: 'post',
|
||||
data: apiParams('create', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function editBatch (data) {
|
||||
return request({
|
||||
url: BASE + 'edit',
|
||||
method: 'put',
|
||||
data: apiParams('edit', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteBatch (data) {
|
||||
return request({
|
||||
url: BASE + 'delete',
|
||||
method: 'delete',
|
||||
data: apiParams('delete', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function getProcessBatch (data) {
|
||||
return request({
|
||||
url: BASE + 'getProcessBatch',
|
||||
method: 'post',
|
||||
data: apiParams('getProcessBatch', data)
|
||||
})
|
||||
}
|
||||
43
src/api/planning-production/batch-tray.js
Normal file
43
src/api/planning-production/batch-tray.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { request } from '@/api/_service'
|
||||
|
||||
const BASE = 'planning_production/production_batch_management/batch_tray/'
|
||||
|
||||
function apiParams (method, data = {}) {
|
||||
return {
|
||||
method: `planning_production_production_batch_management_batch_tray_${method}`,
|
||||
platform: 'background',
|
||||
...data
|
||||
}
|
||||
}
|
||||
|
||||
export function getBatchTrayList (data) {
|
||||
return request({
|
||||
url: BASE + 'list',
|
||||
method: 'get',
|
||||
params: apiParams('list', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function trayUnbinding (data) {
|
||||
return request({
|
||||
url: BASE + 'unbinding',
|
||||
method: 'get',
|
||||
params: apiParams('unbinding', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function trayInactivity (data) {
|
||||
return request({
|
||||
url: BASE + 'inactivity',
|
||||
method: 'get',
|
||||
params: apiParams('inactivity', data)
|
||||
})
|
||||
}
|
||||
|
||||
export function getBatteryParam (data) {
|
||||
return request({
|
||||
url: BASE + 'get_battery_param',
|
||||
method: 'get',
|
||||
params: apiParams('get_battery_param', data)
|
||||
})
|
||||
}
|
||||
15
src/api/production-master-data/workerman/index.js
Normal file
15
src/api/production-master-data/workerman/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { request } from '@/api/_service'
|
||||
|
||||
const BASE = 'production_configuration/workerman/'
|
||||
|
||||
export function sendWorkerman (data) {
|
||||
return request({
|
||||
url: BASE + 'send',
|
||||
method: 'get',
|
||||
params: {
|
||||
method: 'planning_production_produce_traymanage_send_workerman',
|
||||
module: 'api',
|
||||
...data
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -868,6 +868,129 @@
|
||||
"preview_warning": "Language switching demo only, no actual language data configured",
|
||||
"preview_doc": "Documentation: <a class=\"el-link el-link--primary is-underline\" target=\"_blank\" href=\"https://d2.pub/doc/d2-admin/locales\">Internationalization | D2Admin</a>"
|
||||
}
|
||||
},
|
||||
"planning_production": {
|
||||
"batch_management": {
|
||||
"batch_list": {
|
||||
"search": "Search",
|
||||
"reset": "Reset",
|
||||
"add": "Add",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"confirm": "Confirm",
|
||||
"cancel": "Cancel",
|
||||
"prompt": "Tip",
|
||||
"operation_success": "Operation succeeded",
|
||||
"validation_failed": "Validation failed, please check the form",
|
||||
"batch_no": "Batch No.",
|
||||
"batch": "Batch",
|
||||
"process_flow": "Process Routing",
|
||||
"process_flow_name": "Process Routing Name",
|
||||
"product_model": "Product Model",
|
||||
"factory_area": "Factory Area",
|
||||
"production_line": "Production Line",
|
||||
"create_time": "Created At",
|
||||
"start_time": "Start Time",
|
||||
"end_time": "End Time",
|
||||
"planned_completion_date": "Planned Completion Date",
|
||||
"planned_completion_quantity": "Planned Completion Quantity",
|
||||
"input_quantity": "Input Quantity",
|
||||
"remark": "Remark",
|
||||
"operation": "Actions",
|
||||
"enter_batch_no": "Please enter batch no.",
|
||||
"enter_remark": "Please enter remark",
|
||||
"select_process_flow": "Please select process routing",
|
||||
"select_product_model": "Please select product model",
|
||||
"select_area": "Please select factory area",
|
||||
"select_line": "Please select production line",
|
||||
"select_planned_completion_date": "Please select planned completion date",
|
||||
"enter_positive_integer": "Please enter a positive integer",
|
||||
"length_1_100": "Length should be 1 to 100 characters",
|
||||
"add_batch": "Add Batch",
|
||||
"edit_batch": "Edit Batch",
|
||||
"confirm_operation": "Are you sure to perform this action?",
|
||||
"battery_batch_login": "Battery Batch Login",
|
||||
"upload_warning": "Select a batch first, then import a TXT file with one battery barcode per line.",
|
||||
"data_import_text_file": "Import Text File",
|
||||
"select_batch": "Please select batch",
|
||||
"select_file": "Select File",
|
||||
"preview": "Preview",
|
||||
"quantity": "Quantity",
|
||||
"barcode": "Barcode",
|
||||
"activation_status": "Activation Status",
|
||||
"file_not_exist": "File does not exist",
|
||||
"file_format_error": "Invalid file format. Please select a TXT file",
|
||||
"upload_file_error": "Uploaded file content is invalid",
|
||||
"import_data_success": "Import data succeeded",
|
||||
"please_import_data": "Please import data first",
|
||||
"active_battery_exist": "The imported data contains activated batteries",
|
||||
"upload_failed": "Upload failed"
|
||||
},
|
||||
"tray_tracking": {
|
||||
"search": "Search",
|
||||
"reset": "Reset",
|
||||
"confirm": "Confirm",
|
||||
"cancel": "Cancel",
|
||||
"prompt": "Tip",
|
||||
"operation_success": "Operation succeeded",
|
||||
"operation_failed": "Operation failed",
|
||||
"confirm_operation": "Are you sure to perform this action?",
|
||||
"enter_tray_no": "Please enter tray number",
|
||||
"enter_batch_no": "Please enter batch number",
|
||||
"select_status": "Please select status",
|
||||
"project_name": "Project Name",
|
||||
"enter_project_name_search": "Enter project name to search",
|
||||
"content": "Content",
|
||||
"tray_details": "Tray Details",
|
||||
"battery_details": "Battery Details",
|
||||
"tray_no": "Tray No.",
|
||||
"lot": "Lot",
|
||||
"status": "Status",
|
||||
"batch_no": "Batch No.",
|
||||
"flow_name": "Process Flow",
|
||||
"next_process_code": "Next Process",
|
||||
"loaded_battery_qty": "Loaded Battery Qty",
|
||||
"login_time": "Login Time",
|
||||
"actions": "Actions",
|
||||
"detail": "Detail",
|
||||
"unbind": "Unbind",
|
||||
"stop": "Stop",
|
||||
"activated": "Activated",
|
||||
"inactive": "Inactive",
|
||||
"tray_unbind_confirm": "Are you sure to unbind this tray?",
|
||||
"tray_stop_confirm": "Are you sure to stop this tray?",
|
||||
"process": "Process",
|
||||
"current_process": "Current Process",
|
||||
"start_time": "Start Time",
|
||||
"end_time": "End Time",
|
||||
"device_number": "Device No.",
|
||||
"battery_barcode": "Battery Barcode",
|
||||
"please_enter_battery_barcode": "Please enter battery barcode",
|
||||
"serial_number": "No.",
|
||||
"activation_status": "Activation Status",
|
||||
"grade": "Grade"
|
||||
},
|
||||
"batch_defect_report": {
|
||||
"query": "Search",
|
||||
"reset": "Reset",
|
||||
"batch": "Batch",
|
||||
"export": "Export",
|
||||
"time_range": "Production Time Range",
|
||||
"time_placeholder": "Select date and time",
|
||||
"time_start": "Start Date",
|
||||
"to": "To",
|
||||
"time_end": "End Date",
|
||||
"enter_batch_no": "Please enter batch number",
|
||||
"battery_code": "Battery Barcode",
|
||||
"batch_no": "Batch Number",
|
||||
"tray_no": "Tray Number",
|
||||
"lot": "No.",
|
||||
"status": "Status",
|
||||
"finished": "Completed",
|
||||
"incomplete": "Incomplete",
|
||||
"batch_defect_detail": "Batch Defect Report Details"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"__MENU_TEMP_BEGIN__": "===== 以下为临时菜单翻译,后续统一删除 =====",
|
||||
|
||||
@@ -868,6 +868,129 @@
|
||||
"preview_warning": "仅提供切换功能,没有配置具体的语言数据",
|
||||
"preview_doc": "文档参考:<a class=\"el-link el-link--primary is-underline\" target=\"_blank\" href=\"https://d2.pub/doc/d2-admin/locales\">《国际化 | D2Admin》</a>"
|
||||
}
|
||||
},
|
||||
"planning_production": {
|
||||
"batch_management": {
|
||||
"batch_list": {
|
||||
"search": "查询",
|
||||
"reset": "重置",
|
||||
"add": "新增",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"confirm": "确定",
|
||||
"cancel": "取消",
|
||||
"prompt": "提示",
|
||||
"operation_success": "操作成功",
|
||||
"validation_failed": "表单校验失败,请检查",
|
||||
"batch_no": "批次号",
|
||||
"batch": "批次",
|
||||
"process_flow": "工艺流程",
|
||||
"process_flow_name": "工艺流程名称",
|
||||
"product_model": "产品代号",
|
||||
"factory_area": "所区",
|
||||
"production_line": "产线",
|
||||
"create_time": "创建时间",
|
||||
"start_time": "开始时间",
|
||||
"end_time": "结束时间",
|
||||
"planned_completion_date": "计划完成日期",
|
||||
"planned_completion_quantity": "计划完成数量",
|
||||
"input_quantity": "投入数量",
|
||||
"remark": "备注",
|
||||
"operation": "操作",
|
||||
"enter_batch_no": "请输入批次号",
|
||||
"enter_remark": "请输入备注",
|
||||
"select_process_flow": "请选择工艺流程",
|
||||
"select_product_model": "请选择产品代号",
|
||||
"select_area": "请选择所区",
|
||||
"select_line": "请选择产线",
|
||||
"select_planned_completion_date": "请选择计划完成日期",
|
||||
"enter_positive_integer": "请输入正整数",
|
||||
"length_1_100": "长度在 1 到 100 个字符",
|
||||
"add_batch": "新增批次",
|
||||
"edit_batch": "编辑批次",
|
||||
"confirm_operation": "确定要执行该操作吗?",
|
||||
"battery_batch_login": "电池批量登录",
|
||||
"upload_warning": "请先选择批次,再选择 TXT 文件导入电池条码;文件中每行一个条码。",
|
||||
"data_import_text_file": "数据导入文本文件",
|
||||
"select_batch": "请选择批次",
|
||||
"select_file": "选择文件",
|
||||
"preview": "预览",
|
||||
"quantity": "数量",
|
||||
"barcode": "条码",
|
||||
"activation_status": "激活状态",
|
||||
"file_not_exist": "文件不存在",
|
||||
"file_format_error": "文件格式错误,请选择 TXT 文件",
|
||||
"upload_file_error": "上传文件内容错误",
|
||||
"import_data_success": "导入数据成功",
|
||||
"please_import_data": "请先导入数据",
|
||||
"active_battery_exist": "导入数据中存在已激活电池",
|
||||
"upload_failed": "上传失败"
|
||||
},
|
||||
"tray_tracking": {
|
||||
"search": "查询",
|
||||
"reset": "重置",
|
||||
"confirm": "确定",
|
||||
"cancel": "取消",
|
||||
"prompt": "提示",
|
||||
"operation_success": "操作成功",
|
||||
"operation_failed": "操作失败",
|
||||
"confirm_operation": "确定要执行该操作吗?",
|
||||
"enter_tray_no": "请输入托盘号",
|
||||
"enter_batch_no": "请输入批次号",
|
||||
"select_status": "请选择状态",
|
||||
"project_name": "项目名称",
|
||||
"enter_project_name_search": "请输入项目名称查询",
|
||||
"content": "内容",
|
||||
"tray_details": "托盘详情",
|
||||
"battery_details": "电池详情",
|
||||
"tray_no": "托盘号",
|
||||
"lot": "Lot",
|
||||
"status": "状态",
|
||||
"batch_no": "批次号",
|
||||
"flow_name": "工艺流程",
|
||||
"next_process_code": "下一工序",
|
||||
"loaded_battery_qty": "已装载电池数",
|
||||
"login_time": "登录时间",
|
||||
"actions": "操作",
|
||||
"detail": "详情",
|
||||
"unbind": "解绑",
|
||||
"stop": "停用",
|
||||
"activated": "已激活",
|
||||
"inactive": "未激活",
|
||||
"tray_unbind_confirm": "确定要解绑该托盘吗?",
|
||||
"tray_stop_confirm": "确定要停用该托盘吗?",
|
||||
"process": "工序",
|
||||
"current_process": "当前工序",
|
||||
"start_time": "开始时间",
|
||||
"end_time": "结束时间",
|
||||
"device_number": "设备编号",
|
||||
"battery_barcode": "电池条码",
|
||||
"please_enter_battery_barcode": "请输入电池条码",
|
||||
"serial_number": "序号",
|
||||
"activation_status": "激活状态",
|
||||
"grade": "等级"
|
||||
},
|
||||
"batch_defect_report": {
|
||||
"query": "查询",
|
||||
"reset": "重置",
|
||||
"batch": "批次",
|
||||
"export": "导出",
|
||||
"time_range": "生产时间范围",
|
||||
"time_placeholder": "选择日期时间",
|
||||
"time_start": "开始日期",
|
||||
"to": "至",
|
||||
"time_end": "结束日期",
|
||||
"enter_batch_no": "请输入批次号",
|
||||
"battery_code": "电池编码",
|
||||
"batch_no": "批次号",
|
||||
"tray_no": "托盘号",
|
||||
"lot": "流水号",
|
||||
"status": "状态",
|
||||
"finished": "已完成",
|
||||
"incomplete": "未完成",
|
||||
"batch_defect_detail": "批次不良报表详情"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"__MENU_TEMP_BEGIN__": "===== 以下为临时菜单翻译,后续统一删除 =====",
|
||||
|
||||
@@ -13,6 +13,24 @@ export default {
|
||||
name: `${pre}index`,
|
||||
meta: { ...meta, title: '计划与生产', root: '/planning_production' },
|
||||
component: _import('system/function/module-index')
|
||||
},
|
||||
{
|
||||
path: 'production_batch_management/batch',
|
||||
name: `${pre}production_batch_management-batch`,
|
||||
meta: { ...meta, cache: true, title: '批次列表' },
|
||||
component: _import('planning-production/batch-management/batch-list')
|
||||
},
|
||||
{
|
||||
path: 'production_batch_management/batch_tray',
|
||||
name: `${pre}production_batch_management-batch_tray`,
|
||||
meta: { ...meta, cache: true, title: '批次托盘' },
|
||||
component: _import('planning-production/batch-management/tray-tracking')
|
||||
},
|
||||
{
|
||||
path: 'production_batch_management/bad',
|
||||
name: `${pre}production_batch_management-bad`,
|
||||
meta: { ...meta, cache: true, title: '生产批次不良报表' },
|
||||
component: _import('planning-production/batch-management/batch-defect-report')
|
||||
}
|
||||
])('planning_production-')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<d2-container>
|
||||
<template #header>
|
||||
<div class="search-bar">
|
||||
<el-form :inline="true" :model="search" ref="searchForm" size="mini">
|
||||
<el-form-item :label="$t(key('batch'))" prop="batch">
|
||||
<el-input
|
||||
v-model="search.batch"
|
||||
:placeholder="$t(key('enter_batch_no'))"
|
||||
clearable
|
||||
style="width:220px"
|
||||
@keyup.enter.native="onSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('time_range'))" prop="time">
|
||||
<el-date-picker
|
||||
v-model="search.time"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="datetimerange"
|
||||
:range-separator="$t(key('to'))"
|
||||
:start-placeholder="$t(key('time_start'))"
|
||||
:end-placeholder="$t(key('time_end'))"
|
||||
style="width:360px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" :disabled="loading" @click="onSearch">
|
||||
{{ $t(key('query')) }}
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh" :disabled="loading" @click="onReset">
|
||||
{{ $t(key('reset')) }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<page-table
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:loading="loading"
|
||||
:toolbar-buttons="[]"
|
||||
:row-buttons="[]"
|
||||
:pagination="pagination"
|
||||
:table-attrs="{ size: 'mini' }"
|
||||
auto-height
|
||||
@page-change="onPageChange"
|
||||
>
|
||||
<template #col-is_batch_finish="{ row }">
|
||||
<el-tag v-if="row.is_batch_finish == 1" type="success">
|
||||
{{ $t(key('finished')) }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="danger">
|
||||
{{ $t(key('incomplete')) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template #empty>
|
||||
<el-empty :description="$t('暂无数据')" :image-size="80" />
|
||||
</template>
|
||||
</page-table>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useTableColumns } from '@/composables/useTableColumns'
|
||||
import { i18nMixin } from '@/composables/useI18n'
|
||||
import PageTable from '@/components/page-table'
|
||||
import { getBatchDefectReport } from '@/api/planning-production/batch-defect-report'
|
||||
|
||||
export default {
|
||||
name: 'planning-production-batch-defect-report',
|
||||
components: { PageTable },
|
||||
mixins: [i18nMixin('page.planning_production.batch_management.batch_defect_report')],
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
search: {
|
||||
batch: '',
|
||||
time: []
|
||||
},
|
||||
tableData: [],
|
||||
title1: [],
|
||||
title2: [],
|
||||
pagination: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns () {
|
||||
return useTableColumns(this.normalizeColumns(this.title1), {
|
||||
selectionWidth: 0,
|
||||
indexWidth: 0
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
normalizeColumns (source) {
|
||||
if (!Array.isArray(source) || !source.length) {
|
||||
return [
|
||||
{ prop: 'batch', label: this.key('batch_no'), minWidth: 150 },
|
||||
{ prop: 'is_batch_finish', label: this.key('status'), width: 120, slot: 'is_batch_finish' }
|
||||
]
|
||||
}
|
||||
|
||||
return source.map((item, index) => {
|
||||
const prop = item.prop || item.field || item.key || item.name || `col_${index}`
|
||||
const label = item.name || item.label || prop
|
||||
const column = {
|
||||
prop,
|
||||
label,
|
||||
minWidth: item.minWidth || item.width || 120
|
||||
}
|
||||
|
||||
if (item.width) {
|
||||
column.width = item.width
|
||||
delete column.minWidth
|
||||
}
|
||||
if (prop === 'is_batch_finish') {
|
||||
column.slot = 'is_batch_finish'
|
||||
}
|
||||
|
||||
return column
|
||||
})
|
||||
},
|
||||
buildParams () {
|
||||
return {
|
||||
...this.search,
|
||||
page_no: this.pagination.current,
|
||||
page_size: this.pagination.size
|
||||
}
|
||||
},
|
||||
fetchData () {
|
||||
this.loading = true
|
||||
getBatchDefectReport(this.buildParams())
|
||||
.then(res => {
|
||||
const data = res.data || {}
|
||||
this.tableData = data.data || []
|
||||
this.title1 = data.title1 || []
|
||||
this.title2 = data.title2 || []
|
||||
this.pagination.total = Number(data.count || 0)
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
onSearch () {
|
||||
this.pagination.current = 1
|
||||
this.fetchData()
|
||||
},
|
||||
onReset () {
|
||||
this.$refs.searchForm.resetFields()
|
||||
this.pagination.current = 1
|
||||
this.fetchData()
|
||||
},
|
||||
onPageChange (page) {
|
||||
this.pagination = page
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search-bar {
|
||||
margin-bottom: -18px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,771 @@
|
||||
<template>
|
||||
<d2-container>
|
||||
<template #header>
|
||||
<div class="search-bar">
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item :label="$t(key('batch_no'))">
|
||||
<el-input
|
||||
v-model="search.batch"
|
||||
:placeholder="$t(key('enter_batch_no'))"
|
||||
clearable
|
||||
style="width:200px"
|
||||
@keyup.enter.native="onSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('process_flow'))">
|
||||
<el-select
|
||||
v-model="search.flow_id"
|
||||
:placeholder="$t(key('select_process_flow'))"
|
||||
clearable
|
||||
filterable
|
||||
style="width:200px"
|
||||
@focus="loadFlowOptions"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in flowOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('product_model'))">
|
||||
<el-select
|
||||
v-model="search.product_model_id"
|
||||
:placeholder="$t(key('select_product_model'))"
|
||||
clearable
|
||||
filterable
|
||||
style="width:200px"
|
||||
@focus="loadProductOptions"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in productOptions"
|
||||
:key="item.product_model_id || item.id"
|
||||
:label="item.name || item.code"
|
||||
:value="item.product_model_id || item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('factory_area'))">
|
||||
<el-select
|
||||
v-model="search.area_id"
|
||||
:placeholder="$t(key('select_area'))"
|
||||
clearable
|
||||
filterable
|
||||
style="width:180px"
|
||||
@focus="loadAreaOptions"
|
||||
@change="onSearchAreaChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in areaOptions"
|
||||
:key="item.area_id || item.id"
|
||||
:label="item.name"
|
||||
:value="item.area_id || item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('production_line'))">
|
||||
<el-select
|
||||
v-model="search.line_id"
|
||||
:placeholder="$t(key('select_line'))"
|
||||
clearable
|
||||
filterable
|
||||
style="width:180px"
|
||||
@focus="loadLineOptions(search.area_id)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in searchLineOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('create_time'))">
|
||||
<el-date-picker
|
||||
v-model="search.create_time"
|
||||
type="datetimerange"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
range-separator="-"
|
||||
:start-placeholder="$t(key('start_time'))"
|
||||
:end-placeholder="$t(key('end_time'))"
|
||||
style="width:330px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="onSearch">
|
||||
{{ $t(key('search')) }}
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="onReset">
|
||||
{{ $t(key('reset')) }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<page-table
|
||||
ref="pageTable"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:loading="loading"
|
||||
:toolbar-buttons="toolbarButtons"
|
||||
:row-buttons="rowButtons"
|
||||
:pagination="pagination"
|
||||
:help-text="$t(ckey('help'))"
|
||||
auto-height
|
||||
@page-change="onPageChange"
|
||||
/>
|
||||
|
||||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
:title="$t(dialogTitle)"
|
||||
width="35%"
|
||||
:close-on-click-modal="false"
|
||||
:destroy-on-close="true"
|
||||
@close="onDialogClose"
|
||||
>
|
||||
<el-form ref="batchForm" :model="formData" :rules="rules" label-width="130px" size="mini">
|
||||
<el-form-item :label="$t(key('process_flow'))" prop="flow_id">
|
||||
<el-select
|
||||
v-model="formData.flow_id"
|
||||
:placeholder="$t(key('select_process_flow'))"
|
||||
:disabled="isEdit"
|
||||
clearable
|
||||
filterable
|
||||
style="width:90%"
|
||||
@focus="loadFlowOptions"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in flowOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('batch_no'))" prop="batch">
|
||||
<el-input
|
||||
v-model="formData.batch"
|
||||
:placeholder="$t(key('enter_batch_no'))"
|
||||
:disabled="isEdit"
|
||||
clearable
|
||||
style="width:90%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('factory_area'))" prop="area_id">
|
||||
<el-select
|
||||
v-model="formData.area_id"
|
||||
:placeholder="$t(key('select_area'))"
|
||||
:disabled="isEdit"
|
||||
clearable
|
||||
filterable
|
||||
style="width:90%"
|
||||
@focus="loadAreaOptions"
|
||||
@change="onFormAreaChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in areaOptions"
|
||||
:key="item.area_id || item.id"
|
||||
:label="item.name"
|
||||
:value="item.area_id || item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('production_line'))" prop="line_id">
|
||||
<el-select
|
||||
v-model="formData.line_id"
|
||||
:placeholder="$t(key('select_line'))"
|
||||
:disabled="isEdit"
|
||||
clearable
|
||||
filterable
|
||||
style="width:90%"
|
||||
@focus="loadLineOptions(formData.area_id)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in formLineOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('planned_completion_date'))" prop="planned_completion_date">
|
||||
<el-date-picker
|
||||
v-model="formData.planned_completion_date"
|
||||
type="date"
|
||||
value-format="yyyy-MM-dd"
|
||||
:placeholder="$t(key('select_planned_completion_date'))"
|
||||
clearable
|
||||
style="width:90%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('planned_completion_quantity'))" prop="planned_completion_quantity">
|
||||
<el-input-number
|
||||
v-model="formData.planned_completion_quantity"
|
||||
:min="1"
|
||||
:step="1"
|
||||
:precision="0"
|
||||
controls-position="right"
|
||||
style="width:90%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('remark'))" prop="remark">
|
||||
<el-input
|
||||
v-model="formData.remark"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 6 }"
|
||||
:placeholder="$t(key('enter_remark'))"
|
||||
clearable
|
||||
style="width:90%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button size="mini" @click="dialogVisible = false">{{ $t(key('cancel')) }}</el-button>
|
||||
<el-button size="mini" type="primary" :loading="submitting" @click="onDialogSubmit">
|
||||
{{ $t(key('confirm')) }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
:visible.sync="importVisible"
|
||||
:title="$t(key('battery_batch_login'))"
|
||||
width="50%"
|
||||
:close-on-click-modal="false"
|
||||
:destroy-on-close="true"
|
||||
@close="resetImport"
|
||||
>
|
||||
<el-form label-width="140px" size="mini">
|
||||
<el-alert :title="$t(key('upload_warning'))" :closable="false" type="warning" />
|
||||
<el-form-item class="import-row" :label="$t(key('data_import_text_file'))">
|
||||
<el-select
|
||||
v-model="importBatch"
|
||||
:placeholder="$t(key('select_batch'))"
|
||||
clearable
|
||||
filterable
|
||||
style="width:220px"
|
||||
@focus="loadBatchOptions"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in batchOptions"
|
||||
:key="item.id || item.batch"
|
||||
:label="item.batch"
|
||||
:value="item.batch"
|
||||
/>
|
||||
</el-select>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
class="upload-inline"
|
||||
action=""
|
||||
accept=".txt"
|
||||
:multiple="false"
|
||||
:show-file-list="true"
|
||||
:file-list="importFileList"
|
||||
:http-request="handleTxtUpload"
|
||||
:disabled="!importBatch"
|
||||
>
|
||||
<el-button size="mini" type="success" :disabled="!importBatch">
|
||||
{{ $t(key('select_file')) }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<el-button size="mini" type="warning" @click="resetImport">
|
||||
{{ $t(key('reset')) }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('preview'))">
|
||||
<page-table
|
||||
:columns="importColumns"
|
||||
:data="importTableData"
|
||||
:loading="importLoading"
|
||||
:height="350"
|
||||
:toolbar-buttons="[]"
|
||||
:row-buttons="[]"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="import-count">{{ $t(key('quantity')) }}: {{ importTableData.length }}</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button size="mini" @click="importVisible = false">{{ $t(key('cancel')) }}</el-button>
|
||||
<el-button size="mini" type="primary" :loading="importLoading" @click="submitImport">
|
||||
{{ $t(key('confirm')) }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useTableColumns } from '@/composables/useTableColumns'
|
||||
import { useTableButtons } from '@/composables/useTableButtons'
|
||||
import { i18nMixin } from '@/composables/useI18n'
|
||||
import { confirmMixin } from '@/composables/useConfirmHandle'
|
||||
import {
|
||||
getBatchAll,
|
||||
getBatchList,
|
||||
createBatch,
|
||||
editBatch,
|
||||
deleteBatch,
|
||||
getProcessBatch
|
||||
} from '@/api/planning-production/batch-list'
|
||||
import { getProcessRoutingList } from '@/api/production-master-data/process-routing'
|
||||
import { getProductBatteryAll } from '@/api/production-master-data/product-management'
|
||||
import { getFactoryAreaALL } from '@/api/production-master-data/factory-area'
|
||||
import { getProductionLineList } from '@/api/production-master-data/production-line'
|
||||
import { sendWorkerman } from '@/api/production-master-data/workerman'
|
||||
import PageTable from '@/components/page-table'
|
||||
|
||||
export default {
|
||||
name: 'planning-production-batch-list',
|
||||
components: { PageTable },
|
||||
mixins: [i18nMixin('page.planning_production.batch_management.batch_list'), confirmMixin],
|
||||
data () {
|
||||
const positiveInteger = (rule, value, callback) => {
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
callback()
|
||||
return
|
||||
}
|
||||
if (!/^[1-9][0-9]*$/.test(String(value))) {
|
||||
callback(new Error(this.$t(this.key('enter_positive_integer'))))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
return {
|
||||
loading: false,
|
||||
submitting: false,
|
||||
importLoading: false,
|
||||
tableData: [],
|
||||
dialogVisible: false,
|
||||
importVisible: false,
|
||||
dialogTitle: '',
|
||||
handleType: 'create',
|
||||
editId: null,
|
||||
search: {
|
||||
batch: '',
|
||||
flow_id: '',
|
||||
product_model_id: '',
|
||||
area_id: '',
|
||||
line_id: '',
|
||||
create_time: []
|
||||
},
|
||||
pagination: { current: 1, size: 10, total: 0 },
|
||||
formData: this.getDefaultForm(),
|
||||
rules: {
|
||||
batch: [
|
||||
{ required: true, message: this.key('enter_batch_no'), trigger: 'blur' },
|
||||
{ min: 1, max: 100, message: this.key('length_1_100'), trigger: 'blur' }
|
||||
],
|
||||
flow_id: [
|
||||
{ required: true, message: this.key('select_process_flow'), trigger: 'change' }
|
||||
],
|
||||
area_id: [
|
||||
{ required: true, message: this.key('select_area'), trigger: 'change' }
|
||||
],
|
||||
line_id: [
|
||||
{ required: true, message: this.key('select_line'), trigger: 'change' }
|
||||
],
|
||||
planned_completion_quantity: [
|
||||
{ validator: positiveInteger, trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
columns: [],
|
||||
toolbarButtons: [],
|
||||
rowButtons: [],
|
||||
importColumns: [],
|
||||
flowOptions: [],
|
||||
productOptions: [],
|
||||
areaOptions: [],
|
||||
searchLineOptions: [],
|
||||
formLineOptions: [],
|
||||
batchOptions: [],
|
||||
importBatch: '',
|
||||
importFileList: [],
|
||||
importTableData: [],
|
||||
hasActiveBattery: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isEdit () {
|
||||
return this.handleType === 'edit'
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.columns = useTableColumns([
|
||||
{ prop: 'batch', label: this.key('batch_no'), minWidth: 150 },
|
||||
{ prop: 'planned_completion_date', label: this.key('planned_completion_date'), minWidth: 160 },
|
||||
{ prop: 'planned_completion_quantity', label: this.key('planned_completion_quantity'), minWidth: 170 },
|
||||
{ prop: 'flow_name', label: this.key('process_flow_name'), minWidth: 160 },
|
||||
{ prop: 'area_name', label: this.key('factory_area'), minWidth: 130 },
|
||||
{ prop: 'line_name', label: this.key('production_line'), minWidth: 130 },
|
||||
{ prop: 'product_model_code', label: this.key('product_model'), minWidth: 150 },
|
||||
{ prop: 'input_amount', label: this.key('input_quantity'), minWidth: 120 },
|
||||
{ prop: 'remark', label: this.key('remark'), minWidth: 180 },
|
||||
{ prop: 'create_time', label: this.key('create_time'), minWidth: 170 },
|
||||
{ prop: '_actions', label: this.key('operation'), width: 180, fixed: 'right' }
|
||||
], { selectionWidth: 0 })
|
||||
|
||||
this.importColumns = useTableColumns([
|
||||
{ prop: 'batch', label: this.key('batch'), minWidth: 150 },
|
||||
{ prop: 'battery_id', label: this.key('barcode'), minWidth: 180 },
|
||||
{ prop: 'active', label: this.key('activation_status'), minWidth: 140 }
|
||||
], { selectionWidth: 0 })
|
||||
|
||||
const btns = useTableButtons({
|
||||
toolbar: [
|
||||
{
|
||||
key: 'add',
|
||||
label: this.key('add'),
|
||||
icon: 'el-icon-plus',
|
||||
type: 'primary',
|
||||
auth: '/planning_production/production_batch_management/batch/create',
|
||||
onClick: this.openAdd
|
||||
},
|
||||
{
|
||||
key: 'battery-login',
|
||||
label: this.key('battery_batch_login'),
|
||||
icon: 'el-icon-upload2',
|
||||
type: 'success',
|
||||
auth: '/planning_production/production_batch_management/batch/import',
|
||||
onClick: this.openImport
|
||||
}
|
||||
],
|
||||
row: [
|
||||
{
|
||||
key: 'edit',
|
||||
label: this.key('edit'),
|
||||
icon: 'el-icon-edit',
|
||||
auth: '/planning_production/production_batch_management/batch/edit',
|
||||
onClick: this.openEdit
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
label: this.key('delete'),
|
||||
icon: 'el-icon-delete',
|
||||
color: 'danger',
|
||||
auth: '/planning_production/production_batch_management/batch/delete',
|
||||
onClick: this.handleDelete
|
||||
}
|
||||
]
|
||||
}, this.$permission)
|
||||
this.toolbarButtons = btns.toolbarButtons
|
||||
this.rowButtons = btns.rowButtons
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
getDefaultForm () {
|
||||
return {
|
||||
flow_id: '',
|
||||
batch: '',
|
||||
area_id: '',
|
||||
line_id: '',
|
||||
planned_completion_date: '',
|
||||
planned_completion_quantity: undefined,
|
||||
remark: ''
|
||||
}
|
||||
},
|
||||
normalizeListResponse (res) {
|
||||
const data = Array.isArray(res) ? res : (res && res.data) || []
|
||||
if (Array.isArray(data)) return { list: data, total: data.length }
|
||||
return {
|
||||
list: data.data || [],
|
||||
total: data.count || 0
|
||||
}
|
||||
},
|
||||
async fetchData () {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await getBatchList({
|
||||
...this.search,
|
||||
page_no: this.pagination.current,
|
||||
page_size: this.pagination.size
|
||||
})
|
||||
const { list, total } = this.normalizeListResponse(res)
|
||||
this.tableData = list
|
||||
this.pagination.total = total
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
onSearch () {
|
||||
this.pagination.current = 1
|
||||
this.fetchData()
|
||||
},
|
||||
onReset () {
|
||||
this.search = {
|
||||
batch: '',
|
||||
flow_id: '',
|
||||
product_model_id: '',
|
||||
area_id: '',
|
||||
line_id: '',
|
||||
create_time: []
|
||||
}
|
||||
this.searchLineOptions = []
|
||||
this.pagination.current = 1
|
||||
this.fetchData()
|
||||
},
|
||||
onPageChange (page) {
|
||||
this.pagination.current = page.current
|
||||
this.pagination.size = page.size
|
||||
this.fetchData()
|
||||
},
|
||||
onSearchAreaChange () {
|
||||
this.search.line_id = ''
|
||||
this.searchLineOptions = []
|
||||
},
|
||||
onFormAreaChange () {
|
||||
this.formData.line_id = ''
|
||||
this.formLineOptions = []
|
||||
},
|
||||
async loadFlowOptions () {
|
||||
if (this.flowOptions.length) return
|
||||
try {
|
||||
const res = await getProcessRoutingList({ page_no: 1, page_size: 1000 })
|
||||
this.flowOptions = this.normalizeListResponse(res).list
|
||||
} catch { /* handled by interceptor */ }
|
||||
},
|
||||
async loadProductOptions () {
|
||||
if (this.productOptions.length) return
|
||||
try {
|
||||
const res = await getProductBatteryAll({})
|
||||
const data = Array.isArray(res) ? res : (res && res.data) || []
|
||||
this.productOptions = Array.isArray(data) ? data : []
|
||||
} catch { /* handled by interceptor */ }
|
||||
},
|
||||
async loadAreaOptions () {
|
||||
if (this.areaOptions.length) return
|
||||
try {
|
||||
const res = await getFactoryAreaALL({})
|
||||
const data = Array.isArray(res) ? res : (res && res.data) || []
|
||||
this.areaOptions = Array.isArray(data) ? data : []
|
||||
} catch { /* handled by interceptor */ }
|
||||
},
|
||||
async loadLineOptions (areaId) {
|
||||
try {
|
||||
const res = await getProductionLineList({
|
||||
area_id: areaId || '',
|
||||
page_no: 1,
|
||||
page_size: 1000
|
||||
})
|
||||
const lines = this.normalizeListResponse(res).list
|
||||
if (this.dialogVisible) {
|
||||
this.formLineOptions = lines
|
||||
} else {
|
||||
this.searchLineOptions = lines
|
||||
}
|
||||
} catch { /* handled by interceptor */ }
|
||||
},
|
||||
openAdd () {
|
||||
this.handleType = 'create'
|
||||
this.dialogTitle = this.key('add_batch')
|
||||
this.editId = null
|
||||
this.formData = this.getDefaultForm()
|
||||
this.formLineOptions = []
|
||||
this.loadFlowOptions()
|
||||
this.loadAreaOptions()
|
||||
this.$nextTick(() => {
|
||||
this.$refs.batchForm && this.$refs.batchForm.clearValidate()
|
||||
this.dialogVisible = true
|
||||
})
|
||||
},
|
||||
openEdit (row) {
|
||||
this.handleType = 'edit'
|
||||
this.dialogTitle = this.key('edit_batch')
|
||||
this.editId = row.id
|
||||
this.formData = {
|
||||
flow_id: row.flow_id || '',
|
||||
batch: row.batch || '',
|
||||
area_id: row.area_id || '',
|
||||
line_id: row.line_id || '',
|
||||
planned_completion_date: row.planned_completion_date || '',
|
||||
planned_completion_quantity: row.planned_completion_quantity || undefined,
|
||||
remark: row.remark || ''
|
||||
}
|
||||
this.loadFlowOptions()
|
||||
this.loadAreaOptions()
|
||||
this.loadLineOptions(row.area_id)
|
||||
this.dialogVisible = true
|
||||
},
|
||||
onDialogSubmit () {
|
||||
this.$refs.batchForm.validate(async valid => {
|
||||
if (!valid) {
|
||||
this.$message.warning(this.$t(this.key('validation_failed')))
|
||||
return
|
||||
}
|
||||
this.submitting = true
|
||||
try {
|
||||
if (this.handleType === 'create') {
|
||||
await createBatch(this.formData)
|
||||
} else {
|
||||
await editBatch({ ...this.formData, id: this.editId })
|
||||
}
|
||||
this.$message.success(this.$t(this.key('operation_success')))
|
||||
this.dialogVisible = false
|
||||
this.fetchData()
|
||||
} finally {
|
||||
this.submitting = false
|
||||
}
|
||||
})
|
||||
},
|
||||
onDialogClose () {
|
||||
this.formData = this.getDefaultForm()
|
||||
this.editId = null
|
||||
this.formLineOptions = []
|
||||
},
|
||||
async handleDelete (row) {
|
||||
await this.$confirmAction(
|
||||
{
|
||||
message: this.key('confirm_operation'),
|
||||
title: this.key('prompt')
|
||||
},
|
||||
() => deleteBatch({ batch: row.batch })
|
||||
)
|
||||
this.$message.success(this.$t(this.key('operation_success')))
|
||||
this.pagination.current = Math.min(
|
||||
this.pagination.current,
|
||||
Math.ceil((this.pagination.total - 1) / this.pagination.size) || 1
|
||||
)
|
||||
this.fetchData()
|
||||
},
|
||||
openImport () {
|
||||
this.importVisible = true
|
||||
this.importBatch = ''
|
||||
this.importFileList = []
|
||||
this.importTableData = []
|
||||
this.hasActiveBattery = false
|
||||
},
|
||||
async loadBatchOptions () {
|
||||
if (this.batchOptions.length) return
|
||||
try {
|
||||
const res = await getBatchAll({})
|
||||
const data = Array.isArray(res) ? res : (res && res.data) || []
|
||||
this.batchOptions = Array.isArray(data) ? data : []
|
||||
} catch { /* handled by interceptor */ }
|
||||
},
|
||||
resetImport () {
|
||||
this.importBatch = ''
|
||||
this.importFileList = []
|
||||
this.importTableData = []
|
||||
this.hasActiveBattery = false
|
||||
this.importLoading = false
|
||||
if (this.$refs.upload) this.$refs.upload.clearFiles()
|
||||
},
|
||||
handleTxtUpload (upload) {
|
||||
const file = upload.file
|
||||
if (!file) {
|
||||
this.$message.error(this.$t(this.key('file_not_exist')))
|
||||
return
|
||||
}
|
||||
if (!/\.txt$/i.test(file.name)) {
|
||||
this.$message.error(this.$t(this.key('file_format_error')))
|
||||
return
|
||||
}
|
||||
if (!this.importBatch) {
|
||||
this.$message.error(this.$t(this.key('select_batch')))
|
||||
return
|
||||
}
|
||||
|
||||
this.importLoading = true
|
||||
const reader = new FileReader()
|
||||
reader.onload = async event => {
|
||||
try {
|
||||
const lines = String(event.target.result || '')
|
||||
.split(/\r?\n/)
|
||||
.map(line => line.trim())
|
||||
.filter(Boolean)
|
||||
if (!lines.length) {
|
||||
this.$message.error(this.$t(this.key('upload_file_error')))
|
||||
return
|
||||
}
|
||||
|
||||
const res = await getProcessBatch({
|
||||
battery: lines.map(batteryIds => ({ battery_ids: batteryIds }))
|
||||
})
|
||||
const data = res && res.data !== undefined ? res.data : res
|
||||
if (data && data.status === 1 && Array.isArray(data.battery_id)) {
|
||||
this.hasActiveBattery = false
|
||||
this.importTableData = data.battery_id.map(batteryId => ({
|
||||
battery_id: batteryId,
|
||||
active: 0,
|
||||
batch: this.importBatch
|
||||
}))
|
||||
} else {
|
||||
const rows = Array.isArray(data) ? data : []
|
||||
this.hasActiveBattery = rows.some(item => item.active === 1)
|
||||
this.importTableData = rows.map(item => ({
|
||||
...item,
|
||||
batch: this.importBatch
|
||||
}))
|
||||
}
|
||||
this.$message.success(this.$t(this.key('import_data_success')))
|
||||
} finally {
|
||||
this.importLoading = false
|
||||
}
|
||||
}
|
||||
reader.onerror = () => {
|
||||
this.importLoading = false
|
||||
this.$message.error(this.$t(this.key('upload_file_error')))
|
||||
}
|
||||
reader.readAsText(file)
|
||||
},
|
||||
async submitImport () {
|
||||
if (!this.importTableData.length) {
|
||||
this.$message.error(this.$t(this.key('please_import_data')))
|
||||
return
|
||||
}
|
||||
if (this.hasActiveBattery) {
|
||||
this.$message.error(this.$t(this.key('active_battery_exist')))
|
||||
return
|
||||
}
|
||||
|
||||
this.importLoading = true
|
||||
try {
|
||||
await sendWorkerman({
|
||||
sendData: {
|
||||
action: 'set_single_login',
|
||||
param: {
|
||||
battery_ids: this.importTableData.map(row => row.battery_id),
|
||||
device_code: 'WEBMAN_LOGIN',
|
||||
batch: this.importTableData[0].batch,
|
||||
lot: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
this.$message.success(this.$t(this.key('operation_success')))
|
||||
this.importVisible = false
|
||||
this.resetImport()
|
||||
this.fetchData()
|
||||
} finally {
|
||||
this.importLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.search-bar {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/deep/ .el-form-item--mini.el-form-item {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.import-row /deep/ .el-form-item__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.upload-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.import-count {
|
||||
margin-left: 140px;
|
||||
line-height: 28px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,454 @@
|
||||
<template>
|
||||
<d2-container>
|
||||
<template #header>
|
||||
<div class="search-bar">
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item :label="$t(key('tray_no'))">
|
||||
<el-input
|
||||
v-model="search.tray"
|
||||
:placeholder="$t(key('enter_tray_no'))"
|
||||
clearable
|
||||
style="width:220px"
|
||||
@keyup.enter.native="onSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('batch_no'))">
|
||||
<el-input
|
||||
v-model="search.batch"
|
||||
:placeholder="$t(key('enter_batch_no'))"
|
||||
clearable
|
||||
style="width:220px"
|
||||
@keyup.enter.native="onSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('status'))">
|
||||
<el-select
|
||||
v-model="search.active"
|
||||
:placeholder="$t(key('select_status'))"
|
||||
clearable
|
||||
style="width:180px"
|
||||
>
|
||||
<el-option :label="$t(key('stop'))" value="0" />
|
||||
<el-option :label="$t(key('activated'))" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t(key('login_time'))">
|
||||
<el-date-picker
|
||||
v-model="search.create_time"
|
||||
type="datetimerange"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
range-separator="-"
|
||||
:start-placeholder="$t(key('start_time'))"
|
||||
:end-placeholder="$t(key('end_time'))"
|
||||
style="width:330px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="onSearch">
|
||||
{{ $t(key('search')) }}
|
||||
</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="onReset">
|
||||
{{ $t(key('reset')) }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<page-table
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:loading="loading"
|
||||
:toolbar-buttons="[]"
|
||||
:row-buttons="rowButtons"
|
||||
:pagination="pagination"
|
||||
:help-text="$t(ckey('help'))"
|
||||
auto-height
|
||||
@page-change="onPageChange"
|
||||
>
|
||||
<template #col-status="{ row }">
|
||||
<el-tag v-if="row.active == 1" type="success">{{ $t(key('activated')) }}</el-tag>
|
||||
<el-tag v-else type="danger">{{ $t(key('stop')) }}</el-tag>
|
||||
</template>
|
||||
</page-table>
|
||||
|
||||
<el-drawer
|
||||
:visible.sync="trayDrawerVisible"
|
||||
:with-header="false"
|
||||
size="100%"
|
||||
append-to-body
|
||||
>
|
||||
<div class="drawer-header">
|
||||
<el-page-header @back="trayDrawerVisible = false" :content="trayDrawerTitle" />
|
||||
</div>
|
||||
<el-row>
|
||||
<el-col :span="trayTimeline.length ? 6 : 0" v-if="trayTimeline.length">
|
||||
<div class="details-left">
|
||||
<el-timeline class="timeline">
|
||||
<el-timeline-item v-for="(item, index) in trayTimeline" :key="index">
|
||||
<p>
|
||||
{{ $t(key('process')) }}: {{ item.process_name }}
|
||||
<span v-if="item.is_next_process_code == 1" class="current-process">
|
||||
{{ $t(key('current_process')) }}
|
||||
</span>
|
||||
</p>
|
||||
<el-card>
|
||||
<p>{{ $t(key('start_time')) }}: {{ item.beginTime }}</p>
|
||||
<p>{{ $t(key('end_time')) }}: {{ item.endTime }}</p>
|
||||
<p>{{ $t(key('device_number')) }}: {{ item.device_code }}</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="trayTimeline.length ? 18 : 24">
|
||||
<div class="drawer-main">
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item :label="$t(key('battery_barcode'))">
|
||||
<el-input
|
||||
v-model="traySearch"
|
||||
:placeholder="$t(key('please_enter_battery_barcode'))"
|
||||
clearable
|
||||
style="width:320px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="filteredTrayDetails" border height="calc(100vh - 160px)">
|
||||
<el-table-column type="index" width="60" :label="$t(key('serial_number'))" />
|
||||
<el-table-column min-width="160" prop="battery_id" :label="$t(key('battery_barcode'))">
|
||||
<template #default="{ row }">
|
||||
<span class="link-text" @click="openBatteryDetails(row)">{{ row.battery_id }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="140" prop="batch" :label="$t(key('batch_no'))" />
|
||||
<el-table-column min-width="140" prop="tray" :label="$t(key('tray_no'))" />
|
||||
<el-table-column min-width="120" prop="lot" :label="$t(key('lot'))" />
|
||||
<el-table-column min-width="130" prop="active" :label="$t(key('activation_status'))">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.active == 1 ? 'success' : 'warning'">
|
||||
{{ row.active == 1 ? $t(key('activated')) : $t(key('stop')) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-drawer>
|
||||
|
||||
<el-drawer
|
||||
:visible.sync="batteryDrawerVisible"
|
||||
:with-header="false"
|
||||
size="100%"
|
||||
append-to-body
|
||||
>
|
||||
<div class="drawer-header">
|
||||
<el-page-header @back="batteryDrawerVisible = false" :content="batteryDrawerTitle" />
|
||||
</div>
|
||||
<el-row v-loading="batteryLoading">
|
||||
<el-col :span="batteryTimeline.length ? 6 : 0" v-if="batteryTimeline.length">
|
||||
<div class="details-left">
|
||||
<el-timeline class="timeline">
|
||||
<el-timeline-item
|
||||
v-for="(item, index) in batteryTimeline"
|
||||
:key="index"
|
||||
:icon="item.is_select === '1' ? 'el-icon-check' : ''"
|
||||
:type="item.is_select === '1' ? 'success' : ''"
|
||||
:color="item.is_select === '1' ? '#67C23A' : ''"
|
||||
@click.native="selectBatteryTimeline(index)"
|
||||
>
|
||||
<p>
|
||||
{{ $t(key('process')) }}: {{ item.process_name }}
|
||||
<span v-if="item.is_next_process_code == 1" class="current-process">
|
||||
{{ $t(key('current_process')) }}
|
||||
</span>
|
||||
</p>
|
||||
<el-card :class="{ selected: item.is_select === '1' }">
|
||||
<p>{{ $t(key('start_time')) }}: {{ item.beginTime }}</p>
|
||||
<p>{{ $t(key('end_time')) }}: {{ item.endTime }}</p>
|
||||
<p>{{ $t(key('device_number')) }}: {{ item.device_code }}</p>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="batteryTimeline.length ? 18 : 24">
|
||||
<div class="drawer-main">
|
||||
<el-form :inline="true" size="mini">
|
||||
<el-form-item :label="$t(key('project_name'))">
|
||||
<el-input
|
||||
v-model="batterySearch"
|
||||
:placeholder="$t(key('enter_project_name_search'))"
|
||||
clearable
|
||||
style="width:320px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="filteredBatteryDetails" border height="calc(100vh - 160px)">
|
||||
<el-table-column type="index" width="60" :label="$t(key('serial_number'))" />
|
||||
<el-table-column min-width="180" prop="name" :label="$t(key('project_name'))" />
|
||||
<el-table-column min-width="220" prop="content" :label="$t(key('content'))" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-drawer>
|
||||
</d2-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useTableColumns } from '@/composables/useTableColumns'
|
||||
import { useTableButtons } from '@/composables/useTableButtons'
|
||||
import { i18nMixin } from '@/composables/useI18n'
|
||||
import { confirmMixin } from '@/composables/useConfirmHandle'
|
||||
import {
|
||||
getBatchTrayList,
|
||||
trayUnbinding,
|
||||
getBatteryParam
|
||||
} from '@/api/planning-production/batch-tray'
|
||||
import { sendWorkerman } from '@/api/production-master-data/workerman'
|
||||
import PageTable from '@/components/page-table'
|
||||
|
||||
export default {
|
||||
name: 'planning-production-tray-tracking',
|
||||
components: { PageTable },
|
||||
mixins: [i18nMixin('page.planning_production.batch_management.tray_tracking'), confirmMixin],
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
tableData: [],
|
||||
pagination: { current: 1, size: 10, total: 0 },
|
||||
search: {
|
||||
tray: '',
|
||||
batch: '',
|
||||
active: '',
|
||||
create_time: []
|
||||
},
|
||||
columns: [],
|
||||
rowButtons: [],
|
||||
trayDrawerVisible: false,
|
||||
trayDrawerTitle: '',
|
||||
trayTimeline: [],
|
||||
trayDetailData: [],
|
||||
traySearch: '',
|
||||
batteryDrawerVisible: false,
|
||||
batteryDrawerTitle: '',
|
||||
batteryLoading: false,
|
||||
batteryTimeline: [],
|
||||
batteryDetailData: [],
|
||||
batterySearch: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredTrayDetails () {
|
||||
const keyword = String(this.traySearch || '').toLowerCase()
|
||||
if (!keyword) return this.trayDetailData
|
||||
return this.trayDetailData.filter(row => String(row.battery_id || '').toLowerCase().includes(keyword))
|
||||
},
|
||||
filteredBatteryDetails () {
|
||||
const keyword = String(this.batterySearch || '').toLowerCase()
|
||||
if (!keyword) return this.batteryDetailData
|
||||
return this.batteryDetailData.filter(row => String(row.name || '').toLowerCase().includes(keyword))
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.search.tray = this.$route.params.tray || ''
|
||||
this.search.batch = this.$route.params.batch || ''
|
||||
this.columns = useTableColumns([
|
||||
{ prop: 'tray', label: this.key('tray_no'), minWidth: 140 },
|
||||
{ prop: 'lot', label: this.key('lot'), minWidth: 120 },
|
||||
{ prop: 'status', label: this.key('status'), slot: 'status', minWidth: 110 },
|
||||
{ prop: 'batch', label: this.key('batch_no'), minWidth: 140 },
|
||||
{ prop: 'flow_name', label: this.key('flow_name'), minWidth: 160 },
|
||||
{ prop: 'next_process_code', label: this.key('next_process_code'), minWidth: 140 },
|
||||
{ prop: 'actual_input_battery_count', label: this.key('loaded_battery_qty'), minWidth: 150 },
|
||||
{ prop: 'create_time', label: this.key('login_time'), minWidth: 170 },
|
||||
{ prop: '_actions', label: this.key('actions'), width: 220, fixed: 'right' }
|
||||
], { selectionWidth: 0 })
|
||||
const btns = useTableButtons({
|
||||
row: [
|
||||
{
|
||||
key: 'detail',
|
||||
label: this.key('detail'),
|
||||
icon: 'el-icon-position',
|
||||
auth: '/planning_production/production_batch_management/batch_tray/trace',
|
||||
onClick: this.openTrayDetails
|
||||
},
|
||||
{
|
||||
key: 'unbind',
|
||||
label: this.key('unbind'),
|
||||
icon: 'el-icon-unlock',
|
||||
auth: '/planning_production/production_batch_management/batch_tray/unbinding',
|
||||
cssStyle: { color: '#E6A23C', marginRight: '10px', cursor: 'pointer' },
|
||||
onClick: this.handleTrayUnbinding
|
||||
},
|
||||
{
|
||||
key: 'stop',
|
||||
label: this.key('stop'),
|
||||
icon: 'el-icon-close',
|
||||
color: 'danger',
|
||||
auth: '/planning_production/production_batch_management/batch_tray/inactivity',
|
||||
onClick: this.handleTrayInactivity
|
||||
}
|
||||
]
|
||||
}, this.$permission)
|
||||
this.rowButtons = btns.rowButtons
|
||||
this.fetchData()
|
||||
},
|
||||
methods: {
|
||||
normalizeListResponse (res) {
|
||||
const data = Array.isArray(res) ? res : (res && res.data) || []
|
||||
if (Array.isArray(data)) return { list: data, total: data.length }
|
||||
return {
|
||||
list: data.data || [],
|
||||
total: data.count || 0
|
||||
}
|
||||
},
|
||||
async fetchData () {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await getBatchTrayList({
|
||||
...this.search,
|
||||
page_no: this.pagination.current,
|
||||
page_size: this.pagination.size
|
||||
})
|
||||
const { list, total } = this.normalizeListResponse(res)
|
||||
this.tableData = list
|
||||
this.pagination.total = total
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
onSearch () {
|
||||
this.pagination.current = 1
|
||||
this.fetchData()
|
||||
},
|
||||
onReset () {
|
||||
this.search = { tray: '', batch: '', active: '', create_time: [] }
|
||||
this.pagination.current = 1
|
||||
this.fetchData()
|
||||
},
|
||||
onPageChange (page) {
|
||||
this.pagination.current = page.current
|
||||
this.pagination.size = page.size
|
||||
this.fetchData()
|
||||
},
|
||||
openTrayDetails (row) {
|
||||
this.trayDrawerTitle = `【${row.tray || ''}】${this.$t(this.key('tray_details'))}`
|
||||
this.trayTimeline = row.date_log || []
|
||||
this.trayDetailData = row.trayDetailsData || []
|
||||
this.traySearch = ''
|
||||
this.trayDrawerVisible = true
|
||||
},
|
||||
async openBatteryDetails (row) {
|
||||
this.batteryDrawerTitle = `【${row.battery_id || ''}】${this.$t(this.key('battery_details'))}`
|
||||
this.batteryDrawerVisible = true
|
||||
this.batteryLoading = true
|
||||
this.batterySearch = ''
|
||||
try {
|
||||
const res = await getBatteryParam({
|
||||
subbatch: row.subbatch,
|
||||
batch: row.batch,
|
||||
tray: row.tray,
|
||||
lot: row.lot,
|
||||
battery_id: row.battery_id
|
||||
})
|
||||
const data = Array.isArray(res) ? res : (res && res.data) || []
|
||||
this.batteryTimeline = data.map((item, index) => ({
|
||||
...item,
|
||||
is_select: index === 0 ? '1' : '0'
|
||||
}))
|
||||
this.batteryDetailData = this.batteryTimeline[0] ? (this.batteryTimeline[0].batteryDetailsData || []) : []
|
||||
} finally {
|
||||
this.batteryLoading = false
|
||||
}
|
||||
},
|
||||
selectBatteryTimeline (index) {
|
||||
this.batteryTimeline = this.batteryTimeline.map((item, itemIndex) => ({
|
||||
...item,
|
||||
is_select: itemIndex === index ? '1' : '0'
|
||||
}))
|
||||
this.batteryDetailData = this.batteryTimeline[index]
|
||||
? (this.batteryTimeline[index].batteryDetailsData || [])
|
||||
: []
|
||||
},
|
||||
async handleTrayUnbinding (row) {
|
||||
await this.$confirmAction(
|
||||
{
|
||||
message: this.key('tray_unbind_confirm'),
|
||||
title: this.key('prompt')
|
||||
},
|
||||
() => trayUnbinding({ batch: row.batch, tray: row.tray })
|
||||
)
|
||||
this.$message.success(this.$t(this.key('operation_success')))
|
||||
this.pagination.current = Math.min(
|
||||
this.pagination.current,
|
||||
Math.ceil((this.pagination.total - 1) / this.pagination.size) || 1
|
||||
)
|
||||
this.fetchData()
|
||||
},
|
||||
async handleTrayInactivity (row) {
|
||||
await this.$confirmAction(
|
||||
{
|
||||
message: this.key('tray_stop_confirm'),
|
||||
title: this.key('prompt')
|
||||
},
|
||||
() => sendWorkerman({
|
||||
sendData: {
|
||||
action: 'set_tray_inactivity',
|
||||
param: {
|
||||
batch: row.batch,
|
||||
tray: row.tray
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
this.$message.success(this.$t(this.key('operation_success')))
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.search-bar {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/deep/ .el-form-item--mini.el-form-item {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.details-left {
|
||||
height: calc(100vh - 73px);
|
||||
overflow-y: auto;
|
||||
background: #f2f3f5;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.drawer-main {
|
||||
padding: 20px 20px 0;
|
||||
}
|
||||
|
||||
.current-process {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.link-text {
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: #fff;
|
||||
background-color: #67c23a;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user