20260712:1、权限临时方案;2、简易分配设备给用户

This commit is contained in:
zhugongping 2026-07-12 21:31:32 +08:00
parent 95d35341ac
commit bfd1b9580d
24 changed files with 239 additions and 56 deletions

View File

@ -25,7 +25,9 @@
"Bash(git diff:*)", "Bash(git diff:*)",
"Bash(source \"$HOME/.nvm/nvm.sh\")", "Bash(source \"$HOME/.nvm/nvm.sh\")",
"Bash(nvm use:*)", "Bash(nvm use:*)",
"Bash(npm run:*)" "Bash(npm run:*)",
"mcp__filesystem__read_text_file",
"Bash(sips:*)"
] ]
} }
} }

View File

@ -111,6 +111,8 @@ fastbee-plugs/
**认证方式:** 通过 `Authorization` 请求头传递 JWT Token。Token 配置在 `application.yml` 的 `token:` 节点下。 **认证方式:** 通过 `Authorization` 请求头传递 JWT Token。Token 配置在 `application.yml` 的 `token:` 节点下。
**权限策略(重要):** 后端接口权限基于若依 `@PreAuthorize("@ss.hasPermi(...)" )` / `@ss.hasAnyPermi(...)`。`sys_menu.menu_type = C` 通常代表页面权限,`menu_type = F` 代表按钮/功能权限。由于前端页面会跨模块复用选择器/列表/详情接口(例如设备计算公式页面复用产品物模型接口、数据中心复用设备/场景接口),读接口、列表接口、下拉选择器、详情接口应优先使用 `hasAnyPermi`,允许“接口原所属权限 + 实际使用页面的页面级权限”。示例:`@PreAuthorize("@ss.hasAnyPermi('iot:model:list,iot:device:list')")`。写接口(新增/修改/删除/导入/导出)不要默认用页面 `list` 权限放开;只有确认该写操作属于该页面功能时,才追加对应页面的 `add/edit/remove` 权限,例如设备页维护计算公式可考虑 `iot:model:edit,iot:device:edit`。
**API 文档:** 服务运行时可通过 `/swagger-ui/index.html` 访问 Swagger/OpenAPI 文档。 **API 文档:** 服务运行时可通过 `/swagger-ui/index.html` 访问 Swagger/OpenAPI 文档。
### 前端架构 ### 前端架构

View File

