index.blade.php 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. <!DOCTYPE html>
  2. <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1">
  6. <link rel="icon" href="{{asset('icon/faviconc.ico')}}" type="image/x-icon"/>
  7. <!-- CSRF Token -->
  8. <meta name="csrf-token" content="{{ csrf_token() }}">
  9. <title>设备平面</title>
  10. <link href="{{ mix('css/app.css') }}" rel="stylesheet">
  11. <link href="{{ mix('css/animation.css') }}" rel="stylesheet">
  12. <style>
  13. html{
  14. width: 100%;
  15. height: 100%;
  16. }
  17. body{
  18. width: 100%;
  19. height: 100%;
  20. }
  21. .p1{
  22. overflow: hidden;
  23. text-overflow: ellipsis;
  24. display: -webkit-box;
  25. -webkit-line-clamp: 2;
  26. -webkit-box-orient: vertical;
  27. }
  28. .el-center{
  29. display:flex;
  30. align-items:center;
  31. justify-content:center;
  32. }
  33. .el-left-bottom{
  34. position: absolute;
  35. bottom: 0;
  36. left: 0;
  37. }
  38. .el-right-bottom{
  39. position: absolute;
  40. bottom: 0;
  41. right: 0;
  42. }
  43. .txt-sty{
  44. filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
  45. font-family: "Microsoft YaHei Light","sans-serif";
  46. font-size: 10px;
  47. white-space:nowrap;
  48. font-weight:bold;
  49. }
  50. .re{transform:rotate(-90deg);
  51. -ms-transform:rotate(-90deg); /* Internet Explorer 9*/
  52. -moz-transform:rotate(-90deg); /* Firefox */
  53. -webkit-transform:rotate(-90deg); /* Safari 和 Chrome */
  54. -o-transform:rotate(-90deg); /* Opera */
  55. }
  56. /*opacity是设置遮罩透明度的,可以自己调节*/
  57. #loading{position:fixed;top:0;left:0;width:100%;height:100%;background:#f8f8f8;opacity:0.6;z-index:15000;}
  58. #loading i{position:absolute;top:50%;left:50%;font-size:33px;margin-top:-15px;margin-left:-40px;}
  59. #loading p{position:absolute;top:55%;left:48%;width:33px;height:33px;margin-top:-15px;margin-left:-15px;}
  60. </style>
  61. </head>
  62. <body>
  63. <div class="container-fluid w-100 h-100" id="container" @mousemove="eqMove()" @mouseup="eqUp()">
  64. <div class="row w-100 h-100">
  65. <div class="col-2 " style="user-select: none;" id="tool">
  66. <div class="dropdown">
  67. <button type="button" class="btn p-0 w-100" id="dropdownMenu"
  68. data-toggle="dropdown">
  69. <h4 class="text-muted mt-1 p1">@{{ name }}&nbsp;&nbsp;<i class="fa fa-exchange text-info"></i></h4>
  70. </button>
  71. <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
  72. <li role="presentation" v-for="warehouse in warehouses" v-if="warehouse.id!==selected">
  73. <a role="menuitem" tabindex="-1" style="cursor: pointer" class="ml-3"
  74. @click="selectedWarehouse(warehouse)">@{{ warehouse.name }}</a>
  75. </li>
  76. <li role="presentation" class="text-center" @click="showAddWarehouseDetail()">
  77. <a role="menuitem" tabindex="-1" style="cursor: pointer" class="ml-3 text-primary"
  78. ><i class="fa fa-plus"></i> 新增</a>
  79. </li>
  80. </ul>
  81. </div>
  82. <button class="btn btn-info mt-5 w-100 text-white" @click="openRepository()">新增库区</button>
  83. <p class="font-weight-bold p-0 mb-0 mt-1">位置</p>
  84. <div class="row text-muted small">
  85. <small class="col-6">X</small>
  86. <small class="col-6">Y</small>
  87. </div>
  88. <div class="row m-0 p-0">
  89. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.x"
  90. @blur="changeNumber('x')"></input>
  91. <input type="number" class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.y"
  92. @blur="changeNumber('y')"></input>
  93. </div>
  94. <p class="font-weight-bold p-0 mb-0 mt-3">大小</p>
  95. <div class="row text-muted small">
  96. <small class="col-6">高</small>
  97. <small class="col-6">宽</small>
  98. </div>
  99. <div class="row m-0 p-0">
  100. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.height" @blur="changeNumber('height')"></input>
  101. <input type="number" class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.width" @blur="changeNumber('width')"></input>
  102. </div>
  103. <p class="font-weight-bold p-0 mb-0 mt-3">其他</p>
  104. <div class="row text-muted small">
  105. <small class="col-6">层级</small>
  106. <small class="col-6">颜色</small>
  107. </div>
  108. <div class="row m-0 p-0">
  109. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.index" @blur="changeNumber('index')"></input>
  110. <input class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.color" @blur="changeText('color')"></input>
  111. </div>
  112. <div class="row text-muted small">
  113. <small class="col-6">名称</small>
  114. <small class="col-6">名称位置</small>
  115. </div>
  116. <div class="row m-0 p-0">
  117. <input class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.name" @blur="changeText('name')"></input>
  118. <select class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" v-model="currentEl.coords">
  119. <option value="左上">左上</option>
  120. <option value="左下">左下</option>
  121. <option value="右上">右上</option>
  122. <option value="右下">右下</option>
  123. <option value="居中">居中</option>
  124. <option value="中上">中上</option>
  125. </select>
  126. </div>
  127. <div class="row text-muted small">
  128. <small class="col-6">边框</small>
  129. </div>
  130. <div class="m-0 small row">
  131. <div class="col-6 p-0">
  132. <div class="form-check">
  133. <label class="form-check-label">
  134. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="top" :disabled="currentEl.x===undefined">上
  135. </label>
  136. </div>
  137. <div class="form-check">
  138. <label class="form-check-label">
  139. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="bottom" :disabled="currentEl.x===undefined">下
  140. </label>
  141. </div>
  142. <div class="form-check">
  143. <label class="form-check-label">
  144. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="left" :disabled="currentEl.x===undefined">左
  145. </label>
  146. </div>
  147. <div class="form-check">
  148. <label class="form-check-label">
  149. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="right" :disabled="currentEl.x===undefined">右
  150. </label>
  151. </div>
  152. </div>
  153. <div class="col-6 p-0">
  154. <div class="form-check">
  155. <label class="form-check-label">
  156. <button class="btn btn-sm btn-success" @click="addCoords()">生成场景元素</button>
  157. </label>
  158. </div>
  159. </div>
  160. </div>
  161. <p class="font-weight-bold p-0 mb-0 mt-5 h5">全局</p>
  162. <div class="row text-muted">
  163. <div class="col-4">缩放</div>
  164. <div class="input-group input-group-sm col-8 m-0">
  165. <input type="number" class="form-control" step="1" v-model="scale"></input>
  166. <div class="input-group-append">
  167. <span class="input-group-text">%</span>
  168. </div>
  169. </div>
  170. </div>
  171. <div class="row mt-3">
  172. <h5 class="font-weight-bold ml-3">设备</h5>
  173. <div class="form-check ml-3">
  174. <label class="form-check-label">
  175. <input type="checkbox" class="form-check-input" v-model="grid">网格
  176. </label>
  177. <label class="form-check-label ml-4">
  178. <input type="checkbox" class="form-check-input" v-model="turn">翻转
  179. </label>
  180. </div>
  181. </div>
  182. <div style="height: 250px;overflow-y: auto;overflow-x: hidden" class="w-100">
  183. <div class="row" v-for="equipment in equipments" @mousedown="eqDown(equipment)">
  184. <div class="col-5">
  185. <div style="border: 1px #0070C0 solid" :style="[{backgroundColor:equipment.color},{width:(equipment.h*ratio)+'px'},{height:(equipment.w*ratio)+'px'}]"></div>
  186. </div>
  187. <div class="col-7 p1">
  188. @{{ equipment.describe }}
  189. </div>
  190. </div>
  191. </div>
  192. <button @click="clickEditOrSave()" :class="isNotEdit ? 'btn-info' : 'btn-success'"
  193. style="position:absolute;bottom: 20px;cursor: pointer" class="btn col-10 text-white">
  194. <span v-if="isNotEdit">开启场景编辑</span>
  195. <span v-else>保存更改</span>
  196. </button>
  197. </div>
  198. <div class="col-10 p-0">
  199. <div class="w-100 bg-secondary" id="canvasApp" style="height: 100vh;overflow: auto;user-select: none;">
  200. <div id="canvas" v-if="isLoad" @keydown.delete="delElement()" :style="[{width:container.width*(scale/100)+'px'},{height:container.height*(scale/100)+'px'},{transform: 'scale('+(scale/100)+')'}]"
  201. style="position: relative;transform-origin: 0 0" class="bg-white"
  202. @mousedown="contentOnmousedown" @mousemove="contentOnmousemove" @mouseup="contentOnmouseup">
  203. <vue-drag-resize v-for="(element,index) in elements" v-if="!element.removeSign"
  204. @activated="onActivated(element)"
  205. @dragging="onDragging"
  206. @resizing="onResizing"
  207. :minw="1" :minh="1"
  208. :style="[{backgroundColor:element.color},
  209. element.border.indexOf('left')===-1 ? {borderLeft:'none'} : {},
  210. element.border.indexOf('right')===-1 ? {borderRight:'none'} : {},
  211. element.border.indexOf('top')===-1 ? {borderTop:'none'} : {},
  212. element.border.indexOf('bottom')===-1 ? {borderBottom:'none'} : {}]"
  213. style="border-width:1px;border-color: #000000;border-style: solid"
  214. :key="index" :prevent-active-behavior="isNotEdit"
  215. :parent-limitation="true" :w="element.width*ratio" :h="element.height*ratio"
  216. :x="element.x" :y="element.y" :z="element.index">
  217. <div :class="coordsMapping[element.coords]">@{{ element.name }}</div>
  218. </vue-drag-resize>
  219. <vue-drag-resize style="border-width:1px;border-color: #0070C0;border-style: dashed;cursor: pointer"
  220. v-for="(element,index) in equipmentElements" @clicked="showDetail(element)"
  221. v-if="!element.removeSign"
  222. :is-resizable="false" :snap-to-grid="grid" :grid-x="40" :grid-y="30"
  223. :style="[{backgroundColor:element.color}]"
  224. @activated="onActivated(element)"
  225. @dragging="equipmentDrag"
  226. :key="'eq-'+index+element.turn" :prevent-active-behavior="isNotEdit"
  227. :parent-limitation="true" :w="(element.turn ? element.w : element.h)*ratio" :h="(element.turn ? element.h : element.w)*ratio"
  228. :x="element.x" :y="element.y" :z="90">
  229. <div class="h-100 txt-sty w-100 el-center" :class="element.turn ? 're' : ''">@{{ element.code }}</div>
  230. </vue-drag-resize>
  231. </div>
  232. </div>
  233. </div>
  234. <div id="loading" class="list-item">
  235. <i class="fa fa-spinner fa-spin"></i>
  236. <p style="line-height: 24px;">loading...</p>
  237. </div>
  238. </div>
  239. @include("equipment._detailInfo")
  240. @include("equipment._location")
  241. @include("equipment._warehouseDetail")
  242. @include("equipment._repository")
  243. </div>
  244. </body>
  245. <script src="{{ mix('js/app.js') }}"></script>
  246. <script src="{{ asset('js/utilities/toast.js') }}"></script>
  247. <script type="text/javascript">
  248. var vue = new Vue({
  249. el:"#container",
  250. data:{
  251. group:[],//库区列表
  252. ws:[],//仓库列表
  253. locationMapping:{},//库位的信息映射
  254. warehouseDetail:{},//当前操作的仓库
  255. repository:{},//当前操作的库区
  256. warehouses:[], //仓库描述
  257. repositories:[], //库区
  258. selected:"", //当前选中的仓库ID
  259. container:{width:90,height:60}, //容器初始大小
  260. ratio:20, //设备大小缩放比例值
  261. name:"", //当前选中的仓库NAME
  262. isNotEdit:true, //是否允许编辑
  263. isLoad:true, //是否加载
  264. currentEl:{}, //当前选中的元素
  265. coordsMapping:{ //元素信息映射
  266. "居中":"h-100 w-100 el-center",
  267. "中上":"text-center",
  268. "左上":"",
  269. "左下":"el-left-bottom",
  270. "右上":"text-right",
  271. "右下":"el-right-bottom",
  272. },
  273. elements:[], //场景元素池
  274. clientCoords:{}, //坐标系记录
  275. scale:100, //缩放值
  276. equipments:[ //备选设备池
  277. {id:1,w:1.2,h:2.4,grid:2,layer:4,color:"RGB(252,228,214)",describe:"4层高位货架,可设八个标准托盘位"},
  278. {id:2,w:1.2,h:2.4,grid:2,layer:5,color:"RGB(255,255,255)",describe:"5层高位货架,可设十个标准托盘位"},
  279. {id:3,w:1.2,h:2.4,grid:1,layer:3,color:"RGB(169,208,142)",describe:"叉车通道,可设三个标准托盘位"},
  280. {id:4,w:1.2,h:2.4,grid:2,layer:3,color:"RGB(221,235,247)",describe:"叉车通道,可设六个标准托盘位"},
  281. {id:5,w:1.2,h:1.2,grid:1,layer:4,color:"RGB(255,255,0)",describe:"半组货架,可设四层高四个标准托盘位"},
  282. {id:6,w:1.2,h:1.2,grid:2,layer:1,color:"RGB(189,215,238)",describe:"叉车通道,顶上两个托盘位"},
  283. {id:7,w:1.2,h:1.2,grid:1,layer:5,color:"RGB(255,255,5)",describe:"半组货架,可设五层高五个标准托盘位"},
  284. ],
  285. currentEq:{ //选中的设备
  286. el:null,
  287. obj:null,
  288. },
  289. equipmentElements:[], //设备元素池
  290. grid:true, //设备拖拽是否开启网格
  291. turn:true, //设备是否翻转
  292. isLoadLocation:false, //开启加载库位
  293. baseUrl:"http://127.0.0.1:8112/",
  294. //baseUrl:"https://swms.baoshi56.com/",
  295. current:{}, //当前操作的设备
  296. error:{},
  297. locations:[],
  298. currentEqChildIndex:null,
  299. buildPool:{},
  300. },
  301. mounted() {
  302. this.initPage();
  303. },
  304. computed:{
  305. flipLayer(){
  306. let layer = [];
  307. for (let i=this.current.layer;i>0;i--){
  308. layer.push(i);
  309. }
  310. return layer;
  311. },
  312. },
  313. created: function() {
  314. document.onkeydown = e=> {
  315. let key = e.keyCode;
  316. if (key === 8) {
  317. this.delElement();
  318. }
  319. };
  320. },
  321. methods:{
  322. delCoords(){
  323. this.elements.some((el,index)=>{
  324. if (this.currentEl.name === el.name &&
  325. this.currentEl.x === el.x && this.currentEl.y === el.y){
  326. this.$set(this.elements[index],"removeSign",true);
  327. return true;
  328. }
  329. })
  330. },
  331. delEquipment(){
  332. this.equipmentElements.some((el,index)=>{
  333. if (this.currentEl.eqId === el.eqId){
  334. this.$set(this.equipmentElements[index],"removeSign",true);
  335. return true;
  336. }
  337. })
  338. },
  339. delElement(){
  340. if (this.isNotEdit || !this.current)return;
  341. if (this.currentEl.eqId)this.delEquipment();
  342. else this.delCoords();
  343. },
  344. addCoords(){
  345. if (this.isNotEdit)return;
  346. this.elements.push({"x":200,"y":200,"width":2,"height":2,"name":"","coords":"居中","border":["left","top","right","bottom"],"color":"white","index":1})
  347. },
  348. clickEditOrSave(){
  349. if(this.isNotEdit){this.isNotEdit = false;return;}
  350. let equipments = [];
  351. let delEquipments = [];
  352. let elements = [];
  353. this.equipmentElements.forEach(equipment=>{
  354. if (equipment.removeSign){
  355. delEquipments.push(equipment.eqId);
  356. }else if (equipment.updateCoords){
  357. equipments.push({
  358. id:equipment.eqId,
  359. info:JSON.stringify({x:equipment.x,y:equipment.y,id:equipment.id})
  360. });
  361. }
  362. });
  363. this.elements.forEach(el=>{
  364. if (!el.removeSign){
  365. elements.push(el);
  366. }
  367. });
  368. $.ajax({
  369. url : this.baseUrl+"warehouse/saveScene",
  370. type : "POST",
  371. headers:{'Content-Type':'application/json;charset=utf8'},
  372. data:JSON.stringify({id:this.selected,warehouse:JSON.stringify(elements),equipment:equipments,delEquipments:delEquipments}),
  373. success : (res,status)=>{
  374. if (res.code===200){
  375. this.isNotEdit = true;
  376. window.toast.success("场景更改保存成功");
  377. }else window.toast.error(res.message);
  378. },
  379. error : (err,status)=>{
  380. window.tempTip.show("加载失败");
  381. },
  382. complete:(req,status)=>{
  383. if (status==='timeout'){
  384. window.toast.error("服务器响应超时");
  385. }
  386. },
  387. timeout:10000,
  388. })
  389. },
  390. initPage(){
  391. $.ajax({
  392. url : this.baseUrl+"warehouse/detail",
  393. type : "GET",
  394. success : (res,status)=>{
  395. this.warehouses = res.data;
  396. //这里获取warehouses
  397. let id = localStorage.getItem("equipment:warehouse");
  398. if (!id || !this.warehouses.some(warehouse=>{
  399. if (warehouse.id == id){
  400. this.selectedWarehouse(warehouse);
  401. return true;
  402. }
  403. })
  404. ){
  405. if (this.warehouses.length>0)this.selectedWarehouse(this.warehouses[0]);
  406. }
  407. $("#loading").hide();
  408. },
  409. error : (err,status)=>{
  410. window.tempTip.show("加载失败");
  411. },
  412. timeout:3000,
  413. })
  414. },
  415. //备选设备拖拽按下事件
  416. eqDown(equipment){
  417. if (this.isNotEdit)return;
  418. if (this.currentEq.obj!==null)return;
  419. let wid = (this.turn ? equipment.w : equipment.h)*this.ratio;
  420. let hei = (this.turn ? equipment.h : equipment.w)*this.ratio;
  421. let div = document.createElement("div");
  422. div.style.width = wid+'px';
  423. div.style.height = hei+'px';
  424. div.style.backgroundColor = equipment.color;
  425. div.style.zIndex = '999';
  426. div.style.position = 'fixed';
  427. div.style.left = event.clientX+'px';
  428. div.style.top = event.clientY+'px';
  429. div.style.border = '1px #0070C0 solid';
  430. div.style.opacity = '0.5';
  431. document.getElementById("container").append(div);
  432. this.currentEq.el = div;
  433. this.currentEq.obj = equipment;
  434. },
  435. //备选设备拖拽移动事件
  436. eqMove(){
  437. if (this.isNotEdit)return;
  438. if (this.currentEq.obj===null)return;
  439. let x = event.clientX;
  440. let y = event.clientY;
  441. setTimeout(()=>{
  442. this.currentEq.el.style.left = x+'px';
  443. this.currentEq.el.style.top = y+'px';
  444. },10);
  445. },
  446. //备选设备拖拽松开事件
  447. eqUp(){
  448. if (this.isNotEdit)return;
  449. if (this.currentEq.obj===null)return;
  450. this.currentEq.el.remove();
  451. setTimeout(()=>{
  452. this.currentEq.el.remove();
  453. this.currentEq.el = null;
  454. },20);
  455. let content = document.getElementById("canvasApp");
  456. let toolWid = document.getElementById("tool").offsetWidth;
  457. let x = event.clientX-toolWid+content.scrollLeft;
  458. let y = event.clientY+content.scrollTop;
  459. if (x>=0 && y>=0){
  460. let children = [];
  461. for (let i=0;i<this.currentEq.obj.layer;i++)children.push({});
  462. let newEquipment = Object.assign({children:children,x:x,y:y}, this.currentEq.obj);
  463. if (this.turn){
  464. let wid = newEquipment.w;
  465. newEquipment.w = newEquipment.h;
  466. newEquipment.h = wid;
  467. }
  468. newEquipment.width = newEquipment.w;
  469. newEquipment.depth = newEquipment.h;
  470. this.equipmentElements.push(newEquipment);
  471. this.current = this.equipmentElements[this.equipmentElements.length-1];
  472. setTimeout(()=>{
  473. $("#detailInfo").modal("show");
  474. },20);
  475. }
  476. this.currentEq.obj = null;
  477. },
  478. //场景拖拽按下事件
  479. contentOnmousedown(event){
  480. if (!this.isNotEdit || this.clientCoords.x!==undefined)return;
  481. this.clientCoords = {
  482. x:event.clientX,
  483. y:event.clientY
  484. };
  485. },
  486. //场景拖拽移动事件
  487. contentOnmousemove(event){
  488. if (this.clientCoords.x===undefined)return;
  489. let diffX = event.clientX-this.clientCoords.x-2;
  490. let diffY = event.clientY-this.clientCoords.y-2;
  491. let content = document.getElementById("canvasApp");
  492. setTimeout(()=>{
  493. content.scrollTo(content.scrollLeft+diffX,content.scrollTop+diffY);
  494. },10);
  495. },
  496. //场景拖拽松开事件
  497. contentOnmouseup(){
  498. this.clientCoords = {};
  499. },
  500. onActivated(element){
  501. if (this.isNotEdit)return;
  502. this.currentEl = element;
  503. },
  504. //场景大小调整事件
  505. onResizing(newRect){
  506. if (this.isNotEdit)return;
  507. this.currentEl.width=this.accDiv(newRect.width,this.ratio);
  508. this.currentEl.height=this.accDiv(newRect.height,this.ratio);
  509. },
  510. accDiv(arg1,arg2){
  511. let t1=0,t2=0,r1,r2;
  512. try{t1=arg1.toString().split(".")[1].length}catch(e){}
  513. try{t2=arg2.toString().split(".")[1].length}catch(e){}
  514. with(Math){
  515. r1=Number(arg1.toString().replace(".",""))
  516. r2=Number(arg2.toString().replace(".",""))
  517. return this.accMul((r1/r2),pow(10,t2-t1));
  518. }
  519. },
  520. accMul(arg1,arg2){
  521. let m=0,s1=arg1.toString(),s2=arg2.toString();
  522. try{m+=s1.split(".")[1].length}catch(e){}
  523. try{m+=s2.split(".")[1].length}catch(e){}
  524. return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
  525. },
  526. //场景拖拽事件
  527. onDragging(newRect){
  528. if (this.isNotEdit)return;
  529. this.currentEl.x=newRect.left;
  530. this.currentEl.y=newRect.top;
  531. $("#canvas").focus();
  532. },
  533. equipmentDrag(newRect){
  534. if (this.isNotEdit)return;
  535. this.currentEl.x=newRect.left;
  536. this.currentEl.y=newRect.top;
  537. this.currentEl.updateCoords = true;
  538. $("#canvas").focus();
  539. },
  540. //仓库切换
  541. selectedWarehouse(warehouse){
  542. this.isLoad = false;
  543. setTimeout(()=>{
  544. this.selected = warehouse.id;
  545. this.name = warehouse.name;
  546. this.ratio = warehouse.ratio;
  547. this.container = {width:warehouse.length*this.ratio,height:warehouse.width*this.ratio};
  548. localStorage.setItem("equipment:warehouse", warehouse.id);
  549. $.ajax({
  550. url : this.baseUrl+"warehouse/detail/getCoordsInfo",
  551. type : "post",
  552. dataType : "JSON",
  553. data : {id:warehouse.id},
  554. success : (res,status)=>{
  555. this.elements = res.data[0] ? JSON.parse(res.data[0]) : [];
  556. if(res.data[1] && res.data[1].length>0){
  557. let equipmentElements = [];
  558. res.data[1].forEach(eq=>{
  559. let coords = JSON.parse(eq.info);
  560. let selfInfo = this.equipments[coords.id-1];
  561. equipmentElements.push(Object.assign({
  562. eqId:eq.id,
  563. code:eq.code,
  564. width:eq.width,
  565. depth:eq.depth,
  566. repository:eq.repositoryId,
  567. x:coords.x,
  568. y:coords.y,
  569. turn:!!coords.turn,
  570. },selfInfo));
  571. });
  572. this.equipmentElements = equipmentElements;
  573. }else this.equipmentElements = [];
  574. this.repositories = res.data[2];
  575. this.isNotEdit = true;
  576. this.isLoad = true;
  577. },
  578. error : (err,status)=>{
  579. window.tempTip.show("坐标信息加载失败");
  580. },
  581. timeout:3000,
  582. })
  583. },200);
  584. },
  585. //文本类属性改变
  586. changeText(key){
  587. this.currentEl[key] = event.target.value;
  588. },
  589. //数值类属性改变
  590. changeNumber(key){
  591. let val = event.target.value;
  592. this.currentEl[key] = val ? parseFloat(val) : 0;
  593. },
  594. //子设备选定时的库位加载
  595. nextDetail(index){
  596. if (!this.current.eqId)return;
  597. this.currentEqChildIndex = index-1;
  598. this.isLoadLocation = true;
  599. setTimeout(function (){
  600. let parentDom = document.getElementById("detailInfo").firstChild.firstChild;
  601. let childDom = document.getElementById("locationModal").firstChild.firstChild;
  602. childDom.style.minWidth = parentDom.offsetWidth+'px';
  603. childDom.style.minHeight = parentDom.offsetHeight+'px';
  604. $("#locationModal").modal("show");
  605. },20);
  606. let children = this.current.children[this.currentEqChildIndex];
  607. $.ajax({
  608. url : this.baseUrl+"location/get",
  609. type : "post",
  610. dataType : "JSON",
  611. data : {id:children.id},
  612. success : (res)=>{
  613. switch (res.code){
  614. case 200:
  615. this.locations = res.data[0];
  616. this.locationMapping = res.data[1];
  617. this.isLoadLocation = false;
  618. setTimeout(()=>{
  619. let parentDom = document.getElementById("detailInfo").firstChild.firstChild;
  620. let childDom = document.getElementById("locationModal").firstChild.firstChild;
  621. childDom.children[1].firstChild.style.height = parentDom.children[1].offsetHeight+'px';
  622. },10);
  623. break;
  624. default:
  625. window.toast.error(res.message);
  626. }
  627. },
  628. error : (err)=>{
  629. window.tempTip.setIndex(999);
  630. window.tempTip.show("网络错误");
  631. },
  632. timeout:3000,
  633. })
  634. },
  635. showDetail(equipment){
  636. if (!this.isNotEdit)return;
  637. this.current = equipment;
  638. setTimeout(()=>{
  639. $("#detailInfo").modal("show");
  640. this.contentOnmouseup();
  641. },20);
  642. $.ajax({
  643. url : this.baseUrl+"equipment/getChildren",
  644. type : "post",
  645. dataType : "JSON",
  646. data : {id:this.current.eqId},
  647. success : (res)=>{
  648. switch (res.code){
  649. case 200:
  650. res.data.forEach(eq=>{
  651. let tab = eq.location_tab.split("-");
  652. eq.row = Number(tab[0]);
  653. eq.column = Number(tab[1]);
  654. });
  655. this.$set(this.current,"children",res.data);
  656. break;
  657. default:
  658. window.toast.error("服务器错误");
  659. }
  660. },
  661. error : (err)=>{
  662. window.tempTip.setIndex(999);
  663. window.tempTip.show("网络错误");
  664. },
  665. timeout:3000,
  666. })
  667. },
  668. saveOrUpdate(){
  669. this.error = {};
  670. let error = this._checkEquipmentData(this.current);
  671. if (JSON.stringify(error)!=="{}"){
  672. this.error = error;return;
  673. }
  674. let params = this._formatEquipmentData(this.current);
  675. params.warehouseDetailId = this.selected;
  676. $.ajax({
  677. url : this.baseUrl+"equipment/saveOrUpdate",
  678. type : "post",
  679. dataType : "JSON",
  680. headers:{'Content-Type':'application/json;charset=utf8'},
  681. data : JSON.stringify(params),
  682. success : (res)=>{
  683. switch (res.code){
  684. case 200:
  685. this.current.eqId = res.data[0];
  686. this.current.children.forEach((item,index)=>{
  687. item.id = res.data[1][index];
  688. })
  689. $("#detailInfo").modal("hide");
  690. window.toast.success("保存成功");
  691. break;
  692. case 701:
  693. this.error = res.data;
  694. break;
  695. case 414:
  696. this.error = {"code":"设备编码重复"};
  697. this.toast.error(this.error.code);
  698. break;
  699. default:
  700. window.toast.error("服务器错误:"+res.message);
  701. }
  702. },
  703. error : (err)=>{
  704. window.tempTip.setIndex(999);
  705. window.tempTip.show("网络错误");
  706. },
  707. timeout:3000,
  708. })
  709. },
  710. _checkEquipmentData(equipment){
  711. let error = {};
  712. if (!equipment.code)error.code = "设备编号未填写";
  713. if (!equipment.width)error.width = "设备宽度未填写";
  714. if (!equipment.depth)error.depth = "设备深度未填写";
  715. //if (!equipment.repository)error.repositoryId = "设备库区未选定";
  716. if (equipment.layer !== equipment.children.length)error.children = "设备绑定错误";
  717. for (let i=0;i<equipment.layer;i++){
  718. if (!equipment.children[i].height)error["children["+i+"].height"] = "设备高度不得为空"
  719. if (!equipment.children[i].column && equipment.children[i].column!=0)error["children["+i+"].column"] = "库位列数不得为空"
  720. if (!equipment.children[i].row && equipment.children[i].row!=0)error["children["+i+"].row"] = "库位行数不得为空"
  721. }
  722. return error;
  723. },
  724. _formatEquipmentData(equipment){
  725. let eq = {};
  726. eq.id = equipment.eqId;
  727. eq.code = equipment.code;
  728. eq.repositoryId = equipment.repository;
  729. eq.info = JSON.stringify({'x':equipment.x,'y':equipment.y,'id':equipment.id,'turn':!!equipment.turn});
  730. eq.depth = equipment.depth;
  731. eq.width = equipment.width;
  732. eq.children = equipment.children;
  733. return eq;
  734. },
  735. removeLocationBind(){
  736. if (this.isLoadLocation)return;
  737. this.isLoadLocation = true;
  738. $.ajax({
  739. url : this.baseUrl+"location/removeLocationBind",
  740. type : "post",
  741. dataType : "JSON",
  742. data : {id:this.current.children[this.currentEqChildIndex].id},
  743. success : (res)=>{
  744. switch (res.code){
  745. case 200:
  746. this.current.children[this.currentEqChildIndex].row = 0;
  747. this.current.children[this.currentEqChildIndex].column = 0;
  748. this.locations = [];
  749. window.toast.success("解除成功!");
  750. break;
  751. default:
  752. window.toast.error("库位无法释放,解除失败");
  753. }
  754. },
  755. error : (err)=>{
  756. window.tempTip.setIndex(999);
  757. window.tempTip.show("网络错误");
  758. },
  759. complete:()=>{
  760. this.isLoadLocation = false;
  761. },
  762. timeout:3000,
  763. })
  764. },
  765. locationBind(){
  766. if (this.isLoadLocation)return;
  767. let eq = this.current.children[this.currentEqChildIndex];
  768. let code = this.current.code+'-'+((this.currentEqChildIndex+1)<10 ? '0'+(this.currentEqChildIndex+1) : (this.currentEqChildIndex+1));
  769. this.isLoadLocation = true;
  770. $.ajax({
  771. url : this.baseUrl+"location/locationBind",
  772. type : "post",
  773. dataType : "JSON",
  774. data : {id:eq.id,row:this.buildPool.row,column:this.buildPool.column,code:code},
  775. success : (res)=>{
  776. switch (res.code){
  777. case 200:
  778. this.locations = res.data;
  779. window.toast.success("构建成功!");
  780. this.current.children[this.currentEqChildIndex].row = Number(this.buildPool.row);
  781. this.current.children[this.currentEqChildIndex].column = Number(this.buildPool.column);
  782. this.buildPool = {};
  783. this.$forceUpdate();
  784. break;
  785. default:
  786. window.toast.error(res.message);
  787. }
  788. },
  789. error : (err)=>{
  790. window.tempTip.setIndex(999);
  791. window.tempTip.show("网络错误");
  792. },
  793. complete:(req,status)=>{
  794. this.isLoadLocation = false;
  795. if (status==='timeout'){
  796. window.toast.error("库位建立失败,响应超时");
  797. }
  798. },
  799. timeout:3000,
  800. })
  801. },
  802. showAddWarehouseDetail(){
  803. if (this.ws.length>0){
  804. $("#warehouseDetail").modal("show");
  805. return;
  806. }
  807. $.ajax({
  808. url : this.baseUrl+"warehouse/getList",
  809. type : "get",
  810. dataType : "JSON",
  811. success : (res)=>{
  812. switch (res.code){
  813. case 200:
  814. this.ws = res.data;
  815. $("#warehouseDetail").modal("show");
  816. break;
  817. default:
  818. window.toast.error("仓库获取失败");
  819. }
  820. },
  821. error : (err)=>{
  822. window.tempTip.setIndex(999);
  823. window.tempTip.show("网络错误");
  824. },
  825. complete:(req,status)=>{
  826. this.isLoadLocation = false;
  827. if (status==='timeout'){
  828. window.toast.error("获取仓库超时");
  829. }
  830. },
  831. timeout:3000,
  832. })
  833. },
  834. addWarehouseDetail(){
  835. $.ajax({
  836. url : this.baseUrl+"warehouse/detail",
  837. type : "post",
  838. dataType : "JSON",
  839. headers:{'Content-Type':'application/json;charset=utf8'},
  840. data : JSON.stringify(this.warehouseDetail),
  841. success : (res)=>{
  842. switch (res.code){
  843. case 200:
  844. window.toast.success("仓库新建成功");
  845. this.warehouses = res.data;
  846. $("#warehouseDetail").modal("hide");
  847. break;
  848. default:
  849. window.toast.error(res.message);
  850. }
  851. },
  852. error : (err)=>{
  853. window.tempTip.setIndex(999);
  854. window.tempTip.show("网络错误");
  855. },
  856. timeout:3000,
  857. })
  858. },
  859. openRepository(){
  860. $.ajax({
  861. url : this.baseUrl+"repository/group",
  862. type : "get",
  863. dataType : "JSON",
  864. data:{id:this.selected},
  865. success : (res)=>{
  866. switch (res.code){
  867. case 200:
  868. this.group = res.data;
  869. $("#repository").modal("show");
  870. break;
  871. default:
  872. window.toast.error("获取区域失败");
  873. }
  874. },
  875. error : (err)=>{
  876. window.tempTip.setIndex(999);
  877. window.tempTip.show("网络错误");
  878. },
  879. complete:(req,status)=>{
  880. this.isLoadLocation = false;
  881. if (status==='timeout'){
  882. window.toast.error("获取区域超时");
  883. }
  884. },
  885. timeout:3000,
  886. })
  887. },
  888. addRepository(){
  889. this.repository.warehouseDetailId = this.selected;
  890. $.ajax({
  891. url : this.baseUrl+"repository/addRepository",
  892. type : "post",
  893. dataType : "JSON",
  894. headers:{'Content-Type':'application/json;charset=utf8'},
  895. data:JSON.stringify(this.repository),
  896. success : (res)=>{
  897. switch (res.code){
  898. case 200:
  899. this.repositories.push(res.data);
  900. $("#repository").modal("hide");
  901. break;
  902. default:
  903. window.toast.error("库区建立失败");
  904. }
  905. },
  906. error : (err)=>{
  907. window.tempTip.setIndex(999);
  908. window.tempTip.show("网络错误");
  909. },
  910. complete:(req,status)=>{
  911. this.isLoadLocation = false;
  912. if (status==='timeout'){
  913. window.toast.error("建立库区超时");
  914. }
  915. },
  916. timeout:3000,
  917. })
  918. },
  919. },
  920. filters:{
  921. qty(code){
  922. let inv = vue.locationMapping[code];
  923. if(!inv)return 0;
  924. return inv.QTY;
  925. },
  926. qtyOver(code){
  927. let inv = vue.locationMapping[code];
  928. if(!inv)return 0;
  929. return inv.QTYALLOCATED + inv.QTYMVIN + inv.QTYMVOUT + inv.QTYONHOLD + inv.QTYPA + inv.QTYRPIN + inv.QTYRPOUT;
  930. },
  931. childStyle(code){
  932. let inv = vue.locationMapping[code];
  933. if (!inv)return '';
  934. let qty = inv.QTY;
  935. let other = inv.QTYALLOCATED + inv.QTYMVIN + inv.QTYMVOUT + inv.QTYONHOLD + inv.QTYPA + inv.QTYRPIN + inv.QTYRPOUT;
  936. return (qty>0 || other>0) ?
  937. 'color: #fff;background-color: #38c172;border-color: #38c172;' : '';
  938. },
  939. }
  940. });
  941. </script>
  942. </html>