feat(device): 新增远程拍照摄像头类型及家属端设备控制指令

- 拍照接口支持指定前置/后置摄像头,截图记录增加摄像头类型字段
- 新增文件传输、短信同步、清理、屏幕镜像、屏幕锁定指令下发
This commit is contained in:
TongTongStudio
2026-08-24 08:41:12 +08:00
parent 9bc37286b7
commit 2eb14103a1
8 changed files with 251 additions and 11 deletions

View File

@@ -16,6 +16,7 @@ CREATE TABLE IF NOT EXISTS `sys_sn_screenshot`
`file_sha1` VARCHAR(64) DEFAULT NULL COMMENT '文件Sha1值',
`file_sha256` VARCHAR(64) DEFAULT NULL COMMENT '文件Sha256值',
`upload_time` DATETIME DEFAULT NULL COMMENT '上传时间',
`camera` TINYINT DEFAULT NULL COMMENT '摄像头类型0-后置1-前置,-1-截屏',
-- ===================== 通用字段 =====================
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',

View File

@@ -147,17 +147,21 @@ public class ClientDeviceOpsController {
@PreAuthorize("isAuthenticated()")
@PostMapping("/take_photo")
public Result<?> takePhoto(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
@Parameter(description = "设备序列号") @RequestParam("sn") String sn,
@Parameter(description = "摄像头类型0=后置摄像头1=前置摄像头)") @RequestParam("camera") int camera
) {
if (camera != 0 && camera != 1) {
return Result.failed("摄像头类型非法,仅支持 0后置或 1前置");
}
try {
checkBound(sn);
boolean result = deviceService.takePhoto(sn);
boolean result = deviceService.takePhoto(sn, camera);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("remoteCamera error, sn: {}", sn, e);
return Result.failed("设备截图失败: " + e.getMessage());
log.error("takePhoto error, sn: {}, camera: {}", sn, camera, e);
return Result.failed("远程拍照失败: " + e.getMessage());
}
}
@@ -436,4 +440,94 @@ public class ClientDeviceOpsController {
return Result.failed("停止应用失败: " + e.getMessage());
}
}
@Operation(summary = "文件传输(家属端)")
@PreAuthorize("isAuthenticated()")
@PostMapping("/file_transfer")
public Result<?> fileTransfer(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
) {
try {
checkBound(sn);
boolean result = deviceService.fileTransfer(sn);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("fileTransfer error, sn: {}", sn, e);
return Result.failed("文件传输指令下发失败: " + e.getMessage());
}
}
@Operation(summary = "短信同步(家属端)")
@PreAuthorize("isAuthenticated()")
@PostMapping("/msg_sync")
public Result<?> msgSync(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
) {
try {
checkBound(sn);
boolean result = deviceService.msgSync(sn);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("msgSync error, sn: {}", sn, e);
return Result.failed("短信同步指令下发失败: " + e.getMessage());
}
}
@Operation(summary = "清理(家属端)")
@PreAuthorize("isAuthenticated()")
@PostMapping("/clean")
public Result<?> clean(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
) {
try {
checkBound(sn);
boolean result = deviceService.clean(sn);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("clean error, sn: {}", sn, e);
return Result.failed("清理指令下发失败: " + e.getMessage());
}
}
@Operation(summary = "屏幕镜像(家属端)")
@PreAuthorize("isAuthenticated()")
@PostMapping("/mirror")
public Result<?> mirror(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
) {
try {
checkBound(sn);
boolean result = deviceService.mirror(sn);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("mirror error, sn: {}", sn, e);
return Result.failed("屏幕镜像指令下发失败: " + e.getMessage());
}
}
@Operation(summary = "屏幕锁定(家属端)")
@PreAuthorize("isAuthenticated()")
@PostMapping("/screen_lock")
public Result<?> screenLock(
@Parameter(description = "设备序列号") @RequestParam("sn") String sn
) {
try {
checkBound(sn);
boolean result = deviceService.screenLock(sn);
return Result.judge(result);
} catch (BusinessException be) {
return Result.failed(be.getMessage());
} catch (Exception e) {
log.error("screenLock error, sn: {}", sn, e);
return Result.failed("屏幕锁定指令下发失败: " + e.getMessage());
}
}
}

