新增三模块批量删除API+采集地址启用停用+安装测试脚本

main
haoliang 5 days ago
parent bfb9c5a014
commit b76f1acc55

@ -1,11 +1,17 @@
<template> <template>
<div> <div>
<div class="mb-16"><el-button type="primary" @click="handleAdd">+ </el-button></div> <div class="mb-16">
<el-button type="primary" @click="handleAdd">+ </el-button>
<el-button v-if="selectedRows.length" size="default" @click="batchToggle(1)">({{ selectedRows.length }})</el-button>
<el-button v-if="selectedRows.length" size="default" @click="batchToggle(0)">({{ selectedRows.length }})</el-button>
<el-button v-if="selectedRows.length" size="default" type="danger" @click="handleBatchDelete">({{ selectedRows.length }})</el-button>
</div>
<el-form :inline="true" class="mb-16"> <el-form :inline="true" class="mb-16">
<el-form-item label="品牌"><el-select v-model="query.brandId" clearable><el-option v-for="b in brandList" :key="b.id" :label="b.brandName" :value="b.id"/></el-select></el-form-item> <el-form-item label="品牌"><el-select v-model="query.brandId" clearable><el-option v-for="b in brandList" :key="b.id" :label="b.brandName" :value="b.id"/></el-select></el-form-item>
<el-form-item><el-button type="primary" @click="loadData"></el-button><el-button @click="resetQuery"></el-button></el-form-item> <el-form-item><el-button type="primary" @click="loadData"></el-button><el-button @click="resetQuery"></el-button></el-form-item>
</el-form> </el-form>
<el-table :data="tableData" border stripe v-loading="loading"> <el-table :data="tableData" border stripe v-loading="loading" @selection-change="(rows: CollectAddress[]) => selectedRows = rows">
<el-table-column type="selection" width="50" fixed="left" align="center" />
<el-table-column prop="name" label="名称"><template #default="{row}"><el-link type="primary" @click="goDetail(row.id)">{{row.name}}</el-link></template></el-table-column> <el-table-column prop="name" label="名称"><template #default="{row}"><el-link type="primary" @click="goDetail(row.id)">{{row.name}}</el-link></template></el-table-column>
<el-table-column prop="url" label="URL" min-width="200" show-overflow-tooltip/> <el-table-column prop="url" label="URL" min-width="200" show-overflow-tooltip/>
<el-table-column prop="brandName" label="品牌" align="center"/> <el-table-column prop="brandName" label="品牌" align="center"/>
@ -67,7 +73,7 @@ import request from '@/utils/request'
import {useMockMode} from '@/composables/useMockMode' import {useMockMode} from '@/composables/useMockMode'
import type { ApiResponse, Brand, CollectAddress } from '@/types' import type { ApiResponse, Brand, CollectAddress } from '@/types'
const router=useRouter();const{isMock}=useMockMode() const router=useRouter();const{isMock}=useMockMode()
const loading=ref(false);const tableData=ref<CollectAddress[]>([]);const brandList=ref<Brand[]>([]) const loading=ref(false);const tableData=ref<CollectAddress[]>([]);const brandList=ref<Brand[]>([]);const selectedRows=ref<CollectAddress[]>([])
const dialogVisible=ref(false);const submitting=ref(false);const editingId=ref<number|null>(null) const dialogVisible=ref(false);const submitting=ref(false);const editingId=ref<number|null>(null)
const query=reactive({brandId:undefined as number|undefined}) const query=reactive({brandId:undefined as number|undefined})
const form=reactive({name:'',url:'',brandId:undefined as number|undefined,collectInterval:30,machineIds:[] as number[]}) const form=reactive({name:'',url:'',brandId:undefined as number|undefined,collectInterval:30,machineIds:[] as number[]})
@ -133,6 +139,22 @@ async function handleDelete(row:any){
} }
async function loadDrops(){const r:any=await request.get('/admin/brand');brandList.value=r.data?.items||[]} async function loadDrops(){const r:any=await request.get('/admin/brand');brandList.value=r.data?.items||[]}
async function batchToggle(isEnabled:number){
await ElMessageBox.confirm('确定对选中的'+selectedRows.value.length+'项操作?','提示',{type:'warning'})
for(const row of selectedRows.value){
if((isEnabled===1&&!row.isEnabled)||(isEnabled===0&&row.isEnabled)){
await request.put(`/admin/collect-address/${row.id}/toggle`)
}
}
ElMessage.success('操作成功');loadData()
}
async function handleBatchDelete(){
await ElMessageBox.confirm('确定删除选中的'+selectedRows.value.length+'个采集地址?此操作不可恢复。','提示',{type:'warning'})
await request.post('/admin/collect-address/batch-delete',{ids:selectedRows.value.map((r:any)=>r.id)})
ElMessage.success('批量删除成功');loadData()
}
/** 机床状态色点 */ /** 机床状态色点 */
function dotStyle(m: TransferMachine): Record<string, string> { function dotStyle(m: TransferMachine): Record<string, string> {
const color = !m.isEnabled ? '#f56c6c' : m.isOnline ? '#67c23a' : '#c0c4cc' const color = !m.isEnabled ? '#f56c6c' : m.isOnline ? '#67c23a' : '#c0c4cc'

@ -6,6 +6,7 @@
<el-button type="success" @click="handleExport"></el-button> <el-button type="success" @click="handleExport"></el-button>
<el-button v-if="selectedRows.length" size="default" @click="batchToggle(0)" :disabled="!selectedRows.some(r => r.isEnabled)">({{ selectedRows.length }})</el-button> <el-button v-if="selectedRows.length" size="default" @click="batchToggle(0)" :disabled="!selectedRows.some(r => r.isEnabled)">({{ selectedRows.length }})</el-button>
<el-button v-if="selectedRows.length" size="default" type="primary" @click="batchToggle(1)" :disabled="!selectedRows.some(r => !r.isEnabled)">({{ selectedRows.length }})</el-button> <el-button v-if="selectedRows.length" size="default" type="primary" @click="batchToggle(1)" :disabled="!selectedRows.some(r => !r.isEnabled)">({{ selectedRows.length }})</el-button>
<el-button v-if="selectedRows.length" size="default" type="danger" @click="handleBatchDelete">({{ selectedRows.length }})</el-button>
</div> </div>
<el-form :inline="true" class="mb-16"> <el-form :inline="true" class="mb-16">
@ -268,6 +269,13 @@ async function batchToggle(isEnabled: number) {
loadData() loadData()
} }
async function handleBatchDelete() {
await ElMessageBox.confirm(`确定删除选中的${selectedRows.value.length}台机床?此操作不可恢复。`, '提示', { type: 'warning' })
await request.post('/admin/machine/batch-delete', { ids: selectedRows.value.map((r: Machine) => r.id) })
ElMessage.success('批量删除成功')
loadData()
}
async function handleExport() { async function handleExport() {
const baseURL = (request as any).defaults?.baseURL || '' const baseURL = (request as any).defaults?.baseURL || ''
const qs = new URLSearchParams(query as any).toString() const qs = new URLSearchParams(query as any).toString()

@ -4,13 +4,14 @@
<el-button type="primary" @click="handleAdd">+ </el-button> <el-button type="primary" @click="handleAdd">+ </el-button>
<el-button v-if="selectedRows.length" size="default" @click="batchStatus(1)">({{ selectedRows.length }})</el-button> <el-button v-if="selectedRows.length" size="default" @click="batchStatus(1)">({{ selectedRows.length }})</el-button>
<el-button v-if="selectedRows.length" size="default" @click="batchStatus(0)">({{ selectedRows.length }})</el-button> <el-button v-if="selectedRows.length" size="default" @click="batchStatus(0)">({{ selectedRows.length }})</el-button>
<el-button v-if="selectedRows.length" size="default" type="danger" @click="handleBatchDelete">({{ selectedRows.length }})</el-button>
</div> </div>
<el-form :inline="true" class="mb-16"> <el-form :inline="true" class="mb-16">
<el-form-item label="状态"><el-select v-model="query.isEnabled" clearable><el-option label="启用" :value="1"/><el-option label="停用" :value="0"/></el-select></el-form-item> <el-form-item label="状态"><el-select v-model="query.isEnabled" clearable><el-option label="启用" :value="1"/><el-option label="停用" :value="0"/></el-select></el-form-item>
<el-form-item><el-input v-model="query.keyword" placeholder="工号/姓名" clearable/></el-form-item> <el-form-item><el-input v-model="query.keyword" placeholder="工号/姓名" clearable/></el-form-item>
<el-form-item><el-button type="primary" @click="loadData"></el-button><el-button @click="resetQuery"></el-button></el-form-item> <el-form-item><el-button type="primary" @click="loadData"></el-button><el-button @click="resetQuery"></el-button></el-form-item>
</el-form> </el-form>
<el-table :data="tableData" border stripe v-loading="loading"> <el-table :data="tableData" border stripe v-loading="loading" @selection-change="(rows: Worker[]) => selectedRows = rows">
<el-table-column type="selection" width="50"/> <el-table-column type="selection" width="50"/>
<el-table-column prop="code" label="工号"/> <el-table-column prop="code" label="工号"/>
<el-table-column prop="name" label="姓名"><template #default="{row}"><el-link type="primary" @click="goDetail(row.id)">{{row.name}}</el-link></template></el-table-column> <el-table-column prop="name" label="姓名"><template #default="{row}"><el-link type="primary" @click="goDetail(row.id)">{{row.name}}</el-link></template></el-table-column>
@ -146,6 +147,7 @@ async function loadTransferData(workerId?: number){
async function handleSubmit(){submitting.value=true;try{const ok = await (workerForm.value?.validate ? new Promise<boolean>((resolve)=>workerForm.value!.validate((valid:boolean)=>resolve(valid))) : Promise.resolve(true)); if(!ok){return} await request[editingId.value?'put':'post'](editingId.value?`/admin/worker/${editingId.value}`:'/admin/worker',{...form});ElMessage.success('保存成功');dialogVisible.value=false;loadData()}finally{submitting.value=false}} async function handleSubmit(){submitting.value=true;try{const ok = await (workerForm.value?.validate ? new Promise<boolean>((resolve)=>workerForm.value!.validate((valid:boolean)=>resolve(valid))) : Promise.resolve(true)); if(!ok){return} await request[editingId.value?'put':'post'](editingId.value?`/admin/worker/${editingId.value}`:'/admin/worker',{...form});ElMessage.success('保存成功');dialogVisible.value=false;loadData()}finally{submitting.value=false}}
async function handleDelete(row:any){await ElMessageBox.confirm('确定删除【'+row.name+'】?此操作不可恢复。','提示',{type:'warning'});await request.delete(`/admin/worker/${row.id}`);ElMessage.success('已删除');loadData()} async function handleDelete(row:any){await ElMessageBox.confirm('确定删除【'+row.name+'】?此操作不可恢复。','提示',{type:'warning'});await request.delete(`/admin/worker/${row.id}`);ElMessage.success('已删除');loadData()}
async function batchStatus(isEnabled:number){await ElMessageBox.confirm('确定对选中的'+selectedRows.value.length+'项操作?','提示',{type:'warning'});for(const id of selectedRows.value.map((r:any)=>r.id)){await request.put(`/admin/worker/${id}/toggle`,{isEnabled})};ElMessage.success('操作成功');loadData()} async function batchStatus(isEnabled:number){await ElMessageBox.confirm('确定对选中的'+selectedRows.value.length+'项操作?','提示',{type:'warning'});for(const id of selectedRows.value.map((r:any)=>r.id)){await request.put(`/admin/worker/${id}/toggle`,{isEnabled})};ElMessage.success('操作成功');loadData()}
async function handleBatchDelete(){await ElMessageBox.confirm('确定删除选中的'+selectedRows.value.length+'个员工?此操作不可恢复。','提示',{type:'warning'});await request.post('/admin/worker/batch-delete',{ids:selectedRows.value.map((r:any)=>r.id)});ElMessage.success('批量删除成功');loadData()}
function handlePageChange(page:number){pagination.value.currentPage=page;loadData()} function handlePageChange(page:number){pagination.value.currentPage=page;loadData()}
function handleSizeChange(size:number){pagination.value.pageSize=size;pagination.value.currentPage=1;loadData()} function handleSizeChange(size:number){pagination.value.pageSize=size;pagination.value.currentPage=1;loadData()}
/** 根据机床在线/启用状态返回色点内联样式 */ /** 根据机床在线/启用状态返回色点内联样式 */

@ -0,0 +1,116 @@
# CNC 采集服务 - 一键安装脚本
# 需要管理员权限运行
# 用法: .\install.ps1
$ErrorActionPreference = "Stop"
$serviceName = "CncCollector"
$installDir = "C:\CncCollector"
$projectDir = Split-Path -Parent $PSScriptRoot
$exePath = Join-Path $projectDir "bin\CncCollector.exe"
Write-Host "================================================" -ForegroundColor Cyan
Write-Host " CNC 机床数据采集服务 - 安装脚本 v1.0" -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
# 检查管理员权限
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "[错误] 请以管理员权限运行此脚本!" -ForegroundColor Red
exit 1
}
# 检查 exe 是否存在
if (-not (Test-Path $exePath)) {
Write-Host "[错误] 找不到 CncCollector.exe请先编译项目。" -ForegroundColor Red
Write-Host " 预期路径: $exePath" -ForegroundColor Yellow
exit 1
}
# 步骤1创建安装目录
Write-Host "`n[1/5] 创建安装目录: $installDir" -ForegroundColor Green
if (-not (Test-Path $installDir)) {
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
}
# 步骤2复制文件
Write-Host "[2/5] 复制程序文件..." -ForegroundColor Green
$binDir = Join-Path $projectDir "bin"
$files = Get-ChildItem -Path $binDir -Filter "*.dll" | Select-Object -ExpandProperty FullName
$files += Get-ChildItem -Path $binDir -Filter "*.exe" | Select-Object -ExpandProperty FullName
$configFiles = @(
(Join-Path $projectDir "collector.json"),
(Join-Path $projectDir "log4net.config")
)
foreach ($f in $files) {
Copy-Item $f $installDir -Force
}
foreach ($f in $configFiles) {
if (Test-Path $f) {
Copy-Item $f $installDir -Force
}
}
Write-Host " 已复制 $($files.Count) 个程序文件 + 配置文件" -ForegroundColor Gray
# 步骤3检查是否已安装
Write-Host "[3/5] 检查服务状态..." -ForegroundColor Green
$existingService = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($existingService) {
Write-Host " 服务已存在,正在停止并删除..." -ForegroundColor Yellow
if ($existingService.Status -eq 'Running') {
Stop-Service -Name $serviceName -Force
Start-Sleep -Seconds 2
}
sc.exe delete $serviceName | Out-Null
Start-Sleep -Seconds 1
}
# 步骤4使用 NSSM 或 sc 安装服务
Write-Host "[4/5] 安装Windows服务..." -ForegroundColor Green
$nssmPath = Join-Path $installDir "nssm.exe"
$targetExe = Join-Path $installDir "CncCollector.exe"
# 优先尝试 NSSM更可靠
$nssmAvailable = $false
try {
$nssmCheck = Get-Command nssm -ErrorAction SilentlyContinue
if ($nssmCheck) {
$nssmAvailable = $true
}
} catch {}
if ($nssmAvailable) {
Write-Host " 使用 NSSM 安装服务..." -ForegroundColor Gray
nssm install $serviceName $targetExe
nssm set $serviceName AppDirectory $installDir
nssm set $serviceName DisplayName "CNC 机床数据采集服务"
nssm set $serviceName Description "CNC机床HTTP采集、数据解析、产量跟踪和日终汇总"
nssm set $serviceName Start SERVICE_AUTO_START
nssm set $serviceName AppStdout (Join-Path $installDir "service_stdout.log")
nssm set $serviceName AppStderr (Join-Path $installDir "service_stderr.log")
} else {
Write-Host " 使用 sc.exe 安装服务..." -ForegroundColor Gray
sc.exe create $serviceName binPath= $targetExe start= auto DisplayName= "CNC 机床数据采集服务" | Out-Null
}
# 步骤5启动服务
Write-Host "[5/5] 启动服务..." -ForegroundColor Green
Start-Service -Name $serviceName -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3
$svc = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($svc -and $svc.Status -eq 'Running') {
Write-Host "`n[成功] 采集服务已安装并启动!" -ForegroundColor Green
Write-Host " 服务名称: $serviceName" -ForegroundColor Gray
Write-Host " 安装目录: $installDir" -ForegroundColor Gray
Write-Host " 管理API: http://localhost:5800/api/collector/status" -ForegroundColor Gray
} else {
Write-Host "`n[警告] 服务已安装但未能启动,请检查配置和日志。" -ForegroundColor Yellow
Write-Host " 日志目录: $installDir" -ForegroundColor Gray
}
Write-Host "`n常用命令:" -ForegroundColor Cyan
Write-Host " 启动: Start-Service $serviceName" -ForegroundColor Gray
Write-Host " 停止: Stop-Service $serviceName" -ForegroundColor Gray
Write-Host " 卸载: .\uninstall.ps1" -ForegroundColor Gray
Write-Host " 状态: Get-Service $serviceName" -ForegroundColor Gray

@ -0,0 +1,87 @@
# CNC 采集服务 - 快速测试脚本
# 无需安装Windows Service直接在控制台模式下测试
# 用法: .\test.ps1
$ErrorActionPreference = "Continue"
$projectDir = Split-Path -Parent $PSScriptRoot
$exePath = Join-Path $projectDir "bin\CncCollector.exe"
Write-Host "================================================" -ForegroundColor Cyan
Write-Host " CNC 采集服务 - 快速测试脚本" -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
# 检查exe
if (-not (Test-Path $exePath)) {
Write-Host "[错误] 找不到 CncCollector.exe请先编译。" -ForegroundColor Red
Write-Host " 运行: dotnet build src\CncCollector\CncCollector.csproj -c Release" -ForegroundColor Yellow
exit 1
}
# 检查数据库连接
Write-Host "`n[1/4] 检查数据库连接..." -ForegroundColor Green
$connStr = "Server=localhost;Database=cnc_business;Uid=root;Pwd=root;Charset=utf8mb4;SslMode=None;"
try {
$conn = New-Object MySql.Data.MySqlClient.MySqlConnection($connStr)
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "SELECT COUNT(*) FROM cnc_collect_address WHERE is_enabled=1"
$addrCount = $cmd.ExecuteScalar()
Write-Host " 数据库连接成功,启用地址数: $addrCount" -ForegroundColor Gray
$conn.Close()
} catch {
Write-Host " [警告] 数据库连接失败: $($_.Exception.Message)" -ForegroundColor Yellow
Write-Host " 将使用模拟器模式测试..." -ForegroundColor Yellow
}
# 检查模拟器
Write-Host "`n[2/4] 检查CncSimulator模拟器..." -ForegroundColor Green
$simProcess = Get-Process -Name "CncSimulator" -ErrorAction SilentlyContinue
if ($simProcess) {
Write-Host " 模拟器已在运行 (PID: $($simProcess.Id))" -ForegroundColor Gray
} else {
$simPath = Join-Path (Split-Path -Parent (Split-Path -Parent $projectDir)) "src\CncSimulator\bin\CncSimulator.exe"
$simPath2 = Join-Path $projectDir "..\..\CncSimulator\bin\CncSimulator.exe"
if (Test-Path $simPath2) { $simPath = $simPath2 }
if (Test-Path $simPath) {
Write-Host " 启动模拟器: $simPath" -ForegroundColor Gray
Start-Process $simPath
Start-Sleep -Seconds 3
} else {
Write-Host " [提示] 模拟器未找到,跳过。采集服务将连接配置的地址。" -ForegroundColor Yellow
}
}
# 启动采集服务
Write-Host "`n[3/4] 启动采集服务(控制台模式)..." -ForegroundColor Green
Write-Host " 程序路径: $exePath" -ForegroundColor Gray
Write-Host " 配置文件: $(Join-Path $projectDir 'collector.json')" -ForegroundColor Gray
Write-Host "`n >>> 采集服务输出 (按 Ctrl+C 退出) <<<`n" -ForegroundColor Yellow
$proc = Start-Process -FilePath $exePath -WorkingDirectory (Split-Path -Parent $exePath) -PassThru -NoNewWindow
# 等待启动
Start-Sleep -Seconds 5
# 测试管理API
Write-Host "`n[4/4] 测试管理API..." -ForegroundColor Green
try {
$response = Invoke-RestMethod -Uri "http://localhost:5800/api/collector/status" -Headers @{ "X-API-Key" = "collector_api_key_2026" } -TimeoutSec 10
Write-Host " 状态API响应:" -ForegroundColor Gray
Write-Host " 运行中: $($response.data.isRunning)" -ForegroundColor Gray
Write-Host " 工作线程: $($response.data.workerCount)" -ForegroundColor Gray
Write-Host " 运行时间: $([math]::Round($response.data.uptimeSeconds, 1))" -ForegroundColor Gray
Write-Host "`n[成功] 采集服务运行正常!" -ForegroundColor Green
} catch {
Write-Host " [警告] 状态API请求失败: $($_.Exception.Message)" -ForegroundColor Yellow
}
# 等待用户操作
Write-Host "`n采集服务正在运行中,按任意键停止..." -ForegroundColor Cyan
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
# 停止
if (-not $proc.HasExited) {
Stop-Process -Id $proc.Id -Force
Write-Host "采集服务已停止。" -ForegroundColor Gray
}

@ -0,0 +1,43 @@
# CNC 采集服务 - 卸载脚本
# 需要管理员权限运行
# 用法: .\uninstall.ps1
$ErrorActionPreference = "Stop"
$serviceName = "CncCollector"
Write-Host "================================================" -ForegroundColor Cyan
Write-Host " CNC 机床数据采集服务 - 卸载脚本" -ForegroundColor Cyan
Write-Host "================================================" -ForegroundColor Cyan
# 检查管理员权限
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "[错误] 请以管理员权限运行此脚本!" -ForegroundColor Red
exit 1
}
$svc = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if (-not $svc) {
Write-Host "[提示] 服务未安装,无需卸载。" -ForegroundColor Yellow
exit 0
}
# 停止服务
if ($svc.Status -eq 'Running') {
Write-Host "[1/2] 停止服务..." -ForegroundColor Green
Stop-Service -Name $serviceName -Force
Start-Sleep -Seconds 3
}
# 删除服务
Write-Host "[2/2] 删除服务..." -ForegroundColor Green
sc.exe delete $serviceName | Out-Null
Start-Sleep -Seconds 2
$check = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if (-not $check) {
Write-Host "`n[成功] 服务已卸载。" -ForegroundColor Green
Write-Host " 提示: 安装目录 C:\CncCollector 未删除,如需请手动清理。" -ForegroundColor Yellow
} else {
Write-Host "[错误] 服务删除失败,请手动检查。" -ForegroundColor Red
}

@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace CncModels.Dto
{
/// <summary>
/// 批量删除请求
/// </summary>
public class BatchDeleteRequest
{
/// <summary>要删除的ID列表</summary>
public List<int> Ids { get; set; }
}
}

@ -101,6 +101,16 @@ namespace CncRepository.Impl
} }
} }
public int BatchDelete(List<int> ids)
{
if (ids == null || ids.Count == 0) return 0;
using (var conn = CreateConnection())
{
var sql = @"DELETE FROM cnc_collect_address WHERE id IN @Ids";
return conn.Execute(sql, new { Ids = ids });
}
}
public bool ToggleEnabled(int id) public bool ToggleEnabled(int id)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())