@ -32,7 +32,7 @@ public class SysNoticeController extends BaseController {
* 获取通知公告列表 * 获取通知公告列表
*/ */
@ApiOperation("获取通知公告列表") @ApiOperation("获取通知公告列表")
@PreAuthorize("@ss.hasPermi('system:notice:list')") @PreAuthorize("@ss.hasAnyPermi('system:notice:list,iot:device:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysNotice notice) { public TableDataInfo list(SysNotice notice) {
startPage(); startPage();
@ -44,7 +44,7 @@ public class SysNoticeController extends BaseController {
* 根据通知公告编号获取详细信息 * 根据通知公告编号获取详细信息
*/ */
@ApiOperation("根据通知公告编号获取详细信息") @ApiOperation("根据通知公告编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:notice:query')") @PreAuthorize("@ss.hasAnyPermi('system:notice:query,iot:device:list')")
@GetMapping(value = "/{noticeId}") @GetMapping(value = "/{noticeId}")
public AjaxResult getInfo(@PathVariable Long noticeId) { public AjaxResult getInfo(@PathVariable Long noticeId) {
return success(noticeService.selectNoticeById(noticeId)); return success(noticeService.selectNoticeById(noticeId));

View File

@ -55,7 +55,7 @@ public class SysUserController extends BaseController {
* 获取用户列表 * 获取用户列表
*/ */
@ApiOperation("获取用户分页列表") @ApiOperation("获取用户分页列表")
@PreAuthorize("@ss.hasPermi('system:user:list')") @PreAuthorize("@ss.hasAnyPermi('system:user:list,iot:project:list,iot:device:list,iot:push:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysUser user) { public TableDataInfo list(SysUser user) {
startPage(); startPage();
@ -245,7 +245,7 @@ public class SysUserController extends BaseController {
* 获取部门树列表 * 获取部门树列表
*/ */
@ApiOperation("获取部门树列表") @ApiOperation("获取部门树列表")
@PreAuthorize("@ss.hasAnyPermi('system:user:list,iot:device:list')") @PreAuthorize("@ss.hasAnyPermi('system:user:list,iot:device:list,dataCenter:history:list,iot:project:list')")
@GetMapping("/deptTree") @GetMapping("/deptTree")
public AjaxResult deptTree(SysDept dept) { public AjaxResult deptTree(SysDept dept) {
return success(deptService.selectDeptTreeList(dept)); return success(deptService.selectDeptTreeList(dept));

View File

@ -41,7 +41,7 @@ public class NotifyTemplateController extends BaseController {
/** /**
* 查询通知模版列表 * 查询通知模版列表
*/ */
@PreAuthorize("@ss.hasPermi('notify:template:list')") @PreAuthorize("@ss.hasAnyPermi('notify:template:list,iot:alert:list,iot:push:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询通知模版列表") @ApiOperation("查询通知模版列表")
public TableDataInfo list(NotifyTemplate notifyTemplate) { public TableDataInfo list(NotifyTemplate notifyTemplate) {
@ -66,7 +66,7 @@ public class NotifyTemplateController extends BaseController {
/** /**
* 获取通知模版详细信息 * 获取通知模版详细信息
*/ */
@PreAuthorize("@ss.hasPermi('notify:template:query')") @PreAuthorize("@ss.hasAnyPermi('notify:template:query,iot:alert:list,iot:push:list')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取通知模版详细信息") @ApiOperation("获取通知模版详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) { public AjaxResult getInfo(@PathVariable("id") Long id) {
@ -109,7 +109,7 @@ public class NotifyTemplateController extends BaseController {
/** /**
* 获取消息通知模版参数信息 * 获取消息通知模版参数信息
*/ */
@PreAuthorize("@ss.hasPermi('notify:template:query')") @PreAuthorize("@ss.hasAnyPermi('notify:template:query,iot:alert:list,iot:push:list')")
@GetMapping(value = "/msgParams") @GetMapping(value = "/msgParams")
@ApiOperation("获取模板参数配置") @ApiOperation("获取模板参数配置")
public AjaxResult msgParams(Long channelId, String msgType) { public AjaxResult msgParams(Long channelId, String msgType) {
@ -120,7 +120,7 @@ public class NotifyTemplateController extends BaseController {
/** /**
* 获取通知模版详细信息 * 获取通知模版详细信息
*/ */
@PreAuthorize("@ss.hasPermi('notify:template:query')") @PreAuthorize("@ss.hasAnyPermi('notify:template:query,iot:alert:list,iot:push:list')")
@GetMapping(value = "/getUsable") @GetMapping(value = "/getUsable")
@ApiOperation("获取同一业务的模板是否有可用的") @ApiOperation("获取同一业务的模板是否有可用的")
public AjaxResult getUsable(NotifyTemplate notifyTemplate) { public AjaxResult getUsable(NotifyTemplate notifyTemplate) {
@ -142,7 +142,7 @@ public class NotifyTemplateController extends BaseController {
/** /**
* 获取消息通知模版参数变量 * 获取消息通知模版参数变量
*/ */
@PreAuthorize("@ss.hasPermi('notify:template:query')") @PreAuthorize("@ss.hasAnyPermi('notify:template:query,iot:alert:list,iot:push:list')")
@GetMapping(value = "/listVariables") @GetMapping(value = "/listVariables")
@ApiOperation("获取模板内容变量") @ApiOperation("获取模板内容变量")
public AjaxResult listVariables(Long id, String channelType, String provider) { public AjaxResult listVariables(Long id, String channelType, String provider) {

View File

@ -58,7 +58,7 @@ public class DataCenterController {
* @return com.fastbee.common.core.domain.AjaxResult * @return com.fastbee.common.core.domain.AjaxResult
*/ */
@ApiOperation("查询设备的历史数据") @ApiOperation("查询设备的历史数据")
@PreAuthorize("@ss.hasPermi('dataCenter:history:list')") @PreAuthorize("@ss.hasAnyPermi('dataCenter:history:list,iot:device:list')")
@PostMapping("/deviceHistory") @PostMapping("/deviceHistory")
public AjaxResult deviceHistory(@RequestBody DeviceHistoryParam deviceHistoryParam) { public AjaxResult deviceHistory(@RequestBody DeviceHistoryParam deviceHistoryParam) {
if (StringUtils.isEmpty(deviceHistoryParam.getSerialNumber())) { if (StringUtils.isEmpty(deviceHistoryParam.getSerialNumber())) {
@ -134,7 +134,7 @@ public class DataCenterController {
} }
@ApiOperation("网关计算物模型历史(查询时按公式计算,按分钟对齐,缺数沿用上一分钟)") @ApiOperation("网关计算物模型历史(查询时按公式计算,按分钟对齐,缺数沿用上一分钟)")
@PreAuthorize("@ss.hasPermi('dataCenter:history:list')") @PreAuthorize("@ss.hasAnyPermi('dataCenter:history:list,iot:device:list')")
@PostMapping("/deviceHistoryCalculated") @PostMapping("/deviceHistoryCalculated")
public AjaxResult deviceHistoryCalculated(@RequestBody DeviceHistoryParam deviceHistoryParam) { public AjaxResult deviceHistoryCalculated(@RequestBody DeviceHistoryParam deviceHistoryParam) {
if (deviceHistoryParam.getDeviceId() == null || StringUtils.isEmpty(deviceHistoryParam.getSerialNumber())) { if (deviceHistoryParam.getDeviceId() == null || StringUtils.isEmpty(deviceHistoryParam.getSerialNumber())) {
@ -217,14 +217,14 @@ public class DataCenterController {
} }
@ApiOperation("网关设备仅计算物模型列表(历史记录-网关计算量 变量下拉用)") @ApiOperation("网关设备仅计算物模型列表(历史记录-网关计算量 变量下拉用)")
@PreAuthorize("@ss.hasPermi('dataCenter:history:list')") @PreAuthorize("@ss.hasAnyPermi('dataCenter:history:list,iot:device:list')")
@GetMapping("/gatewayCalculatedModels") @GetMapping("/gatewayCalculatedModels")
public AjaxResult listGatewayCalculatedModels(@RequestParam Long deviceId) { public AjaxResult listGatewayCalculatedModels(@RequestParam Long deviceId) {
return AjaxResult.success(dataCenterService.listGatewayCalculatedModels(deviceId)); return AjaxResult.success(dataCenterService.listGatewayCalculatedModels(deviceId));
} }
@ApiOperation("多设备对比历史(支持多变量,按分钟对齐,缺数沿用上一分钟)") @ApiOperation("多设备对比历史(支持多变量,按分钟对齐,缺数沿用上一分钟)")
@PreAuthorize("@ss.hasPermi('dataCenter:history:list')") @PreAuthorize("@ss.hasAnyPermi('dataCenter:history:list,iot:device:list')")
@PostMapping("/subDeviceComparativeHistory") @PostMapping("/subDeviceComparativeHistory")
public AjaxResult subDeviceComparativeHistory(@RequestBody SubDeviceCompareParam param) { public AjaxResult subDeviceComparativeHistory(@RequestBody SubDeviceCompareParam param) {
boolean hasIdentifier = (param.getIdentifierList() != null && !param.getIdentifierList().isEmpty()) boolean hasIdentifier = (param.getIdentifierList() != null && !param.getIdentifierList().isEmpty())
@ -292,7 +292,7 @@ public class DataCenterController {
} }
@ApiOperation("查询场景变量历史数据") @ApiOperation("查询场景变量历史数据")
@PreAuthorize("@ss.hasPermi('dataCenter:history:list')") @PreAuthorize("@ss.hasAnyPermi('dataCenter:history:list,iot:device:list,scene:model:list')")
@GetMapping("/sceneHistory") @GetMapping("/sceneHistory")
public AjaxResult sceneHistory(SceneHistoryParam sceneHistoryParam) { public AjaxResult sceneHistory(SceneHistoryParam sceneHistoryParam) {
if (StringUtils.isNotEmpty(sceneHistoryParam.getSerialNumber())) { if (StringUtils.isNotEmpty(sceneHistoryParam.getSerialNumber())) {

View File

@ -107,7 +107,7 @@ public class DeviceController extends BaseController {
/** /**
* 查询设备简短列表,主页列表数据 * 查询设备简短列表,主页列表数据
*/ */
@PreAuthorize("@ss.hasPermi('iot:device:list')") @PreAuthorize("@ss.hasAnyPermi('iot:device:list,iot:scene:list,dataCenter:history:list,dataCenter:analysis:list,dataCenter:repair:list')")
@GetMapping("/shortList") @GetMapping("/shortList")
@ApiOperation("设备分页简短列表") @ApiOperation("设备分页简短列表")
public TableDataInfo shortList(Device device) { public TableDataInfo shortList(Device device) {
@ -382,6 +382,23 @@ public class DeviceController extends BaseController {
return deviceService.assignment(deptId, deviceIds); return deviceService.assignment(deptId, deviceIds);
} }
/**
* 超级管理员将设备分配给指定用户
*/
@PreAuthorize("@ss.hasPermi('iot:device:assignment')")
@ApiOperation("超级管理员分配设备给指定用户")
@PostMapping("/assignUser")
public AjaxResult assignUser(@RequestParam("deviceId") Long deviceId,
@RequestParam("userId") Long userId) {
if (null == deviceId) {
return error(MessageUtils.message("device.id.null"));
}
if (null == userId) {
return error(MessageUtils.message("device.user.id.null"));
}
return deviceService.assignUser(deviceId, userId);
}
/** /**
* 回收设备 * 回收设备
* *
@ -424,7 +441,7 @@ public class DeviceController extends BaseController {
/** /**
* 查询变量概况 * 查询变量概况
*/ */
@PreAuthorize("@ss.hasPermi('iot:device:query')") @PreAuthorize("@ss.hasAnyPermi('iot:device:query,iot:device:list,dataCenter:history:list,dataCenter:analysis:list,dataCenter:repair:list')")
@GetMapping("/listThingsModel") @GetMapping("/listThingsModel")
@ApiOperation("查询变量概况") @ApiOperation("查询变量概况")
public TableDataInfo listThingsModel(Integer pageNum, Integer pageSize, Long deviceId, String modelName, Integer type) { public TableDataInfo listThingsModel(Integer pageNum, Integer pageSize, Long deviceId, String modelName, Integer type) {

View File

@ -34,7 +34,7 @@ public class GroupController extends BaseController {
/** /**
* 查询设备分组列表 * 查询设备分组列表
*/ */
@PreAuthorize("@ss.hasAnyPermi('iot:group:list,iot:device:list')") @PreAuthorize("@ss.hasAnyPermi('iot:group:list,iot:device:list,dataCenter:history:list,iot:project:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("分组分页列表") @ApiOperation("分组分页列表")
public TableDataInfo list(Group group) { public TableDataInfo list(Group group) {
@ -58,7 +58,7 @@ public class GroupController extends BaseController {
/** /**
* 获取设备分组详细信息 * 获取设备分组详细信息
*/ */
@PreAuthorize("@ss.hasPermi('iot:group:query')") @PreAuthorize("@ss.hasAnyPermi('iot:group:query,iot:device:list,dataCenter:history:list,iot:project:list')")
@GetMapping(value = "/{groupId}") @GetMapping(value = "/{groupId}")
@ApiOperation("获取分组详情") @ApiOperation("获取分组详情")
public AjaxResult getInfo(@PathVariable("groupId") Long groupId) { public AjaxResult getInfo(@PathVariable("groupId") Long groupId) {
@ -68,7 +68,7 @@ public class GroupController extends BaseController {
/** /**
* 获取分组下的所有关联设备ID数组 * 获取分组下的所有关联设备ID数组
*/ */
@PreAuthorize("@ss.hasPermi('iot:group:query')") @PreAuthorize("@ss.hasAnyPermi('iot:group:query,iot:device:list,dataCenter:history:list,iot:project:list')")
@GetMapping(value = "/getDeviceIds/{groupId}") @GetMapping(value = "/getDeviceIds/{groupId}")
@ApiOperation("获取分组下的所有关联设备ID数组") @ApiOperation("获取分组下的所有关联设备ID数组")
public AjaxResult getDeviceIds(@PathVariable("groupId") Long groupId) { public AjaxResult getDeviceIds(@PathVariable("groupId") Long groupId) {

View File

@ -44,7 +44,7 @@ public class ThingsModelController extends BaseController {
/** /**
* 查询物模型列表 * 查询物模型列表
*/ */
@PreAuthorize("@ss.hasPermi('iot:model:list')") @PreAuthorize("@ss.hasAnyPermi('iot:model:list,iot:device:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("产品物模型分页列表") @ApiOperation("产品物模型分页列表")
public TableDataInfo list(ThingsModel thingsModel) { public TableDataInfo list(ThingsModel thingsModel) {
@ -56,7 +56,7 @@ public class ThingsModelController extends BaseController {
/** /**
* 查询物模型列表 * 查询物模型列表
*/ */
@PreAuthorize("@ss.hasPermi('iot:model:list')") @PreAuthorize("@ss.hasAnyPermi('iot:model:list,iot:device:list')")
@GetMapping("/listByProductIdAndSerialNumber") @GetMapping("/listByProductIdAndSerialNumber")
@ApiOperation("产品物模型分页列表(根据产品ID和设备编号查询)") @ApiOperation("产品物模型分页列表(根据产品ID和设备编号查询)")
public TableDataInfo listByProductIdAndSerialNumber(@RequestParam("productId") Long productId, public TableDataInfo listByProductIdAndSerialNumber(@RequestParam("productId") Long productId,
@ -80,7 +80,7 @@ public class ThingsModelController extends BaseController {
/** /**
* 获取物模型详细信息 * 获取物模型详细信息
*/ */
@PreAuthorize("@ss.hasPermi('iot:model:query')") @PreAuthorize("@ss.hasAnyPermi('iot:model:query,iot:device:list')")
@GetMapping(value = "/{modelId}") @GetMapping(value = "/{modelId}")
@ApiOperation("获取产品物模型详情") @ApiOperation("获取产品物模型详情")
public AjaxResult getInfo(@PathVariable("modelId") Long modelId) { public AjaxResult getInfo(@PathVariable("modelId") Long modelId) {
@ -150,7 +150,7 @@ public class ThingsModelController extends BaseController {
/** /**
* 获取缓存的JSON物模型 * 获取缓存的JSON物模型
*/ */
@PreAuthorize("@ss.hasAnyPermi('iot:model:query,iot:device:list')") @PreAuthorize("@ss.hasAnyPermi('iot:model:query,iot:device:list,iot:scene:list')")
@GetMapping(value = "/cache/{productId}") @GetMapping(value = "/cache/{productId}")
@ApiOperation("获取缓存的JSON物模型") @ApiOperation("获取缓存的JSON物模型")
public AjaxResult getCacheThingsModelByProductId(@PathVariable("productId") Long productId) { public AjaxResult getCacheThingsModelByProductId(@PathVariable("productId") Long productId) {
@ -182,7 +182,7 @@ public class ThingsModelController extends BaseController {
/** /**
* 获取modbus配置可选择物模型 * 获取modbus配置可选择物模型
*/ */
@PreAuthorize("@ss.hasPermi('iot:model:list')") @PreAuthorize("@ss.hasAnyPermi('iot:model:list,iot:device:list')")
@GetMapping("/listModbus") @GetMapping("/listModbus")
@ApiOperation("获取modbus配置可选择物模型") @ApiOperation("获取modbus配置可选择物模型")
public TableDataInfo listModbus(Long productId) { public TableDataInfo listModbus(Long productId) {
@ -195,7 +195,7 @@ public class ThingsModelController extends BaseController {
/** /**
* 根据设备获取可读写物模型 * 根据设备获取可读写物模型
*/ */
@PreAuthorize("@ss.hasPermi('iot:model:list')") @PreAuthorize("@ss.hasAnyPermi('iot:model:list,iot:device:list')")
@GetMapping("/write") @GetMapping("/write")
@ApiOperation("根据设备获取可读写物模型") @ApiOperation("根据设备获取可读写物模型")
public TableDataInfo write(Long deviceId) { public TableDataInfo write(Long deviceId) {

View File

@ -34,7 +34,7 @@ public class EventLogController extends BaseController {
* 查询事件日志列表 * 查询事件日志列表
*/ */
@ApiOperation("查询事件日志列表") @ApiOperation("查询事件日志列表")
@PreAuthorize("@ss.hasPermi('iot:event:list')") @PreAuthorize("@ss.hasAnyPermi('iot:event:list,iot:device:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(EventLog eventLog) { public TableDataInfo list(EventLog eventLog) {
startPage(); startPage();
@ -59,7 +59,7 @@ public class EventLogController extends BaseController {
* 获取事件日志详细信息 * 获取事件日志详细信息
*/ */
@ApiOperation("获取事件日志详细信息") @ApiOperation("获取事件日志详细信息")
@PreAuthorize("@ss.hasPermi('iot:event:query')") @PreAuthorize("@ss.hasAnyPermi('iot:event:query,iot:device:list')")
@GetMapping(value = "/{logId}") @GetMapping(value = "/{logId}")
public AjaxResult getInfo(@PathVariable("logId") Long logId) { public AjaxResult getInfo(@PathVariable("logId") Long logId) {
return success(eventLogService.getById(logId)); return success(eventLogService.getById(logId));

View File

@ -34,7 +34,7 @@ public class FunctionLogController extends BaseController {
* 查询设备服务下发日志列表 * 查询设备服务下发日志列表
*/ */
@ApiOperation("查询设备服务下发日志列表") @ApiOperation("查询设备服务下发日志列表")
@PreAuthorize("@ss.hasPermi('iot:log:list')") @PreAuthorize("@ss.hasAnyPermi('iot:log:list,iot:device:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(FunctionLog functionLog) { public TableDataInfo list(FunctionLog functionLog) {
startPage(); startPage();
@ -59,7 +59,7 @@ public class FunctionLogController extends BaseController {
* 获取设备服务下发日志详细信息 * 获取设备服务下发日志详细信息
*/ */
@ApiOperation("获取设备服务下发日志详细信息") @ApiOperation("获取设备服务下发日志详细信息")
@PreAuthorize("@ss.hasPermi('iot:log:query')") @PreAuthorize("@ss.hasAnyPermi('iot:log:query,iot:device:list')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) { public AjaxResult getInfo(@PathVariable("id") Long id) {
return AjaxResult.success(functionLogService.selectFunctionLogById(id)); return AjaxResult.success(functionLogService.selectFunctionLogById(id));

View File

@ -32,7 +32,7 @@ public class SubGatewayController extends BaseController {
/** /**
* 查询网关与子设备关联列表 * 查询网关与子设备关联列表
*/ */
@PreAuthorize("@ss.hasPermi('sub:gateway:list')") @PreAuthorize("@ss.hasAnyPermi('sub:gateway:list,iot:device:list,dataCenter:history:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询网关与子设备关联列表") @ApiOperation("查询网关与子设备关联列表")
public TableDataInfo list(SubGateway gateway) { public TableDataInfo list(SubGateway gateway) {
@ -44,7 +44,7 @@ public class SubGatewayController extends BaseController {
/** /**
* 获取网关与子设备关联详细信息 * 获取网关与子设备关联详细信息
*/ */
@PreAuthorize("@ss.hasPermi('sub:gateway:query')") @PreAuthorize("@ss.hasAnyPermi('sub:gateway:query,iot:device:list,dataCenter:history:list')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取网关与子设备关联详细信息") @ApiOperation("获取网关与子设备关联详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) { public AjaxResult getInfo(@PathVariable("id") Long id) {
@ -84,7 +84,7 @@ public class SubGatewayController extends BaseController {
/** /**
* 获取可选择的网关子设备列表 * 获取可选择的网关子设备列表
*/ */
@PreAuthorize("@ss.hasPermi('sub:gateway:query')") @PreAuthorize("@ss.hasAnyPermi('sub:gateway:query,iot:device:list')")
@GetMapping(value = "/subDevice") @GetMapping(value = "/subDevice")
@ApiOperation("获取可选择的网关子设备列表") @ApiOperation("获取可选择的网关子设备列表")
public TableDataInfo subDevice(GateSubDeviceVO subDeviceVO) { public TableDataInfo subDevice(GateSubDeviceVO subDeviceVO) {

View File

@ -33,7 +33,7 @@ public class PlatformDeviceMappingController extends BaseController {
return getDataTable(mappingService.selectList(query)); return getDataTable(mappingService.selectList(query));
} }
@PreAuthorize("@ss.hasPermi('platform:deviceMapping:query')") @PreAuthorize("@ss.hasAnyPermi('platform:deviceMapping:query,platform:deviceMapping:list')")
@GetMapping("/{id}") @GetMapping("/{id}")
@ApiOperation("获取设备绑定详情") @ApiOperation("获取设备绑定详情")
public AjaxResult getInfo(@PathVariable Long id) { public AjaxResult getInfo(@PathVariable Long id) {
@ -75,7 +75,7 @@ public class PlatformDeviceMappingController extends BaseController {
// ==================== 子映射管理 ==================== // ==================== 子映射管理 ====================
@PreAuthorize("@ss.hasPermi('platform:deviceMapping:query')") @PreAuthorize("@ss.hasAnyPermi('platform:deviceMapping:query,platform:deviceMapping:list')")
@GetMapping("/{id}/sub-mappings") @GetMapping("/{id}/sub-mappings")
@ApiOperation("查询子设备映射列表") @ApiOperation("查询子设备映射列表")
public AjaxResult listSubMappings(@PathVariable Long id) { public AjaxResult listSubMappings(@PathVariable Long id) {

View File

@ -31,7 +31,7 @@ public class BridgeController extends BaseController {
/** /**
* 查询数据桥接列表 * 查询数据桥接列表
*/ */
@PreAuthorize("@ss.hasPermi('iot:bridge:list')") @PreAuthorize("@ss.hasAnyPermi('iot:bridge:list,iot:scene:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询数据桥接列表") @ApiOperation("查询数据桥接列表")
public TableDataInfo list(Bridge bridge) { public TableDataInfo list(Bridge bridge) {
@ -55,7 +55,7 @@ public class BridgeController extends BaseController {
/** /**
* 获取数据桥接详细信息 * 获取数据桥接详细信息
*/ */
@PreAuthorize("@ss.hasPermi('iot:bridge:query')") @PreAuthorize("@ss.hasAnyPermi('iot:bridge:query,iot:scene:list')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取数据桥接详细信息") @ApiOperation("获取数据桥接详细信息")
public AjaxResult getInfo(@PathVariable("id") Long id) { public AjaxResult getInfo(@PathVariable("id") Long id) {

View File

@ -33,7 +33,7 @@ public class SceneModelController extends BaseController {
/** /**
* 查询场景管理列表 * 查询场景管理列表
*/ */
@PreAuthorize("@ss.hasAnyPermi('scene:model:list,iot:device:list')") @PreAuthorize("@ss.hasAnyPermi('scene:model:list,iot:device:list,dataCenter:history:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询场景管理列表") @ApiOperation("查询场景管理列表")
public TableDataInfo list(SceneModel sceneModel) { public TableDataInfo list(SceneModel sceneModel) {
@ -58,7 +58,7 @@ public class SceneModelController extends BaseController {
/** /**
* 获取场景管理详细信息 * 获取场景管理详细信息
*/ */
@PreAuthorize("@ss.hasPermi('scene:model:query')") @PreAuthorize("@ss.hasAnyPermi('scene:model:query,scene:model:list,dataCenter:history:list')")
@GetMapping(value = "/{sceneModelId}") @GetMapping(value = "/{sceneModelId}")
@ApiOperation("获取场景管理详细信息") @ApiOperation("获取场景管理详细信息")
public AjaxResult getInfo(@PathVariable("sceneModelId") Long sceneModelId) { public AjaxResult getInfo(@PathVariable("sceneModelId") Long sceneModelId) {

View File

@ -37,7 +37,7 @@ public class SceneModelDataController extends BaseController {
/** /**
* 查询所有变量列表 * 查询所有变量列表
*/ */
@PreAuthorize("@ss.hasPermi('scene:modelData:list')") @PreAuthorize("@ss.hasAnyPermi('scene:modelData:list,scene:model:list,dataCenter:history:list')")
@GetMapping("/list") @GetMapping("/list")
@ApiOperation("查询所有变量列表") @ApiOperation("查询所有变量列表")
public TableDataInfo list(SceneModelData sceneModelData) { public TableDataInfo list(SceneModelData sceneModelData) {
@ -55,7 +55,7 @@ public class SceneModelDataController extends BaseController {
/** /**
* 查询关联设备变量的列表 * 查询关联设备变量的列表
*/ */
@PreAuthorize("@ss.hasPermi('scene:modelDeviceData:list')") @PreAuthorize("@ss.hasAnyPermi('scene:modelDeviceData:list,scene:model:list,dataCenter:history:list,iot:scene:list')")
@GetMapping("/listByType") @GetMapping("/listByType")
@ApiOperation("查询关联设备变量的列表") @ApiOperation("查询关联设备变量的列表")
public TableDataExtendInfo listByType(SceneModelData sceneModelData) { public TableDataExtendInfo listByType(SceneModelData sceneModelData) {
@ -82,7 +82,7 @@ public class SceneModelDataController extends BaseController {
/** /**
* 获取【请填写功能名称】详细信息 * 获取【请填写功能名称】详细信息
*/ */
@PreAuthorize("@ss.hasPermi('scene:modelData:query')") @PreAuthorize("@ss.hasAnyPermi('scene:modelData:query,scene:model:list,dataCenter:history:list')")
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
@ApiOperation("获取场景变量详情") @ApiOperation("获取场景变量详情")
public AjaxResult getInfo(@PathVariable("id") Long id) { public AjaxResult getInfo(@PathVariable("id") Long id) {

View File

@ -96,16 +96,15 @@ public class PubMqttCallBack implements MqttCallbackExtended {
@Override @Override
public void connectComplete(boolean reconnect, String serverURI) { public void connectComplete(boolean reconnect, String serverURI) {
log.info("MQTT内部客户端已经连接!"); log.info("MQTT内部客户端已经连接!");
System.out.print("" + System.out.print(
" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \n" + "▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌ ▍▌▌▌▌▍ ▌▌▌ ▌▌▌▌ ▌▌▌▌▌▍ ▌▌▌▌\n" +
" * _⚲_⚲_ ______ _ ____ * \n" + " ▌▌▌▌▎▌▌▌▌ ▌▌▌ ▌▌▌ ▍▌▌▌▌▌▌▎ ▌▌▌ ▌▌▌▎▌▌ ▌▌▌▌▌▌▌ ▌▌▌▌\n" +
" * | / \\ | | ____| | | | _ \\ * \n" + " ▌▌▌▌▌▌ ▌▌▌▌ ▌▌▌ ▍▌▌▌▏▌▌▌▌ ▌▌▌ ▌▌▌ ▌▌▌ ▌▌▌▌▌▌▌▌ ▌▌▌▌\n" +
" * | | | ● | | | | |__ __ _ ___| |_ | |_) | ___ ___ * \n" + " ▌▌▌▍ ▌▌▌▍▍▍▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌▌ ▌▌▌▌▍▍▍▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌▌▌\n" +
" * | \\ / | | __/ _` / __| __| | _ < / _ \\/ _ \\ * \n" + " ▌▌▌▏ ▌▌▌▌▌▌▌▌▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌ ▌▌▌▌▌▌▌▌▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌\n" +
" * \\ / | | | (_| \\__ \\ |_ | |_) | __/ __/ * \n" + " ▌▌▌▏ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌"
" * V |_| \\__,_|___/\\__| |____/ \\___|\\___| * \n" + );
" * * \n" +
" * * * * * * * * * * * * FastBee物联网平台[✔启动成功] * * * * * * * * * * * * \n");
//连接后订阅, enable为false表示使用emq //连接后订阅, enable为false表示使用emq
if (!enabled) { if (!enabled) {

View File

@ -356,6 +356,11 @@ public interface DeviceMapper extends BaseMapperX<Device> {
*/ */
int updateTenantIdByDeptIds(@Param("tenantId") Long tenantId, @Param("tenantName") String tenantName, @Param("deviceIdList") List<Long> deviceIdList); int updateTenantIdByDeptIds(@Param("tenantId") Long tenantId, @Param("tenantName") String tenantName, @Param("deviceIdList") List<Long> deviceIdList);
/**
* 更新单个设备所属用户
*/
int updateTenantIdByDeviceId(@Param("tenantId") Long tenantId, @Param("tenantName") String tenantName, @Param("deviceId") Long deviceId);
/** /**
* 查询终端用户设备简短列表,主页列表数据 * 查询终端用户设备简短列表,主页列表数据
*/ */

View File

@ -354,6 +354,15 @@ public interface IDeviceService {
*/ */
AjaxResult assignment(Long deptId, String deviceIds); AjaxResult assignment(Long deptId, String deviceIds);
/**
* 超级管理员将设备分配给指定用户
*
* @param deviceId 设备id
* @param userId 用户id
* @return com.fastbee.common.core.domain.AjaxResult
*/
AjaxResult assignUser(Long deviceId, Long userId);
/** /**
* 回收设备 * 回收设备
* *

View File

@ -2113,6 +2113,40 @@ public class DeviceServiceImpl implements IDeviceService {
return result > 0 ? AjaxResult.success("分配设备成功") : AjaxResult.error("分配设备失败"); return result > 0 ? AjaxResult.success("分配设备成功") : AjaxResult.error("分配设备失败");
} }
@Override
public AjaxResult assignUser(Long deviceId, Long userId) {
if (!Objects.equals(SecurityUtils.getUserId(), 1L)) {
return AjaxResult.error("只有超级管理员可以分配设备");
}
Device device = deviceMapper.selectDeviceByDeviceId(deviceId);
if (null == device) {
return AjaxResult.error("设备不存在");
}
SysUser targetUser = userService.selectUserById(userId);
if (null == targetUser) {
return AjaxResult.error("用户不存在");
}
int result = deviceMapper.updateTenantIdByDeviceId(targetUser.getUserId(), targetUser.getUserName(), deviceId);
if (result > 0) {
SysUser currSysUser = getLoginUser().getUser();
DeviceRecord deviceRecord = new DeviceRecord();
deviceRecord.setOperateDeptId(currSysUser.getDeptId())
.setTargetDeptId(targetUser.getDeptId())
.setDeviceId(device.getDeviceId())
.setProductId(device.getProductId())
.setSerialNumber(device.getSerialNumber())
.setType(DeviceRecordTypeEnum.ASSIGNMENT_DETAIL.getType())
.setDistributeType(DeviceDistributeTypeEnum.SELECT.getType())
.setTenantId(device.getTenantId())
.setTenantName(device.getTenantName())
.setStatus(StatusEnum.SUCCESS.getStatus())
.setCreateBy(currSysUser.getUserName());
deviceRecordMapper.insertDeviceRecord(deviceRecord);
return AjaxResult.success("分配设备成功");
}
return AjaxResult.error("分配设备失败");
}
@Override @Override
public AjaxResult recovery(String deviceIds, Long recoveryDeptId) { public AjaxResult recovery(String deviceIds, Long recoveryDeptId) {
SysUser currSysUser = getLoginUser().getUser(); SysUser currSysUser = getLoginUser().getUser();

View File

@ -1033,6 +1033,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
</update> </update>
<update id="updateTenantIdByDeviceId">
update iot_device
set tenant_id = #{tenantId},
tenant_name = #{tenantName},
update_time = now()
where device_id = #{deviceId}
</update>
<select id="selectDeviceByChannelId" resultMap="DeviceResult"> <select id="selectDeviceByChannelId" resultMap="DeviceResult">
select device_name,device_id from iot_device select device_name,device_id from iot_device
where channel_id = #{channelId} where channel_id = #{channelId}

View File

@ -84,6 +84,15 @@ export function distributionDevice(deptId, deviceIds) {
method: 'post', method: 'post',
}); });
} }
// 超级管理员分配设备给指定用户
export function assignDeviceUser(deviceId, userId) {
return request({
url: '/iot/device/assignUser',
method: 'post',
params: { deviceId, userId },
});
}
//回收设备 //回收设备
export function recycleDevice(deviceIds, recoveryDeptId) { export function recycleDevice(deviceIds, recoveryDeptId) {
return request({ return request({

View File

@ -31,7 +31,11 @@
<span style="color: red;">*</span> <span style="color: red;">*</span>
{{ $t('device.device-edit.tenant') }} {{ $t('device.device-edit.tenant') }}
</template> </template>
<el-input v-model="form.tenantName" disabled /> <el-input v-model="form.tenantName" disabled>
<el-button v-if="isSuperAdmin && form.deviceId != 0" slot="append" @click="openAssignUserDialog">
分配
</el-button>
</el-input>
</el-form-item> </el-form-item>
<el-form-item label="" prop="serialNumber"> <el-form-item label="" prop="serialNumber">
<template slot="label"> <template slot="label">
@ -235,7 +239,7 @@
<alert-user ref="alertUser" :device="form"/> <alert-user ref="alertUser" :device="form"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="deviceAlert" :disabled="form.deviceId == 0"> <el-tab-pane name="deviceAlert" :disabled="form.deviceId == 0">
<span slot="label" v-hasPermi="['iot:alertLog:list']">{{ $t('device.device-edit.148398-81') }}</span> <span slot="label" v-hasPermi="['iot:alertLog:list', 'iot:device:list']">{{ $t('device.device-edit.148398-81') }}</span>
<device-alert ref="deviceAlert" :device="form"/> <device-alert ref="deviceAlert" :device="form"/>
</el-tab-pane> </el-tab-pane>
@ -360,6 +364,38 @@
<el-button @click="closeSummaryDialog">{{ $t('device.device-edit.148398-57') }}</el-button> <el-button @click="closeSummaryDialog">{{ $t('device.device-edit.148398-57') }}</el-button>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog title="分配设备" :visible.sync="assignUserOpen" width="800px" append-to-body>
<el-form :model="assignUserQuery" ref="assignUserQueryForm" :inline="true" label-width="80px" @submit.native.prevent>
<el-form-item label="用户名" prop="userName">
<el-input v-model="assignUserQuery.userName" clearable size="small" placeholder="请输入用户名" @keyup.enter.native="handleAssignUserQuery" />
</el-form-item>
<el-form-item label="手机号" prop="phonenumber">
<el-input v-model="assignUserQuery.phonenumber" clearable size="small" placeholder="请输入手机号" @keyup.enter.native="handleAssignUserQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleAssignUserQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetAssignUserQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="assignUserLoading" :data="assignUserList" highlight-current-row size="mini" border @current-change="handleAssignUserChange">
<el-table-column label="选择" width="55" align="center">
<template slot-scope="scope">
<input type="radio" :checked="selectedAssignUser && selectedAssignUser.userId === scope.row.userId" name="assignUser" />
</template>
</el-table-column>
<el-table-column label="用户ID" align="center" prop="userId" width="90" />
<el-table-column label="用户名" align="center" prop="userName" />
<el-table-column label="昵称" align="center" prop="nickName" />
<el-table-column label="手机号" align="center" prop="phonenumber" width="120" />
<el-table-column label="部门" align="center" prop="dept.deptName" />
</el-table>
<pagination v-show="assignUserTotal > 0" :total="assignUserTotal" :page.sync="assignUserQuery.pageNum" :limit.sync="assignUserQuery.pageSize" @pagination="getAssignUserList" />
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitAssignUser">确定</el-button>
<el-button @click="assignUserOpen = false">取消</el-button>
</div>
</el-dialog>
</el-card> </el-card>
</template> </template>
@ -399,9 +435,12 @@ import {
addDevice, addDevice,
updateDevice, updateDevice,
generatorDeviceNum, generatorDeviceNum,
getMqttConnect getMqttConnect,
assignDeviceUser
} from '@/api/iot/device'; } from '@/api/iot/device';
import {getDeviceRunningStatus} from '@/api/iot/device'; import {getDeviceRunningStatus} from '@/api/iot/device';
import {listUser} from '@/api/system/user';
import {getUserId} from '@/utils/auth';
import {cacheJsonThingsModel} from '@/api/iot/model'; import {cacheJsonThingsModel} from '@/api/iot/model';
import DeviceFunc from '@/views/iot/device/device-functionlog'; import DeviceFunc from '@/views/iot/device/device-functionlog';
import RealTimeStatus from '@/views/iot/device/realTime-status'; import RealTimeStatus from '@/views/iot/device/realTime-status';
@ -470,6 +509,9 @@ export default {
return 0; return 0;
}, },
}, },
isSuperAdmin() {
return Number(getUserId()) === 1;
},
}, },
data() { data() {
return { return {
@ -488,6 +530,18 @@ export default {
mqttList: [], mqttList: [],
// 遮罩层 // 遮罩层
loading: true, loading: true,
assignUserOpen: false,
assignUserLoading: false,
assignUserList: [],
assignUserTotal: 0,
selectedAssignUser: null,
assignUserQuery: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: 0,
},
// 设备开始状态 // 设备开始状态
oldDeviceStatus: null, oldDeviceStatus: null,
deviceId: '', deviceId: '',
@ -573,6 +627,50 @@ export default {
this.mqttUnSubscribe(this.form); this.mqttUnSubscribe(this.form);
}, },
methods: { methods: {
openAssignUserDialog() {
this.assignUserOpen = true;
this.selectedAssignUser = null;
this.getAssignUserList();
},
getAssignUserList() {
this.assignUserLoading = true;
listUser(this.assignUserQuery).then((response) => {
this.assignUserList = response.rows;
this.assignUserTotal = response.total;
this.assignUserLoading = false;
}).catch(() => {
this.assignUserLoading = false;
});
},
handleAssignUserQuery() {
this.assignUserQuery.pageNum = 1;
this.getAssignUserList();
},
resetAssignUserQuery() {
this.assignUserQuery = {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: 0,
};
this.selectedAssignUser = null;
this.getAssignUserList();
},
handleAssignUserChange(user) {
this.selectedAssignUser = user;
},
submitAssignUser() {
if (!this.selectedAssignUser) {
this.$modal.msgWarning('请选择用户');
return;
}
assignDeviceUser(this.form.deviceId, this.selectedAssignUser.userId).then(() => {
this.$modal.msgSuccess('分配成功');
this.assignUserOpen = false;
this.getDevice(this.form.deviceId);
});
},
/* 连接Mqtt消息服务器 */ /* 连接Mqtt消息服务器 */
async connectMqtt() { async connectMqtt() {
if (this.$mqttTool.client == null) { if (this.$mqttTool.client == null) {

View File

@ -271,7 +271,7 @@
<alert-user ref="alertUser" :device="form"/> <alert-user ref="alertUser" :device="form"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="deviceAlert" :disabled="form.deviceId == 0"> <el-tab-pane name="deviceAlert" :disabled="form.deviceId == 0">
<span slot="label" v-hasPermi="['iot:alertLog:list']">{{ $t('device.device-edit.148398-81') }}</span> <span slot="label" v-hasPermi="['iot:alertLog:list', 'iot:device:list']">{{ $t('device.device-edit.148398-81') }}</span>
<device-alert ref="deviceAlert" :device="form"/> <device-alert ref="deviceAlert" :device="form"/>
</el-tab-pane> </el-tab-pane>