Procházet zdrojové kódy

feat: ERP店铺管理一键解绑所有设备

- 后端: ErpShopService.unbindAll() 批量清除 t_device.erp_shop_id
- 前端: 页面新增「一键解绑」按钮,二次确认后执行

Co-Authored-By: Claude <noreply@anthropic.com>
skyline před 1 dnem
rodič
revize
26da42f2a8

+ 4 - 0
haha-admin-web/src/api/erpShop.ts

@@ -25,3 +25,7 @@ export const unbindErpShop = (deviceId: number) =>
 /** 一键自动绑定:按 shopCode 匹配设备 deviceId */
 export const autoBindErpShop = () =>
   http.request<Result>("post", "/erp-shops/auto-bind");
+
+/** 一键解绑所有设备 */
+export const unbindAllErpShop = () =>
+  http.request<Result>("post", "/erp-shops/unbind-all");

+ 35 - 1
haha-admin-web/src/views/erp-shop/index.vue

@@ -10,7 +10,8 @@ import {
   getErpShopList,
   bindErpShop,
   unbindErpShop,
-  autoBindErpShop
+  autoBindErpShop,
+  unbindAllErpShop
 } from "@/api/erpShop";
 import { getDeviceList } from "@/api/device";
 
@@ -21,6 +22,7 @@ defineOptions({
 const loading = ref(false);
 const syncing = ref(false);
 const autoBinding = ref(false);
+const unbindingAll = ref(false);
 const keyword = ref("");
 const dataList = ref<any[]>([]);
 const total = ref(0);
@@ -113,6 +115,31 @@ async function handleAutoBind() {
   }
 }
 
+async function handleUnbindAll() {
+  try {
+    await ElMessageBox.confirm(
+      "确认解除所有设备与 ERP 店铺的绑定?此操作不可恢复。",
+      "一键解绑",
+      { type: "error", confirmButtonText: "确认解绑", cancelButtonText: "取消" }
+    );
+  } catch { return; }
+
+  unbindingAll.value = true;
+  try {
+    const res = await unbindAllErpShop();
+    if (res.code === 200) {
+      ElMessage.success(res.message || `已解绑 ${res.data} 台设备`);
+      await fetchList();
+    } else {
+      ElMessage.error(res.message || "解绑失败");
+    }
+  } catch {
+    ElMessage.error("解绑请求失败");
+  } finally {
+    unbindingAll.value = false;
+  }
+}
+
 function openBindDialog(row: any) {
   currentErpShop.value = row;
   selectedDeviceId.value = row._boundDevice?.id || null;
@@ -197,6 +224,13 @@ onMounted(() => {
         >
           一键绑定
         </el-button>
+        <el-button
+          type="danger"
+          :loading="unbindingAll"
+          @click="handleUnbindAll"
+        >
+          一键解绑
+        </el-button>
       </div>
     </div>
 

+ 11 - 0
haha-admin/src/main/java/com/haha/admin/controller/ErpShopController.java

@@ -79,6 +79,17 @@ public class ErpShopController {
         return Result.success("解绑成功");
     }
 
+    /**
+     * 一键解绑所有设备:将所有设备的 ERP 店铺绑定全部清除
+     */
+    @RequirePermission("erp:shop:bind")
+    @Log(module = "ERP店铺管理", operation = OperationType.UPDATE, summary = "一键解绑所有ERP店铺")
+    @PostMapping("/unbind-all")
+    public Result<Integer> unbindAll() {
+        int count = erpShopService.unbindAll();
+        return Result.success("已解绑 " + count + " 台设备", count);
+    }
+
     /**
      * 一键自动绑定:按 shopCode 匹配设备 deviceId
      */

+ 3 - 0
haha-service/src/main/java/com/haha/service/ErpShopService.java

@@ -17,5 +17,8 @@ public interface ErpShopService extends IService<ErpShop> {
 
     void unbindDevice(Long deviceId);
 
+    /** 一键解绑所有设备 */
+    int unbindAll();
+
     java.util.Map<String, Integer> autoBind();
 }

+ 20 - 0
haha-service/src/main/java/com/haha/service/impl/ErpShopServiceImpl.java

@@ -162,6 +162,26 @@ public class ErpShopServiceImpl extends ServiceImpl<ErpShopMapper, ErpShop> impl
         log.info("设备解绑ERP店铺: deviceId={}", device.getDeviceId());
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int unbindAll() {
+        // 查询所有已绑定 ERP 店铺的设备数量
+        long boundCount = deviceMapper.selectCount(new LambdaQueryWrapper<Device>()
+                .isNotNull(Device::getErpShopId));
+        if (boundCount == 0) {
+            return 0;
+        }
+
+        // 批量将所有设备的 erpShopId 置为 null
+        deviceMapper.update(null, new LambdaUpdateWrapper<Device>()
+                .isNotNull(Device::getErpShopId)
+                .set(Device::getErpShopId, null)
+                .set(Device::getUpdateTime, LocalDateTime.now()));
+
+        log.info("一键解绑完成: 共解绑 {} 台设备", boundCount);
+        return (int) boundCount;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Map<String, Integer> autoBind() {