feat: 新增多模块功能并完善功能清单
1. 新增BOM物料清单、班组管理、班次管理、排班日历、监控设置页面及对应路由 2. 新增相关业务API接口 3. 完善多语言国际化配置 4. 更新功能迁移状态清单,完成所有功能迁移 5. 新增各模块测试用例文档
This commit is contained in:
20
docs/功能测试-BOM物料清单.md
Normal file
20
docs/功能测试-BOM物料清单.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# 功能测试任务列表 - BOM物料清单
|
||||||
|
|
||||||
|
> 路由:`/production_configuration/matetial_model/bom`
|
||||||
|
|
||||||
|
| 序号 | 测试项 | 操作步骤 | 预期结果 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 页面入口 | 从菜单进入“BOM物料清单”,或直接访问路由 | 页面正常打开,表格展示 BOM 编码、名称、产品型号、状态、创建人、创建时间和备注 | ☐ |
|
||||||
|
| 2 | 条件查询 | 输入 BOM 编码、名称或选择产品型号后点击“查询” | 列表按条件刷新,分页回到第一页 | ☐ |
|
||||||
|
| 3 | 重置查询 | 点击“重置” | 查询条件清空,列表恢复默认数据 | ☐ |
|
||||||
|
| 4 | 新增校验 | 点击“新增”,不填写编码、名称或产品型号直接确认 | 表单提示必填校验,不提交请求 | ☐ |
|
||||||
|
| 5 | 新增 BOM | 填写 BOM 编码、名称、产品型号、状态和备注后确认 | 弹窗关闭,提示操作成功,列表出现新增 BOM | ☐ |
|
||||||
|
| 6 | 编辑 BOM | 点击“编辑”,修改名称、状态或备注后确认 | 表单回显旧值,保存后列表展示新值 | ☐ |
|
||||||
|
| 7 | 删除 BOM | 点击“删除”并确认 | 提示操作成功,记录被删除,分页刷新正确 | ☐ |
|
||||||
|
| 8 | 打开 BOM 关系 | 点击“设置BOM” | 全屏关系弹窗打开,左侧显示工序单元,右侧显示当前工序 IN/OUT 关系 | ☐ |
|
||||||
|
| 9 | 切换工序 | 在左侧选择不同工序单元 | IN/OUT 列表按工序刷新 | ☐ |
|
||||||
|
| 10 | 添加 IN 物料 | 在 IN 区域点击“新增”,选择一个或多个物料后确认 | 物料加入 IN 列表,重复物料提示不可重复选择 | ☐ |
|
||||||
|
| 11 | 编辑 IN 投入数量 | 修改 IN 列表的投入数量并移出输入框 | 数量保存成功,刷新后仍保持新值 | ☐ |
|
||||||
|
| 12 | 添加 OUT 物料限制 | 在 OUT 区域尝试选择多个物料或已有 OUT 后继续新增 | 系统提示 OUT 结构只允许 1 个半成品 | ☐ |
|
||||||
|
| 13 | 删除 BOM 关系 | 勾选 IN/OUT 关系后点击删除,或点击行内删除 | 关系删除成功,列表刷新 | ☐ |
|
||||||
|
| 14 | 权限按钮 | 使用缺少新增/编辑/删除/设置BOM权限的账号进入页面 | 对应按钮不显示或不可操作 | ☐ |
|
||||||
14
docs/功能测试-排班日历.md
Normal file
14
docs/功能测试-排班日历.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# 功能测试任务列表 - 排班日历
|
||||||
|
|
||||||
|
> 路由:`/system_settings/organization/production_shift_calender`
|
||||||
|
|
||||||
|
| 序号 | 测试项 | 操作步骤 | 预期结果 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 页面入口 | 从菜单进入“排班日历” | 页面正常打开,展示当前月份日历 | ☐ |
|
||||||
|
| 2 | 初始数据加载 | 打开页面后观察日历单元格 | 系统请求当前日历可视范围的排班数据,并在日期下显示班次计划标签 | ☐ |
|
||||||
|
| 3 | 休息日展示 | 查看包含休息日的日期 | 休息日以灰色标签显示“休” | ☐ |
|
||||||
|
| 4 | 工作日展示 | 查看包含排班的日期 | 日期下展示班次计划标签 | ☐ |
|
||||||
|
| 5 | 明细悬浮 | 鼠标悬浮工作日班次计划标签 | 弹出层展示班次名称、开始/结束时间、绑定班组和跨天标识 | ☐ |
|
||||||
|
| 6 | 跨月切换 | 点击日历上一月/下一月 | 日历切换月份并重新加载新可视范围数据 | ☐ |
|
||||||
|
| 7 | 选择日期 | 点击任意日期 | 日期高亮状态正常,不影响排班数据显示 | ☐ |
|
||||||
|
| 8 | 空数据展示 | 切换到无排班数据的月份 | 日历正常显示,无错误提示或残留旧数据 | ☐ |
|
||||||
19
docs/功能测试-班次管理.md
Normal file
19
docs/功能测试-班次管理.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 功能测试任务列表 - 班次管理
|
||||||
|
|
||||||
|
> 路由:`/system_settings/organization/production_shift_management`
|
||||||
|
|
||||||
|
| 序号 | 测试项 | 操作步骤 | 预期结果 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 页面入口 | 从菜单进入“班次管理” | 页面正常打开,展示班次计划名称、编码、起止时间、状态、创建/更新时间 | ☐ |
|
||||||
|
| 2 | 条件查询 | 输入计划名称、编码或创建时间后查询 | 列表按条件刷新 | ☐ |
|
||||||
|
| 3 | 新增校验 | 点击新增,不填名称、编码或时间范围直接确认 | 显示必填校验 | ☐ |
|
||||||
|
| 4 | 新增班次计划 | 填写计划信息、选择班组、添加班次明细后确认 | 保存成功,列表出现新计划 | ☐ |
|
||||||
|
| 5 | 班组绑定唯一性 | 两条班次明细绑定同一个班组 | 第二次绑定被阻止并提示 | ☐ |
|
||||||
|
| 6 | 明细必填校验 | 添加班次明细但缺少名称、开始时间或结束时间 | 提示对应行缺失字段 | ☐ |
|
||||||
|
| 7 | 编辑班次计划 | 点击编辑,修改状态、休息日、明细后确认 | 保存成功,重新打开可回显新数据 | ☐ |
|
||||||
|
| 8 | 单条删除 | 点击删除并确认 | 计划删除成功 | ☐ |
|
||||||
|
| 9 | 批量删除 | 勾选多条计划后批量删除 | 所选计划删除成功 | ☐ |
|
||||||
|
| 10 | 导入模板 | 点击导入后下载模板 | 浏览器下载班次计划导入模板 | ☐ |
|
||||||
|
| 11 | 导入数据 | 选择合法 xls/xlsx 文件并确认导入 | 预览展示后提交成功,列表刷新 | ☐ |
|
||||||
|
| 12 | 导出任务 | 点击导出并确认 | 提示下载任务创建成功 | ☐ |
|
||||||
|
| 13 | 权限按钮 | 使用缺少权限账号进入页面 | 对应新增/编辑/删除/导入/导出按钮隐藏或不可操作 | ☐ |
|
||||||
19
docs/功能测试-班组管理.md
Normal file
19
docs/功能测试-班组管理.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 功能测试任务列表 - 班组管理
|
||||||
|
|
||||||
|
> 路由:`/system_settings/organization/production_team_manage`
|
||||||
|
|
||||||
|
| 序号 | 测试项 | 操作步骤 | 预期结果 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 页面入口 | 从菜单进入“班组管理” | 页面正常打开,展示班组名称、所属厂区、所属产线、创建/更新时间 | ☐ |
|
||||||
|
| 2 | 条件查询 | 输入班组名称、选择厂区/产线或创建时间后查询 | 列表按条件刷新 | ☐ |
|
||||||
|
| 3 | 新增校验 | 点击新增,不填班组名称、厂区或产线直接确认 | 显示必填校验,不提交 | ☐ |
|
||||||
|
| 4 | 新增班组 | 填写班组信息,添加成员并设置班组长后确认 | 提示操作成功,列表出现新班组 | ☐ |
|
||||||
|
| 5 | 班组长唯一性 | 添加多个成员并尝试设置两个班组长 | 第二个班组长被拦截,提示只允许一个班组长 | ☐ |
|
||||||
|
| 6 | 编辑班组 | 点击编辑,修改成员或班组信息后确认 | 保存成功,重新打开可看到新数据 | ☐ |
|
||||||
|
| 7 | 删除成员 | 编辑已有班组,删除已有成员 | 成员删除成功,列表刷新 | ☐ |
|
||||||
|
| 8 | 单条删除 | 点击行内删除并确认 | 班组删除成功 | ☐ |
|
||||||
|
| 9 | 批量删除 | 勾选多条数据后点击批量删除并确认 | 所选班组删除成功 | ☐ |
|
||||||
|
| 10 | 导入模板 | 点击导入后下载模板 | 浏览器下载班组导入模板 | ☐ |
|
||||||
|
| 11 | 导入数据 | 选择合法 xls/xlsx 文件并确认导入 | 预览数据正确,提交后提示成功并刷新列表 | ☐ |
|
||||||
|
| 12 | 导出任务 | 点击导出并确认 | 提示下载任务创建成功 | ☐ |
|
||||||
|
| 13 | 权限按钮 | 使用缺少权限账号进入页面 | 对应新增/编辑/删除/导入/导出按钮隐藏或不可操作 | ☐ |
|
||||||
15
docs/功能测试-监控设置.md
Normal file
15
docs/功能测试-监控设置.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# 功能测试任务列表 - 监控设置
|
||||||
|
|
||||||
|
> 路由:`/system_settings/system_monitoring/setting`
|
||||||
|
|
||||||
|
| 序号 | 测试项 | 操作步骤 | 预期结果 | 结果 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 页面入口 | 从菜单进入“监控设置”,或直接访问路由 | 页面正常打开,表格展示监控编码、名称、IP、端口、版本和预警阈值字段 | ☐ |
|
||||||
|
| 2 | 条件查询 | 输入监控编码或监控名称后点击“查询” | 列表按条件刷新,分页回到第一页 | ☐ |
|
||||||
|
| 3 | 重置查询 | 输入查询条件后点击“重置” | 查询条件清空,列表恢复默认数据 | ☐ |
|
||||||
|
| 4 | 新增必填校验 | 点击“新增”,不填写编码、名称、IP 或端口直接确认 | 表单提示对应必填校验,不提交请求 | ☐ |
|
||||||
|
| 5 | 新增监控配置 | 填写编码、名称、IP、端口、刷新间隔、CPU/磁盘/内存阈值和 Python 版本后确认 | 弹窗关闭,提示操作成功,列表出现新增记录 | ☐ |
|
||||||
|
| 6 | 编辑监控配置 | 点击某条记录“编辑”,修改名称或阈值后确认 | 弹窗回显旧值,保存后列表展示新值 | ☐ |
|
||||||
|
| 7 | 删除取消 | 点击“删除”后在确认框选择取消 | 数据不删除,列表保持不变 | ☐ |
|
||||||
|
| 8 | 删除确认 | 点击“删除”后确认 | 提示操作成功,记录从列表移除,分页数量正确刷新 | ☐ |
|
||||||
|
| 9 | 权限按钮 | 使用无新增/编辑/删除权限的账号进入页面 | 对应按钮不显示或不可操作 | ☐ |
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
> 根据 `后台Webman界面截图对照表.md` 生成。状态以当前 V2 项目中已落地的页面目录为准。
|
> 根据 `后台Webman界面截图对照表.md` 生成。状态以当前 V2 项目中已落地的页面目录为准。
|
||||||
|
|
||||||
- 总功能数:79
|
- 总功能数:79
|
||||||
- 已迁移:74
|
- 已迁移:79
|
||||||
- 未迁移:5
|
- 未迁移:0
|
||||||
|
|
||||||
| 状态 | 一级模块 | 二级模块 | 三级模块 | 功能说明 | V2 目标路径 |
|
| 状态 | 一级模块 | 二级模块 | 三级模块 | 功能说明 | V2 目标路径 |
|
||||||
|:---:|---|---|---|---|---|
|
|:---:|---|---|---|---|---|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
| ✅ | 系统设置 (System Administration) | 菜单管理 (Menu Management) | 菜单配置 (Menu Configuration) | 系统菜单配置 | `src/views/system-administration/menu-management/menu-configuration/` |
|
| ✅ | 系统设置 (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) | 操作日志 (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 Utilities) | 接口日志 (API Logs) | 与设备对接流程交互日志(支持按 IP 和接口名称查询) | `src/views/system-administration/system-utilities/api-logs/` |
|
||||||
| ⬜ | 系统设置 (System Administration) | 系统监控 (System Monitoring) | 监控设置 (Monitoring Configuration) | 系统监控配置 | 待确认 |
|
| ✅ | 系统设置 (System Administration) | 系统监控 (System Monitoring) | 监控设置 (Monitoring Configuration) | 系统监控配置 | `src/views/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) | 产线设置 (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) | 工厂模型 (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 Category) | 工艺流程类别的增删改查 | `src/views/production-master-data/process-model/process-category/` |
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
| ✅ | 生产配置 (Production Master Data) | 产品管理 (Product Management) | 不良管理 (Defect Management) | 不良代码及描述管理,支持批量导入 | `src/views/production-master-data/product-model/product-ng-info/` |
|
| ✅ | 生产配置 (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 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) | 物料信息管理 (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) | BOM物料清单 (Bill of Materials) | 产品BOM管理 | `src/views/production-master-data/material-model/bill-of-materials/` |
|
||||||
| ✅ | 生产配置 (Production Master Data) | 物料模型 (Material Model) | 计量单位 (Unit of Measure) | 计量单位配置与管理 | `src/views/production-master-data/material-model/material-unit/` |
|
| ✅ | 生产配置 (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) | 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) | 班组管理 (Team Management) | 管理生产班组 | `src/views/production-master-data/team-model/team-management/` |
|
||||||
| ⬜ | 生产配置 (Production Master Data) | 班组模型 (Team Model) | 班次管理 (Shift Management) | 管理生产班次 | 待确认 |
|
| ✅ | 生产配置 (Production Master Data) | 班组模型 (Team Model) | 班次管理 (Shift Management) | 管理生产班次 | `src/views/production-master-data/team-model/shift-management/` |
|
||||||
| ⬜ | 生产配置 (Production Master Data) | 班组模型 (Team Model) | 排班日历 (Scheduling Calendar) | 查看排班日历 | 待确认 |
|
| ✅ | 生产配置 (Production Master Data) | 班组模型 (Team Model) | 排班日历 (Scheduling Calendar) | 查看排班日历 | `src/views/production-master-data/team-model/scheduling-calendar/` |
|
||||||
| ✅ | 设备模型 (Equipment Management) | 设备类别 (Equipment Category) | 设备类别 (Equipment Category) | 管理设备类别 | `src/views/equipment-management/equipment-model/equipment-category/` |
|
| ✅ | 设备模型 (Equipment Management) | 设备类别 (Equipment Category) | 设备类别 (Equipment Category) | 管理设备类别 | `src/views/equipment-management/equipment-model/equipment-category/` |
|
||||||
| ✅ | 设备模型 (Equipment Management) | 设备信息 (Equipment Management) | 设备信息 (Equipment Registry) | 管理设备信息 | `src/views/equipment-management/equipment-model/equipment-registry/` |
|
| ✅ | 设备模型 (Equipment Management) | 设备信息 (Equipment Management) | 设备信息 (Equipment Registry) | 管理设备信息 | `src/views/equipment-management/equipment-model/equipment-registry/` |
|
||||||
| ✅ | 设备模型 (Equipment Management) | 设备点检 (Inspection Management) | 设备点检项目 (Inspection Items) | 点检项目管理 | `src/views/equipment-management/inspection-management/inspection-items/` |
|
| ✅ | 设备模型 (Equipment Management) | 设备点检 (Inspection Management) | 设备点检项目 (Inspection Items) | 点检项目管理 | `src/views/equipment-management/inspection-management/inspection-items/` |
|
||||||
|
|||||||
56
src/api/production-master-data/bill-of-materials.js
Normal file
56
src/api/production-master-data/bill-of-materials.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'production_configuration/matetial_model/bom/'
|
||||||
|
const RELATION_BASE = 'production_configuration/matetial_model/bom_relationship/'
|
||||||
|
|
||||||
|
function apiParams (method, data = {}) {
|
||||||
|
return {
|
||||||
|
method: `production_configuration_matetial_model_bom_${method}`,
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function relationApiParams (method, data = {}) {
|
||||||
|
return {
|
||||||
|
method: `production_configuration_matetial_model_bom_relationship_${method}`,
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBomAll (data) {
|
||||||
|
return request({ url: BASE + 'all', method: 'get', params: apiParams('all', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBomList (data) {
|
||||||
|
return request({ url: BASE + 'list', method: 'get', params: apiParams('list', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createBom (data) {
|
||||||
|
return request({ url: BASE + 'create', method: 'post', data: apiParams('create', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editBom (data) {
|
||||||
|
return request({ url: BASE + 'edit', method: 'put', data: apiParams('edit', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteBom (data) {
|
||||||
|
return request({ url: BASE + 'delete', method: 'delete', data: apiParams('delete', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBomRelationshipList (data) {
|
||||||
|
return request({ url: RELATION_BASE + 'list', method: 'get', params: relationApiParams('list', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createBomRelationship (data) {
|
||||||
|
return request({ url: RELATION_BASE + 'create', method: 'post', data: relationApiParams('create', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editBomRelationship (data) {
|
||||||
|
return request({ url: RELATION_BASE + 'edit', method: 'put', data: relationApiParams('edit', data) })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteBomRelationship (data) {
|
||||||
|
return request({ url: RELATION_BASE + 'delete', method: 'delete', data: relationApiParams('delete', data) })
|
||||||
|
}
|
||||||
17
src/api/production-master-data/shift-management.js
Normal file
17
src/api/production-master-data/shift-management.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'system_settings/organization/production_shift_management/'
|
||||||
|
|
||||||
|
function params (method, data = {}) {
|
||||||
|
return { method: `system_settings_organization_production_shift_management_${method}`, platform: 'background', ...data }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getShiftAll (data) { return request({ url: BASE + 'all', method: 'get', params: params('all', data) }) }
|
||||||
|
export function getShiftList (data) { return request({ url: BASE + 'list', method: 'get', params: params('list', data) }) }
|
||||||
|
export function createShift (data) { return request({ url: BASE + 'create', method: 'post', data: params('create', data) }) }
|
||||||
|
export function editShift (data) { return request({ url: BASE + 'edit', method: 'put', data: params('edit', data) }) }
|
||||||
|
export function deleteShift (data) { return request({ url: BASE + 'delete', method: 'delete', data: params('delete', data) }) }
|
||||||
|
export function getShiftImportTemplate (data) { return request({ url: BASE + 'get_import_template', method: 'post', responseType: 'blob', data: params('get_import_template', data) }) }
|
||||||
|
export function importShiftData (data) { return request({ url: BASE + 'data_import', method: 'post', data: params('data_import', data) }) }
|
||||||
|
export function exportShiftTask (data) { return request({ url: BASE + 'data_export_task', method: 'post', data: params('data_export_task', data) }) }
|
||||||
|
export function getShiftCalendarByDateRange (data) { return request({ url: BASE + 'get_shift_by_date_range', method: 'get', params: params('get_shift_by_date_range', data) }) }
|
||||||
@@ -1,76 +1,24 @@
|
|||||||
import { request } from '@/api/_service'
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
const BASE = 'system_settings/organization/production_team_manage/'
|
const BASE = 'system_settings/organization/production_team_manage/'
|
||||||
|
const MEMBER_BASE = 'system_settings/organization/production_members_manage/'
|
||||||
|
|
||||||
function apiParams (method, data = {}) {
|
function params (method, data = {}) {
|
||||||
return {
|
return { method: `system_settings_organization_production_team_manage_${method}`, platform: 'background', ...data }
|
||||||
method: `system_settings_organization_production_team_manage_${method}`,
|
|
||||||
platform: 'background',
|
|
||||||
...data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTeamManagementList (data) {
|
function memberParams (method, data = {}) {
|
||||||
return request({
|
return { method: `system_settings_organization_production_members_manage_${method}`, platform: 'background', ...data }
|
||||||
url: BASE + 'list',
|
|
||||||
method: 'get',
|
|
||||||
params: apiParams('list', data)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTeamManagement (data) {
|
export function getTeamAll (data) { return request({ url: BASE + 'all', method: 'get', params: params('all', data) }) }
|
||||||
return request({
|
export function getTeamList (data) { return request({ url: BASE + 'list', method: 'get', params: params('list', data) }) }
|
||||||
url: BASE + 'create',
|
export function createTeam (data) { return request({ url: BASE + 'create', method: 'post', data: params('create', data) }) }
|
||||||
method: 'post',
|
export function editTeam (data) { return request({ url: BASE + 'edit', method: 'put', data: params('edit', data) }) }
|
||||||
data: apiParams('create', data)
|
export function deleteTeam (data) { return request({ url: BASE + 'delete', method: 'delete', data: params('delete', data) }) }
|
||||||
})
|
export function getTeamImportTemplate (data) { return request({ url: BASE + 'get_import_template', method: 'post', responseType: 'blob', data: params('get_import_template', data) }) }
|
||||||
}
|
export function importTeamData (data) { return request({ url: BASE + 'data_import', method: 'post', data: params('data_import', data) }) }
|
||||||
|
export function exportTeamTask (data) { return request({ url: BASE + 'data_export_task', method: 'post', data: params('data_export_task', data) }) }
|
||||||
|
|
||||||
export function editTeamManagement (data) {
|
export function getTeamMemberList (data) { return request({ url: MEMBER_BASE + 'list', method: 'get', params: memberParams('list', data) }) }
|
||||||
return request({
|
export function deleteTeamMember (data) { return request({ url: MEMBER_BASE + 'delete', method: 'delete', data: memberParams('delete', data) }) }
|
||||||
url: BASE + 'edit',
|
|
||||||
method: 'put',
|
|
||||||
data: apiParams('edit', data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteTeamManagement (data) {
|
|
||||||
return request({
|
|
||||||
url: BASE + 'delete',
|
|
||||||
method: 'delete',
|
|
||||||
data: apiParams('delete', data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTeamManagementALL (data) {
|
|
||||||
return request({
|
|
||||||
url: BASE + 'all',
|
|
||||||
method: 'get',
|
|
||||||
params: apiParams('all', data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getImportTemplate (data) {
|
|
||||||
return request({
|
|
||||||
url: BASE + 'get_import_template',
|
|
||||||
method: 'post',
|
|
||||||
responseType: 'blob',
|
|
||||||
data: apiParams('get_import_template', data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function importTeamManagement (data) {
|
|
||||||
return request({
|
|
||||||
url: BASE + 'data_import',
|
|
||||||
method: 'post',
|
|
||||||
data: apiParams('data_import', data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function exportTeamManagementTask (data) {
|
|
||||||
return request({
|
|
||||||
url: BASE + 'data_export_task',
|
|
||||||
method: 'post',
|
|
||||||
data: apiParams('data_export_task', data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
43
src/api/system-administration/monitoring-configuration.js
Normal file
43
src/api/system-administration/monitoring-configuration.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'system_settings/system_monitor/setting/'
|
||||||
|
|
||||||
|
function apiParams (method, data = {}) {
|
||||||
|
return {
|
||||||
|
method: `system_settings_system_monitoring_setting_${method}`,
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMonitoringConfigurationList (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'list',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('list', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createMonitoringConfiguration (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'create',
|
||||||
|
method: 'post',
|
||||||
|
data: apiParams('create', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function editMonitoringConfiguration (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'edit',
|
||||||
|
method: 'post',
|
||||||
|
data: apiParams('edit', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteMonitoringConfiguration (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'delete',
|
||||||
|
method: 'post',
|
||||||
|
data: apiParams('delete', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -356,6 +356,55 @@
|
|||||||
"please_enter": "Please enter {name}",
|
"please_enter": "Please enter {name}",
|
||||||
"help": "Material master data is used to maintain material code, name, specifications, etc."
|
"help": "Material master data is used to maintain material code, name, specifications, etc."
|
||||||
},
|
},
|
||||||
|
"bill_of_materials": {
|
||||||
|
"query": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"set_bom": "Set BOM",
|
||||||
|
"operation": "Operation",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"return": "Back",
|
||||||
|
"prompt": "Notice",
|
||||||
|
"operation_success": "Operation successful",
|
||||||
|
"confirm_message": "Are you sure you want to perform this operation?",
|
||||||
|
"bom_version_code": "BOM Version Code",
|
||||||
|
"bom_version_name": "BOM Version Name",
|
||||||
|
"product_model_name": "Product Model",
|
||||||
|
"status": "Status",
|
||||||
|
"enable": "Enabled",
|
||||||
|
"disable": "Disabled",
|
||||||
|
"select_status": "Please select status",
|
||||||
|
"create_user": "Created By",
|
||||||
|
"create_time": "Created At",
|
||||||
|
"remark": "Remark",
|
||||||
|
"enter_remark": "Please enter remark",
|
||||||
|
"enter_bom_version_code": "Please enter BOM version code",
|
||||||
|
"enter_bom_version_name": "Please enter BOM version name",
|
||||||
|
"select_product_model_name": "Please select product model",
|
||||||
|
"enter_bom_code": "Please enter BOM code",
|
||||||
|
"enter_bom_name": "Please enter BOM name",
|
||||||
|
"select_product_model": "Please select product model",
|
||||||
|
"length_1_45": "Length must be 1-45 characters",
|
||||||
|
"add_bom_info": "Add BOM",
|
||||||
|
"edit_bom_info": "Edit BOM",
|
||||||
|
"bom_management": "BOM Management",
|
||||||
|
"material_category": "Material Category",
|
||||||
|
"material_code": "Material Code",
|
||||||
|
"material_name": "Material Name",
|
||||||
|
"input_quantity": "Input Quantity",
|
||||||
|
"enter_input_quantity": "Please enter input quantity",
|
||||||
|
"unit": "Unit",
|
||||||
|
"select_add_material": "Select Material",
|
||||||
|
"all": "All",
|
||||||
|
"selected": "Selected",
|
||||||
|
"search_by_code_or_name": "Search by code or name",
|
||||||
|
"duplicate_material_selected": "Selected materials cannot be selected again",
|
||||||
|
"out_only_one": "OUT structure allows only one semi-finished item",
|
||||||
|
"please_select_data": "Please select data first"
|
||||||
|
},
|
||||||
"material_unit": {
|
"material_unit": {
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
@@ -438,6 +487,156 @@
|
|||||||
"help": "Error/NG management is used to maintain equipment error types and product NG types"
|
"help": "Error/NG management is used to maintain equipment error types and product NG types"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"team_model": {
|
||||||
|
"team_management": {
|
||||||
|
"search": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"batch_delete": "Batch Delete",
|
||||||
|
"import": "Import",
|
||||||
|
"export": "Export",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"prompt": "Notice",
|
||||||
|
"operation": "Operation",
|
||||||
|
"team_name": "Team Name",
|
||||||
|
"enter_team_name": "Please enter team name",
|
||||||
|
"area": "Area",
|
||||||
|
"select_area": "Please select area",
|
||||||
|
"production_line": "Production Line",
|
||||||
|
"select_area_then_line": "Select area before line",
|
||||||
|
"last_create_time": "Create Time",
|
||||||
|
"select_create_time": "Please select create time",
|
||||||
|
"start_time": "Start Time",
|
||||||
|
"end_time": "End Time",
|
||||||
|
"serial_number": "No.",
|
||||||
|
"affiliated_factory": "Factory Area",
|
||||||
|
"affiliated_production_line": "Production Line",
|
||||||
|
"create_time": "Created At",
|
||||||
|
"update_time": "Updated At",
|
||||||
|
"add_team": "Add Team",
|
||||||
|
"edit_team": "Edit Team",
|
||||||
|
"please_select": "Please select",
|
||||||
|
"please_select_factory_then_line": "Select factory before line",
|
||||||
|
"select_affiliated_factory": "Please select factory",
|
||||||
|
"select_affiliated_production_line": "Please select production line",
|
||||||
|
"please_enter_team_name": "Please enter team name",
|
||||||
|
"please_select_affiliated_factory": "Please select factory",
|
||||||
|
"please_select_affiliated_production_line": "Please select production line",
|
||||||
|
"length_2_to_20_characters": "Length must be 2-20 characters",
|
||||||
|
"add_member": "Add Member",
|
||||||
|
"member_name": "Member Name",
|
||||||
|
"is_team_leader": "Team Leader",
|
||||||
|
"yes": "Yes",
|
||||||
|
"no": "No",
|
||||||
|
"only_one_team_leader_allowed": "Only one team leader is allowed",
|
||||||
|
"operation_successful": "Operation successful",
|
||||||
|
"delete_team_confirm_message": "Are you sure to delete this team?",
|
||||||
|
"batch_delete_confirm_message": "Are you sure to delete selected teams?",
|
||||||
|
"please_select_table_data": "Please select table data first",
|
||||||
|
"export_confirm_message": "Export current query result?",
|
||||||
|
"download_task_created": "Download task created",
|
||||||
|
"operation_cancelled": "Operation cancelled",
|
||||||
|
"production_team_data_import": "Import Team Data",
|
||||||
|
"upload_file_alert_title": "Import using the template format",
|
||||||
|
"upload_file_alert_description": "Download the template before importing",
|
||||||
|
"production_team_data_import_table": "Team Import Table",
|
||||||
|
"select_file": "Select File",
|
||||||
|
"download_template": "Download Template",
|
||||||
|
"preview": "Preview",
|
||||||
|
"please_import_department_data": "Please import team data first",
|
||||||
|
"team_data_import_template": "Team Import Template",
|
||||||
|
"upload_format_error": "Please upload xls or xlsx file"
|
||||||
|
},
|
||||||
|
"shift_management": {
|
||||||
|
"search": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"batch_delete": "Batch Delete",
|
||||||
|
"import": "Import",
|
||||||
|
"export": "Export",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"prompt": "Notice",
|
||||||
|
"operation": "Operation",
|
||||||
|
"shift_plan_name": "Shift Plan Name",
|
||||||
|
"shift_plan_code": "Shift Plan Code",
|
||||||
|
"enter_shift_plan_name": "Please enter shift plan name",
|
||||||
|
"enter_shift_plan_code": "Please enter shift plan code",
|
||||||
|
"last_create_time": "Create Time",
|
||||||
|
"serial_number": "No.",
|
||||||
|
"start_time": "Start Time",
|
||||||
|
"end_time": "End Time",
|
||||||
|
"start_date": "Start Date",
|
||||||
|
"end_date": "End Date",
|
||||||
|
"status": "Status",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"disabled": "Disabled",
|
||||||
|
"creator": "Creator",
|
||||||
|
"create_time": "Created At",
|
||||||
|
"update_time": "Updated At",
|
||||||
|
"add_shift_plan": "Add Shift Plan",
|
||||||
|
"edit_shift_plan": "Edit Shift Plan",
|
||||||
|
"shift_name": "Shift Name",
|
||||||
|
"shift_code": "Shift Code",
|
||||||
|
"enter_shift_name": "Please enter shift name",
|
||||||
|
"enter_shift_code": "Please enter shift code",
|
||||||
|
"shift_time_range": "Shift Time Range",
|
||||||
|
"please_select_shift_time_range": "Please select shift time range",
|
||||||
|
"rotation_mode": "Rotation Mode",
|
||||||
|
"enter_content": "Please enter content",
|
||||||
|
"day": "Day",
|
||||||
|
"week": "Week",
|
||||||
|
"month": "Month",
|
||||||
|
"rest_day_setting": "Rest Days",
|
||||||
|
"monday": "Mon",
|
||||||
|
"tuesday": "Tue",
|
||||||
|
"wednesday": "Wed",
|
||||||
|
"thursday": "Thu",
|
||||||
|
"friday": "Fri",
|
||||||
|
"saturday": "Sat",
|
||||||
|
"sunday": "Sun",
|
||||||
|
"production_team": "Production Team",
|
||||||
|
"please_select": "Please select",
|
||||||
|
"remark": "Remark",
|
||||||
|
"enter_remark": "Please enter remark",
|
||||||
|
"add_shift": "Add Shift",
|
||||||
|
"shift_start_time": "Shift Start Time",
|
||||||
|
"shift_end_time": "Shift End Time",
|
||||||
|
"select_shift_start_time": "Please select shift start time",
|
||||||
|
"select_shift_end_time": "Please select shift end time",
|
||||||
|
"production_team_binding": "Team Binding",
|
||||||
|
"production_team_can_only_bind_one_shift": "One team can only bind one shift",
|
||||||
|
"please_enter_shift_plan_name": "Please enter shift plan name",
|
||||||
|
"please_enter_shift_plan_code": "Please enter shift plan code",
|
||||||
|
"please_enter_shift_name_row": "Please enter shift name, row: ",
|
||||||
|
"please_select_shift_start_time_row": "Please select shift start time, row: ",
|
||||||
|
"please_select_shift_end_time_row": "Please select shift end time, row: ",
|
||||||
|
"operation_successful": "Operation successful",
|
||||||
|
"delete_department_confirm_message": "Are you sure to delete this shift plan?",
|
||||||
|
"batch_delete_confirm_message": "Are you sure to delete selected shift plans?",
|
||||||
|
"please_select_table_data": "Please select table data first",
|
||||||
|
"export_confirm_message": "Export current query result?",
|
||||||
|
"download_task_created": "Download task created",
|
||||||
|
"shift_plan_data_import": "Import Shift Plan Data",
|
||||||
|
"upload_file_alert_title": "Import using the template format",
|
||||||
|
"upload_file_alert_description": "Download the template before importing",
|
||||||
|
"select_file": "Select File",
|
||||||
|
"download_template": "Download Template",
|
||||||
|
"please_import_department_data": "Please import shift plan data first",
|
||||||
|
"shift_plan_data_import_template": "Shift Plan Import Template",
|
||||||
|
"upload_format_error": "Please upload xls or xlsx file"
|
||||||
|
} ,
|
||||||
|
"scheduling_calendar": {
|
||||||
|
"rest": "Rest",
|
||||||
|
"cross_day": "Cross Day"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
"spc_configuration": {
|
"spc_configuration": {
|
||||||
"data_collection_configuration": {
|
"data_collection_configuration": {
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
@@ -2219,6 +2418,47 @@
|
|||||||
"please_select": "Please select"
|
"please_select": "Please select"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"system_monitoring": {
|
||||||
|
"monitoring_configuration": {
|
||||||
|
"search": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"prompt": "Notice",
|
||||||
|
"operation": "Operation",
|
||||||
|
"operation_success": "Operation successful",
|
||||||
|
"confirm_operation": "Are you sure you want to perform this operation?",
|
||||||
|
"serial_number": "No.",
|
||||||
|
"monitor_code": "Monitor Code",
|
||||||
|
"monitor_name": "Monitor Name",
|
||||||
|
"ip_address": "IP Address",
|
||||||
|
"port": "Port",
|
||||||
|
"python_version": "Python Version",
|
||||||
|
"refresh_interval": "Refresh Interval",
|
||||||
|
"cpu_warning": "CPU Warning",
|
||||||
|
"disk_warning": "Disk Warning",
|
||||||
|
"memory_swap_warning": "Memory/Swap Warning",
|
||||||
|
"enter_monitor_code": "Please enter monitor code",
|
||||||
|
"enter_monitor_name": "Please enter monitor name",
|
||||||
|
"enter_ip_address": "Please enter IP address",
|
||||||
|
"enter_port": "Please enter port",
|
||||||
|
"enter_refresh_interval": "Please enter refresh interval",
|
||||||
|
"enter_disk_warning": "Please enter disk warning",
|
||||||
|
"enter_cpu_warning": "Please enter CPU warning",
|
||||||
|
"enter_memory_swap_warning": "Please enter memory/swap warning",
|
||||||
|
"enter_python_version": "Please enter Python version",
|
||||||
|
"please_enter_monitor_code": "Please enter monitor code",
|
||||||
|
"please_enter_monitor_name": "Please enter monitor name",
|
||||||
|
"please_enter_ip_address": "Please enter IP address",
|
||||||
|
"please_enter_port": "Please enter port",
|
||||||
|
"length_1_to_100": "Length must be 1-100 characters",
|
||||||
|
"add_monitor_config": "Add Monitoring Configuration",
|
||||||
|
"edit_monitor_config": "Edit Monitoring Configuration"
|
||||||
|
}
|
||||||
|
},
|
||||||
"system_utilities": {
|
"system_utilities": {
|
||||||
"api_logs": {
|
"api_logs": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
|||||||
@@ -356,6 +356,55 @@
|
|||||||
"please_enter": "请输入{name}",
|
"please_enter": "请输入{name}",
|
||||||
"help": "物料信息用于维护物料编码、名称、规格等属性"
|
"help": "物料信息用于维护物料编码、名称、规格等属性"
|
||||||
},
|
},
|
||||||
|
"bill_of_materials": {
|
||||||
|
"query": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"add": "新增",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"set_bom": "设置BOM",
|
||||||
|
"operation": "操作",
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"return": "返回",
|
||||||
|
"prompt": "提示",
|
||||||
|
"operation_success": "操作成功",
|
||||||
|
"confirm_message": "确定要执行该操作吗?",
|
||||||
|
"bom_version_code": "BOM版本编码",
|
||||||
|
"bom_version_name": "BOM版本名称",
|
||||||
|
"product_model_name": "型号名称",
|
||||||
|
"status": "状态",
|
||||||
|
"enable": "启用",
|
||||||
|
"disable": "禁用",
|
||||||
|
"select_status": "请选择状态",
|
||||||
|
"create_user": "创建人",
|
||||||
|
"create_time": "创建时间",
|
||||||
|
"remark": "备注",
|
||||||
|
"enter_remark": "请输入备注",
|
||||||
|
"enter_bom_version_code": "请输入BOM版本编码",
|
||||||
|
"enter_bom_version_name": "请输入BOM版本名称",
|
||||||
|
"select_product_model_name": "请选择型号名称",
|
||||||
|
"enter_bom_code": "请输入BOM编码",
|
||||||
|
"enter_bom_name": "请输入BOM名称",
|
||||||
|
"select_product_model": "请选择产品型号",
|
||||||
|
"length_1_45": "长度在 1 到 45 个字符",
|
||||||
|
"add_bom_info": "新增BOM信息",
|
||||||
|
"edit_bom_info": "编辑BOM信息",
|
||||||
|
"bom_management": "BOM管理",
|
||||||
|
"material_category": "物料类别",
|
||||||
|
"material_code": "物料编码",
|
||||||
|
"material_name": "物料名称",
|
||||||
|
"input_quantity": "投入数量",
|
||||||
|
"enter_input_quantity": "请输入投入数量",
|
||||||
|
"unit": "单位",
|
||||||
|
"select_add_material": "选择添加物料",
|
||||||
|
"all": "全部",
|
||||||
|
"selected": "已选",
|
||||||
|
"search_by_code_or_name": "按编码或名称搜索",
|
||||||
|
"duplicate_material_selected": "已选择物料请勿重复选择",
|
||||||
|
"out_only_one": "OUT结构只允许存在1个半成品,请勿选择1个以上半成品",
|
||||||
|
"please_select_data": "请先选择数据"
|
||||||
|
},
|
||||||
"material_unit": {
|
"material_unit": {
|
||||||
"search": "查询",
|
"search": "查询",
|
||||||
"reset": "重置",
|
"reset": "重置",
|
||||||
@@ -438,6 +487,156 @@
|
|||||||
"help": "异常不良管理用于维护设备的异常种类和产品的不良种类信息"
|
"help": "异常不良管理用于维护设备的异常种类和产品的不良种类信息"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"team_model": {
|
||||||
|
"team_management": {
|
||||||
|
"search": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"add": "新增",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"batch_delete": "批量删除",
|
||||||
|
"import": "导入",
|
||||||
|
"export": "导出",
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"prompt": "提示",
|
||||||
|
"operation": "操作",
|
||||||
|
"team_name": "班组名称",
|
||||||
|
"enter_team_name": "请输入班组名称",
|
||||||
|
"area": "厂区",
|
||||||
|
"select_area": "请选择厂区",
|
||||||
|
"production_line": "产线",
|
||||||
|
"select_area_then_line": "请先选择厂区再选择产线",
|
||||||
|
"last_create_time": "创建时间",
|
||||||
|
"select_create_time": "请选择创建时间",
|
||||||
|
"start_time": "开始时间",
|
||||||
|
"end_time": "结束时间",
|
||||||
|
"serial_number": "序号",
|
||||||
|
"affiliated_factory": "所属厂区",
|
||||||
|
"affiliated_production_line": "所属产线",
|
||||||
|
"create_time": "创建时间",
|
||||||
|
"update_time": "更新时间",
|
||||||
|
"add_team": "新增班组",
|
||||||
|
"edit_team": "编辑班组",
|
||||||
|
"please_select": "请选择",
|
||||||
|
"please_select_factory_then_line": "请先选择厂区再选择产线",
|
||||||
|
"select_affiliated_factory": "请选择所属厂区",
|
||||||
|
"select_affiliated_production_line": "请选择所属产线",
|
||||||
|
"please_enter_team_name": "请输入班组名称",
|
||||||
|
"please_select_affiliated_factory": "请选择所属厂区",
|
||||||
|
"please_select_affiliated_production_line": "请选择所属产线",
|
||||||
|
"length_2_to_20_characters": "长度在 2 到 20 个字符",
|
||||||
|
"add_member": "添加成员",
|
||||||
|
"member_name": "成员名称",
|
||||||
|
"is_team_leader": "是否班组长",
|
||||||
|
"yes": "是",
|
||||||
|
"no": "否",
|
||||||
|
"only_one_team_leader_allowed": "只允许设置一个班组长",
|
||||||
|
"operation_successful": "操作成功",
|
||||||
|
"delete_team_confirm_message": "确定要删除该班组吗?",
|
||||||
|
"batch_delete_confirm_message": "确定要删除所选班组吗?",
|
||||||
|
"please_select_table_data": "请先选择表格数据",
|
||||||
|
"export_confirm_message": "确定要导出当前查询结果吗?",
|
||||||
|
"download_task_created": "下载任务创建成功",
|
||||||
|
"operation_cancelled": "操作已取消",
|
||||||
|
"production_team_data_import": "班组数据导入",
|
||||||
|
"upload_file_alert_title": "请按模板格式导入文件",
|
||||||
|
"upload_file_alert_description": "导入前请先下载模板并按模板字段填写",
|
||||||
|
"production_team_data_import_table": "班组数据导入表",
|
||||||
|
"select_file": "选择文件",
|
||||||
|
"download_template": "下载模板",
|
||||||
|
"preview": "预览",
|
||||||
|
"please_import_department_data": "请先导入班组数据",
|
||||||
|
"team_data_import_template": "班组数据导入模板",
|
||||||
|
"upload_format_error": "请上传 xls 或 xlsx 文件"
|
||||||
|
},
|
||||||
|
"shift_management": {
|
||||||
|
"search": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"add": "新增",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"batch_delete": "批量删除",
|
||||||
|
"import": "导入",
|
||||||
|
"export": "导出",
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"prompt": "提示",
|
||||||
|
"operation": "操作",
|
||||||
|
"shift_plan_name": "班次计划名称",
|
||||||
|
"shift_plan_code": "班次计划编码",
|
||||||
|
"enter_shift_plan_name": "请输入班次计划名称",
|
||||||
|
"enter_shift_plan_code": "请输入班次计划编码",
|
||||||
|
"last_create_time": "创建时间",
|
||||||
|
"serial_number": "序号",
|
||||||
|
"start_time": "开始时间",
|
||||||
|
"end_time": "结束时间",
|
||||||
|
"start_date": "开始日期",
|
||||||
|
"end_date": "结束日期",
|
||||||
|
"status": "状态",
|
||||||
|
"enabled": "启用",
|
||||||
|
"disabled": "禁用",
|
||||||
|
"creator": "创建人",
|
||||||
|
"create_time": "创建时间",
|
||||||
|
"update_time": "更新时间",
|
||||||
|
"add_shift_plan": "新增班次计划",
|
||||||
|
"edit_shift_plan": "编辑班次计划",
|
||||||
|
"shift_name": "班次名称",
|
||||||
|
"shift_code": "班次编码",
|
||||||
|
"enter_shift_name": "请输入班次名称",
|
||||||
|
"enter_shift_code": "请输入班次编码",
|
||||||
|
"shift_time_range": "班次计划时间范围",
|
||||||
|
"please_select_shift_time_range": "请选择班次时间范围",
|
||||||
|
"rotation_mode": "轮转模式",
|
||||||
|
"enter_content": "请输入内容",
|
||||||
|
"day": "天",
|
||||||
|
"week": "周",
|
||||||
|
"month": "月",
|
||||||
|
"rest_day_setting": "休息日设置",
|
||||||
|
"monday": "周一",
|
||||||
|
"tuesday": "周二",
|
||||||
|
"wednesday": "周三",
|
||||||
|
"thursday": "周四",
|
||||||
|
"friday": "周五",
|
||||||
|
"saturday": "周六",
|
||||||
|
"sunday": "周日",
|
||||||
|
"production_team": "生产班组",
|
||||||
|
"please_select": "请选择",
|
||||||
|
"remark": "备注",
|
||||||
|
"enter_remark": "请输入备注",
|
||||||
|
"add_shift": "添加班次",
|
||||||
|
"shift_start_time": "班次开始时间",
|
||||||
|
"shift_end_time": "班次结束时间",
|
||||||
|
"select_shift_start_time": "请选择班次开始时间",
|
||||||
|
"select_shift_end_time": "请选择班次结束时间",
|
||||||
|
"production_team_binding": "生产班组绑定",
|
||||||
|
"production_team_can_only_bind_one_shift": "一个生产班组只能绑定一个班次",
|
||||||
|
"please_enter_shift_plan_name": "请输入班次计划名称",
|
||||||
|
"please_enter_shift_plan_code": "请输入班次计划编码",
|
||||||
|
"please_enter_shift_name_row": "请输入班次名称,行号:",
|
||||||
|
"please_select_shift_start_time_row": "请选择班次开始时间,行号:",
|
||||||
|
"please_select_shift_end_time_row": "请选择班次结束时间,行号:",
|
||||||
|
"operation_successful": "操作成功",
|
||||||
|
"delete_department_confirm_message": "确定要删除该班次计划吗?",
|
||||||
|
"batch_delete_confirm_message": "确定要删除所选班次计划吗?",
|
||||||
|
"please_select_table_data": "请先选择表格数据",
|
||||||
|
"export_confirm_message": "确定要导出当前查询结果吗?",
|
||||||
|
"download_task_created": "下载任务创建成功",
|
||||||
|
"shift_plan_data_import": "班次计划数据导入",
|
||||||
|
"upload_file_alert_title": "请按模板格式导入文件",
|
||||||
|
"upload_file_alert_description": "导入前请先下载模板并按模板字段填写",
|
||||||
|
"select_file": "选择文件",
|
||||||
|
"download_template": "下载模板",
|
||||||
|
"please_import_department_data": "请先导入班次计划数据",
|
||||||
|
"shift_plan_data_import_template": "班次计划数据导入模板",
|
||||||
|
"upload_format_error": "请上传 xls 或 xlsx 文件"
|
||||||
|
} ,
|
||||||
|
"scheduling_calendar": {
|
||||||
|
"rest": "休",
|
||||||
|
"cross_day": "跨天"
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
"spc_configuration": {
|
"spc_configuration": {
|
||||||
"data_collection_configuration": {
|
"data_collection_configuration": {
|
||||||
"search": "查询",
|
"search": "查询",
|
||||||
@@ -2219,6 +2418,47 @@
|
|||||||
"please_select": "请选择"
|
"please_select": "请选择"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"system_monitoring": {
|
||||||
|
"monitoring_configuration": {
|
||||||
|
"search": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"add": "新增",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"prompt": "提示",
|
||||||
|
"operation": "操作",
|
||||||
|
"operation_success": "操作成功",
|
||||||
|
"confirm_operation": "确定要执行该操作吗?",
|
||||||
|
"serial_number": "序号",
|
||||||
|
"monitor_code": "监控编码",
|
||||||
|
"monitor_name": "监控名称",
|
||||||
|
"ip_address": "IP地址",
|
||||||
|
"port": "端口",
|
||||||
|
"python_version": "Python版本",
|
||||||
|
"refresh_interval": "刷新间隔",
|
||||||
|
"cpu_warning": "CPU预警值",
|
||||||
|
"disk_warning": "磁盘预警值",
|
||||||
|
"memory_swap_warning": "内存/交换区预警值",
|
||||||
|
"enter_monitor_code": "请输入监控编码",
|
||||||
|
"enter_monitor_name": "请输入监控名称",
|
||||||
|
"enter_ip_address": "请输入IP地址",
|
||||||
|
"enter_port": "请输入端口",
|
||||||
|
"enter_refresh_interval": "请输入刷新间隔",
|
||||||
|
"enter_disk_warning": "请输入磁盘预警值",
|
||||||
|
"enter_cpu_warning": "请输入CPU预警值",
|
||||||
|
"enter_memory_swap_warning": "请输入内存/交换区预警值",
|
||||||
|
"enter_python_version": "请输入Python版本",
|
||||||
|
"please_enter_monitor_code": "请输入监控编码",
|
||||||
|
"please_enter_monitor_name": "请输入监控名称",
|
||||||
|
"please_enter_ip_address": "请输入IP地址",
|
||||||
|
"please_enter_port": "请输入端口",
|
||||||
|
"length_1_to_100": "长度在 1 到 100 个字符",
|
||||||
|
"add_monitor_config": "新增监控配置",
|
||||||
|
"edit_monitor_config": "编辑监控配置"
|
||||||
|
}
|
||||||
|
},
|
||||||
"system_utilities": {
|
"system_utilities": {
|
||||||
"api_logs": {
|
"api_logs": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ export default {
|
|||||||
meta: { ...meta, cache: true, title: '物料信息管理' },
|
meta: { ...meta, cache: true, title: '物料信息管理' },
|
||||||
component: _import('production-master-data/material-model/material-master')
|
component: _import('production-master-data/material-model/material-master')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'matetial_model/bom',
|
||||||
|
name: `${pre}material_model-bill_of_materials`,
|
||||||
|
meta: { ...meta, cache: true, title: 'BOM物料清单' },
|
||||||
|
component: _import('production-master-data/material-model/bill-of-materials')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'matetial_model/unit',
|
path: 'matetial_model/unit',
|
||||||
name: `${pre}material_model-material_unit`,
|
name: `${pre}material_model-material_unit`,
|
||||||
|
|||||||
@@ -49,6 +49,30 @@ export default {
|
|||||||
name: `${pre}system_assistant-problem_help`,
|
name: `${pre}system_assistant-problem_help`,
|
||||||
meta: { ...meta, cache: true, title: '问题帮助' },
|
meta: { ...meta, cache: true, title: '问题帮助' },
|
||||||
component: _import('system-administration/system-utilities/problem-help')
|
component: _import('system-administration/system-utilities/problem-help')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'system_monitoring/setting',
|
||||||
|
name: `${pre}system_monitoring-setting`,
|
||||||
|
meta: { ...meta, cache: true, title: '监控设置' },
|
||||||
|
component: _import('system-administration/system-monitoring/monitoring-configuration')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'organization/production_team_manage',
|
||||||
|
name: `${pre}organization-production_team_manage`,
|
||||||
|
meta: { ...meta, cache: true, title: '班组管理' },
|
||||||
|
component: _import('production-master-data/team-model/team-management')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'organization/production_shift_management',
|
||||||
|
name: `${pre}organization-production_shift_management`,
|
||||||
|
meta: { ...meta, cache: true, title: '班次管理' },
|
||||||
|
component: _import('production-master-data/team-model/shift-management')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'organization/production_shift_calender',
|
||||||
|
name: `${pre}organization-production_shift_calender`,
|
||||||
|
meta: { ...meta, cache: true, title: '排班日历' },
|
||||||
|
component: _import('production-master-data/team-model/scheduling-calendar')
|
||||||
}
|
}
|
||||||
])('system_settings-')
|
])('system_settings-')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :visible.sync="visibleProxy" append-to-body :close-on-click-modal="false" fullscreen :show-close="false" @open="bootstrap">
|
||||||
|
<template #title>
|
||||||
|
<div class="dialog-title">
|
||||||
|
<span>{{ relationshipTitle }}</span>
|
||||||
|
<el-button size="small" @click="handleClose">{{ $t(key('return')) }}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-row class="relationship-layout">
|
||||||
|
<el-col :span="4" class="step-panel">
|
||||||
|
<el-menu :default-active="activeStep" @select="handleStepSelect">
|
||||||
|
<el-menu-item v-for="item in stepOptions" :key="item.code" :index="item.code">
|
||||||
|
<span slot="title">{{ item.name }}</span>
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="20" class="relation-panel">
|
||||||
|
<el-card shadow="never" class="relation-card relation-card-in">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<span>IN</span>
|
||||||
|
<div>
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteSelected('in')">{{ $t(key('delete')) }}</el-button>
|
||||||
|
<el-button size="mini" type="success" icon="el-icon-plus" @click="openMaterialDialog('in')">{{ $t(key('add')) }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-table ref="inTable" :data="inData" border height="360" v-loading="loading" @selection-change="inSelection = $event">
|
||||||
|
<el-table-column type="selection" width="48" />
|
||||||
|
<el-table-column prop="bom_source_category_name" :label="$t(key('material_category'))" width="120" />
|
||||||
|
<el-table-column prop="bom_source_code" :label="$t(key('material_code'))" min-width="180" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="bom_source_name" :label="$t(key('material_name'))" min-width="180" show-overflow-tooltip />
|
||||||
|
<el-table-column :label="$t(key('input_quantity'))" width="180">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<el-input v-model="row.input_quantity" size="mini" @blur="saveQuantity(row)" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="unit_name" :label="$t(key('unit'))" width="100" />
|
||||||
|
<el-table-column :label="$t(key('operation'))" width="100">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<el-button type="text" size="mini" style="color:#F56C6C" @click="deleteRows([row])">{{ $t(key('delete')) }}</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never" class="relation-card">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<span>OUT</span>
|
||||||
|
<div>
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-delete" @click="deleteSelected('out')">{{ $t(key('delete')) }}</el-button>
|
||||||
|
<el-button size="mini" type="success" icon="el-icon-plus" @click="openMaterialDialog('out')">{{ $t(key('add')) }}</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-table ref="outTable" :data="outData" border height="250" v-loading="loading" @selection-change="outSelection = $event">
|
||||||
|
<el-table-column type="selection" width="48" />
|
||||||
|
<el-table-column prop="bom_source_category_name" :label="$t(key('material_category'))" width="120" />
|
||||||
|
<el-table-column prop="bom_source_code" :label="$t(key('material_code'))" min-width="180" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="bom_source_name" :label="$t(key('material_name'))" min-width="180" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="unit_name" :label="$t(key('unit'))" width="140" />
|
||||||
|
<el-table-column :label="$t(key('operation'))" width="100">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<el-button type="text" size="mini" style="color:#F56C6C" @click="deleteRows([row])">{{ $t(key('delete')) }}</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-dialog :title="$t(key('select_add_material'))" :visible.sync="materialVisible" append-to-body width="820px" :close-on-click-modal="false" @open="loadMaterials(true)">
|
||||||
|
<el-form :inline="true" size="mini" @submit.native.prevent>
|
||||||
|
<el-form-item>
|
||||||
|
<el-radio-group v-model="materialOnlySelected" @change="loadMaterials(true)">
|
||||||
|
<el-radio-button :label="false">{{ $t(key('all')) }}</el-radio-button>
|
||||||
|
<el-radio-button :label="true">{{ $t(key('selected')) }}</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button @click="changeMaterialCategory('')">{{ $t(key('all')) }}</el-button>
|
||||||
|
<el-button v-for="item in materialCategories" :key="item.id" @click="changeMaterialCategory(item.id)">{{ item.name }}</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-input v-model.trim="materialSearch.all" :placeholder="$t(key('search_by_code_or_name'))" clearable style="width:220px" @keyup.enter.native="loadMaterials(true)">
|
||||||
|
<el-button slot="append" icon="el-icon-search" @click="loadMaterials(true)" />
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-table ref="materialTable" :data="materialData" border height="380" row-key="id" @selection-change="materialSelection = $event">
|
||||||
|
<el-table-column type="selection" reserve-selection width="50" />
|
||||||
|
<el-table-column prop="bom_source_category_name" :label="$t(key('material_category'))" width="130" />
|
||||||
|
<el-table-column prop="code" :label="$t(key('material_code'))" min-width="150" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="name" :label="$t(key('material_name'))" min-width="150" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="remark" :label="$t(key('remark'))" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
<el-pagination class="material-pagination" :current-page="materialPagination.current" :page-size="materialPagination.size" :total="materialPagination.total" layout="total, prev, pager, next" @current-change="onMaterialPageChange" />
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button size="small" @click="materialVisible = false">{{ $t(key('cancel')) }}</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="confirmMaterialSelection">{{ $t(key('confirm')) }}</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import { getWorkingsubclassAll } from '@/api/production-master-data/process-step'
|
||||||
|
import { getMaterialCategoryAll } from '@/api/production-master-data/material-category'
|
||||||
|
import { getMaterialMasterList } from '@/api/production-master-data/material-master'
|
||||||
|
import { getBomRelationshipList, createBomRelationship, editBomRelationship, deleteBomRelationship } from '@/api/production-master-data/bill-of-materials'
|
||||||
|
|
||||||
|
function readPageData (res) {
|
||||||
|
const data = res && res.data ? res.data : res
|
||||||
|
if (!data) return { list: [], total: 0 }
|
||||||
|
if (Array.isArray(data)) return { list: data, total: data.length }
|
||||||
|
return { list: data.data || data.list || [], total: Number(data.count || data.total || 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BomRelationship',
|
||||||
|
mixins: [i18nMixin('page.production_master_data.material_model.bill_of_materials')],
|
||||||
|
props: {
|
||||||
|
visible: { type: Boolean, default: false },
|
||||||
|
bom: { type: Object, default: () => ({}) }
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
stepOptions: [],
|
||||||
|
materialCategories: [],
|
||||||
|
activeStep: '',
|
||||||
|
inData: [],
|
||||||
|
outData: [],
|
||||||
|
inSelection: [],
|
||||||
|
outSelection: [],
|
||||||
|
materialVisible: false,
|
||||||
|
materialDirection: 'in',
|
||||||
|
materialCategoryId: '',
|
||||||
|
materialOnlySelected: false,
|
||||||
|
materialSearch: { all: '' },
|
||||||
|
materialData: [],
|
||||||
|
materialSelection: [],
|
||||||
|
materialPagination: { current: 1, size: 10, total: 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visibleProxy: {
|
||||||
|
get () { return this.visible },
|
||||||
|
set (val) { this.$emit('update:visible', val) }
|
||||||
|
},
|
||||||
|
relationshipTitle () {
|
||||||
|
return this.bom && this.bom.name ? `【${this.bom.name}】${this.$t(this.key('bom_management'))}` : this.$t(this.key('bom_management'))
|
||||||
|
},
|
||||||
|
currentCheckList () {
|
||||||
|
return this.materialDirection === 'in' ? this.inData : this.outData
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async bootstrap () {
|
||||||
|
this.inData = []
|
||||||
|
this.outData = []
|
||||||
|
this.stepOptions = []
|
||||||
|
const [steps, categories] = await Promise.all([getWorkingsubclassAll({}), getMaterialCategoryAll({})])
|
||||||
|
this.stepOptions = (steps && steps.data) || steps || []
|
||||||
|
this.materialCategories = (categories && categories.data) || categories || []
|
||||||
|
this.activeStep = this.stepOptions.length ? this.stepOptions[0].code : ''
|
||||||
|
if (this.activeStep) this.loadRelationship()
|
||||||
|
},
|
||||||
|
handleClose () {
|
||||||
|
this.visibleProxy = false
|
||||||
|
this.$emit('saved')
|
||||||
|
},
|
||||||
|
handleStepSelect (key) {
|
||||||
|
this.activeStep = key
|
||||||
|
this.loadRelationship()
|
||||||
|
},
|
||||||
|
async loadRelationship () {
|
||||||
|
if (!this.bom.id || !this.activeStep) return
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await getBomRelationshipList({ product_bom_id: this.bom.id, workingsubclass_in: this.activeStep, workingsubclass_out: this.activeStep })
|
||||||
|
const data = (res && res.data) || res || {}
|
||||||
|
this.inData = data.in || []
|
||||||
|
this.outData = data.out || []
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openMaterialDialog (direction) {
|
||||||
|
this.materialDirection = direction
|
||||||
|
this.materialOnlySelected = false
|
||||||
|
this.materialCategoryId = ''
|
||||||
|
this.materialSearch = { all: '' }
|
||||||
|
this.materialPagination.current = 1
|
||||||
|
this.materialVisible = true
|
||||||
|
},
|
||||||
|
changeMaterialCategory (categoryId) {
|
||||||
|
this.materialCategoryId = categoryId
|
||||||
|
this.loadMaterials(true)
|
||||||
|
},
|
||||||
|
async loadMaterials (resetPage = false) {
|
||||||
|
if (resetPage) this.materialPagination.current = 1
|
||||||
|
this.$nextTick(() => this.$refs.materialTable && this.$refs.materialTable.clearSelection())
|
||||||
|
const idList = this.currentCheckList.map(item => item.bom_source_id).filter(Boolean)
|
||||||
|
if (this.materialOnlySelected && this.materialSelection.length === 0) {
|
||||||
|
this.materialData = []
|
||||||
|
this.materialPagination.total = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const selectedId = this.materialOnlySelected ? this.materialSelection.map(item => item.id) : undefined
|
||||||
|
const res = await getMaterialMasterList({
|
||||||
|
bom_source_category_id: this.materialCategoryId,
|
||||||
|
idList,
|
||||||
|
selected_id: selectedId,
|
||||||
|
all: this.materialSearch.all,
|
||||||
|
page_no: this.materialPagination.current,
|
||||||
|
page_size: this.materialPagination.size
|
||||||
|
})
|
||||||
|
const { list, total } = readPageData(res)
|
||||||
|
this.materialData = list
|
||||||
|
this.materialPagination.total = total
|
||||||
|
},
|
||||||
|
onMaterialPageChange (page) {
|
||||||
|
this.materialPagination.current = page
|
||||||
|
this.loadMaterials(false)
|
||||||
|
},
|
||||||
|
async confirmMaterialSelection () {
|
||||||
|
const relationData = this.materialSelection.map(item => ({ bom_source_id: item.id }))
|
||||||
|
if (this.materialDirection === 'in') {
|
||||||
|
const duplicates = relationData.filter(next => this.inData.some(old => old.bom_source_id === next.bom_source_id))
|
||||||
|
if (duplicates.length) {
|
||||||
|
this.$message.warning(this.$t(this.key('duplicate_material_selected')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if (this.outData.length !== 0 || relationData.length > 1) {
|
||||||
|
this.$message.warning(this.$t(this.key('out_only_one')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await createBomRelationship({
|
||||||
|
bom_id: this.bom.id,
|
||||||
|
type: this.materialDirection === 'in' ? 'in_workingsubclass' : 'out_workingsubclass',
|
||||||
|
workingsubclass: this.activeStep,
|
||||||
|
relation_data: relationData
|
||||||
|
})
|
||||||
|
this.materialVisible = false
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.loadRelationship()
|
||||||
|
},
|
||||||
|
async saveQuantity (row) {
|
||||||
|
await editBomRelationship(row)
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.loadRelationship()
|
||||||
|
},
|
||||||
|
deleteSelected (direction) {
|
||||||
|
const rows = direction === 'in' ? this.inSelection : this.outSelection
|
||||||
|
if (!rows.length) {
|
||||||
|
this.$message.warning(this.$t(this.key('please_select_data')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.deleteRows(rows)
|
||||||
|
},
|
||||||
|
async deleteRows (rows) {
|
||||||
|
await deleteBomRelationship({ id: rows.map(item => item.id) })
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.loadRelationship()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dialog-title { display: flex; justify-content: space-between; align-items: center; padding: 0 20px; }
|
||||||
|
.relationship-layout { border-top: 1px solid #dcdfe6; }
|
||||||
|
.step-panel { height: calc(100vh - 100px); overflow: auto; border-right: 1px solid #ebeef5; }
|
||||||
|
.relation-panel { height: calc(100vh - 100px); overflow: auto; padding: 16px; }
|
||||||
|
.relation-card { margin-bottom: 12px; }
|
||||||
|
.relation-card-in { min-height: 430px; }
|
||||||
|
.card-header { display: flex; align-items: center; justify-content: space-between; }
|
||||||
|
.material-pagination { margin-top: 12px; text-align: right; }
|
||||||
|
/deep/ .el-dialog__body { padding: 0; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<template #header>
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" size="mini">
|
||||||
|
<el-form-item :label="$t(key('bom_version_code'))">
|
||||||
|
<el-input v-model.trim="search.code" :placeholder="$t(key('enter_bom_version_code'))" clearable style="width:220px" @keyup.enter.native="onSearch" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('bom_version_name'))">
|
||||||
|
<el-input v-model.trim="search.name" :placeholder="$t(key('enter_bom_version_name'))" clearable style="width:220px" @keyup.enter.native="onSearch" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('product_model_name'))">
|
||||||
|
<el-select v-model="search.product_model_id" :placeholder="$t(key('select_product_model_name'))" clearable filterable style="width:220px">
|
||||||
|
<el-option v-for="item in productOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" @click="onSearch">{{ $t(key('query')) }}</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" auto-height @page-change="onPageChange">
|
||||||
|
<template #col-status="{ row }">
|
||||||
|
<span v-if="String(row.status) === '1'" class="status-on"><i class="el-icon-circle-check" /> {{ $t(key('enable')) }}</span>
|
||||||
|
<span v-else class="status-off"><i class="el-icon-circle-close" /> {{ $t(key('disable')) }}</span>
|
||||||
|
</template>
|
||||||
|
<template #col-remark="{ row }">
|
||||||
|
<el-popover v-if="row.remark && row.remark.length > 20" placement="top-start" width="300" trigger="hover" :content="row.remark">
|
||||||
|
<span slot="reference" style="cursor:pointer">{{ row.remark.substr(0, 20) }}...</span>
|
||||||
|
</el-popover>
|
||||||
|
<span v-else>{{ row.remark }}</span>
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
|
||||||
|
<page-dialog-form ref="dialogForm" :visible.sync="dialogVisible" :title="dialogTitle" width="38%" :form-cols="dialogFormCols" :form-data="formData" :rules="rules" label-width="120px" :submitting="submitting" :confirm-text="key('confirm')" :cancel-text="key('cancel')" @submit="onDialogSubmit" @close="onDialogClose" />
|
||||||
|
|
||||||
|
<bom-relationship :visible.sync="relationshipVisible" :bom="currentBom" @saved="fetchData" />
|
||||||
|
</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 PageTable from '@/components/page-table'
|
||||||
|
import PageDialogForm from '@/components/page-dialog-form'
|
||||||
|
import BomRelationship from './components/BomRelationship'
|
||||||
|
import { getProductBatteryAll } from '@/api/production-master-data/product-management'
|
||||||
|
import { getBomList, createBom, editBom, deleteBom } from '@/api/production-master-data/bill-of-materials'
|
||||||
|
|
||||||
|
function readPageData (res) {
|
||||||
|
const data = res && res.data ? res.data : res
|
||||||
|
if (!data) return { list: [], total: 0 }
|
||||||
|
if (Array.isArray(data)) return { list: data, total: data.length }
|
||||||
|
return { list: data.data || data.list || [], total: Number(data.count || data.total || 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'production-master-data-bill-of-materials',
|
||||||
|
components: { PageTable, PageDialogForm, BomRelationship },
|
||||||
|
mixins: [i18nMixin('page.production_master_data.material_model.bill_of_materials'), confirmMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
submitting: false,
|
||||||
|
tableData: [],
|
||||||
|
productOptions: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '',
|
||||||
|
editId: '',
|
||||||
|
handleType: 'create',
|
||||||
|
relationshipVisible: false,
|
||||||
|
currentBom: {},
|
||||||
|
search: { code: '', name: '', product_model_id: '' },
|
||||||
|
pagination: { current: 1, size: 10, total: 0 },
|
||||||
|
formData: this.defaultFormData(),
|
||||||
|
rules: {
|
||||||
|
code: [
|
||||||
|
{ required: true, message: this.key('enter_bom_code'), trigger: 'blur' },
|
||||||
|
{ min: 1, max: 45, message: this.key('length_1_45'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
name: [
|
||||||
|
{ required: true, message: this.key('enter_bom_name'), trigger: 'blur' },
|
||||||
|
{ min: 1, max: 45, message: this.key('length_1_45'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
product_model_id: [{ required: true, message: this.key('select_product_model'), trigger: 'change' }]
|
||||||
|
},
|
||||||
|
columns: [],
|
||||||
|
toolbarButtons: [],
|
||||||
|
rowButtons: [],
|
||||||
|
baseFormCols: [
|
||||||
|
[{ type: 'input', prop: 'code', label: this.key('bom_version_code'), placeholder: this.key('enter_bom_version_code'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'name', label: this.key('bom_version_name'), placeholder: this.key('enter_bom_version_name'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'select', prop: 'product_model_id', label: this.key('product_model_name'), placeholder: this.key('select_product_model_name'), clearable: true, filterable: true, style: { width: '90%' }, options: [] }],
|
||||||
|
[{ type: 'select', prop: 'status', label: this.key('status'), placeholder: this.key('select_status'), clearable: true, style: { width: '90%' }, options: [{ label: this.$t(this.key('disable')), value: '0' }, { label: this.$t(this.key('enable')), value: '1' }] }],
|
||||||
|
[{ type: 'input', prop: 'remark', inputType: 'textarea', autosize: { minRows: 2, maxRows: 6 }, label: this.key('remark'), placeholder: this.key('enter_remark'), clearable: true, style: { width: '90%' } }]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dialogFormCols () {
|
||||||
|
return this.baseFormCols.map(row => row.map(item => {
|
||||||
|
if (item.prop === 'product_model_id') return { ...item, options: this.productOptions }
|
||||||
|
return item
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.loadProductOptions()
|
||||||
|
this.columns = useTableColumns([
|
||||||
|
{ prop: 'code', label: this.key('bom_version_code'), minWidth: 140 },
|
||||||
|
{ prop: 'name', label: this.key('bom_version_name'), minWidth: 160 },
|
||||||
|
{ prop: 'product_model_name', label: this.key('product_model_name'), minWidth: 160 },
|
||||||
|
{ prop: 'status', label: this.key('status'), slot: 'status', width: 110 },
|
||||||
|
{ prop: 'username', label: this.key('create_user'), minWidth: 100 },
|
||||||
|
{ prop: 'create_time', label: this.key('create_time'), minWidth: 160 },
|
||||||
|
{ prop: 'remark', label: this.key('remark'), slot: 'remark', minWidth: 160 },
|
||||||
|
{ prop: '_actions', label: this.key('operation'), width: 230, fixed: 'right' }
|
||||||
|
])
|
||||||
|
const btns = useTableButtons({
|
||||||
|
toolbar: [{ key: 'add', label: this.key('add'), icon: 'el-icon-plus', type: 'primary', auth: '/production_configuration/matetial_model/bom/create', onClick: this.openAdd }],
|
||||||
|
row: [
|
||||||
|
{ key: 'set_bom', label: this.key('set_bom'), icon: 'el-icon-setting', auth: '/production_configuration/matetial_model/bom/edit_bom_relationship', onClick: this.openRelationship },
|
||||||
|
{ key: 'edit', label: this.key('edit'), icon: 'el-icon-edit', auth: '/production_configuration/matetial_model/bom/edit', onClick: this.openEdit },
|
||||||
|
{ key: 'delete', label: this.key('delete'), icon: 'el-icon-delete', color: 'danger', auth: '/production_configuration/matetial_model/bom/delete', onClick: this.handleDelete }
|
||||||
|
]
|
||||||
|
}, this.$permission)
|
||||||
|
this.toolbarButtons = btns.toolbarButtons
|
||||||
|
this.rowButtons = btns.rowButtons
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
defaultFormData () {
|
||||||
|
return { code: '', name: '', product_model_id: '', status: '1', remark: '' }
|
||||||
|
},
|
||||||
|
async loadProductOptions () {
|
||||||
|
const res = await getProductBatteryAll({})
|
||||||
|
const list = (res && res.data) || res || []
|
||||||
|
this.productOptions = list.map(item => ({ label: item.name, value: item.product_model_id || item.id }))
|
||||||
|
},
|
||||||
|
async fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await getBomList({ ...this.search, page_no: this.pagination.current, page_size: this.pagination.size })
|
||||||
|
const { list, total } = readPageData(res)
|
||||||
|
this.tableData = list
|
||||||
|
this.pagination.total = total
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSearch () {
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onReset () {
|
||||||
|
this.search = { code: '', name: '', product_model_id: '' }
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onPageChange (page) {
|
||||||
|
this.pagination.current = page.current
|
||||||
|
this.pagination.size = page.size
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
resetForm () {
|
||||||
|
this.formData = this.defaultFormData()
|
||||||
|
this.editId = ''
|
||||||
|
},
|
||||||
|
openAdd () {
|
||||||
|
this.handleType = 'create'
|
||||||
|
this.dialogTitle = this.key('add_bom_info')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.dialogForm && this.$refs.dialogForm.reset()
|
||||||
|
this.resetForm()
|
||||||
|
this.dialogVisible = true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openEdit (row) {
|
||||||
|
this.handleType = 'edit'
|
||||||
|
this.dialogTitle = this.key('edit_bom_info')
|
||||||
|
this.editId = row.id
|
||||||
|
this.formData = { code: row.code, name: row.name, product_model_id: row.product_model_id, status: String(row.status), remark: row.remark || '' }
|
||||||
|
this.dialogVisible = true
|
||||||
|
},
|
||||||
|
openRelationship (row) {
|
||||||
|
this.currentBom = { id: row.id, name: row.name }
|
||||||
|
this.relationshipVisible = true
|
||||||
|
},
|
||||||
|
async onDialogSubmit () {
|
||||||
|
this.submitting = true
|
||||||
|
try {
|
||||||
|
if (this.handleType === 'create') await createBom(this.formData)
|
||||||
|
else await editBom({ ...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.resetForm()
|
||||||
|
},
|
||||||
|
async handleDelete (row) {
|
||||||
|
const cancelled = await this.$confirmAction({ message: this.key('confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteBom({ id: [row.id] }))
|
||||||
|
if (cancelled) return
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-bar { padding: 10px 0; }
|
||||||
|
.status-on { color: #67C23A; }
|
||||||
|
.status-off { color: #909399; }
|
||||||
|
/deep/ .el-form-item--mini.el-form-item { margin-bottom: 4px; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<el-calendar ref="calendar" v-model="calendarDate" first-day-of-week="7">
|
||||||
|
<template slot="dateCell" slot-scope="{ data }">
|
||||||
|
<div :class="data.isSelected ? 'is-selected' : ''" class="calendar-cell">
|
||||||
|
<div class="date-number">{{ data.day.split('-')[2] }}</div>
|
||||||
|
<div class="shift-box">
|
||||||
|
<template v-for="(plan, index) in productionShiftData">
|
||||||
|
<div v-if="plan[data.day]" :key="index" class="shift-item">
|
||||||
|
<el-tag v-if="plan[data.day].is_rest_day === true" type="info" size="small">{{ index }}-{{ $t(key('rest')) }}</el-tag>
|
||||||
|
<el-popover v-else placement="top-start" width="360" trigger="hover">
|
||||||
|
<div class="popover-title">{{ index }}</div>
|
||||||
|
<div v-for="item in plan[data.day].shifts" :key="item.name + item.start_time" class="popover-shift">
|
||||||
|
<el-tag size="small" type="warning">{{ item.name }}</el-tag>
|
||||||
|
<el-tag v-if="item.cross_day" size="small" class="cross-day">{{ $t(key('cross_day')) }}</el-tag>
|
||||||
|
<span>{{ item.start_time }}-{{ item.finish_time }} {{ item.team }}</span>
|
||||||
|
</div>
|
||||||
|
<el-tag slot="reference" type="warning" size="small">{{ index }}</el-tag>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-calendar>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import { getShiftCalendarByDateRange } from '@/api/production-master-data/shift-management'
|
||||||
|
|
||||||
|
function pad (value) {
|
||||||
|
return String(value).padStart(2, '0')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate (date) {
|
||||||
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDays (date, days) {
|
||||||
|
const next = new Date(date)
|
||||||
|
next.setDate(next.getDate() + days)
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCalendarRange (date) {
|
||||||
|
const first = new Date(date.getFullYear(), date.getMonth(), 1)
|
||||||
|
const start = addDays(first, -first.getDay())
|
||||||
|
const last = new Date(date.getFullYear(), date.getMonth() + 1, 0)
|
||||||
|
const end = addDays(last, 6 - last.getDay())
|
||||||
|
return { start_time: formatDate(start), finish_time: formatDate(end) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'production-master-data-scheduling-calendar',
|
||||||
|
mixins: [i18nMixin('page.production_master_data.team_model.scheduling_calendar')],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
calendarDate: new Date(),
|
||||||
|
productionShiftData: [],
|
||||||
|
loading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
calendarDate () {
|
||||||
|
this.fetchCalendarData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.fetchCalendarData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchCalendarData () {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const range = getCalendarRange(this.calendarDate || new Date())
|
||||||
|
const res = await getShiftCalendarByDateRange(range)
|
||||||
|
this.productionShiftData = (res && res.data) || res || []
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.calendar-cell {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.date-number {
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
.is-selected .date-number {
|
||||||
|
color: #409EFF;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.shift-box {
|
||||||
|
height: 90px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.shift-item {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.popover-title {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.popover-shift {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.cross-day {
|
||||||
|
margin-left: 4px;
|
||||||
|
background: #D4EEA7;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
.shift-box::-webkit-scrollbar {
|
||||||
|
width: 3px;
|
||||||
|
}
|
||||||
|
.shift-box::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.shift-box::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
/deep/ .el-calendar-day {
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<template #header>
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" size="mini">
|
||||||
|
<el-form-item :label="$t(key('shift_plan_name'))"><el-input v-model.trim="search.name" :placeholder="$t(key('enter_shift_plan_name'))" clearable style="width:200px" @keyup.enter.native="onSearch" /></el-form-item>
|
||||||
|
<el-form-item :label="$t(key('shift_plan_code'))"><el-input v-model.trim="search.code" :placeholder="$t(key('enter_shift_plan_code'))" clearable style="width:200px" @keyup.enter.native="onSearch" /></el-form-item>
|
||||||
|
<el-form-item :label="$t(key('last_create_time'))"><el-date-picker v-model="search.create_time" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" :start-placeholder="$t(key('start_date'))" :end-placeholder="$t(key('end_date'))" 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="toolbarButtons" :row-buttons="rowButtons" :pagination="pagination" auto-height @page-change="onPageChange" @selection-change="selectedRows = $event">
|
||||||
|
<template #col-status="{ row }"><span v-if="Number(row.status) === 1" class="status-on">{{ $t(key('enabled')) }}</span><span v-else class="status-off">{{ $t(key('disabled')) }}</span></template>
|
||||||
|
</page-table>
|
||||||
|
|
||||||
|
<el-dialog :title="$t(dialogTitle)" :visible.sync="dialogVisible" width="80%" :close-on-click-modal="false" @close="closeDialog">
|
||||||
|
<el-form ref="form" :model="formData" :rules="translatedRules" label-width="150px" size="small">
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('shift_name'))" prop="name"><el-input v-model="formData.name" :placeholder="$t(key('enter_shift_name'))" /></el-form-item></el-col>
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('shift_code'))" prop="code"><el-input v-model="formData.code" :placeholder="$t(key('enter_shift_code'))" /></el-form-item></el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('shift_time_range'))" prop="time_range"><el-date-picker v-model="formData.time_range" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" :start-placeholder="$t(key('start_date'))" :end-placeholder="$t(key('end_date'))" style="width:100%" /></el-form-item></el-col>
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('status'))"><el-switch v-model="formData.status" :active-text="$t(key('enabled'))" :inactive-text="$t(key('disabled'))" :active-value="1" :inactive-value="0" /></el-form-item></el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('rotation_mode'))"><el-input v-model="formData.cycle.length" class="input-with-select" :placeholder="$t(key('enter_content'))"><el-select slot="append" v-model="formData.cycle.unit" style="width:90px"><el-option :label="$t(key('day'))" value="day" /><el-option :label="$t(key('week'))" value="week" /><el-option :label="$t(key('month'))" value="month" /></el-select></el-input></el-form-item></el-col>
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('rest_day_setting'))"><el-checkbox-group v-model="formData.weekly_rest_days"><el-checkbox v-for="day in weekOptions" :key="day.value" :label="day.value">{{ $t(day.label) }}</el-checkbox></el-checkbox-group></el-form-item></el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('production_team'))"><el-select v-model="formData.productionTeamIds" multiple collapse-tags clearable filterable style="width:100%" :placeholder="$t(key('please_select'))"><el-option v-for="item in teamOptions" :key="item.id" :label="item.name" :value="item.id" /></el-select></el-form-item></el-col>
|
||||||
|
<el-col :span="12"><el-form-item :label="$t(key('remark'))"><el-input v-model="formData.remark" type="textarea" :rows="2" :placeholder="$t(key('enter_remark'))" /></el-form-item></el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<el-divider />
|
||||||
|
<el-button size="mini" type="success" icon="el-icon-plus" @click="addShiftDetail">{{ $t(key('add_shift')) }}</el-button>
|
||||||
|
<el-table :data="shiftsData" border style="width:100%;margin-top:10px">
|
||||||
|
<el-table-column :label="$t(key('shift_name'))"><template slot-scope="scope"><el-input v-model="shiftsData[scope.$index].name" :placeholder="$t(key('enter_shift_name'))" /></template></el-table-column>
|
||||||
|
<el-table-column :label="$t(key('shift_start_time'))" width="190"><template slot-scope="scope"><el-time-picker v-model="shiftsData[scope.$index].start_time" format="HH:mm" value-format="HH:mm" :placeholder="$t(key('select_shift_start_time'))" /></template></el-table-column>
|
||||||
|
<el-table-column :label="$t(key('shift_end_time'))" width="190"><template slot-scope="scope"><el-time-picker v-model="shiftsData[scope.$index].finish_time" format="HH:mm" value-format="HH:mm" :placeholder="$t(key('select_shift_end_time'))" /></template></el-table-column>
|
||||||
|
<el-table-column :label="$t(key('production_team_binding'))"><template slot-scope="scope"><el-select v-model="shiftsData[scope.$index].production_team_id" clearable filterable :placeholder="$t(key('please_select'))" @change="val => changeProductionTeam(val, scope.$index)"><el-option v-for="item in selectableTeams" :key="item.id" :label="item.name" :value="item.id" /></el-select></template></el-table-column>
|
||||||
|
<el-table-column :label="$t(key('operation'))" width="120"><template slot-scope="scope"><el-button type="danger" size="mini" icon="el-icon-delete" @click="shiftsData.splice(scope.$index, 1)">{{ $t(key('delete')) }}</el-button></template></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<span slot="footer"><el-button @click="closeDialog">{{ $t(key('cancel')) }}</el-button><el-button type="primary" :loading="submitting" @click="submitDialog">{{ $t(key('confirm')) }}</el-button></span>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :title="$t(key('shift_plan_data_import'))" :visible.sync="importVisible" width="80%" :close-on-click-modal="false">
|
||||||
|
<el-alert :title="$t(key('upload_file_alert_title'))" :description="$t(key('upload_file_alert_description'))" :closable="false" type="warning" />
|
||||||
|
<el-upload action="" :multiple="false" :auto-upload="false" :show-file-list="true" :file-list="importFileList" accept=".xls,.xlsx" :on-change="onImportFileChange"><el-button slot="trigger" size="mini" type="success">{{ $t(key('select_file')) }}</el-button><el-button style="margin-left:10px" size="mini" type="primary" :loading="importLoading" @click.stop="downloadTemplate">{{ $t(key('download_template')) }}</el-button></el-upload>
|
||||||
|
<el-table :data="importRows" height="330" border style="margin-top:12px" v-loading="importTableLoading"><el-table-column prop="name" :label="$t(key('shift_plan_name'))" /><el-table-column prop="code" :label="$t(key('shift_plan_code'))" /><el-table-column prop="start_time" :label="$t(key('start_time'))" /><el-table-column prop="finish_time" :label="$t(key('end_time'))" /><el-table-column prop="status" :label="$t(key('status'))" /><el-table-column prop="shift_name" :label="$t(key('shift_name'))" /></el-table>
|
||||||
|
<span slot="footer"><el-button @click="importVisible = false">{{ $t(key('cancel')) }}</el-button><el-button type="primary" @click="submitImport">{{ $t(key('confirm')) }}</el-button></span>
|
||||||
|
</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 PageTable from '@/components/page-table'
|
||||||
|
import { downloadRename, readExcel } from '@/utils/file'
|
||||||
|
import { getTeamAll } from '@/api/production-master-data/team-management'
|
||||||
|
import { getShiftList, createShift, editShift, deleteShift, getShiftImportTemplate, importShiftData, exportShiftTask } from '@/api/production-master-data/shift-management'
|
||||||
|
|
||||||
|
function readPageData (res) {
|
||||||
|
const data = res && res.data ? res.data : res
|
||||||
|
if (!data) return { list: [], total: 0 }
|
||||||
|
if (Array.isArray(data)) return { list: data, total: data.length }
|
||||||
|
return { list: data.data || data.list || [], total: Number(data.count || data.total || 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeJson (value, fallback) {
|
||||||
|
if (!value) return fallback
|
||||||
|
if (typeof value !== 'string') return value
|
||||||
|
try { return JSON.parse(value) } catch { return fallback }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'production-master-data-shift-management',
|
||||||
|
components: { PageTable },
|
||||||
|
mixins: [i18nMixin('page.production_master_data.team_model.shift_management'), confirmMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
submitting: false,
|
||||||
|
tableData: [],
|
||||||
|
selectedRows: [],
|
||||||
|
columns: [],
|
||||||
|
toolbarButtons: [],
|
||||||
|
rowButtons: [],
|
||||||
|
search: { name: '', code: '', create_time: '' },
|
||||||
|
pagination: { current: 1, size: 10, total: 0 },
|
||||||
|
teamOptions: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '',
|
||||||
|
handleType: 'create',
|
||||||
|
editId: '',
|
||||||
|
formData: this.defaultFormData(),
|
||||||
|
shiftsData: [],
|
||||||
|
importVisible: false,
|
||||||
|
importFileList: [],
|
||||||
|
importRows: [],
|
||||||
|
importLoading: false,
|
||||||
|
importTableLoading: false,
|
||||||
|
weekOptions: [{ value: 1, label: this.key('monday') }, { value: 2, label: this.key('tuesday') }, { value: 3, label: this.key('wednesday') }, { value: 4, label: this.key('thursday') }, { value: 5, label: this.key('friday') }, { value: 6, label: this.key('saturday') }, { value: 7, label: this.key('sunday') }],
|
||||||
|
rules: { name: [{ required: true, message: this.key('please_enter_shift_plan_name'), trigger: 'blur' }], code: [{ required: true, message: this.key('please_enter_shift_plan_code'), trigger: 'blur' }], time_range: [{ required: true, message: this.key('please_select_shift_time_range'), trigger: 'change' }] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
translatedRules () { const next = {}; Object.keys(this.rules).forEach(key => { next[key] = this.rules[key].map(rule => ({ ...rule, message: this.$t(rule.message) })) }); return next },
|
||||||
|
selectableTeams () { return this.teamOptions.filter(item => this.formData.productionTeamIds.indexOf(item.id) > -1) }
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.loadTeams()
|
||||||
|
this.columns = useTableColumns([{ prop: 'sort', label: this.key('serial_number'), width: 80 }, { prop: 'name', label: this.key('shift_plan_name'), minWidth: 150 }, { prop: 'code', label: this.key('shift_plan_code'), minWidth: 130 }, { prop: 'start_time', label: this.key('start_time'), minWidth: 150 }, { prop: 'finish_time', label: this.key('end_time'), minWidth: 150 }, { prop: 'status', label: this.key('status'), slot: 'status', width: 100 }, { prop: 'nickname', label: this.key('creator'), minWidth: 110 }, { prop: 'create_time', label: this.key('create_time'), minWidth: 160 }, { prop: 'update_time', label: this.key('update_time'), minWidth: 160 }, { prop: '_actions', label: this.key('operation'), width: 180, fixed: 'right' }])
|
||||||
|
const btns = useTableButtons({ toolbar: [{ key: 'add', label: this.key('add'), icon: 'el-icon-plus', type: 'primary', auth: '/system_settings/organization/production_shift_management/create', onClick: this.openAdd }, { key: 'batch_delete', label: this.key('batch_delete'), icon: 'el-icon-delete', color: 'danger', auth: '/system_settings/organization/production_shift_management/batch-delete', needSelection: true, onClick: this.handleBatchDelete }, { key: 'import', label: this.key('import'), icon: 'el-icon-upload2', type: 'success', auth: '/system_settings/organization/production_shift_management/import', onClick: this.openImport }, { key: 'export', label: this.key('export'), icon: 'el-icon-download', type: 'primary', auth: '/system_settings/organization/production_shift_management/export', onClick: this.handleExport }], row: [{ key: 'edit', label: this.key('edit'), icon: 'el-icon-edit', auth: '/system_settings/organization/production_shift_management/edit', onClick: this.openEdit }, { key: 'delete', label: this.key('delete'), icon: 'el-icon-delete', color: 'danger', auth: '/system_settings/organization/production_shift_management/delete', onClick: this.handleDelete }] }, this.$permission)
|
||||||
|
this.toolbarButtons = btns.toolbarButtons; this.rowButtons = btns.rowButtons; this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
defaultFormData () { return { name: '', code: '', time_range: '', status: 1, remark: '', weekly_rest_days: [6, 7], cycle: { unit: 'day', length: 0 }, productionTeamIds: [] } },
|
||||||
|
async loadTeams () { const res = await getTeamAll({}); this.teamOptions = (res && res.data) || res || [] },
|
||||||
|
async fetchData () { this.loading = true; try { const res = await getShiftList({ ...this.search, page_no: this.pagination.current, page_size: this.pagination.size }); const { list, total } = readPageData(res); this.tableData = list; this.pagination.total = total } finally { this.loading = false } },
|
||||||
|
onSearch () { this.pagination.current = 1; this.fetchData() },
|
||||||
|
onReset () { this.search = { name: '', code: '', create_time: '' }; this.pagination.current = 1; this.fetchData() },
|
||||||
|
onPageChange (page) { this.pagination.current = page.current; this.pagination.size = page.size; this.fetchData() },
|
||||||
|
openAdd () { this.handleType = 'create'; this.dialogTitle = this.key('add_shift_plan'); this.dialogVisible = true },
|
||||||
|
openEdit (row) { this.handleType = 'edit'; this.dialogTitle = this.key('edit_shift_plan'); this.editId = row.id; this.formData = { name: row.name, code: row.code, time_range: [row.start_time, row.finish_time], status: Number(row.status), remark: row.remark || '', weekly_rest_days: safeJson(row.weekly_rest_days, []), cycle: safeJson(row.cycle, { unit: 'day', length: 0 }), productionTeamIds: safeJson(row.production_team_ids, []) }; this.shiftsData = safeJson(row.shifts, []); this.dialogVisible = true },
|
||||||
|
addShiftDetail () { this.shiftsData.push({ name: '', start_time: '', finish_time: '', production_team_id: '' }) },
|
||||||
|
changeProductionTeam (value, index) { if (!value) return; if (this.shiftsData.some((item, i) => i !== index && item.production_team_id === value)) { this.shiftsData[index].production_team_id = ''; this.$message.warning(this.$t(this.key('production_team_can_only_bind_one_shift'))) } },
|
||||||
|
validateShifts () { for (let i = 0; i < this.shiftsData.length; i++) { const item = this.shiftsData[i]; if (!item.name) return this.$t(this.key('please_enter_shift_name_row')) + (i + 1); if (!item.start_time) return this.$t(this.key('please_select_shift_start_time_row')) + (i + 1); if (!item.finish_time) return this.$t(this.key('please_select_shift_end_time_row')) + (i + 1) } return '' },
|
||||||
|
submitDialog () { this.$refs.form.validate(async valid => { if (!valid) return; const error = this.validateShifts(); if (error) { this.$message.error(error); return } this.submitting = true; try { const payload = { ...this.formData, start_time: this.formData.time_range[0], finish_time: this.formData.time_range[1], is_shift: Number(this.formData.cycle.length) > 0 ? 1 : 0, rest_enabled: this.formData.weekly_rest_days.length !== 7 ? 1 : 0, shiftsData: JSON.stringify(this.shiftsData) }; if (this.handleType === 'create') await createShift(payload); else await editShift({ ...payload, id: this.editId }); this.$message.success(this.$t(this.key('operation_successful'))); this.closeDialog(); this.fetchData() } finally { this.submitting = false } }) },
|
||||||
|
closeDialog () { this.dialogVisible = false; this.formData = this.defaultFormData(); this.shiftsData = []; this.editId = '' },
|
||||||
|
async handleDelete (row) { const cancelled = await this.$confirmAction({ message: this.key('delete_department_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteShift({ id: [row.id] })); if (cancelled) return; this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData() },
|
||||||
|
async handleBatchDelete () { if (!this.selectedRows.length) { this.$message.error(this.$t(this.key('please_select_table_data'))); return } const cancelled = await this.$confirmAction({ message: this.key('batch_delete_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteShift({ id: this.selectedRows.map(item => item.id) })); if (cancelled) return; this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData() },
|
||||||
|
openImport () { this.importFileList = []; this.importRows = []; this.importVisible = true },
|
||||||
|
async downloadTemplate () { this.importLoading = true; try { const res = await getShiftImportTemplate({}); downloadRename(res, 'xlsx', this.$t(this.key('shift_plan_data_import_template'))) } finally { this.importLoading = false } },
|
||||||
|
async onImportFileChange (file) { if (!file || !/\.(xls|xlsx)$/i.test(file.name)) { this.$message.error(this.$t(this.key('upload_format_error'))); return } this.importFileList = [file]; this.importTableLoading = true; try { const rows = await readExcel(file.raw); this.importRows = rows.map(row => ({ name: row[this.$t(this.key('shift_plan_name'))], code: row[this.$t(this.key('shift_plan_code'))], start_time: row[this.$t(this.key('start_time'))], finish_time: row[this.$t(this.key('end_time'))], status: row[this.$t(this.key('status'))], shift_name: row[this.$t(this.key('shift_name'))], shifts: { name: row[this.$t(this.key('shift_name'))], start_time: row[this.$t(this.key('shift_start_time'))], finish_time: row[this.$t(this.key('shift_end_time'))], production_team_id: row[this.$t(this.key('production_team_binding'))] } })) } finally { this.importTableLoading = false } },
|
||||||
|
async submitImport () { if (!this.importRows.length) { this.$message.error(this.$t(this.key('please_import_department_data'))); return } await importShiftData({ import_data: JSON.stringify(this.importRows) }); this.$message.success(this.$t(this.key('operation_successful'))); this.importVisible = false; this.fetchData() },
|
||||||
|
async handleExport () { const cancelled = await this.$confirmAction({ message: this.key('export_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => exportShiftTask({ ...this.search, action: 'download' })); if (cancelled) return; this.$message.success(this.$t(this.key('download_task_created'))) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-bar { padding: 10px 0; }
|
||||||
|
.status-on { color: #67C23A; }
|
||||||
|
.status-off { color: #909399; }
|
||||||
|
.input-with-select /deep/ .el-input-group__append { width: 90px; }
|
||||||
|
/deep/ .el-form-item--mini.el-form-item { margin-bottom: 4px; }
|
||||||
|
</style>
|
||||||
@@ -4,298 +4,88 @@
|
|||||||
<div class="search-bar">
|
<div class="search-bar">
|
||||||
<el-form :inline="true" size="mini">
|
<el-form :inline="true" size="mini">
|
||||||
<el-form-item :label="$t(key('team_name'))">
|
<el-form-item :label="$t(key('team_name'))">
|
||||||
<el-input
|
<el-input v-model.trim="search.name" :placeholder="$t(key('enter_team_name'))" clearable style="width:200px" @keyup.enter.native="onSearch" />
|
||||||
v-model="search.name"
|
|
||||||
:placeholder="$t(key('enter_team_name'))"
|
|
||||||
clearable
|
|
||||||
style="width:200px"
|
|
||||||
@keyup.enter.native="onSearch"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t(key('area'))">
|
<el-form-item :label="$t(key('area'))">
|
||||||
<el-select
|
<el-select v-model="search.area_id" :placeholder="$t(key('select_area'))" clearable filterable style="width:200px" @change="onSearchAreaChange">
|
||||||
v-model="search.area_id"
|
<el-option v-for="item in areaOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
:placeholder="$t(key('select_area'))"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
style="width:200px"
|
|
||||||
@change="onAreaChange"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in areaOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t(key('production_line'))">
|
<el-form-item :label="$t(key('production_line'))">
|
||||||
<el-select
|
<el-select v-model="search.line_id" :placeholder="$t(key('select_area_then_line'))" clearable filterable style="width:200px">
|
||||||
v-model="search.line_id"
|
<el-option v-for="item in searchLineOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
:placeholder="$t(key('select_area_then_line'))"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
style="width:200px"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in lineOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t(key('last_create_time'))">
|
<el-form-item :label="$t(key('last_create_time'))">
|
||||||
<el-date-picker
|
<el-date-picker v-model="search.create_time" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" :start-placeholder="$t(key('start_time'))" :end-placeholder="$t(key('end_time'))" style="width:330px" />
|
||||||
v-model="search.create_time"
|
|
||||||
type="datetimerange"
|
|
||||||
range-separator="-"
|
|
||||||
start-placeholder="开始日期"
|
|
||||||
end-placeholder="结束日期"
|
|
||||||
format="yyyy-MM-dd HH:mm:ss"
|
|
||||||
value-format="yyyy-MM-dd HH:mm:ss"
|
|
||||||
style="width:350px"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="el-icon-search" @click="onSearch">
|
<el-button type="primary" icon="el-icon-search" @click="onSearch">{{ $t(key('search')) }}</el-button>
|
||||||
{{ $t(key('search')) }}
|
<el-button icon="el-icon-refresh" @click="onReset">{{ $t(key('reset')) }}</el-button>
|
||||||
</el-button>
|
|
||||||
<el-button icon="el-icon-refresh" @click="onReset">
|
|
||||||
{{ $t(key('reset')) }}
|
|
||||||
</el-button>
|
|
||||||
<el-dropdown @command="handleExportCommand" style="margin-left: 10px;">
|
|
||||||
<el-button type="info">
|
|
||||||
{{ $t(key('export')) }}<i class="el-icon-arrow-down el-icon--right"></i>
|
|
||||||
</el-button>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item command="export">{{ $t(key('export')) }}</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="export_task">{{ $t(key('create_download_task')) }}</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<page-table
|
<page-table ref="pageTable" :columns="columns" :data="tableData" :loading="loading" :toolbar-buttons="toolbarButtons" :row-buttons="rowButtons" :pagination="pagination" auto-height @page-change="onPageChange" @selection-change="selectedRows = $event" />
|
||||||
ref="pageTable"
|
|
||||||
:columns="columns"
|
|
||||||
:data="tableData"
|
|
||||||
:loading="loading"
|
|
||||||
:toolbar-buttons="toolbarButtons"
|
|
||||||
:row-buttons="rowButtons"
|
|
||||||
:pagination="pagination"
|
|
||||||
help-url="/help/team-management"
|
|
||||||
:help-text="$t(ckey('help'))"
|
|
||||||
auto-height
|
|
||||||
@page-change="onPageChange"
|
|
||||||
@selection-change="onSelect"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 新增/编辑班组弹框 -->
|
<el-dialog :title="$t(dialogTitle)" :visible.sync="dialogVisible" width="80%" :close-on-click-modal="false" @close="closeDialog">
|
||||||
<el-dialog
|
<el-form ref="form" :model="formData" :rules="translatedRules" inline label-width="150px" size="small">
|
||||||
:visible.sync="dialogVisible"
|
<el-form-item :label="$t(key('team_name'))" prop="name"><el-input v-model="formData.name" /></el-form-item>
|
||||||
:title="dialogTitle"
|
<el-form-item :label="$t(key('affiliated_factory'))" prop="area_id">
|
||||||
:width="'60%'"
|
<el-select v-model="formData.area_id" clearable filterable :placeholder="$t(key('please_select'))" @change="onFormAreaChange">
|
||||||
@close="handleDialogClose"
|
<el-option v-for="item in areaOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
>
|
</el-select>
|
||||||
<el-form
|
</el-form-item>
|
||||||
ref="teamForm"
|
<el-form-item :label="$t(key('affiliated_production_line'))" prop="line_id">
|
||||||
:model="formData"
|
<el-select v-model="formData.line_id" clearable filterable :placeholder="$t(key('please_select_factory_then_line'))">
|
||||||
:rules="rules"
|
<el-option v-for="item in formLineOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
label-width="150px"
|
</el-select>
|
||||||
size="small"
|
</el-form-item>
|
||||||
>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item :label="$t(key('team_name'))" prop="name">
|
|
||||||
<el-input v-model="formData.name" :placeholder="$t(key('enter_team_name'))"></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item :label="$t(key('affiliated_factory'))" prop="area_id">
|
|
||||||
<el-select
|
|
||||||
v-model="formData.area_id"
|
|
||||||
:placeholder="$t(key('please_select'))"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
@change="areaDataChange"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in areaOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item :label="$t(key('affiliated_production_line'))" prop="line_id">
|
|
||||||
<el-select
|
|
||||||
v-model="formData.line_id"
|
|
||||||
:placeholder="$t(key('please_select_factory_then_line'))"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in lineOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
<el-divider />
|
||||||
<el-divider>{{ $t(key('team_members')) }}</el-divider>
|
<el-button size="mini" type="success" icon="el-icon-plus" @click="addMember">{{ $t(key('add_member')) }}</el-button>
|
||||||
|
<el-table :data="membersData" style="width:100%;margin-top:10px" border>
|
||||||
<el-button @click="handleTeamAddMembers" size="mini" type="success">
|
<el-table-column :label="$t(key('member_name'))">
|
||||||
{{ $t(key('add_member')) }}
|
|
||||||
</el-button>
|
|
||||||
|
|
||||||
<el-table :data="membersData" style="width: 100%; margin-top: 10px;">
|
|
||||||
<el-table-column :label="$t(key('member_name'))" width="250">
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-select
|
<el-select v-model="membersData[scope.$index].user_id" size="small" clearable filterable :placeholder="$t(key('please_select'))">
|
||||||
v-model="membersData[scope.$index]['user_id']"
|
<el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
size="small"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
:placeholder="$t(key('please_select'))"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in userOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="is_main" :label="$t(key('is_team_leader'))" width="150">
|
<el-table-column :label="$t(key('is_team_leader'))" width="220">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-switch
|
<el-switch v-model="membersData[scope.$index].is_main" :active-text="$t(key('yes'))" :inactive-text="$t(key('no'))" :active-value="1" :inactive-value="0" @change="val => onLeaderChange(val, scope.$index)" />
|
||||||
v-model="membersData[scope.$index]['is_main']"
|
|
||||||
:active-text="$t(key('yes'))"
|
|
||||||
:inactive-text="$t(key('no'))"
|
|
||||||
:active-value="1"
|
|
||||||
:inactive-value="0"
|
|
||||||
@change="
|
|
||||||
(val) => {
|
|
||||||
is_main_change(val, scope.$index);
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
|
||||||
</el-switch>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t(key('operation'))" width="100">
|
<el-table-column :label="$t(key('operation'))" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope"><el-button type="danger" size="mini" icon="el-icon-delete" @click="deleteMember(scope.row, scope.$index)">{{ $t(key('delete')) }}</el-button></template>
|
||||||
<el-button
|
|
||||||
type="danger"
|
|
||||||
@click="handleMembersDelete(scope.row, scope.$index)"
|
|
||||||
size="mini"
|
|
||||||
icon="el-icon-delete"
|
|
||||||
>
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
<span slot="footer">
|
||||||
<el-pagination
|
<el-button @click="closeDialog">{{ $t(key('cancel')) }}</el-button>
|
||||||
@size-change="handleSizeChange"
|
<el-button type="primary" :loading="submitting" @click="submitDialog">{{ $t(key('confirm')) }}</el-button>
|
||||||
@current-change="handleCurrentChange"
|
</span>
|
||||||
:current-page="pagination.currentPage"
|
|
||||||
:hide-on-single-page="true"
|
|
||||||
:page-sizes="[8, 20, 50, 100]"
|
|
||||||
:page-size="pagination.pageSize"
|
|
||||||
layout="total, sizes, prev, pager, next, jumper"
|
|
||||||
:total="pagination.total"
|
|
||||||
style="margin-top: 10px;"
|
|
||||||
>
|
|
||||||
</el-pagination>
|
|
||||||
|
|
||||||
<div slot="footer" class="dialog-footer">
|
|
||||||
<el-button @click="handleDialogClose">{{ $t(key('cancel')) }}</el-button>
|
|
||||||
<el-button type="primary" @click="handleSubmitDialogMembersAdd">
|
|
||||||
{{ $t(key('confirm')) }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 导入弹框 -->
|
<el-dialog :title="$t(key('production_team_data_import'))" :visible.sync="importVisible" width="50%" :close-on-click-modal="false">
|
||||||
<el-dialog
|
<el-alert :title="$t(key('upload_file_alert_title'))" :description="$t(key('upload_file_alert_description'))" :closable="false" type="warning" />
|
||||||
:visible.sync="importDialogVisible"
|
<el-upload class="upload" action="" :multiple="false" :auto-upload="false" :show-file-list="true" :file-list="importFileList" accept=".xls,.xlsx" :on-change="onImportFileChange">
|
||||||
:title="$t(key('production_team_data_import'))"
|
<el-button slot="trigger" size="mini" type="success">{{ $t(key('select_file')) }}</el-button>
|
||||||
width="50%"
|
<el-button style="margin-left:10px" size="mini" type="primary" :loading="importLoading" @click.stop="downloadTemplate">{{ $t(key('download_template')) }}</el-button>
|
||||||
@close="handleImportDialogClose"
|
</el-upload>
|
||||||
>
|
<el-table :data="importRows" height="320" border style="margin-top:12px" v-loading="importTableLoading">
|
||||||
<el-form>
|
<el-table-column prop="name" :label="$t(key('team_name'))" />
|
||||||
<el-alert
|
<el-table-column prop="area_name" :label="$t(key('affiliated_factory'))" />
|
||||||
:title="$t(key('upload_file_alert_title'))"
|
<el-table-column prop="line_name" :label="$t(key('affiliated_production_line'))" />
|
||||||
:description="$t(key('upload_file_alert_description'))"
|
<el-table-column prop="members_user_name" :label="$t(key('member_name'))" />
|
||||||
:closable="false"
|
<el-table-column prop="is_main" :label="$t(key('is_team_leader'))" />
|
||||||
type="warning"
|
</el-table>
|
||||||
style="margin-bottom: 20px;"
|
<span slot="footer">
|
||||||
>
|
<el-button @click="importVisible = false">{{ $t(key('cancel')) }}</el-button>
|
||||||
</el-alert>
|
<el-button type="primary" @click="submitImport">{{ $t(key('confirm')) }}</el-button>
|
||||||
<el-form-item :label="$t(key('production_team_data_import_table'))">
|
</span>
|
||||||
<el-upload
|
|
||||||
class="upload-demo"
|
|
||||||
action=""
|
|
||||||
:auto-upload="false"
|
|
||||||
:multiple="false"
|
|
||||||
:show-file-list="true"
|
|
||||||
:file-list="importFileList"
|
|
||||||
accept=".xlsx,.xls"
|
|
||||||
:on-change="handleFileUpload"
|
|
||||||
:limit="1"
|
|
||||||
>
|
|
||||||
<el-button slot="trigger" size="mini" type="success">
|
|
||||||
{{ $t(key('select_file')) }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
style="margin-left: 10px;"
|
|
||||||
size="mini"
|
|
||||||
type="primary"
|
|
||||||
@click="handleDownloadTemplate"
|
|
||||||
>
|
|
||||||
{{ $t(key('download_template')) }}
|
|
||||||
</el-button>
|
|
||||||
</el-upload>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t(key('preview'))">
|
|
||||||
<el-table
|
|
||||||
v-loading="importTableLoading"
|
|
||||||
:data="importPreviewData"
|
|
||||||
height="300"
|
|
||||||
>
|
|
||||||
<el-table-column prop="name" :label="$t(key('team_name'))" width="120"></el-table-column>
|
|
||||||
<el-table-column prop="area_name" :label="$t(key('affiliated_factory'))" width="120"></el-table-column>
|
|
||||||
<el-table-column prop="line_name" :label="$t(key('affiliated_production_line'))" width="120"></el-table-column>
|
|
||||||
<el-table-column prop="members_user_name" :label="$t(key('member_name'))" width="120"></el-table-column>
|
|
||||||
<el-table-column prop="is_main" :label="$t(key('is_team_leader'))" width="100"></el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div slot="footer" class="dialog-footer">
|
|
||||||
<el-button @click="handleImportDialogClose">{{ $t(key('cancel')) }}</el-button>
|
|
||||||
<el-button type="primary" @click="handleStartImport" :loading="importLoading">
|
|
||||||
{{ $t(key('confirm')) }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
</d2-container>
|
</d2-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -304,20 +94,19 @@ import { useTableColumns } from '@/composables/useTableColumns'
|
|||||||
import { useTableButtons } from '@/composables/useTableButtons'
|
import { useTableButtons } from '@/composables/useTableButtons'
|
||||||
import { i18nMixin } from '@/composables/useI18n'
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
import { confirmMixin } from '@/composables/useConfirmHandle'
|
import { confirmMixin } from '@/composables/useConfirmHandle'
|
||||||
import {
|
import PageTable from '@/components/page-table'
|
||||||
getTeamManagementList,
|
|
||||||
createTeamManagement,
|
|
||||||
editTeamManagement,
|
|
||||||
deleteTeamManagement,
|
|
||||||
getTeamManagementALL,
|
|
||||||
getImportTemplate,
|
|
||||||
importTeamManagement,
|
|
||||||
exportTeamManagementTask
|
|
||||||
} from '@/api/production-master-data/team-management'
|
|
||||||
import { getFactoryAreaALL } from '@/api/production-master-data/factory-area'
|
import { getFactoryAreaALL } from '@/api/production-master-data/factory-area'
|
||||||
import { getProductionLineList } from '@/api/production-master-data/production-line'
|
import { getProductionLineList } from '@/api/production-master-data/production-line'
|
||||||
import { getUserAll } from '@/api/system-administration/user'
|
import { getUserList } from '@/api/system-administration/user'
|
||||||
import PageTable from '@/components/page-table'
|
import { downloadRename, readExcel } from '@/utils/file'
|
||||||
|
import { getTeamList, createTeam, editTeam, deleteTeam, getTeamImportTemplate, importTeamData, exportTeamTask, getTeamMemberList, deleteTeamMember } from '@/api/production-master-data/team-management'
|
||||||
|
|
||||||
|
function readPageData (res) {
|
||||||
|
const data = res && res.data ? res.data : res
|
||||||
|
if (!data) return { list: [], total: 0 }
|
||||||
|
if (Array.isArray(data)) return { list: data, total: data.length }
|
||||||
|
return { list: data.data || data.list || [], total: Number(data.count || data.total || 0) }
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'production-master-data-team-management',
|
name: 'production-master-data-team-management',
|
||||||
@@ -329,104 +118,62 @@ export default {
|
|||||||
submitting: false,
|
submitting: false,
|
||||||
tableData: [],
|
tableData: [],
|
||||||
selectedRows: [],
|
selectedRows: [],
|
||||||
dialogVisible: false,
|
|
||||||
importDialogVisible: false,
|
|
||||||
dialogTitle: '',
|
|
||||||
editId: '',
|
|
||||||
handleType: 'create',
|
|
||||||
search: { name: '', area_id: '', line_id: '', create_time: '' },
|
|
||||||
pagination: { current: 1, size: 10, total: 0 },
|
|
||||||
areaOptions: [],
|
|
||||||
lineOptions: [],
|
|
||||||
userOptions: [],
|
|
||||||
formData: { name: '', area_id: '', line_id: '', user_id: '' },
|
|
||||||
membersData: [],
|
|
||||||
membersForm: {
|
|
||||||
members_user_id: undefined,
|
|
||||||
is_main: '1'
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
name: [
|
|
||||||
{ required: true, message: this.key('please_enter_team_name'), trigger: 'blur' },
|
|
||||||
{ min: 2, max: 20, message: this.key('length_2_to_20_characters'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
area_id: [
|
|
||||||
{ required: true, message: this.key('please_select_affiliated_factory'), trigger: 'change' }
|
|
||||||
],
|
|
||||||
line_id: [
|
|
||||||
{ required: true, message: this.key('please_select_affiliated_production_line'), trigger: 'change' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
columns: [],
|
columns: [],
|
||||||
toolbarButtons: [],
|
toolbarButtons: [],
|
||||||
rowButtons: [],
|
rowButtons: [],
|
||||||
|
search: { name: '', area_id: '', line_id: '', create_time: '' },
|
||||||
|
pagination: { current: 1, size: 10, total: 0 },
|
||||||
|
areaOptions: [],
|
||||||
|
searchLineOptions: [],
|
||||||
|
formLineOptions: [],
|
||||||
|
userOptions: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '',
|
||||||
|
handleType: 'create',
|
||||||
|
editId: '',
|
||||||
|
leaderIndex: undefined,
|
||||||
|
formData: { name: '', area_id: '', line_id: '' },
|
||||||
|
membersData: [],
|
||||||
|
importVisible: false,
|
||||||
importFileList: [],
|
importFileList: [],
|
||||||
importPreviewData: [],
|
importRows: [],
|
||||||
importTableLoading: false,
|
|
||||||
importLoading: false,
|
importLoading: false,
|
||||||
pagination: {
|
importTableLoading: false,
|
||||||
total: 0,
|
rules: {
|
||||||
pageSize: 8,
|
name: [{ required: true, message: this.key('please_enter_team_name'), trigger: 'blur' }, { min: 2, max: 20, message: this.key('length_2_to_20_characters'), trigger: 'blur' }],
|
||||||
currentPage: 1,
|
area_id: [{ required: true, message: this.key('please_select_affiliated_factory'), trigger: 'change' }],
|
||||||
|
line_id: [{ required: true, message: this.key('please_select_affiliated_production_line'), trigger: 'change' }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
translatedRules () {
|
||||||
|
const next = {}
|
||||||
|
Object.keys(this.rules).forEach(key => { next[key] = this.rules[key].map(rule => ({ ...rule, message: this.$t(rule.message) })) })
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
},
|
||||||
created () {
|
created () {
|
||||||
this.initAreaOptions()
|
this.initOptions()
|
||||||
this.initUserOptions()
|
|
||||||
this.columns = useTableColumns([
|
this.columns = useTableColumns([
|
||||||
{ prop: 'sort', label: this.key('serial_number'), width: 80 },
|
{ prop: 'sort', label: this.key('serial_number'), width: 80 },
|
||||||
{ prop: 'name', label: this.key('team_name'), minWidth: 120 },
|
{ prop: 'name', label: this.key('team_name'), minWidth: 140 },
|
||||||
{ prop: 'area_name', label: this.key('affiliated_factory'), minWidth: 120 },
|
{ prop: 'area_name', label: this.key('affiliated_factory'), minWidth: 140 },
|
||||||
{ prop: 'line_name', label: this.key('affiliated_production_line'), minWidth: 120 },
|
{ prop: 'line_name', label: this.key('affiliated_production_line'), minWidth: 160 },
|
||||||
{ prop: 'create_time', label: this.key('create_time'), width: 160 },
|
{ prop: 'create_time', label: this.key('create_time'), minWidth: 160 },
|
||||||
{ prop: 'update_time', label: this.key('update_time'), width: 160 },
|
{ prop: 'update_time', label: this.key('update_time'), minWidth: 160 },
|
||||||
{ prop: '_actions', label: this.key('operation'), width: 250, fixed: 'right' }
|
{ prop: '_actions', label: this.key('operation'), width: 180, fixed: 'right' }
|
||||||
])
|
])
|
||||||
const btns = useTableButtons({
|
const btns = useTableButtons({
|
||||||
toolbar: [
|
toolbar: [
|
||||||
{
|
{ key: 'add', label: this.key('add'), icon: 'el-icon-plus', type: 'primary', auth: '/system_settings/organization/production_team_manage/create', onClick: this.openAdd },
|
||||||
key: 'add',
|
{ key: 'batch_delete', label: this.key('batch_delete'), icon: 'el-icon-delete', color: 'danger', auth: '/system_settings/organization/production_team_manage/batch-delete', needSelection: true, onClick: this.handleBatchDelete },
|
||||||
label: this.key('add'),
|
{ key: 'import', label: this.key('import'), icon: 'el-icon-upload2', type: 'success', auth: '/system_settings/organization/production_team_manage/import', onClick: this.openImport },
|
||||||
icon: 'el-icon-plus',
|
{ key: 'export', label: this.key('export'), icon: 'el-icon-download', type: 'primary', auth: '/system_settings/organization/production_team_manage/export', onClick: this.handleExport }
|
||||||
type: 'primary',
|
|
||||||
auth: '/system_settings/organization/production_team_manage/create',
|
|
||||||
onClick: this.openAdd
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'batch_delete',
|
|
||||||
label: this.key('batch_delete'),
|
|
||||||
icon: 'el-icon-delete',
|
|
||||||
type: 'danger',
|
|
||||||
auth: '/system_settings/organization/production_team_manage/batch-delete',
|
|
||||||
onClick: this.handleBatchDelete
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'import',
|
|
||||||
label: this.key('import'),
|
|
||||||
icon: 'el-icon-upload2',
|
|
||||||
type: '',
|
|
||||||
style: { background: '#3CBA92', color: '#FFFFFF' },
|
|
||||||
auth: '/system_settings/organization/production_team_manage/import',
|
|
||||||
onClick: this.openImport
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
row: [
|
row: [
|
||||||
{
|
{ key: 'edit', label: this.key('edit'), icon: 'el-icon-edit', auth: '/system_settings/organization/production_team_manage/edit', onClick: this.openEdit },
|
||||||
key: 'edit',
|
{ key: 'delete', label: this.key('delete'), icon: 'el-icon-delete', color: 'danger', auth: '/system_settings/organization/production_team_manage/delete', onClick: this.handleDelete }
|
||||||
label: this.key('edit'),
|
|
||||||
icon: 'el-icon-edit',
|
|
||||||
auth: '/system_settings/organization/production_team_manage/edit',
|
|
||||||
onClick: this.openEdit
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'delete',
|
|
||||||
label: this.key('delete'),
|
|
||||||
icon: 'el-icon-delete',
|
|
||||||
color: 'danger',
|
|
||||||
auth: '/system_settings/organization/production_team_manage/delete',
|
|
||||||
onClick: this.handleDelete
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}, this.$permission)
|
}, this.$permission)
|
||||||
this.toolbarButtons = btns.toolbarButtons
|
this.toolbarButtons = btns.toolbarButtons
|
||||||
@@ -434,284 +181,107 @@ export default {
|
|||||||
this.fetchData()
|
this.fetchData()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async initOptions () {
|
||||||
|
const [areas, users] = await Promise.all([getFactoryAreaALL({}), getUserList({ page_no: 1, page_size: 10000 })])
|
||||||
|
this.areaOptions = ((areas && areas.data) || areas || []).map(item => ({ label: item.name, value: item.area_id || item.id }))
|
||||||
|
const userPage = readPageData(users)
|
||||||
|
this.userOptions = userPage.list.map(item => ({ label: item.nickname || item.name || item.username, value: item.user_id || item.id }))
|
||||||
|
},
|
||||||
|
async loadLines (areaId, target) {
|
||||||
|
if (!areaId) { this[target] = []; return }
|
||||||
|
const res = await getProductionLineList({ area_id: areaId, page_no: 1, page_size: 10000 })
|
||||||
|
const { list } = readPageData(res)
|
||||||
|
this[target] = list.map(item => ({ label: item.name, value: item.id }))
|
||||||
|
},
|
||||||
|
onSearchAreaChange (areaId) { this.search.line_id = ''; this.loadLines(areaId, 'searchLineOptions') },
|
||||||
|
onFormAreaChange (areaId) { this.formData.line_id = ''; this.loadLines(areaId, 'formLineOptions') },
|
||||||
async fetchData () {
|
async fetchData () {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
try {
|
try {
|
||||||
const res = await getTeamManagementList({
|
const res = await getTeamList({ ...this.search, page_no: this.pagination.current, page_size: this.pagination.size })
|
||||||
...this.search,
|
const { list, total } = readPageData(res)
|
||||||
page_no: this.pagination.current,
|
|
||||||
page_size: this.pagination.size
|
|
||||||
})
|
|
||||||
const list = Array.isArray(res) ? res : (res.data?.data || [])
|
|
||||||
const total = Array.isArray(res) ? res.length : (res.data?.count || 0)
|
|
||||||
this.tableData = list
|
this.tableData = list
|
||||||
this.pagination.total = total
|
this.pagination.total = total
|
||||||
} finally {
|
} finally { this.loading = false }
|
||||||
this.loading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async initAreaOptions () {
|
|
||||||
try {
|
|
||||||
const res = await getFactoryAreaALL()
|
|
||||||
const data = Array.isArray(res) ? res : (res.data || [])
|
|
||||||
this.areaOptions = data.map(item => ({ value: item.area_id || item.id, label: item.name }))
|
|
||||||
} catch { /* 忽略加载失败 */ }
|
|
||||||
},
|
|
||||||
async initUserOptions () {
|
|
||||||
try {
|
|
||||||
const res = await getUserAll()
|
|
||||||
const data = Array.isArray(res) ? res : (res.data || [])
|
|
||||||
this.userOptions = data.map(item => ({ value: item.user_id || item.id, label: item.nickname || item.username }))
|
|
||||||
} catch { /* 忽略加载失败 */ }
|
|
||||||
},
|
|
||||||
async loadLineOptionsByArea(areaId) {
|
|
||||||
if (!areaId) {
|
|
||||||
this.lineOptions = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const res = await getProductionLineList({ area_id: areaId, page_no: 1, page_size: 1000 })
|
|
||||||
const data = Array.isArray(res) ? res : (res.data?.data || [])
|
|
||||||
this.lineOptions = data.map(item => ({ value: item.id, label: item.name }))
|
|
||||||
} catch { /* 忽略加载失败 */ }
|
|
||||||
},
|
|
||||||
onSearch () {
|
|
||||||
this.pagination.current = 1
|
|
||||||
this.fetchData()
|
|
||||||
},
|
|
||||||
onReset () {
|
|
||||||
this.search = { name: '', area_id: '', line_id: '', create_time: '' }
|
|
||||||
this.lineOptions = []
|
|
||||||
this.pagination.current = 1
|
|
||||||
this.fetchData()
|
|
||||||
},
|
|
||||||
onAreaChange(value) {
|
|
||||||
this.search.line_id = '' // 清空产线选择
|
|
||||||
this.loadLineOptionsByArea(value)
|
|
||||||
},
|
|
||||||
onPageChange (page) {
|
|
||||||
this.pagination.current = page.current
|
|
||||||
this.pagination.size = page.size
|
|
||||||
this.fetchData()
|
|
||||||
},
|
|
||||||
onSelect (rows) {
|
|
||||||
this.selectedRows = rows
|
|
||||||
},
|
|
||||||
resetForm () {
|
|
||||||
this.formData = { name: '', area_id: '', line_id: '', user_id: '' }
|
|
||||||
this.membersData = []
|
|
||||||
this.editId = ''
|
|
||||||
},
|
|
||||||
async openAdd () {
|
|
||||||
this.handleType = 'create'
|
|
||||||
this.dialogTitle = this.key('add_team')
|
|
||||||
await this.$nextTick()
|
|
||||||
this.resetForm()
|
|
||||||
this.dialogVisible = true
|
|
||||||
},
|
},
|
||||||
|
onSearch () { this.pagination.current = 1; this.fetchData() },
|
||||||
|
onReset () { this.search = { name: '', 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() },
|
||||||
|
openAdd () { this.handleType = 'create'; this.dialogTitle = this.key('add_team'); this.dialogVisible = true },
|
||||||
async openEdit (row) {
|
async openEdit (row) {
|
||||||
this.handleType = 'edit'
|
this.handleType = 'edit'; this.dialogTitle = this.key('edit_team'); this.editId = row.id
|
||||||
this.dialogTitle = this.key('edit_team')
|
this.formData = { name: row.name, area_id: row.area_id, line_id: row.line_id }
|
||||||
this.editId = row.id
|
await this.loadLines(row.area_id, 'formLineOptions')
|
||||||
this.formData = {
|
const res = await getTeamMemberList({ production_team_id: row.id, page_no: 1, page_size: 10000 })
|
||||||
name: row.name,
|
const { list } = readPageData(res)
|
||||||
area_id: row.area_id,
|
this.membersData = list.map(item => ({ ...item, is_main: Number(item.is_main) }))
|
||||||
line_id: row.line_id
|
this.leaderIndex = this.membersData.findIndex(item => Number(item.is_main) === 1)
|
||||||
}
|
if (this.leaderIndex < 0) this.leaderIndex = undefined
|
||||||
// 加载产线选项
|
|
||||||
await this.loadLineOptionsByArea(row.area_id)
|
|
||||||
// 加载成员数据
|
|
||||||
this.membersData = row.members || []
|
|
||||||
await this.$nextTick()
|
|
||||||
this.dialogVisible = true
|
this.dialogVisible = true
|
||||||
},
|
},
|
||||||
async onDialogSubmit () {
|
addMember () { this.membersData.push({ user_id: '', is_main: 0 }) },
|
||||||
this.submitting = true
|
onLeaderChange (val, index) {
|
||||||
try {
|
if (Number(val) === 1 && this.leaderIndex !== undefined && this.leaderIndex !== index) {
|
||||||
const submitData = {
|
this.$message.error(this.$t(this.key('only_one_team_leader_allowed')))
|
||||||
...this.formData,
|
this.membersData[index].is_main = 0
|
||||||
members: this.membersData
|
} else if (this.leaderIndex === index && Number(val) === 0) this.leaderIndex = undefined
|
||||||
}
|
else if (Number(val) === 1) this.leaderIndex = index
|
||||||
if (this.handleType === 'create') {
|
|
||||||
await createTeamManagement(submitData)
|
|
||||||
} else {
|
|
||||||
await editTeamManagement({ ...submitData, id: this.editId })
|
|
||||||
}
|
|
||||||
this.$message.success(this.$t(this.key('operation_success')))
|
|
||||||
this.dialogVisible = false
|
|
||||||
this.fetchData()
|
|
||||||
} finally {
|
|
||||||
this.submitting = false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
handleDialogClose () {
|
async deleteMember (row, index) {
|
||||||
this.resetForm()
|
if (row.id) { await deleteTeamMember({ id: [row.id] }); this.$message.success(this.$t(this.key('operation_successful'))) }
|
||||||
this.dialogVisible = false
|
|
||||||
},
|
|
||||||
async handleDelete (row) {
|
|
||||||
const cancelled = await this.$confirmAction(
|
|
||||||
{
|
|
||||||
message: this.key('confirm_delete'),
|
|
||||||
title: this.key('tip')
|
|
||||||
},
|
|
||||||
() => deleteTeamManagement({ id: [row.id] })
|
|
||||||
)
|
|
||||||
if (cancelled) return
|
|
||||||
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()
|
|
||||||
},
|
|
||||||
handleBatchDelete () {
|
|
||||||
if (this.selectedRows.length === 0) {
|
|
||||||
this.$message.warning(this.$t(this.key('select_rows_first')))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$confirm(this.$t(this.key('confirm_batch_delete')), this.$t(this.key('tip')), {
|
|
||||||
confirmButtonText: this.$t(this.key('confirm')),
|
|
||||||
cancelButtonText: this.$t(this.key('cancel')),
|
|
||||||
type: 'warning'
|
|
||||||
}).then(async () => {
|
|
||||||
const ids = this.selectedRows.map(row => row.id)
|
|
||||||
await deleteTeamManagement({ id: ids })
|
|
||||||
this.$message.success(this.$t(this.key('operation_success')))
|
|
||||||
this.fetchData()
|
|
||||||
}).catch(() => {})
|
|
||||||
},
|
|
||||||
openImport() {
|
|
||||||
this.importFileList = []
|
|
||||||
this.importPreviewData = []
|
|
||||||
this.importDialogVisible = true
|
|
||||||
},
|
|
||||||
handleImportDialogClose() {
|
|
||||||
this.importDialogVisible = false
|
|
||||||
this.importFileList = []
|
|
||||||
this.importPreviewData = []
|
|
||||||
},
|
|
||||||
handleFileUpload(file, fileList) {
|
|
||||||
this.importFileList = fileList.slice(-1) // 只保留最后一个文件
|
|
||||||
},
|
|
||||||
async handleDownloadTemplate() {
|
|
||||||
try {
|
|
||||||
const res = await getImportTemplate({})
|
|
||||||
// 创建下载链接
|
|
||||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
|
||||||
const url = window.URL.createObjectURL(blob)
|
|
||||||
const a = document.createElement('a')
|
|
||||||
a.href = url
|
|
||||||
a.download = 'team_management_import_template.xlsx'
|
|
||||||
a.click()
|
|
||||||
window.URL.revokeObjectURL(url)
|
|
||||||
} catch (error) {
|
|
||||||
this.$message.error(this.$t(this.key('download_template_failed')))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async handleStartImport() {
|
|
||||||
if (this.importFileList.length === 0) {
|
|
||||||
this.$message.warning(this.$t(this.key('please_select_file')))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.importLoading = true
|
|
||||||
try {
|
|
||||||
const file = this.importFileList[0].raw || this.importFileList[0]
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('file', file)
|
|
||||||
|
|
||||||
await importTeamManagement(formData)
|
|
||||||
this.$message.success(this.$t(this.key('import_success')))
|
|
||||||
this.importDialogVisible = false
|
|
||||||
this.fetchData()
|
|
||||||
} catch (error) {
|
|
||||||
this.$message.error(this.$t(this.key('import_failed')))
|
|
||||||
} finally {
|
|
||||||
this.importLoading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async handleExportCommand(command) {
|
|
||||||
if (command === 'export') {
|
|
||||||
// 直接导出
|
|
||||||
try {
|
|
||||||
const res = await exportTeamManagementTask({...this.search, action: 'download'})
|
|
||||||
// 创建下载链接
|
|
||||||
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
|
||||||
const url = window.URL.createObjectURL(blob)
|
|
||||||
const a = document.createElement('a')
|
|
||||||
a.href = url
|
|
||||||
a.download = 'team_management_export.xlsx'
|
|
||||||
a.click()
|
|
||||||
window.URL.revokeObjectURL(url)
|
|
||||||
} catch (error) {
|
|
||||||
this.$message.error(this.$t(this.key('export_failed')))
|
|
||||||
}
|
|
||||||
} else if (command === 'export_task') {
|
|
||||||
// 创建下载任务
|
|
||||||
try {
|
|
||||||
await exportTeamManagementTask({...this.search, action: 'task'})
|
|
||||||
this.$message.success(this.$t(this.key('download_task_created')))
|
|
||||||
// 跳转到下载任务页面
|
|
||||||
this.$router.push({ name: 'task' })
|
|
||||||
} catch (error) {
|
|
||||||
this.$message.error(this.$t(this.key('create_download_task_failed')))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 以下是成员管理相关方法
|
|
||||||
areaDataChange(value) {
|
|
||||||
this.loadLineOptionsByArea(value)
|
|
||||||
},
|
|
||||||
handleTeamAddMembers() {
|
|
||||||
// 添加一个新的成员行
|
|
||||||
this.membersData.push({
|
|
||||||
user_id: null,
|
|
||||||
is_main: 0
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleMembersDelete(row, index) {
|
|
||||||
this.membersData.splice(index, 1)
|
this.membersData.splice(index, 1)
|
||||||
},
|
},
|
||||||
is_main_change(val, index) {
|
submitDialog () {
|
||||||
// 确保只有一个主负责人
|
this.$refs.form.validate(async valid => {
|
||||||
if (val === 1) {
|
if (!valid) return
|
||||||
this.membersData.forEach((item, idx) => {
|
this.submitting = true
|
||||||
if (idx !== index) {
|
try {
|
||||||
item.is_main = 0
|
const payload = { ...this.formData, membersData: this.membersData }
|
||||||
}
|
if (this.handleType === 'create') await createTeam(payload)
|
||||||
})
|
else await editTeam({ ...payload, id: this.editId })
|
||||||
}
|
this.$message.success(this.$t(this.key('operation_successful')))
|
||||||
},
|
this.closeDialog(); this.fetchData()
|
||||||
handleSizeChange(val) {
|
} finally { this.submitting = false }
|
||||||
this.pagination.pageSize = val
|
|
||||||
this.fetchData()
|
|
||||||
},
|
|
||||||
handleCurrentChange(val) {
|
|
||||||
this.pagination.currentPage = val
|
|
||||||
this.fetchData()
|
|
||||||
},
|
|
||||||
handleSubmitDialogMembersAdd() {
|
|
||||||
// 验证表单
|
|
||||||
this.$refs.teamForm.validate((valid) => {
|
|
||||||
if (valid) {
|
|
||||||
this.onDialogSubmit()
|
|
||||||
} else {
|
|
||||||
this.$message.error(this.$t(this.key('validation_failed')))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
closeDialog () { this.dialogVisible = false; this.formData = { name: '', area_id: '', line_id: '' }; this.membersData = []; this.formLineOptions = []; this.leaderIndex = undefined; this.editId = '' },
|
||||||
|
async handleDelete (row) {
|
||||||
|
const cancelled = await this.$confirmAction({ message: this.key('delete_team_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteTeam({ id: [row.id] }))
|
||||||
|
if (cancelled) return
|
||||||
|
this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData()
|
||||||
|
},
|
||||||
|
async handleBatchDelete () {
|
||||||
|
if (!this.selectedRows.length) { this.$message.error(this.$t(this.key('please_select_table_data'))); return }
|
||||||
|
const cancelled = await this.$confirmAction({ message: this.key('batch_delete_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteTeam({ id: this.selectedRows.map(item => item.id) }))
|
||||||
|
if (cancelled) return
|
||||||
|
this.$message.success(this.$t(this.key('operation_successful'))); this.fetchData()
|
||||||
|
},
|
||||||
|
openImport () { this.importFileList = []; this.importRows = []; this.importVisible = true },
|
||||||
|
async downloadTemplate () { this.importLoading = true; try { const res = await getTeamImportTemplate({}); downloadRename(res, 'xlsx', this.$t(this.key('team_data_import_template'))) } finally { this.importLoading = false } },
|
||||||
|
async onImportFileChange (file) {
|
||||||
|
if (!file || !/\.(xls|xlsx)$/i.test(file.name)) { this.$message.error(this.$t(this.key('upload_format_error'))); return }
|
||||||
|
this.importFileList = [file]
|
||||||
|
this.importTableLoading = true
|
||||||
|
try {
|
||||||
|
const rows = await readExcel(file.raw)
|
||||||
|
this.importRows = rows.map(row => ({ name: row['班组名称'], area_name: row['所属厂区'], line_name: row['所属产线'], members_user_name: row['成员名称'], is_main: row['是否班组组长'] }))
|
||||||
|
} finally { this.importTableLoading = false }
|
||||||
|
},
|
||||||
|
async submitImport () {
|
||||||
|
if (!this.importRows.length) { this.$message.error(this.$t(this.key('please_import_department_data'))); return }
|
||||||
|
await importTeamData({ import_data: JSON.stringify(this.importRows) })
|
||||||
|
this.$message.success(this.$t(this.key('operation_successful'))); this.importVisible = false; this.fetchData()
|
||||||
|
},
|
||||||
|
async handleExport () {
|
||||||
|
const cancelled = await this.$confirmAction({ message: this.key('export_confirm_message'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => exportTeamTask({ ...this.search, action: 'download' }))
|
||||||
|
if (cancelled) return
|
||||||
|
this.$message.success(this.$t(this.key('download_task_created')))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.search-bar {
|
.search-bar { padding: 10px 0; }
|
||||||
padding: 10px 0;
|
/deep/ .el-form-item--mini.el-form-item { margin-bottom: 4px; }
|
||||||
}
|
</style>
|
||||||
/deep/ .el-form-item--mini.el-form-item {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
/deep/ .el-table .el-table__header th {
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<template #header>
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form :inline="true" size="mini">
|
||||||
|
<el-form-item :label="$t(key('monitor_code'))">
|
||||||
|
<el-input v-model.trim="search.code" :placeholder="$t(key('enter_monitor_code'))" clearable style="width:200px" @keyup.enter.native="onSearch" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('monitor_name'))">
|
||||||
|
<el-input v-model.trim="search.name" :placeholder="$t(key('enter_monitor_name'))" clearable style="width:200px" @keyup.enter.native="onSearch" />
|
||||||
|
</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" auto-height @page-change="onPageChange" />
|
||||||
|
|
||||||
|
<page-dialog-form ref="dialogForm" :visible.sync="dialogVisible" :title="dialogTitle" width="42%" :form-cols="formCols" :form-data="formData" :rules="rules" label-width="150px" :submitting="submitting" :confirm-text="key('confirm')" :cancel-text="key('cancel')" @submit="onDialogSubmit" @close="onDialogClose" />
|
||||||
|
</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 PageTable from '@/components/page-table'
|
||||||
|
import PageDialogForm from '@/components/page-dialog-form'
|
||||||
|
import { getMonitoringConfigurationList, createMonitoringConfiguration, editMonitoringConfiguration, deleteMonitoringConfiguration } from '@/api/system-administration/monitoring-configuration'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'system-administration-monitoring-configuration',
|
||||||
|
components: { PageTable, PageDialogForm },
|
||||||
|
mixins: [i18nMixin('page.system_administration.system_monitoring.monitoring_configuration'), confirmMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
submitting: false,
|
||||||
|
tableData: [],
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '',
|
||||||
|
editId: '',
|
||||||
|
handleType: 'create',
|
||||||
|
search: { code: '', name: '' },
|
||||||
|
pagination: { current: 1, size: 10, total: 0 },
|
||||||
|
formData: this.defaultFormData(),
|
||||||
|
rules: {
|
||||||
|
code: [
|
||||||
|
{ required: true, message: this.key('please_enter_monitor_code'), trigger: 'blur' },
|
||||||
|
{ min: 1, max: 100, message: this.key('length_1_to_100'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
name: [
|
||||||
|
{ required: true, message: this.key('please_enter_monitor_name'), trigger: 'blur' },
|
||||||
|
{ min: 1, max: 100, message: this.key('length_1_to_100'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
ip: [
|
||||||
|
{ required: true, message: this.key('please_enter_ip_address'), trigger: 'blur' },
|
||||||
|
{ min: 1, max: 100, message: this.key('length_1_to_100'), trigger: 'blur' }
|
||||||
|
],
|
||||||
|
port: [
|
||||||
|
{ required: true, message: this.key('please_enter_port'), trigger: 'blur' },
|
||||||
|
{ min: 1, max: 100, message: this.key('length_1_to_100'), trigger: 'blur' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
columns: [],
|
||||||
|
toolbarButtons: [],
|
||||||
|
rowButtons: [],
|
||||||
|
formCols: [
|
||||||
|
[{ type: 'input', prop: 'code', label: this.key('monitor_code'), placeholder: this.key('enter_monitor_code'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'name', label: this.key('monitor_name'), placeholder: this.key('enter_monitor_name'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'ip', label: this.key('ip_address'), placeholder: this.key('enter_ip_address'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'port', label: this.key('port'), placeholder: this.key('enter_port'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'refresh_interval', label: this.key('refresh_interval'), placeholder: this.key('enter_refresh_interval'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'disk_warning', label: this.key('disk_warning'), placeholder: this.key('enter_disk_warning'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'cpu_warning', label: this.key('cpu_warning'), placeholder: this.key('enter_cpu_warning'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'mem_warning', label: this.key('memory_swap_warning'), placeholder: this.key('enter_memory_swap_warning'), clearable: true, style: { width: '90%' } }],
|
||||||
|
[{ type: 'input', prop: 'version', label: this.key('python_version'), placeholder: this.key('enter_python_version'), clearable: true, style: { width: '90%' } }]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.columns = useTableColumns([
|
||||||
|
{ prop: 'sort', label: this.key('serial_number'), width: 90 },
|
||||||
|
{ prop: 'code', label: this.key('monitor_code'), minWidth: 120 },
|
||||||
|
{ prop: 'name', label: this.key('monitor_name'), minWidth: 140 },
|
||||||
|
{ prop: 'ip', label: this.key('ip_address'), minWidth: 140 },
|
||||||
|
{ prop: 'port', label: this.key('port'), width: 100 },
|
||||||
|
{ prop: 'version', label: this.key('python_version'), minWidth: 120 },
|
||||||
|
{ prop: 'refresh_interval', label: this.key('refresh_interval'), minWidth: 130 },
|
||||||
|
{ prop: 'cpu_warning', label: this.key('cpu_warning'), minWidth: 120 },
|
||||||
|
{ prop: 'disk_warning', label: this.key('disk_warning'), minWidth: 120 },
|
||||||
|
{ prop: 'mem_warning', label: this.key('memory_swap_warning'), minWidth: 150 },
|
||||||
|
{ prop: '_actions', label: this.key('operation'), width: 160, fixed: 'right' }
|
||||||
|
])
|
||||||
|
const btns = useTableButtons({
|
||||||
|
toolbar: [
|
||||||
|
{ key: 'add', label: this.key('add'), icon: 'el-icon-plus', type: 'primary', auth: '/system_settings/system_monitor/setting/create', onClick: this.openAdd }
|
||||||
|
],
|
||||||
|
row: [
|
||||||
|
{ key: 'edit', label: this.key('edit'), icon: 'el-icon-edit', auth: '/system_settings/system_monitor/setting/edit', onClick: this.openEdit },
|
||||||
|
{ key: 'delete', label: this.key('delete'), icon: 'el-icon-delete', color: 'danger', auth: '/system_settings/system_monitor/setting/delete', onClick: this.handleDelete }
|
||||||
|
]
|
||||||
|
}, this.$permission)
|
||||||
|
this.toolbarButtons = btns.toolbarButtons
|
||||||
|
this.rowButtons = btns.rowButtons
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
defaultFormData () {
|
||||||
|
return { code: '', name: '', ip: '', port: '', refresh_interval: 1000, disk_warning: 90, cpu_warning: 90, mem_warning: 90, version: 3 }
|
||||||
|
},
|
||||||
|
async fetchData () {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await getMonitoringConfigurationList({ ...this.search, page_no: this.pagination.current, page_size: this.pagination.size })
|
||||||
|
const data = res && res.data ? res.data : res
|
||||||
|
this.tableData = (data && data.data) || data || []
|
||||||
|
this.pagination.total = Number((data && data.count) || 0)
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSearch () {
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onReset () {
|
||||||
|
this.search = { code: '', name: '' }
|
||||||
|
this.pagination.current = 1
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
onPageChange (page) {
|
||||||
|
this.pagination.current = page.current
|
||||||
|
this.pagination.size = page.size
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
resetForm () {
|
||||||
|
this.formData = this.defaultFormData()
|
||||||
|
this.editId = ''
|
||||||
|
},
|
||||||
|
openAdd () {
|
||||||
|
this.handleType = 'create'
|
||||||
|
this.dialogTitle = this.key('add_monitor_config')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.dialogForm && this.$refs.dialogForm.reset()
|
||||||
|
this.resetForm()
|
||||||
|
this.dialogVisible = true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
openEdit (row) {
|
||||||
|
this.handleType = 'edit'
|
||||||
|
this.dialogTitle = this.key('edit_monitor_config')
|
||||||
|
this.editId = row.id
|
||||||
|
this.formData = { code: row.code, name: row.name, ip: row.ip, port: row.port, refresh_interval: row.refresh_interval, disk_warning: row.disk_warning, cpu_warning: row.cpu_warning, mem_warning: row.mem_warning, version: row.version }
|
||||||
|
this.dialogVisible = true
|
||||||
|
},
|
||||||
|
async onDialogSubmit () {
|
||||||
|
this.submitting = true
|
||||||
|
try {
|
||||||
|
if (this.handleType === 'create') await createMonitoringConfiguration(this.formData)
|
||||||
|
else await editMonitoringConfiguration({ ...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.resetForm()
|
||||||
|
},
|
||||||
|
async handleDelete (row) {
|
||||||
|
const cancelled = await this.$confirmAction({ message: this.key('confirm_operation'), title: this.key('prompt'), confirmButtonText: this.key('confirm'), cancelButtonText: this.key('cancel') }, () => deleteMonitoringConfiguration({ id: [row.id] }))
|
||||||
|
if (cancelled) return
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-bar {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
/deep/ .el-form-item--mini.el-form-item {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user