@ -128,6 +128,16 @@ namespace CncRepository.Impl
} }
} }
public int BatchDelete(List<int> ids)
{
if (ids == null || ids.Count == 0) return 0;
using (var conn = CreateConnection())
{
var sql = @"DELETE FROM cnc_machine WHERE id IN @Ids";
return conn.Execute(sql, new { Ids = ids });
}
}
public bool ToggleEnabled(int id) public bool ToggleEnabled(int id)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())

@ -92,6 +92,16 @@ namespace CncRepository.Impl
} }
} }
public int BatchDelete(List<int> ids)
{
if (ids == null || ids.Count == 0) return 0;
using (var conn = CreateConnection())
{
var sql = @"DELETE FROM cnc_worker WHERE id IN @Ids";
return conn.Execute(sql, new { Ids = ids });
}
}
public bool ToggleEnabled(int id) public bool ToggleEnabled(int id)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())

@ -15,6 +15,7 @@ namespace CncRepository.Interface
int Create(CollectAddress entity); int Create(CollectAddress entity);
bool Update(CollectAddress entity); bool Update(CollectAddress entity);
bool Delete(int id); bool Delete(int id);
int BatchDelete(List<int> ids);
bool ToggleEnabled(int id); bool ToggleEnabled(int id);
List<CollectAddress> GetEnabledList(); List<CollectAddress> GetEnabledList();
int GetMachineCount(int collectAddressId); int GetMachineCount(int collectAddressId);

