diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index a47f4ae..731c413 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -39,6 +39,8 @@ export interface Machine { isEnabled: boolean workerName?: string collectAddressName?: string + /** 编辑表单用:品牌ID */ + brandId?: number /** 编辑表单用:所属车间ID */ workshopId?: number /** 编辑表单用:采集地址ID */ @@ -91,6 +93,7 @@ export interface CollectAddress { id: number name: string url: string + brandId: number brandName: string interval: number /** 详情页显示用:采集间隔(秒) */ diff --git a/frontend/src/views/machine/MachineDetailPage.vue b/frontend/src/views/machine/MachineDetailPage.vue index c2291e6..e6373c0 100644 --- a/frontend/src/views/machine/MachineDetailPage.vue +++ b/frontend/src/views/machine/MachineDetailPage.vue @@ -85,16 +85,16 @@ let chart: ECharts | null = null async function loadData() { const id = route.params.id const [d, s, t, r] = await Promise.all([ - request.get('/admin/machine/detail', { params: { id } }), - request.get('/admin/machine/status', { params: { id } }), - request.get<{ items: TodayProdRow[] }>('/admin/machine/production/today', { params: { id } }), - request.get<{ items: CollectRecordRow[] }>('/admin/machine/collect-records', { params: { id } }), + request.get(`/admin/machine/${id}`), + request.get(`/admin/machine/${id}/status`), + request.get<{ items: TodayProdRow[] }>(`/admin/machine/${id}/production/today`), + request.get<{ items: CollectRecordRow[] }>(`/admin/machine/${id}/collect-records`), ]) detail.value = d.data || {} as Machine status.value = s.data || {} as MachineStatus todayProd.value = t.data?.items || [] records.value = r.data?.items || [] - const trend = await request.get<{ items: TrendItem[] }>('/admin/machine/production/trend', { params: { id } }) + const trend = await request.get<{ items: TrendItem[] }>(`/admin/machine/${id}/production/trend`) await nextTick() if (chartRef.value) { chart = echarts.init(chartRef.value) @@ -105,7 +105,7 @@ async function loadData() { async function fetchStatus() { const id = route.params.id - const r = await request.get('/admin/machine/status', { params: { id } }) + const r = await request.get(`/admin/machine/${id}/status`) status.value = r.data || {} as MachineStatus } diff --git a/frontend/src/views/machine/MachineListPage.vue b/frontend/src/views/machine/MachineListPage.vue index 4b978bd..586ecea 100644 --- a/frontend/src/views/machine/MachineListPage.vue +++ b/frontend/src/views/machine/MachineListPage.vue @@ -168,7 +168,7 @@ const editingId = ref(null) const formRef = ref() const form = reactive({ name: '', deviceCode: '', workshopId: undefined as number | undefined, - collectAddressId: undefined as number | undefined, brandName: '', + collectAddressId: undefined as number | undefined, brandId: undefined as number | undefined, brandName: '', ipAddress: '', workerId: undefined as number | undefined, }) @@ -215,7 +215,7 @@ function resetQuery() { function handleAdd() { editingId.value = null - Object.assign(form, { name: '', deviceCode: '', workshopId: undefined, collectAddressId: undefined, brandName: '', ipAddress: '', workerId: undefined }) + Object.assign(form, { name: '', deviceCode: '', workshopId: undefined, collectAddressId: undefined, brandId: undefined, brandName: '', ipAddress: '', workerId: undefined }) dialogVisible.value = true } @@ -223,7 +223,7 @@ function handleEdit(row: Machine) { editingId.value = row.id Object.assign(form, { name: row.name, deviceCode: row.deviceCode, workshopId: row.workshopId, - collectAddressId: row.collectAddressId, brandName: row.brandName, + collectAddressId: row.collectAddressId, brandId: row.brandId, brandName: row.brandName, ipAddress: row.ipAddress, workerId: row.workerId, }) dialogVisible.value = true @@ -231,6 +231,7 @@ function handleEdit(row: Machine) { function onAddressChange(addressId: number) { const addr = addressList.value.find((a: CollectAddress) => a.id === addressId) + form.brandId = addr ? addr.brandId : undefined form.brandName = addr ? addr.brandName : '' } @@ -255,7 +256,12 @@ async function handleDelete(row: Machine) { async function batchToggle(isEnabled: number) { await ElMessageBox.confirm(`确定对选中的${selectedRows.value.length}项操作?`, '提示', { type: 'warning' }) - await request.post('/admin/machine/batch-toggle', { ids: selectedRows.value.map((r: {id:number}) => r.id), isEnabled }) + // 逐个调用toggle接口(后端只提供单个toggle) + for (const row of selectedRows.value) { + if ((isEnabled === 1 && !row.isEnabled) || (isEnabled === 0 && row.isEnabled)) { + await request.put(`/admin/machine/${row.id}/toggle`) + } + } ElMessage.success('操作成功') loadData() } diff --git a/src/CncModels/Dto/Machine/MachineCollectRecordItem.cs b/src/CncModels/Dto/Machine/MachineCollectRecordItem.cs new file mode 100644 index 0000000..e9b6c99 --- /dev/null +++ b/src/CncModels/Dto/Machine/MachineCollectRecordItem.cs @@ -0,0 +1,20 @@ +namespace CncModels.Dto.Machine +{ + /// + /// 机床采集记录项 + /// + public class MachineCollectRecordItem + { + /// 采集时间 + public string CollectTime { get; set; } + + /// NC程序名 + public string ProgramName { get; set; } + + /// 零件计数 + public decimal? PartCount { get; set; } + + /// 运行状态 + public string RunStatus { get; set; } + } +} diff --git a/src/CncModels/Dto/Machine/MachineStatusResponse.cs b/src/CncModels/Dto/Machine/MachineStatusResponse.cs index 99c9d2a..8e45eb2 100644 --- a/src/CncModels/Dto/Machine/MachineStatusResponse.cs +++ b/src/CncModels/Dto/Machine/MachineStatusResponse.cs @@ -5,9 +5,28 @@ namespace CncModels.Dto.Machine /// public class MachineStatusResponse { - public int Status { get; set; } - public System.DateTime? LastUpdate { get; set; } - public string LastProgramName { get; set; } - public string Message { get; set; } + /// NC程序名 + public string ProgramName { get; set; } + + /// 零件计数 + public decimal? PartCount { get; set; } + + /// 运行状态 + public string RunStatus { get; set; } + + /// 操作模式 + public string OperationMode { get; set; } + + /// 主轴设定转速 + public decimal? SpindleSpeedSet { get; set; } + + /// 进给设定速度 + public decimal? FeedSpeedSet { get; set; } + + /// 主轴实际转速 + public decimal? SpindleSpeedActual { get; set; } + + /// 主轴负载(%) + public decimal? SpindleLoad { get; set; } } } diff --git a/src/CncModels/Dto/Machine/MachineTodayProdItem.cs b/src/CncModels/Dto/Machine/MachineTodayProdItem.cs new file mode 100644 index 0000000..a49d3b4 --- /dev/null +++ b/src/CncModels/Dto/Machine/MachineTodayProdItem.cs @@ -0,0 +1,20 @@ +namespace CncModels.Dto.Machine +{ + /// + /// 机床今日产量明细项 + /// + public class MachineTodayProdItem + { + /// NC程序名 + public string ProgramName { get; set; } + + /// 产量 + public int Quantity { get; set; } + + /// 运行时间(分钟) + public decimal? RunTime { get; set; } + + /// 切削时间(分钟) + public decimal? CuttingTime { get; set; } + } +} diff --git a/src/CncModels/Dto/Machine/MachineTrendItem.cs b/src/CncModels/Dto/Machine/MachineTrendItem.cs new file mode 100644 index 0000000..830136a --- /dev/null +++ b/src/CncModels/Dto/Machine/MachineTrendItem.cs @@ -0,0 +1,14 @@ +namespace CncModels.Dto.Machine +{ + /// + /// 机床产量趋势数据项 + /// + public class MachineTrendItem + { + /// 日期(yyyy-MM-dd) + public string Date { get; set; } + + /// 当日产量 + public int Quantity { get; set; } + } +} diff --git a/src/CncService/Impl/MachineService.cs b/src/CncService/Impl/MachineService.cs index b89afde..7257aac 100644 --- a/src/CncService/Impl/MachineService.cs +++ b/src/CncService/Impl/MachineService.cs @@ -127,5 +127,45 @@ namespace CncService.Impl if (id <= 0) throw new BusinessException(ErrorCode.BadRequest, "无效的机床ID"); return _machineRepository.ToggleEnabled(id); } + + /// + public MachineStatusResponse GetStatus(int id) + { + if (id <= 0) throw new BusinessException(ErrorCode.BadRequest, "无效的机床ID"); + var machine = _machineRepository.GetById(id); + if (machine == null) throw new BusinessException(ErrorCode.NotFound, "机床未找到"); + // 采集服务尚未运行,返回空状态 + return new MachineStatusResponse(); + } + + /// + public List GetTodayProduction(int id) + { + if (id <= 0) throw new BusinessException(ErrorCode.BadRequest, "无效的机床ID"); + var machine = _machineRepository.GetById(id); + if (machine == null) throw new BusinessException(ErrorCode.NotFound, "机床未找到"); + // 采集服务尚未运行,暂无产量数据 + return new List(); + } + + /// + public List GetProductionTrend(int id) + { + if (id <= 0) throw new BusinessException(ErrorCode.BadRequest, "无效的机床ID"); + var machine = _machineRepository.GetById(id); + if (machine == null) throw new BusinessException(ErrorCode.NotFound, "机床未找到"); + // 采集服务尚未运行,暂无趋势数据 + return new List(); + } + + /// + public List GetCollectRecords(int id) + { + if (id <= 0) throw new BusinessException(ErrorCode.BadRequest, "无效的机床ID"); + var machine = _machineRepository.GetById(id); + if (machine == null) throw new BusinessException(ErrorCode.NotFound, "机床未找到"); + // 采集服务尚未运行,暂无采集记录 + return new List(); + } } } diff --git a/src/CncService/Interface/IMachineService.cs b/src/CncService/Interface/IMachineService.cs index 113f8f7..ee00b6b 100644 --- a/src/CncService/Interface/IMachineService.cs +++ b/src/CncService/Interface/IMachineService.cs @@ -52,5 +52,33 @@ namespace CncService.Interface /// 机床ID /// 是否切换成功 bool ToggleEnabled(int id); + + /// + /// 获取机床实时采集状态 + /// + /// 机床ID + /// 实时状态信息 + MachineStatusResponse GetStatus(int id); + + /// + /// 获取机床今日产量明细 + /// + /// 机床ID + /// 今日产量列表 + List GetTodayProduction(int id); + + /// + /// 获取机床7天产量趋势 + /// + /// 机床ID + /// 趋势数据列表 + List GetProductionTrend(int id); + + /// + /// 获取机床近期采集记录 + /// + /// 机床ID + /// 采集记录列表 + List GetCollectRecords(int id); } } diff --git a/src/CncWebApi/Controllers/MachineController.cs b/src/CncWebApi/Controllers/MachineController.cs index c16401f..3c4b852 100644 --- a/src/CncWebApi/Controllers/MachineController.cs +++ b/src/CncWebApi/Controllers/MachineController.cs @@ -95,5 +95,53 @@ namespace CncWebApi.Controllers var result = _machineService.ToggleEnabled(id); return Ok(ApiResponse.Success(null)); } + + /// + /// 机床实时采集状态 + /// GET /api/admin/machine/{id}/status + /// + [HttpGet] + [Route("{id:int}/status")] + public IHttpActionResult GetStatus(int id) + { + var result = _machineService.GetStatus(id); + return Ok(ApiResponse.Success(result)); + } + + /// + /// 机床今日产量明细 + /// GET /api/admin/machine/{id}/production/today + /// + [HttpGet] + [Route("{id:int}/production/today")] + public IHttpActionResult GetTodayProduction(int id) + { + var result = _machineService.GetTodayProduction(id); + return Ok(ApiResponse.Success(new { items = result })); + } + + /// + /// 机床7天产量趋势 + /// GET /api/admin/machine/{id}/production/trend + /// + [HttpGet] + [Route("{id:int}/production/trend")] + public IHttpActionResult GetProductionTrend(int id) + { + var result = _machineService.GetProductionTrend(id); + return Ok(ApiResponse.Success(new { items = result })); + } + + /// + /// 机床近期采集记录 + /// GET /api/admin/machine/{id}/collect-records + /// + [HttpGet] + [Route("{id:int}/collect-records")] + public IHttpActionResult GetCollectRecords(int id) + { + var result = _machineService.GetCollectRecords(id); + return Ok(ApiResponse.Success(new { items = result })); + } } }