package org.jeecg.modules.demo.mock.vxe.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.VXESocketConst; import org.jeecg.common.system.query.MatchTypeEnum; import org.jeecg.common.system.query.QueryCondition; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.modules.demo.mock.vxe.entity.MockEntity; import org.jeecg.modules.demo.mock.vxe.websocket.VXESocket; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.InputStream; import java.net.URLDecoder; import java.util.*; @RestController @RequestMapping("/mock/vxe") @Slf4j public class VxeMockController { /** * 模拟更改状态 * * @param id * @param status * @return */ @GetMapping("/change1") public Result mockChange1(@RequestParam("id") String id, @RequestParam("status") String status) { /* id 为 行的id(rowId),只要获取到rowId,那么只需要调用 VXESocket.sendMessageToAll() 即可 */ // 封装行数据 JSONObject rowData = new JSONObject(); // 这个字段就是要更改的行数据ID rowData.put("id", id); // 这个字段就是要更改的列的key和具体的值 rowData.put("status", status); // 模拟更改数据 this.mockChange(rowData); return Result.ok(); } /** * 模拟更改拖轮状态 * * @param id * @param tug_status * @return */ @GetMapping("/change2") public Result mockChange2(@RequestParam("id") String id, @RequestParam("tug_status") String tug_status) { /* id 为 行的id(rowId),只要获取到rowId,那么只需要调用 VXESocket.sendMessageToAll() 即可 */ // 封装行数据 JSONObject rowData = new JSONObject(); // 这个字段就是要更改的行数据ID rowData.put("id", id); // 这个字段就是要更改的列的key和具体的值 JSONObject tugStatus = JSON.parseObject(tug_status); rowData.put("tug_status", tugStatus); // 模拟更改数据 this.mockChange(rowData); return Result.ok(); } /** * 模拟更改进度条状态 * * @param id * @param progress * @return */ @GetMapping("/change3") public Result mockChange3(@RequestParam("id") String id, @RequestParam("progress") String progress) { /* id 为 行的id(rowId),只要获取到rowId,那么只需要调用 VXESocket.sendMessageToAll() 即可 */ // 封装行数据 JSONObject rowData = new JSONObject(); // 这个字段就是要更改的行数据ID rowData.put("id", id); // 这个字段就是要更改的列的key和具体的值 rowData.put("progress", progress); // 模拟更改数据 this.mockChange(rowData); return Result.ok(); } private void mockChange(JSONObject rowData) { // 封装socket数据 JSONObject socketData = new JSONObject(); // 这里的 socketKey 必须要和调度计划页面上写的 socketKey 属性保持一致 socketData.put("socketKey", "page-dispatch"); // 这里的 args 必须得是一个数组,下标0是行数据,下标1是caseId,一般不用传 socketData.put("args", new Object[]{rowData, ""}); // 封装消息字符串,这里的 // type 必须是 VXESocketConst.TYPE_UVT String message = VXESocket.packageMessage(VXESocketConst.TYPE_UVT, socketData); // 调用 sendMessageToAll 发送给所有在线的用户 VXESocket.sendMessageToAll(message); } /** * 模拟更改【大船待审】状态 * * @param status * @return */ @GetMapping("/change4") public Result mockChange4(@RequestParam("status") String status) { // 封装socket数据 JSONObject socketData = new JSONObject(); // 这里的 key 是前端注册时使用的key,必须保持一致 socketData.put("key", "dispatch-dcds-status"); // 这里的 args 必须得是一个数组,每一位都是注册方法的参数,按顺序传递 socketData.put("args", new Object[]{status}); // 封装消息字符串,这里的 type 必须是 VXESocketConst.TYPE_UVT String message = VXESocket.packageMessage(VXESocketConst.TYPE_CSD, socketData); // 调用 sendMessageToAll 发送给所有在线的用户 VXESocket.sendMessageToAll(message); return Result.ok(); } /** * 【模拟】即时保存单行数据 * * @param rowData 行数据,实际使用时可以替换成一个实体类 */ @PostMapping("/immediateSaveRow") public Result mockImmediateSaveRow(@RequestBody JSONObject rowData) throws Exception { System.out.println("即时保存.rowData:" + rowData.toJSONString()); // 延时1.5秒,模拟网慢堵塞真实感 Thread.sleep(500); return Result.ok(); } /** * 【模拟】即时保存整个表格的数据 * * @param tableData 表格数据(实际使用时可以替换成一个List实体类) */ @PostMapping("/immediateSaveAll") public Result mockImmediateSaveAll(@RequestBody JSONArray tableData) throws Exception { // 【注】: // 1、tableData里包含该页所有的数据 // 2、如果你实现了“即时保存”,那么除了新增的数据,其他的都是已经保存过的了, // 不需要再进行一次update操作了,所以可以在前端传数据的时候就遍历判断一下, // 只传新增的数据给后台insert即可,否者将会造成性能上的浪费。 // 3、新增的行是没有id的,通过这一点,就可以判断是否是新增的数据 System.out.println("即时保存.tableData:" + tableData.toJSONString()); // 延时1.5秒,模拟网慢堵塞真实感 Thread.sleep(1000); return Result.ok(); } /** * 获取模拟数据 * * @param pageNo 页码 * @param pageSize 页大小 * @param parentId 父ID,不传则查询顶级 * @return */ @GetMapping("/getData") public Result getMockData( @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, // 父级id,根据父级id查询子级,如果为空则查询顶级 @RequestParam(name = "parentId", required = false) String parentId ) { // 模拟JSON数据路径 String path = "classpath:org/jeecg/modules/demo/mock/vxe/json/dlglong.json"; // 读取JSON数据 JSONArray dataList = readJsonData(path); if (dataList == null) { return Result.error("读取数据失败!"); } IPage page = this.queryDataPage(dataList, parentId, pageNo, pageSize); return Result.ok(page); } /** * 获取模拟“调度计划”页面的数据 * * @param pageNo 页码 * @param pageSize 页大小 * @param parentId 父ID,不传则查询顶级 * @return */ @GetMapping("/getDdjhData") public Result getMockDdjhData( // SpringMVC 会自动将参数注入到实体里 MockEntity mockEntity, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, // 父级id,根据父级id查询子级,如果为空则查询顶级 @RequestParam(name = "parentId", required = false) String parentId, @RequestParam(name = "status", required = false) String status, // 高级查询条件 @RequestParam(name = "superQueryParams", required = false) String superQueryParams, // 高级查询模式 @RequestParam(name = "superQueryMatchType", required = false) String superQueryMatchType, HttpServletRequest request ) { // 获取查询条件(前台传递的查询参数) Map parameterMap = request.getParameterMap(); // 遍历输出到控制台 System.out.println("\ngetDdjhData - 普通查询条件:"); for (String key : parameterMap.keySet()) { System.out.println("-- " + key + ": " + JSON.toJSONString(parameterMap.get(key))); } // 输出高级查询 try { System.out.println("\ngetDdjhData - 高级查询条件:"); // 高级查询模式 MatchTypeEnum matchType = MatchTypeEnum.getByValue(superQueryMatchType); if (matchType == null) { System.out.println("-- 高级查询模式:不识别(" + superQueryMatchType + ")"); } else { System.out.println("-- 高级查询模式:" + matchType.getValue()); } superQueryParams = URLDecoder.decode(superQueryParams, "UTF-8"); List conditions = JSON.parseArray(superQueryParams, QueryCondition.class); if (conditions != null) { for (QueryCondition condition : conditions) { System.out.println("-- " + JSON.toJSONString(condition)); } } else { System.out.println("-- 没有传递任何高级查询条件"); } System.out.println(); } catch (Exception e) { log.error("-- 高级查询操作失败:" + superQueryParams, e); e.printStackTrace(); } /* 注:实际使用中不用写上面那种繁琐的代码,这里只是为了直观的输出到控制台里而写的示例, 使用下面这种写法更简洁方便 */ // 封装成 MyBatisPlus 能识别的 QueryWrapper,可以直接使用这个对象进行SQL筛选条件拼接 // 这个方法也会自动封装高级查询条件,但是高级查询参数名必须是superQueryParams和superQueryMatchType QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(mockEntity, parameterMap); System.out.println("queryWrapper: " + queryWrapper.getCustomSqlSegment()); // 模拟JSON数据路径 String path = "classpath:org/jeecg/modules/demo/mock/vxe/json/ddjh.json"; if ("8".equals(status)) { path = "classpath:org/jeecg/modules/demo/mock/vxe/json/ddjh_s8.json"; } // 读取JSON数据 JSONArray dataList = readJsonData(path); if (dataList == null) { return Result.error("读取数据失败!"); } IPage page = this.queryDataPage(dataList, parentId, pageNo, pageSize); // 逐行查询子表数据,用于计算拖轮状态 List records = page.getRecords(); for (JSONObject record : records) { Map tugStatusMap = new HashMap<>(); String id = record.getString("id"); // 查询出主表的拖轮 String tugMain = record.getString("tug"); // 判断是否有值 if (StringUtils.isNotBlank(tugMain)) { // 拖轮根据分号分割 String[] tugs = tugMain.split(";"); // 查询子表数据 List subRecords = this.queryDataPage(dataList, id, null, null).getRecords(); // 遍历子表和拖轮数据,找出进行计算反推拖轮状态 for (JSONObject subData : subRecords) { String subTug = subData.getString("tug"); if (StringUtils.isNotBlank(subTug)) { for (String tug : tugs) { if (tug.equals(subTug)) { // 计算拖轮状态逻辑 int statusCode = 0; /* 如果有发船时间、作业开始时间、作业结束时间、回船时间,则主表中的拖轮列中的每个拖轮背景色要即时变色 */ // 有发船时间,状态 +1 String departureTime = subData.getString("departure_time"); if (StringUtils.isNotBlank(departureTime)) { statusCode += 1; } // 有作业开始时间,状态 +1 String workBeginTime = subData.getString("work_begin_time"); if (StringUtils.isNotBlank(workBeginTime)) { statusCode += 1; } // 有作业结束时间,状态 +1 String workEndTime = subData.getString("work_end_time"); if (StringUtils.isNotBlank(workEndTime)) { statusCode += 1; } // 有回船时间,状态 +1 String returnTime = subData.getString("return_time"); if (StringUtils.isNotBlank(returnTime)) { statusCode += 1; } // 保存拖轮状态,key是拖轮的值,value是状态,前端根据不同的状态码,显示不同的颜色,这个颜色也可以后台计算完之后返回给前端直接使用 tugStatusMap.put(tug, statusCode); break; } } } } } // 新加一个字段用于保存拖轮状态,不要直接覆盖原来的,这个字段可以不保存到数据库里 record.put("tug_status", tugStatusMap); } page.setRecords(records); return Result.ok(page); } /** * 模拟查询数据,可以根据父ID查询,可以分页 * * @param dataList 数据列表 * @param parentId 父ID * @param pageNo 页码 * @param pageSize 页大小 * @return */ private IPage queryDataPage(JSONArray dataList, String parentId, Integer pageNo, Integer pageSize) { // 根据父级id查询子级 JSONArray dataDB = dataList; if (StringUtils.isNotBlank(parentId)) { JSONArray results = new JSONArray(); List parentIds = Arrays.asList(parentId.split(",")); this.queryByParentId(dataDB, parentIds, results); dataDB = results; } // 模拟分页(实际中应用SQL自带的分页) List records = new ArrayList<>(); IPage page; long beginIndex, endIndex; // 如果任意一个参数为null,则不分页 if (pageNo == null || pageSize == null) { page = new Page<>(0, dataDB.size()); beginIndex = 0; endIndex = dataDB.size(); } else { page = new Page<>(pageNo, pageSize); beginIndex = page.offset(); endIndex = page.offset() + page.getSize(); } for (long i = beginIndex; (i < endIndex && i < dataDB.size()); i++) { JSONObject data = dataDB.getJSONObject((int) i); data = JSON.parseObject(data.toJSONString()); // 不返回 children data.remove("children"); records.add(data); } page.setRecords(records); page.setTotal(dataDB.size()); return page; } private void queryByParentId(JSONArray dataList, List parentIds, JSONArray results) { for (int i = 0; i < dataList.size(); i++) { JSONObject data = dataList.getJSONObject(i); JSONArray children = data.getJSONArray("children"); // 找到了该父级 if (parentIds.contains(data.getString("id"))) { if (children != null) { // addAll 的目的是将多个子表的数据合并在一起 results.addAll(children); } } else { if (children != null) { queryByParentId(children, parentIds, results); } } } results.addAll(new JSONArray()); } private JSONArray readJsonData(String path) { try { InputStream stream = getClass().getClassLoader().getResourceAsStream(path.replace("classpath:", "")); if (stream != null) { String json = IOUtils.toString(stream, "UTF-8"); return JSON.parseArray(json); } } catch (IOException e) { log.error(e.getMessage(), e); } return null; } }