@ -16,6 +16,7 @@ namespace CncRepository.Interface
int Create(Machine entity); int Create(Machine entity);
bool Update(Machine entity); bool Update(Machine entity);
bool Delete(int id); bool Delete(int id);
int BatchDelete(List<int> ids);
bool ToggleEnabled(int id); bool ToggleEnabled(int id);
Machine GetByDeviceCode(string deviceCode); Machine GetByDeviceCode(string deviceCode);
List<Machine> GetEnabledByAddressId(int collectAddressId); List<Machine> GetEnabledByAddressId(int collectAddressId);

@ -15,6 +15,7 @@ namespace CncRepository.Interface
int Create(Worker entity); int Create(Worker entity);
bool Update(Worker entity); bool Update(Worker entity);
bool Delete(int id); bool Delete(int id);
int BatchDelete(List<int> ids);
bool ToggleEnabled(int id); bool ToggleEnabled(int id);
Worker GetByCode(string code); Worker GetByCode(string code);
List<Worker> GetAll(); List<Worker> GetAll();

@ -125,6 +125,18 @@ namespace CncService.Impl
return _collectAddressRepository.Delete(id); return _collectAddressRepository.Delete(id);
} }
public int BatchDelete(List<int> ids)
{
if (ids == null || ids.Count == 0) throw new BusinessException(CncModels.Constants.ErrorCode.BadRequest, "请选择要删除的采集地址");
// 检查每个地址下是否有关联机床
foreach (var id in ids)
{
var count = _collectAddressRepository.GetMachineCount(id);
if (count > 0) throw new BusinessException(CncModels.Constants.ErrorCode.DataReferenced, $"地址(ID={id})下有 {count} 台机床,请先解除关联");
}
return _collectAddressRepository.BatchDelete(ids);
}
public bool ToggleEnabled(int id) public bool ToggleEnabled(int id)
{ {
return _collectAddressRepository.ToggleEnabled(id); return _collectAddressRepository.ToggleEnabled(id);

@ -98,6 +98,18 @@ namespace CncService.Impl
return _machineRepository.Delete(id); return _machineRepository.Delete(id);
} }
/// <inheritdoc/>
public int BatchDelete(List<int> ids)
{
if (ids == null || ids.Count == 0) throw new BusinessException(ErrorCode.BadRequest, "请选择要删除的机床");
// 先解绑所有关联工人
foreach (var id in ids)
{
_workerMachineRepository.DeleteByMachineId(id);
}
return _machineRepository.BatchDelete(ids);
}
/// <inheritdoc/> /// <inheritdoc/>
public bool ToggleEnabled(int id) public bool ToggleEnabled(int id)
{ {

@ -136,6 +136,18 @@ namespace CncService.Impl
return _workerRepository.Delete(id); return _workerRepository.Delete(id);
} }
/// <inheritdoc/>
public int BatchDelete(List<int> ids)
{
if (ids == null || ids.Count == 0) throw new BusinessException(ErrorCode.BadRequest, "请选择要删除的员工");
// 先解绑所有机床
foreach (var id in ids)
{
_workerMachineRepository.DeleteByWorkerId(id);
}
return _workerRepository.BatchDelete(ids);
}
/// <inheritdoc/> /// <inheritdoc/>
public bool ToggleEnabled(int id) public bool ToggleEnabled(int id)
{ {

@ -13,6 +13,7 @@ namespace CncService.Interface
int Create(CreateCollectAddressRequest request); int Create(CreateCollectAddressRequest request);
bool Update(int id, UpdateCollectAddressRequest request); bool Update(int id, UpdateCollectAddressRequest request);
bool Delete(int id); bool Delete(int id);
int BatchDelete(List<int> ids);
bool ToggleEnabled(int id); bool ToggleEnabled(int id);
/// <summary> /// <summary>

@ -46,6 +46,13 @@ namespace CncService.Interface
/// <returns>是否删除成功</returns> /// <returns>是否删除成功</returns>
bool Delete(int id); bool Delete(int id);
/// <summary>
/// 批量删除机床并解绑相关工人
/// </summary>
/// <param name="ids">机床ID列表</param>
/// <returns>删除的记录数</returns>
int BatchDelete(List<int> ids);
/// <summary> /// <summary>
/// 启用或禁用机床 /// 启用或禁用机床
/// </summary> /// </summary>

@ -12,6 +12,7 @@ namespace CncService.Interface
int Create(CreateWorkerRequest request); int Create(CreateWorkerRequest request);
bool Update(int id, UpdateWorkerRequest request); bool Update(int id, UpdateWorkerRequest request);
bool Delete(int id); bool Delete(int id);
int BatchDelete(List<int> ids);
bool ToggleEnabled(int id); bool ToggleEnabled(int id);
bool BindMachine(int workerId, int machineId); bool BindMachine(int workerId, int machineId);
bool UnbindMachine(int workerId, int machineId); bool UnbindMachine(int workerId, int machineId);

@ -84,6 +84,18 @@ namespace CncWebApi.Controllers
return Ok(ApiResponse<object>.Success(null)); return Ok(ApiResponse<object>.Success(null));
} }
/// <summary>
/// 批量删除采集地址
/// POST /api/admin/collect-address/batch-delete
/// </summary>
[HttpPost]
[Route("batch-delete")]
public IHttpActionResult BatchDelete([FromBody] BatchDeleteRequest request)
{
var count = _collectAddressService.BatchDelete(request.Ids);
return Ok(ApiResponse<object>.Success(new { count }));
}
/// <summary> /// <summary>
/// 启停地址 /// 启停地址
/// PUT /api/admin/collect-address/{id}/toggle /// PUT /api/admin/collect-address/{id}/toggle

