src/main/java/com/zy/asrs/controller/BasOutStationAreaController.java
New file @@ -0,0 +1,106 @@ package com.zy.asrs.controller; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.annotations.ManagerAuth; import com.core.common.R; import com.zy.asrs.entity.BasDevp; import com.zy.asrs.entity.BasOutArea; import com.zy.asrs.entity.BasOutStationArea; import com.zy.asrs.entity.BasStation; import com.zy.asrs.service.BasDevpService; import com.zy.asrs.service.BasOutAreaService; import com.zy.asrs.service.BasOutStationAreaService; import com.zy.asrs.service.BasStationService; import com.zy.common.web.BaseController; import com.zy.core.model.StationObjModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @RequestMapping("/basOutStationArea") public class BasOutStationAreaController extends BaseController { @Autowired private BasOutAreaService basOutAreaService; @Autowired private BasOutStationAreaService basOutStationAreaService; @Autowired private BasDevpService basDevpService; @Autowired private BasStationService basStationService; @RequestMapping("/data/auth") @ManagerAuth public R data() { Map<String, Object> data = new HashMap<>(); List<Integer> stationIds = new ArrayList<>(); List<BasDevp> devps = basDevpService.selectList(new EntityWrapper<BasDevp>().eq("status", 1)); for (BasDevp devp : devps) { for (StationObjModel stationObjModel : devp.getOutStationList$()) { stationIds.add(stationObjModel.getStationId()); } } List<BasStation> stations = stationIds.isEmpty() ? new ArrayList<>() : basStationService.selectList(new EntityWrapper<BasStation>().in("station_id", stationIds)); data.put("stations", stations); List<BasOutArea> areas = basOutAreaService.selectList(new EntityWrapper<>()); data.put("areas", areas); List<BasOutStationArea> relations = basOutStationAreaService.selectList(new EntityWrapper<>()); data.put("relations", relations); return R.ok(data); } @RequestMapping("/save/auth") @ManagerAuth public R save(@RequestBody JSONObject payload) { JSONArray areas = payload.getJSONArray("areas"); JSONArray relations = payload.getJSONArray("relations"); basOutAreaService.delete(new EntityWrapper<>()); basOutStationAreaService.delete(new EntityWrapper<>()); if (areas != null && !areas.isEmpty()) { List<BasOutArea> areaList = new ArrayList<>(); for (int i = 0; i < areas.size(); i++) { JSONObject o = areas.getJSONObject(i); BasOutArea a = new BasOutArea(); a.setAreaCode(o.getString("areaCode")); a.setAreaName(o.getString("areaName")); areaList.add(a); } if (!areaList.isEmpty()) { basOutAreaService.insertBatch(areaList); } } if (relations != null && !relations.isEmpty()) { List<BasOutStationArea> relList = new ArrayList<>(); for (int i = 0; i < relations.size(); i++) { JSONObject o = relations.getJSONObject(i); BasOutStationArea r = new BasOutStationArea(); r.setStationId(o.getInteger("stationId")); r.setAreaCode(o.getString("areaCode")); relList.add(r); } if (!relList.isEmpty()) { basOutStationAreaService.insertBatch(relList); } } return R.ok(); } } src/main/java/com/zy/asrs/domain/param/CreateOutTaskParam.java
@@ -8,13 +8,16 @@ //wmsä»»å¡å· private String taskNo; //ç®æ ç« private Integer staNo; //åºåºåºä½ private String locNo; //ä»»å¡ä¼å 级 private Integer taskPri; //ç®æ ç« private Integer staNo; //åºåºåºå private String outArea; } src/main/java/com/zy/asrs/entity/BasOutArea.java
New file @@ -0,0 +1,24 @@ package com.zy.asrs.entity; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import lombok.Data; import java.io.Serializable; @Data @TableName("asr_bas_out_area") public class BasOutArea implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Long id; @TableField("area_code") private String areaCode; @TableField("area_name") private String areaName; } src/main/java/com/zy/asrs/entity/BasOutStationArea.java
New file @@ -0,0 +1,24 @@ package com.zy.asrs.entity; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import lombok.Data; import java.io.Serializable; @Data @TableName("asr_bas_out_station_area") public class BasOutStationArea implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Long id; @TableField("station_id") private Integer stationId; @TableField("area_code") private String areaCode; } src/main/java/com/zy/asrs/mapper/BasOutAreaMapper.java
New file @@ -0,0 +1,11 @@ package com.zy.asrs.mapper; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.zy.asrs.entity.BasOutArea; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository; @Mapper @Repository public interface BasOutAreaMapper extends BaseMapper<BasOutArea> { } src/main/java/com/zy/asrs/mapper/BasOutStationAreaMapper.java
New file @@ -0,0 +1,11 @@ package com.zy.asrs.mapper; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.zy.asrs.entity.BasOutStationArea; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository; @Mapper @Repository public interface BasOutStationAreaMapper extends BaseMapper<BasOutStationArea> { } src/main/java/com/zy/asrs/service/BasOutAreaService.java
New file @@ -0,0 +1,7 @@ package com.zy.asrs.service; import com.baomidou.mybatisplus.service.IService; import com.zy.asrs.entity.BasOutArea; public interface BasOutAreaService extends IService<BasOutArea> { } src/main/java/com/zy/asrs/service/BasOutStationAreaService.java
New file @@ -0,0 +1,7 @@ package com.zy.asrs.service; import com.baomidou.mybatisplus.service.IService; import com.zy.asrs.entity.BasOutStationArea; public interface BasOutStationAreaService extends IService<BasOutStationArea> { } src/main/java/com/zy/asrs/service/impl/BasOutAreaServiceImpl.java
New file @@ -0,0 +1,11 @@ package com.zy.asrs.service.impl; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.zy.asrs.entity.BasOutArea; import com.zy.asrs.mapper.BasOutAreaMapper; import com.zy.asrs.service.BasOutAreaService; import org.springframework.stereotype.Service; @Service public class BasOutAreaServiceImpl extends ServiceImpl<BasOutAreaMapper, BasOutArea> implements BasOutAreaService { } src/main/java/com/zy/asrs/service/impl/BasOutStationAreaServiceImpl.java
New file @@ -0,0 +1,11 @@ package com.zy.asrs.service.impl; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.zy.asrs.entity.BasOutStationArea; import com.zy.asrs.mapper.BasOutStationAreaMapper; import com.zy.asrs.service.BasOutStationAreaService; import org.springframework.stereotype.Service; @Service public class BasOutStationAreaServiceImpl extends ServiceImpl<BasOutStationAreaMapper, BasOutStationArea> implements BasOutStationAreaService { } src/main/java/com/zy/common/service/CommonService.java
@@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; @Slf4j @Service @@ -43,6 +44,8 @@ private NavigateUtils navigateUtils; @Autowired private RedisUtil redisUtil; @Autowired private BasOutStationAreaService basOutStationAreaService; /** * çæå·¥ä½å· @@ -302,7 +305,23 @@ } Integer crnNo = findCrnResult.getCrnNo(); Integer sourceStationId = this.findOutStationId(findCrnResult, param.getStaNo()); Integer staNo = param.getStaNo(); String outArea = param.getOutArea(); if(Cools.isEmpty(staNo) && Cools.isEmpty(outArea)) { throw new CoolException("è¯·ä¼ å ¥åºåºç«ç¹æåºåºåºå"); } if(Cools.isEmpty(staNo)) { List<BasOutStationArea> areaList = basOutStationAreaService.selectList(new EntityWrapper<BasOutStationArea>().eq("area_code", outArea)); if (areaList.isEmpty()) { throw new CoolException("åºåºåºåä¸åå¨"); } int nextInt = new Random().nextInt(areaList.size()); BasOutStationArea basOutStationArea = areaList.get(nextInt); staNo = basOutStationArea.getStationId(); } Integer sourceStationId = this.findOutStationId(findCrnResult, staNo); if (sourceStationId == null) { throw new CoolException("æªæ¾å°è¾éç®æ ç«ç¹å¯èµ°è¡è·¯å¾"); } @@ -318,7 +337,7 @@ wrkMast.setIoPri(ioPri); wrkMast.setSourceLocNo(locMast.getLocNo()); // æºåºä½ wrkMast.setSourceStaNo(sourceStationId);//æºç« wrkMast.setStaNo(param.getStaNo());//ç®æ ç« wrkMast.setStaNo(staNo);//ç®æ ç« wrkMast.setWmsWrkNo(param.getTaskNo()); wrkMast.setBarcode(locMast.getBarcode()); wrkMast.setAppeTime(now); src/main/resources/docs/WCSÍⲿHTTP API½Ó¿ÚV1.4.docxBinary files differ
src/main/resources/mapper/BasOutAreaMapper.xml
New file @@ -0,0 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zy.asrs.mapper.BasOutAreaMapper"> <resultMap id="BaseResultMap" type="com.zy.asrs.entity.BasOutArea"> <id column="id" property="id"/> <result column="area_code" property="areaCode"/> <result column="area_name" property="areaName"/> </resultMap> </mapper> src/main/resources/mapper/BasOutStationAreaMapper.xml
New file @@ -0,0 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zy.asrs.mapper.BasOutStationAreaMapper"> <resultMap id="BaseResultMap" type="com.zy.asrs.entity.BasOutStationArea"> <id column="id" property="id"/> <result column="station_id" property="stationId"/> <result column="area_code" property="areaCode"/> </resultMap> </mapper> src/main/webapp/static/js/basOutStationArea/basOutStationArea.js
New file @@ -0,0 +1,167 @@ var app = new Vue({ el: '#app', data: { stations: [], areas: [], relations: [], lines: [], draggingItem: null, draggingLine: null, saving: false, newAreaCode: '', newAreaName: '' }, mounted: function() { this.loadData(); window.addEventListener('resize', this.updateLines); this.$nextTick(function() { if (this.$refs.stationList) this.$refs.stationList.addEventListener('scroll', this.updateLines); if (this.$refs.areaList) this.$refs.areaList.addEventListener('scroll', this.updateLines); }.bind(this)); }, beforeDestroy: function() { window.removeEventListener('resize', this.updateLines); }, methods: { loadData: function() { var that = this; var loading = this.$loading({ lock: true, text: 'å è½½æ°æ®ä¸...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }); $.ajax({ url: baseUrl + '/basOutStationArea/data/auth', headers: { 'token': localStorage.getItem('token') }, method: 'GET', success: function(res) { loading.close(); if (res.code === 200) { that.stations = res.data.stations || []; that.areas = res.data.areas || []; that.relations = res.data.relations || []; that.$nextTick(function() { that.updateLines(); }); } else if (res.code === 403) { top.location.href = baseUrl + "/"; } else { that.$message.error('å è½½æ°æ®å¤±è´¥: ' + res.msg); } }, error: function() { loading.close(); that.$message.error('å 载请æ±å¼å¸¸'); } }); }, saveData: function() { var that = this; this.saving = true; var payload = { areas: this.areas, relations: this.relations }; $.ajax({ url: baseUrl + '/basOutStationArea/save/auth', type: 'POST', headers: { 'token': localStorage.getItem('token') }, contentType: 'application/json', data: JSON.stringify(payload), success: function (res) { that.saving = false; if (res.code === 200) { that.$message.success('ä¿åæå'); that.loadData(); } else { that.$message.error('ä¿å失败: ' + res.msg); } }, error: function () { that.saving = false; that.$message.error('ä¿å请æ±å¼å¸¸'); } }); }, addArea: function() { var code = (this.newAreaCode || '').trim(); var name = (this.newAreaName || '').trim(); if (!code || !name) { this.$message.warning('请è¾å ¥åºåç¼ç ååç§°'); return; } var exists = this.areas.some(function(a) { return a.areaCode === code; }); if (exists) { this.$message.warning('åºåå·²åå¨'); return; } this.areas.push({ areaCode: code, areaName: name }); this.newAreaCode = ''; this.newAreaName = ''; this.$nextTick(this.updateLines); }, removeArea: function(areaCode) { this.areas = this.areas.filter(function(a) { return a.areaCode !== areaCode; }); this.relations = this.relations.filter(function(r) { return r.areaCode !== areaCode; }); this.$nextTick(this.updateLines); }, isStationBound: function(stationId) { return this.relations.some(function(r) { return r.stationId == stationId; }); }, isAreaBound: function(areaCode) { return this.relations.some(function(r) { return r.areaCode == areaCode; }); }, onDragStart: function(event, item, type) { this.draggingItem = { item: item, type: type }; event.dataTransfer.effectAllowed = 'link'; }, onDragEnd: function() { this.draggingItem = null; this.draggingLine = null; }, onDrop: function(event, targetArea) { if (!this.draggingItem || this.draggingItem.type !== 'station') return; var station = this.draggingItem.item; var exists = this.relations.some(function(r) { return r.stationId == station.stationId && r.areaCode == targetArea.areaCode; }); if (exists) { this.$message.warning('该ç»å®å·²åå¨'); return; } this.relations.push({ stationId: station.stationId, areaCode: targetArea.areaCode }); this.$message.success('已建ç«ç»å®: ç«ç¹ ' + station.stationId + ' -> åºå ' + (targetArea.areaName || targetArea.areaCode)); this.$nextTick(this.updateLines); }, confirmDelete: function(index) { var rel = this.lines[index] && this.lines[index].relation; if (!rel) return; this.relations = this.relations.filter(function(r) { return !(r.stationId == rel.stationId && r.areaCode == rel.areaCode); }); this.$nextTick(this.updateLines); }, updateLines: function() { var svg = document.querySelector('svg'); if (!svg) return; var svgRect = svg.getBoundingClientRect(); var newLines = []; this.relations.forEach(function(rel) { var sDom = document.getElementById('station-' + rel.stationId); var aDom = document.getElementById('area-' + rel.areaCode); if (sDom && aDom) { var sRect = sDom.getBoundingClientRect(); var aRect = aDom.getBoundingClientRect(); var x1 = sRect.right - svgRect.left; var y1 = sRect.top + sRect.height / 2 - svgRect.top; var x2 = aRect.left - svgRect.left; var y2 = aRect.top + aRect.height / 2 - svgRect.top; newLines.push({ x1: x1, y1: y1, x2: x2, y2: y2, relation: rel, stationId: rel.stationId, areaCode: rel.areaCode }); } }); this.lines = newLines; } } }); src/main/webapp/views/basOutStationArea/basOutStationArea.html
New file @@ -0,0 +1,86 @@ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <title>åºåºç«ä¸åºåºåºåç»å®é ç½®</title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <link rel="stylesheet" href="../../static/vue/element/element.css"> <link rel="stylesheet" href="../../static/css/cool.css"> <style> html, body { height: 100%; margin: 0; padding: 0; background-color: #f0f2f5; } #app { height: 100%; padding: 20px; box-sizing: border-box; display: flex; flex-direction: column; } .main-card { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .flow-container { flex: 1; display: flex; position: relative; background: #fff; border: 1px solid #ebeef5; overflow: hidden; } .column { width: 300px; display: flex; flex-direction: column; border-right: 1px solid #ebeef5; background-color: #fcfcfc; z-index: 10; } .column.right { border-right: none; border-left: 1px solid #ebeef5; position: absolute; right: 0; top: 0; bottom: 0; } .column-header { padding: 15px; text-align: center; font-weight: bold; background-color: #f5f7fa; border-bottom: 1px solid #ebeef5; color: #606266; } .list-container { flex: 1; overflow-y: auto; padding: 10px; } .node-item { padding: 12px; margin-bottom: 10px; background-color: #fff; border: 1px solid #dcdfe6; border-radius: 4px; cursor: grab; transition: all 0.3s; position: relative; color: #606266; font-size: 14px; display: flex; justify-content: space-between; align-items: center; } .node-item:hover { box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1); border-color: #409eff; } .node-item.active { background-color: #ecf5ff; border-color: #409eff; color: #409eff; } .station-node { border-left: 4px solid #67c23a; } .area-node { border-left: 4px solid #e6a23c; } .canvas-area { flex: 1; position: relative; margin-right: 300px; background-color: #fafafa; overflow: hidden; } svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } svg line { stroke: #909399; stroke-width: 2; cursor: pointer; pointer-events: stroke; transition: stroke-width 0.2s, stroke 0.2s; } svg line:hover { stroke: #f56c6c; stroke-width: 4; } .toolbar { padding: 10px 0; display: flex; justify-content: space-between; align-items: center; } .area-toolbar { padding: 10px; border-bottom: 1px solid #ebeef5; } </style> </head> <body> <div id="app" v-cloak> <el-card class="main-card" :body-style="{ padding: '0px', display: 'flex', flexDirection: 'column', height: '100%' }"> <div slot="header" class="clearfix"> <span style="font-weight: bold; font-size: 16px;">åºåºç«ä¸åºåºåºåç»å®é ç½®</span> <div style="float: right;"> <el-button type="primary" icon="el-icon-check" size="small" @click="saveData" :loading="saving">ä¿åé ç½®</el-button> <el-button icon="el-icon-refresh" size="small" @click="loadData">å·æ°</el-button> </div> </div> <div class="toolbar" style="padding: 10px 20px; border-bottom: 1px solid #ebeef5;"> <el-alert title="æä½è¯´æï¼ææ½å·¦ä¾§ãåºåºç«ç¹ãå°å³ä¾§ãåºåºåºåãä¸å»ºç«ç»å®ãç¹å»è¿çº¿å¯å é¤ç»å®ã" type="info" show-icon :closable="false"></el-alert> </div> <div class="flow-container" ref="flowContainer"> <div class="column"> <div class="column-header">åºåºç«ç¹ ({{ stations.length }})</div> <div class="list-container" ref="stationList"> <div v-for="item in stations" :key="'s-' + item.stationId" :id="'station-' + item.stationId" class="node-item station-node" :class="{ active: isStationBound(item.stationId) }" draggable="true" @dragstart="onDragStart($event, item, 'station')" @dragend="onDragEnd"> <span>{{ item.stationId }}</span> </div> </div> </div> <div class="canvas-area"> <svg width="100%" height="100%"> <line v-for="(link, index) in lines" :key="index" :x1="link.x1" :y1="link.y1" :x2="link.x2" :y2="link.y2" @click="confirmDelete(index)"> <title>ç¹å»å é¤ç»å®: ç«ç¹ {{ link.stationId }} -> åºå {{ link.areaCode }}</title> </line> <line v-if="draggingLine" :x1="draggingLine.x1" :y1="draggingLine.y1" :x2="draggingLine.x2" :y2="draggingLine.y2" stroke="#409eff" stroke-dasharray="5,5" stroke-width="2" /> </svg> </div> <div class="column right"> <div class="column-header">åºåºåºå ({{ areas.length }})</div> <div class="area-toolbar"> <el-input size="small" placeholder="åºåç¼ç " v-model="newAreaCode" style="width: 140px; margin-right: 8px;"></el-input> <el-input size="small" placeholder="åºååç§°" v-model="newAreaName" style="width: 140px; margin-right: 8px;"></el-input> <el-button size="small" type="primary" icon="el-icon-plus" @click="addArea">æ°å¢åºå</el-button> </div> <div class="list-container" ref="areaList"> <div v-for="item in areas" :key="'a-' + item.areaCode" :id="'area-' + item.areaCode" class="node-item area-node" :class="{ active: isAreaBound(item.areaCode) }" @dragover.prevent @drop="onDrop($event, item)"> <span>{{ item.areaCode }} - {{ item.areaName }}</span> <el-button type="text" size="mini" @click="removeArea(item.areaCode)">å é¤</el-button> </div> </div> </div> </div> </el-card> </div> <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="../../static/vue/js/vue.min.js"></script> <script type="text/javascript" src="../../static/vue/element/element.js"></script> <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> <script type="text/javascript" src="../../static/js/basOutStationArea/basOutStationArea.js"></script> </body> </html>