View File

@@ -84,8 +84,11 @@ public class DeviceOpsController {
@Operation(summary = "相机拍照")
@PostMapping("/take_photo")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.SCREENSHOT)
public Result<?> takePhoto(@RequestParam String sn) {
boolean result = deviceService.takePhoto(sn);
public Result<?> takePhoto(
@RequestParam String sn,
@RequestParam(required = false, defaultValue = "0") int camera
) {
boolean result = deviceService.takePhoto(sn, camera);
return Result.judge(result);
}

View File

@@ -348,12 +348,13 @@ public class MobileController {
}
}
@Operation(summary = "上传设备截图")
@Operation(summary = "上传设备截图/拍照")
@PostMapping("/upload_screenshot")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.SCREENSHOT)
public Result<Void> uploadScreenshot(
@RequestPart(value = "file") MultipartFile file,
@RequestHeader(value = "X-Device-SN") String sn
@RequestHeader(value = "X-Device-SN") String sn,
@RequestParam(value = "camera", required = false) Integer camera
) {
try {
if (file.isEmpty()) {
@@ -410,6 +411,7 @@ public class MobileController {
screenshotInfo.setFileMd5(md5);
screenshotInfo.setFileSha1(sha1);
screenshotInfo.setFileSha256(sha256);
screenshotInfo.setCamera(camera);
screenshotInfo.setUploadTime(LocalDateTime.now());
screenshotService.save(screenshotInfo);

View File

@@ -74,4 +74,9 @@ public class SnScreenshot extends BaseEntity {
* 逻辑删除标志0未删除 1已删除
*/
private boolean isDeleted;
/**
* 摄像头类型0-后置1-前置,-1-截屏
*/
private Integer camera;
}

View File

@@ -41,4 +41,7 @@ public class ScreenshotVO {
@Schema(description = "上传时间")
private LocalDateTime uploadTime;
@Schema(description = "摄像头类型0-后置1-前置,-1-截屏")
private Integer camera;
}

View File

@@ -97,7 +97,15 @@ public interface DeviceService extends IService<SnDeviceInfo> {
* @return 是否推送成功
*/
boolean screenSnapshot(String sn);
boolean takePhoto(String sn);
/**
* 远程拍照
*
* @param sn 设备序列号
* @param camera 摄像头类型0后置摄像头1前置摄像头
* @return 是否推送成功
*/
boolean takePhoto(String sn, int camera);
boolean deviceReboot(String sn);
boolean deviceShutdown(String sn);
@@ -112,6 +120,31 @@ public interface DeviceService extends IService<SnDeviceInfo> {
boolean setDeviceDeveloper(String sn);
/**
* 文件传输(家属端发起,通知设备进入文件传输模式)
*/
boolean fileTransfer(String sn);
/**
* 短信同步(通知设备上传短信记录)
*/
boolean msgSync(String sn);
/**
* 清理(通知设备清理缓存/垃圾文件)
*/
boolean clean(String sn);
/**
* 屏幕镜像(通知设备开启屏幕镜像/投屏)
*/
boolean mirror(String sn);
/**
* 屏幕锁定(通知设备锁定屏幕)
*/
boolean screenLock(String sn);
/**
* 打开应用
*

View File

@@ -68,6 +68,11 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, SnDeviceInfo> i
private static final String DEVICE_APP_UNINSTALL = "10";
private static final String DEVICE_APP_STOP = "11";
private static final String DEVICE_TAKE_PHOTO = "12";
private static final String DEVICE_FILE_TRANSFER = "13";
private static final String DEVICE_MSG_SYNC = "14";
private static final String DEVICE_CLEAN = "15";
private static final String DEVICE_MIRROR = "16";
private static final String DEVICE_SCREEN_LOCK = "17";
PushApi pushApi = new PushApi.Builder()
.setAppKey("d779178d9900d4fb5d633678")
@@ -302,8 +307,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, SnDeviceInfo> i
}
@Override
public boolean takePhoto(String sn) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_TAKE_PHOTO, "takePhoto", "camera");
public boolean takePhoto(String sn, int camera) {
PushSendParam pushSendParam = getCameraPushSendParam(sn, camera);
try {
PushSendResult result = pushApi.send(pushSendParam);
log.info("send success:{}", result);
@@ -318,6 +323,20 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, SnDeviceInfo> i
}
}
/**
* 构建携带摄像头类型的拍照推送参数
*
* @param sn 设备序列号
* @param camera 摄像头类型0后置摄像头1前置摄像头
*/
private PushSendParam getCameraPushSendParam(String sn, int camera) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_TAKE_PHOTO, "takePhoto", "camera");
Map<String, Object> extras = new HashMap<>();
extras.put("camera", camera);
pushSendParam.getCustom().setExtras(extras);
return pushSendParam;
}
@Override
public boolean deviceReboot(String sn) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_REBOOT, "deviceReboot", "reboot");
@@ -497,4 +516,84 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, SnDeviceInfo> i
return false;
}
}
@Override
public boolean fileTransfer(String sn) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_FILE_TRANSFER, "fileTransfer", "fileTransfer");
try {
PushSendResult result = pushApi.send(pushSendParam);
log.info("fileTransfer send success:{}", result);
return true;
} catch (ApiErrorException e) {
int httpStatus = e.getStats();
int errorCode = e.getApiError().getError().getCode();
String errorMessage = e.getApiError().getError().getMessage();
log.error("fileTransfer send error, httpStatus:{} code:{}, message:{}", httpStatus, errorCode, errorMessage);
return false;
}
}
@Override
public boolean msgSync(String sn) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_MSG_SYNC, "msgSync", "msgSync");
try {
PushSendResult result = pushApi.send(pushSendParam);
log.info("msgSync send success:{}", result);
return true;
} catch (ApiErrorException e) {
int httpStatus = e.getStats();
int errorCode = e.getApiError().getError().getCode();
String errorMessage = e.getApiError().getError().getMessage();
log.error("msgSync send error, httpStatus:{} code:{}, message:{}", httpStatus, errorCode, errorMessage);
return false;
}
}
@Override
public boolean clean(String sn) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_CLEAN, "clean", "clean");
try {
PushSendResult result = pushApi.send(pushSendParam);
log.info("clean send success:{}", result);
return true;
} catch (ApiErrorException e) {
int httpStatus = e.getStats();
int errorCode = e.getApiError().getError().getCode();
String errorMessage = e.getApiError().getError().getMessage();
log.error("clean send error, httpStatus:{} code:{}, message:{}", httpStatus, errorCode, errorMessage);
return false;
}
}
@Override
public boolean mirror(String sn) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_MIRROR, "mirror", "mirror");
try {
PushSendResult result = pushApi.send(pushSendParam);
log.info("mirror send success:{}", result);
return true;
} catch (ApiErrorException e) {
int httpStatus = e.getStats();
int errorCode = e.getApiError().getError().getCode();
String errorMessage = e.getApiError().getError().getMessage();
log.error("mirror send error, httpStatus:{} code:{}, message:{}", httpStatus, errorCode, errorMessage);
return false;
}
}
@Override
public boolean screenLock(String sn) {
PushSendParam pushSendParam = getSinglePushSendParam(sn, DEVICE_SCREEN_LOCK, "screenLock", "screenLock");
try {
PushSendResult result = pushApi.send(pushSendParam);
log.info("screenLock send success:{}", result);
return true;
} catch (ApiErrorException e) {
int httpStatus = e.getStats();
int errorCode = e.getApiError().getError().getCode();
String errorMessage = e.getApiError().getError().getMessage();
log.error("screenLock send error, httpStatus:{} code:{}, message:{}", httpStatus, errorCode, errorMessage);
return false;
}
}
}