@ -84,6 +84,18 @@ namespace CncWebApi.Controllers
return Ok(ApiResponse<object>.Success(null)); return Ok(ApiResponse<object>.Success(null));
} }
/// <summary>
/// 批量删除机床
/// POST /api/admin/machine/batch-delete
/// </summary>
[HttpPost]
[Route("batch-delete")]
public IHttpActionResult BatchDelete([FromBody] BatchDeleteRequest request)
{
var count = _machineService.BatchDelete(request.Ids);
return Ok(ApiResponse<object>.Success(new { count }));
}
/// <summary> /// <summary>
/// 启停机床 /// 启停机床
/// PUT /api/admin/machine/{id}/toggle /// PUT /api/admin/machine/{id}/toggle

@ -84,6 +84,18 @@ namespace CncWebApi.Controllers
return Ok(ApiResponse<object>.Success(null)); return Ok(ApiResponse<object>.Success(null));
} }
/// <summary>
/// 批量删除工人
/// POST /api/admin/worker/batch-delete
/// </summary>
[HttpPost]
[Route("batch-delete")]
public IHttpActionResult BatchDelete([FromBody] BatchDeleteRequest request)
{
var count = _workerService.BatchDelete(request.Ids);
return Ok(ApiResponse<object>.Success(new { count }));
}
/// <summary> /// <summary>
/// 启停工人 /// 启停工人
/// PUT /api/admin/worker/{id}/toggle /// PUT /api/admin/worker/{id}/toggle

Loading…
Cancel
Save