index.blade.php 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472
  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. .equipment{
  61. cursor: pointer
  62. }
  63. .equipment-exist{
  64. border-width:2px;
  65. border-style: groove;
  66. border-color: #0000FF;
  67. }
  68. .equipment-not-exist{
  69. opacity: 0.5;
  70. border-width:1px;
  71. border-style: dashed;
  72. border-color: #0070C0;
  73. }
  74. </style>
  75. </head>
  76. <body>
  77. <div class="container-fluid w-100 h-100" id="container" @mousemove="eqMove()" @mouseup="eqUp()">
  78. <div class="row w-100 h-100">
  79. <div class="col-2 " style="user-select: none;" id="tool">
  80. <div class="dropdown">
  81. <button type="button" class="btn p-0 w-100" id="dropdownMenu"
  82. data-toggle="dropdown">
  83. <h4 class="text-muted mt-1 p1">@{{ name }}&nbsp;&nbsp;<i class="fa fa-exchange text-info"></i></h4>
  84. </button>
  85. <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
  86. <li role="presentation" v-for="warehouse in warehouses" v-if="warehouse.id!==selected">
  87. <a role="menuitem" tabindex="-1" style="cursor: pointer" class="ml-3"
  88. @click="selectedWarehouse(warehouse)">@{{ warehouse.name }}</a>
  89. </li>
  90. <li role="presentation" class="text-center" @click="showAddWarehouseDetail()">
  91. <a role="menuitem" tabindex="-1" style="cursor: pointer" class="ml-3 text-primary"
  92. ><i class="fa fa-plus"></i> 新增</a>
  93. </li>
  94. </ul>
  95. </div>
  96. <button class="btn btn-info mt-5 w-100 text-white" @click="openRepository()">新增库区</button>
  97. <button class="btn btn-success mt-5 w-100 text-white" @click="searchingSelectEq()">批量构建库位</button>
  98. <p class="font-weight-bold p-0 mb-0 mt-1">位置</p>
  99. <div class="row text-muted small">
  100. <small class="col-6">X</small>
  101. <small class="col-6">Y</small>
  102. </div>
  103. <div class="row m-0 p-0">
  104. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.x"
  105. @blur="changeNumber('x')"></input>
  106. <input type="number" class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.y"
  107. @blur="changeNumber('y')"></input>
  108. </div>
  109. <p class="font-weight-bold p-0 mb-0 mt-3">大小</p>
  110. <div class="row text-muted small">
  111. <small class="col-6">高</small>
  112. <small class="col-6">宽</small>
  113. </div>
  114. <div class="row m-0 p-0">
  115. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.height" @blur="changeNumber('height')"></input>
  116. <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>
  117. </div>
  118. <p class="font-weight-bold p-0 mb-0 mt-3">其他</p>
  119. <div class="row text-muted small">
  120. <small class="col-6">层级</small>
  121. <small class="col-6">颜色</small>
  122. </div>
  123. <div class="row m-0 p-0">
  124. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.index" @blur="changeNumber('index')"></input>
  125. <input class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.color" @blur="changeText('color')"></input>
  126. </div>
  127. <div class="row text-muted small">
  128. <small class="col-6">名称</small>
  129. <small class="col-6">名称位置</small>
  130. </div>
  131. <div class="row m-0 p-0">
  132. <input class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.name" @blur="changeText('name')"></input>
  133. <select class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" v-model="currentEl.coords">
  134. <option value="左上">左上</option>
  135. <option value="左下">左下</option>
  136. <option value="右上">右上</option>
  137. <option value="右下">右下</option>
  138. <option value="居中">居中</option>
  139. <option value="中上">中上</option>
  140. </select>
  141. </div>
  142. <div class="row text-muted small">
  143. <small class="col-6">边框</small>
  144. </div>
  145. <div class="m-0 small row">
  146. <div class="col-6 p-0">
  147. <div class="form-check">
  148. <label class="form-check-label">
  149. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="top" :disabled="currentEl.x===undefined">上
  150. </label>
  151. </div>
  152. <div class="form-check">
  153. <label class="form-check-label">
  154. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="bottom" :disabled="currentEl.x===undefined">下
  155. </label>
  156. </div>
  157. <div class="form-check">
  158. <label class="form-check-label">
  159. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="left" :disabled="currentEl.x===undefined">左
  160. </label>
  161. </div>
  162. <div class="form-check">
  163. <label class="form-check-label">
  164. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="right" :disabled="currentEl.x===undefined">右
  165. </label>
  166. </div>
  167. </div>
  168. <div class="col-6 p-0">
  169. <div class="form-check">
  170. <label class="form-check-label">
  171. <button class="btn btn-sm btn-success" @click="addCoords()">生成场景元素</button>
  172. </label>
  173. </div>
  174. <div class="form-check mt-1">
  175. <label class="form-check-label">
  176. <button class="btn btn-sm btn-success" @click="openBuildEquipmentGroup()">构建设备组</button>
  177. </label>
  178. </div>
  179. </div>
  180. </div>
  181. <p class="font-weight-bold p-0 mb-0 mt-5 h5">全局</p>
  182. <div class="row text-muted">
  183. <div class="col-4">缩放</div>
  184. <div class="input-group input-group-sm col-8 m-0">
  185. <input type="number" class="form-control" step="1" v-model="scale"></input>
  186. <div class="input-group-append">
  187. <span class="input-group-text">%</span>
  188. </div>
  189. </div>
  190. </div>
  191. <div class="row text-muted mt-1">
  192. <div class="col-4">库位比</div>
  193. <div class="input-group input-group-sm col-8 m-0">
  194. <input class="switch" type="checkbox" @change="loadElement()"/>
  195. </div>
  196. </div>
  197. <div class="row mt-3">
  198. <h5 class="font-weight-bold ml-3">设备</h5>
  199. <div class="form-check ml-3">
  200. <label class="form-check-label">
  201. <input type="checkbox" class="form-check-input" v-model="grid">网格
  202. </label>
  203. <label class="form-check-label ml-4">
  204. <input type="checkbox" class="form-check-input" v-model="turn">翻转
  205. </label>
  206. </div>
  207. </div>
  208. <div style="height: 250px;overflow-y: auto;overflow-x: hidden" class="w-100">
  209. <div class="row" v-for="equipment in equipments" @mousedown="eqDown(equipment)">
  210. <div class="col-5">
  211. <div style="border: 1px #0070C0 solid" :style="[{backgroundColor:equipment.color},{width:(equipment.h*ratio)+'px'},{height:(equipment.w*ratio)+'px'}]"></div>
  212. </div>
  213. <div class="col-7 p1">
  214. @{{ equipment.describe }}
  215. </div>
  216. </div>
  217. </div>
  218. <button @click="clickEditOrSave()" :class="isNotEdit ? 'btn-info' : 'btn-success'"
  219. style="position:absolute;bottom: 20px;cursor: pointer" class="btn col-10 text-white">
  220. <span v-if="isNotEdit">开启场景编辑</span>
  221. <span v-else>保存更改</span>
  222. </button>
  223. </div>
  224. <div class="col-10 p-0">
  225. <div class="w-100 bg-secondary" id="canvasApp" style="height: 100vh;overflow: auto;user-select: none;">
  226. <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)+')'}]"
  227. style="position: relative;transform-origin: 0 0" class="bg-white"
  228. @mousedown="contentOnmousedown" @mousemove="contentOnmousemove" @mouseup="contentOnmouseup">
  229. <vue-drag-resize v-for="(element,index) in elements" v-if="!element.removeSign"
  230. @activated="onActivated(element)"
  231. @dragging="onDragging"
  232. @resizing="onResizing"
  233. :minw="1" :minh="1"
  234. :style="[{backgroundColor:element.color},
  235. element.border.indexOf('left')===-1 ? {borderLeft:'none'} : {},
  236. element.border.indexOf('right')===-1 ? {borderRight:'none'} : {},
  237. element.border.indexOf('top')===-1 ? {borderTop:'none'} : {},
  238. element.border.indexOf('bottom')===-1 ? {borderBottom:'none'} : {}]"
  239. style="border-width:1px;border-color: #000000;border-style: solid"
  240. :key="index" :prevent-active-behavior="isNotEdit"
  241. :parent-limitation="true" :w="element.width*ratio" :h="element.height*ratio"
  242. :x="element.x" :y="element.y" :z="element.index">
  243. <div :class="coordsMapping[element.coords]">@{{ element.name }}</div>
  244. </vue-drag-resize>
  245. <vue-drag-resize class="equipment"
  246. v-for="(element,index) in equipmentElements" @clicked="showDetail(element)"
  247. :id="'eq-'+index" :class="element.exist ? 'equipment-exist' : 'equipment-not-exist'"
  248. v-if="!element.removeSign"
  249. :is-resizable="false" :snap-to-grid="grid" :grid-x="40" :grid-y="30"
  250. :style="[{backgroundColor:element.color}]"
  251. @activated="onActivated(element)"
  252. @dragging="equipmentDrag"
  253. :key="'eq-'+index+element.turn" :prevent-active-behavior="isNotEdit"
  254. :parent-limitation="true" :w="(element.turn ? element.w : element.h)*ratio"
  255. :h="(element.turn ? element.h : element.w)*ratio"
  256. :x="element.x" :y="element.y" :z="90">
  257. <div class="h-100 w-100" v-if="isShowRatio">
  258. <div class="h-100 w-100 p-0" v-if="element.children && element.children.length>0">
  259. <div :style="{height:100/element.children.length+'%'}" v-for="(child,idx) in element.children"
  260. :class="(element.children[element.children.length-1-idx]).location_tab==='0-0' ? '' : 'bg-danger'"
  261. class="border border-dark text-dark small el-center w-100 m-0">
  262. @{{ (element.children[element.children.length-1-idx]).location_tab | formatCount }}
  263. </div>
  264. </div>
  265. <div class="h-100 w-100 txt-sty el-center" v-else>
  266. <i class="fa fa-spinner fa-spin"></i>
  267. </div>
  268. </div>
  269. <div class="h-100 txt-sty w-100 el-center" :class="element.turn ? 're' : ''" v-else>@{{ element.code}}</div>
  270. </vue-drag-resize>
  271. </div>
  272. </div>
  273. </div>
  274. <textarea hidden id="clipboardDiv" style="opacity:0"></textarea>
  275. <div id="loading" class="list-item">
  276. <i class="fa fa-spinner fa-spin"></i>
  277. <p style="line-height: 24px;">loading...</p>
  278. </div>
  279. </div>
  280. @include("equipment._detailInfo")
  281. @include("equipment._location")
  282. @include("equipment._warehouseDetail")
  283. @include("equipment._repository")
  284. @include("equipment._buildGroup")
  285. @include("equipment._locationAttr")
  286. @include("equipment._failTipList")
  287. </div>
  288. </body>
  289. <script src="{{ mix('js/app.js') }}"></script>
  290. <script src="{{ asset('js/utilities/drawCheckbox.js') }}"></script>
  291. <script src="{{ asset('js/utilities/h2can.min.js') }}"></script>
  292. <script src="{{ asset('js/utilities/jcanvas.min.js') }}"></script>
  293. <script src="{{ asset('js/utilities/toast.js') }}"></script>
  294. <script type="text/javascript">
  295. var vue = new Vue({
  296. el:"#container",
  297. data:{
  298. increment:true,
  299. group:[],//库区列表
  300. ws:[],//仓库列表
  301. locationMapping:{},//库位的信息映射
  302. warehouseDetail:{},//当前操作的仓库
  303. repository:{},//当前操作的库区
  304. warehouses:[], //仓库描述
  305. repositories:[], //库区
  306. selected:"", //当前选中的仓库ID
  307. container:{width:90,height:60}, //容器初始大小
  308. ratio:20, //设备大小缩放比例值
  309. name:"", //当前选中的仓库NAME
  310. isNotEdit:true, //是否允许编辑
  311. isLoad:true, //是否加载
  312. currentEl:{}, //当前选中的元素
  313. coordsMapping:{ //元素信息映射
  314. "居中":"h-100 w-100 el-center",
  315. "中上":"text-center",
  316. "左上":"",
  317. "左下":"el-left-bottom",
  318. "右上":"text-right",
  319. "右下":"el-right-bottom",
  320. },
  321. elements:[], //场景元素池
  322. clientCoords:{}, //坐标系记录
  323. scale:100, //缩放值
  324. equipments:[ //备选设备池
  325. ],
  326. currentEq:{ //选中的设备
  327. el:null,
  328. obj:null,
  329. },
  330. equipmentElements:[], //设备元素池
  331. grid:false, //设备拖拽是否开启网格
  332. turn:true, //设备是否翻转
  333. isLoadLocation:false, //开启加载库位
  334. //baseUrl:"http://127.0.0.1:8112/",
  335. baseUrl:"https://api.baoshi56.com/",
  336. current:{}, //当前操作的设备
  337. error:{},
  338. locations:[], //库位信息
  339. currentEqChildIndex:null, //当前节点下标
  340. buildPool:{}, //库位构建信息
  341. client:{}, //复制后的坐标记录
  342. buildEqInfo:{}, //设备组构建信息
  343. charArr : [...Array(26).keys()].map(i => String.fromCharCode(i + 65)), //A-Z字符
  344. elSeList:[
  345. {id:-1,w:1.2,h:2.4,grid:2,color:"RGB(255,255,0)",describe:"消防栓设施或立柱,不可设库位"},
  346. ],//场景元素预设列表
  347. locationAttr:null,//库位建立时的可选择属性
  348. batchEquipment:{
  349. },//设备类型 与设备下标的映射
  350. batchEquipmentSign:"",//当前选择的batchEquipment下标
  351. batchSign:false,//当前是否为批量构建
  352. failTipList:{},//构建失败的库位提示信息
  353. isShowRatio:undefined,//是否展示库位现存比例
  354. },
  355. mounted() {
  356. this._loadEquipmentCategory().then(()=>{
  357. this.initPage();
  358. let content = document.getElementById("canvasApp");
  359. content.onmousemove = (event)=>{
  360. this.client = {x:event.clientX,y:event.clientY};
  361. }
  362. })
  363. },
  364. computed:{
  365. flipLayer(){
  366. let layer = [];
  367. for (let i=this.current.layer;i>0;i--){
  368. layer.push(i);
  369. }
  370. return layer;
  371. },
  372. flipChildren(){
  373. if(!this.current.children){
  374. return [];
  375. }
  376. let children = [];
  377. for (let i=this.current.children.length - 1;i>=0;i--){
  378. let obj = this.current.children[i];
  379. obj.idx = i+1
  380. children.push(obj);
  381. }
  382. return children;
  383. },
  384. },
  385. created: function() {
  386. let content = document.getElementById("canvasApp");
  387. document.onkeydown = e=> {
  388. if (this.isNotEdit || !this.current)return;
  389. let key = e.keyCode;
  390. if (key === 8) {
  391. this.delElement();
  392. }
  393. if(key===67 && e.ctrlKey){
  394. this.copyEle();
  395. }
  396. if(key===86 && e.ctrlKey){
  397. let val = $('#clipboardDiv').val();
  398. if (!val || JSON.stringify(val)==="{}")return;
  399. let toolWid = document.getElementById("tool").offsetWidth;
  400. let obj = Object.assign({},JSON.parse(val));
  401. obj.x = this.client.x-toolWid+content.scrollLeft;
  402. obj.y = this.client.y+content.scrollTop;
  403. obj.children = [];
  404. for (let i=0;i<obj.layer;i++)obj.children.push({});
  405. if (this.currentEl.eqId){
  406. obj.eqId = undefined;
  407. this.current = obj;
  408. this.currentEl = obj;
  409. this.showAddModal(obj);
  410. }else{
  411. this.elements.push(obj);
  412. }
  413. }
  414. };
  415. },
  416. methods:{
  417. // 加载设备种类
  418. _loadEquipmentCategory() {
  419. return new Promise((resolve, reject)=>{
  420. $.ajax({
  421. url : this.baseUrl+"api/base/equipment/category",
  422. type : "GET",
  423. success : (res,status)=>{
  424. if(res.code != 200 || !res.data) {
  425. window.tempTip.show(res.message);
  426. return;
  427. }
  428. /*
  429. * {id:1,w:1.2,h:2.4,grid:2,layer:4,color:"RGB(252,228,214)",describe:"4层高位货架,可设八个标准托盘位"},
  430. {id:2,w:1.2,h:2.4,grid:2,layer:5,color:"RGB(255,255,255)",describe:"5层高位货架,可设十个标准托盘位"},
  431. {id:3,w:1.2,h:3.3,grid:3,layer:1,color:"RGB(169,208,142)",describe:"叉车通道,可设三个标准托盘位"},
  432. {id:4,w:1.2,h:3.3,grid:3,layer:2,color:"RGB(221,235,247)",describe:"叉车通道,可设六个标准托盘位"},
  433. {id:5,w:1.2,h:1.2,grid:1,layer:4,color:"RGB(255,255,0)",describe:"半组货架,可设四层高四个标准托盘位"},
  434. {id:6,w:1.2,h:2.4,grid:2,layer:1,color:"RGB(189,215,238)",describe:"叉车通道,顶上两个托盘位"},
  435. {id:7,w:1.2,h:1.2,grid:1,layer:5,color:"RGB(255,255,5)",describe:"半组货架,可设五层高五个标准托盘位"},
  436. {id:8,w:1.2,h:3.3,grid:3,layer:4,color:"RGB(146,208,80)",describe:"4层高位货架,可设十二个标准托盘位"},
  437. {id:9,w:1.2,h:2.4,grid:2,layer:2,color:"RGB(228,243,211)",describe:"叉车通道,可设四个标准托盘位"},
  438. {id:10,w:1,h:2,grid:1,layer:4,color:"RGB(211,160,160)",describe:"小型货架"},
  439. * */
  440. let equipments = [];
  441. if (res.data.length > 0) {
  442. res.data.forEach(category => {
  443. let info = JSON.parse(category.info);
  444. equipments.push({
  445. "id":category.id,
  446. "w":category.depth,
  447. "h":category.width,
  448. "grid":info.grid,
  449. "layer":category.layer,
  450. "color":info.color,
  451. "describe":category.name,
  452. });
  453. });
  454. }
  455. this.equipments = equipments;
  456. resolve();
  457. },
  458. error : (err,status)=>{
  459. window.tempTip.show("设备种类加载失败");
  460. },
  461. timeout:3000,
  462. })
  463. });
  464. },
  465. //仓库切换
  466. selectedWarehouse(warehouse){
  467. this.isLoad = false;
  468. setTimeout(()=>{
  469. this.selected = warehouse.id;
  470. this.name = warehouse.name;
  471. this.ratio = warehouse.ratio;
  472. this.container = {width:warehouse.length*this.ratio,height:warehouse.width*this.ratio};
  473. localStorage.setItem("equipment:warehouse", warehouse.id);
  474. $.ajax({
  475. url : this.baseUrl+"api/base/warehouse/detail/getCoordsInfo",
  476. type : "post",
  477. dataType : "JSON",
  478. data : {id:warehouse.id},
  479. success : (res,status)=>{
  480. this.elements = res.data[0] ? JSON.parse(res.data[0]) : [];
  481. if(res.data[1] && res.data[1].length>0){
  482. let equipmentElements = [];
  483. res.data[1].forEach(eq=>{
  484. let coords = JSON.parse(eq.info);
  485. let selfInfo = this.getCategory(coords.id);
  486. equipmentElements.push(Object.assign({
  487. eqId:eq.id,
  488. exist:eq.exist,
  489. code:eq.code,
  490. repository:eq.repositoryId,
  491. x:coords.x,
  492. y:coords.y,
  493. turn:!!coords.turn,
  494. },selfInfo));
  495. });
  496. this.equipmentElements = equipmentElements;
  497. }else this.equipmentElements = [];
  498. this.repositories = res.data[2];
  499. this.isNotEdit = true;
  500. this.isLoad = true;
  501. },
  502. error : (err,status)=>{
  503. window.tempTip.show("坐标信息加载失败");
  504. },
  505. timeout:30000,
  506. })
  507. },200);
  508. },
  509. getCategory(id) {
  510. for (let i = 0; i < this.equipments.length; i++) {
  511. if(Number(id) === Number(this.equipments[i].id)) {
  512. return this.equipments[i];
  513. }
  514. }
  515. return {}
  516. },
  517. /**
  518. * 初始页加载
  519. */
  520. initPage(){
  521. $.ajax({
  522. url : this.baseUrl+"api/base/warehouse/detail",
  523. type : "GET",
  524. success : (res,status)=>{
  525. this.warehouses = res.data;
  526. //这里获取warehouses
  527. let id = localStorage.getItem("equipment:warehouse");
  528. if (!id || !this.warehouses.some(warehouse=>{
  529. if (warehouse.id == id){
  530. this.selectedWarehouse(warehouse);
  531. return true;
  532. }
  533. })
  534. ){
  535. if (this.warehouses.length>0)this.selectedWarehouse(this.warehouses[0]);
  536. }
  537. $("#loading").hide();
  538. },
  539. error : (err,status)=>{
  540. window.tempTip.show("加载失败");
  541. },
  542. timeout:3000,
  543. })
  544. },
  545. flipArr(arr){
  546. let flip = [];
  547. for (let i=arr.length-1;i>=0;i--){
  548. flip.push(arr[i]);
  549. }
  550. return flip;
  551. },
  552. loadElement(){
  553. if (this.isShowRatio===undefined){
  554. this.isShowRatio = true;
  555. this.equipmentElements.forEach(eq=>{
  556. if (eq.exist){
  557. this.getChildren(eq);
  558. }else if(!eq.children){
  559. eq.children = [];
  560. }
  561. });
  562. }else{
  563. this.isShowRatio = !this.isShowRatio;
  564. }
  565. },
  566. //获取库位的可选择属性
  567. _getLocationAttr(){
  568. if (this.locationAttr!==null){
  569. return;
  570. }
  571. $.ajax({
  572. url : this.baseUrl+"api/base/location/getAttr",
  573. type : "post",
  574. dataType : "JSON",
  575. success : (res,status)=>{
  576. if (res.code===200){
  577. this.locationAttr = res.data;
  578. }else{
  579. window.toast.error(res.message);
  580. }
  581. },
  582. error : (err,status)=>{
  583. window.toast.error("库位选择属性加载失败");
  584. },
  585. timeout:3000,
  586. })
  587. },
  588. /**
  589. * 显示设备编码列表
  590. */
  591. showEquipmentCode(arr){
  592. event.stopPropagation();
  593. let obj = {};
  594. arr.forEach(index=>{
  595. obj[this.equipmentElements[index].code] = "";
  596. });
  597. this.failTipList = obj;
  598. $("#failTipList").modal("show");
  599. },
  600. //检索所有元素,获取在指定范围内的元素
  601. searchingSelectEq(){
  602. afterExt = function (){
  603. new Promise(function(resolve, reject) {
  604. let result = [];
  605. let els = $(".equipment");
  606. for (let i=0;i<els.length;i++){
  607. let client = els[i].getBoundingClientRect();
  608. if (client.x<0 || client.y<0){
  609. continue;
  610. }
  611. //四个角全部包含在此区域内 将元素下标加入结果数组
  612. if (client.x>=clipInfo.x && client.y>=clipInfo.y && client.x<=(clipInfo.x+clipInfo.w) && client.y<=(clipInfo.y+clipInfo.h)
  613. && (client.x+client.width)<=(clipInfo.x+clipInfo.w) && (client.y+client.height)<=(clipInfo.y+clipInfo.h)){
  614. result.push(els[i].id.split('-')[1]);
  615. }
  616. }
  617. resolve(result);
  618. }).then(indexArr=>{
  619. if (indexArr.length===0){
  620. toast.error("未选中任何设备");
  621. return;
  622. }
  623. vue.batchOperationEquipment(indexArr);
  624. });
  625. }
  626. clipScreenshots();
  627. },
  628. /**
  629. * 批量选中设备后唤起构建器
  630. */
  631. batchOperationEquipment(indexArr){
  632. this.current = {};
  633. let obj = {};
  634. indexArr.forEach(index=>{
  635. let eq = this.equipmentElements[index];
  636. let eqTypeIndex = this._getEqTypeIndex(eq.id);
  637. if (!obj[eqTypeIndex])obj[eqTypeIndex] = [];
  638. obj[eqTypeIndex].push(index);
  639. });
  640. this.batchEquipment = obj;
  641. $("#locationAttr").modal('show');
  642. },
  643. /**
  644. * 根据库位类型ID获取库位类型下标
  645. */
  646. _getEqTypeIndex(id){
  647. //当前是ID为下标+1,所以直接ID-1获取下标
  648. return id-1;
  649. for (let i=0;i<this.equipments.length;i++){
  650. if (this.equipments[i].id==id){
  651. return i;
  652. }
  653. }
  654. return null;
  655. },
  656. buildComponent(eq){
  657. let component = {
  658. "x":eq.x,"y":eq.y,"width":eq.turn ? eq.w : eq.h,"height":eq.turn ? eq.h : eq.w,"name":"","color":eq.color,
  659. "coords":"居中","border":["left","top","right","bottom"],"index":2
  660. };
  661. this.elements.push(component);
  662. },
  663. buildEquipment(eq){
  664. let children = [];
  665. let lastHeight = 1;
  666. for (let i=0;i<eq.layer;i++){
  667. let obj = this.currentEl.children[i];
  668. if (obj)lastHeight = obj.height;
  669. children.push({
  670. "height" : lastHeight,
  671. "row" : 0,
  672. "column" : 0,
  673. });
  674. }
  675. eq.children = children;
  676. this.equipmentElements.push(eq);
  677. this.exeSave(this.equipmentElements[this.equipmentElements.length-1]);
  678. },
  679. buildEquipmentGroup(){
  680. let x = this.currentEl.turn ? this.currentEl.x : Number(this.currentEl.x)+(Number(this.currentEl.w)*this.ratio);
  681. let y = this.currentEl.turn ? Number(this.currentEl.y)+(Number(this.currentEl.h)*this.ratio) : this.currentEl.y;
  682. this.buildEqInfo.list.forEach(eq=>{
  683. eq.x = x;
  684. eq.y = y;
  685. if (eq.id<0)this.buildComponent(eq); //构建组件
  686. else this.buildEquipment(eq); //构建设备
  687. if (this.currentEl.turn){
  688. y += eq.h*this.ratio+0.5;
  689. }else{
  690. x += eq.h*this.ratio+0.5;
  691. }
  692. });
  693. window.toast.success("构建完毕");
  694. this.buildEqInfo = {};
  695. $("#buildGroup").modal("hide");
  696. },
  697. getLastChar(str){
  698. let lastChar = str.substr(-1,1);
  699. if (lastChar.search(/[A-Z]/g)===0){
  700. let index = this.charArr.indexOf(lastChar);
  701. let residualCount = this.charArr.length-(index+1);
  702. if (residualCount<this.buildEqInfo.count)return null;
  703. return {type:"CHAR",val:index};
  704. }
  705. if (lastChar.search(/[\d]/g)===0){
  706. let strs = str.replace(/[^\d]/g,'*');
  707. let strsArr = strs.split('*');
  708. return {type:"NUMBER",val:strsArr[strsArr.length-1]};
  709. }
  710. return null;
  711. },
  712. buildGroup(){
  713. let count = this.buildEqInfo.count;
  714. if (!count)return;
  715. let result = this.getLastChar(this.currentEl.code);
  716. if(!result){
  717. window.toast.error("此设备编码不符合组规则");
  718. return;
  719. }
  720. let codeTran = (index)=>{
  721. let size = result.val.toString().length;
  722. let val;
  723. if(result.type==="CHAR"){
  724. if (this.increment){
  725. val=this.charArr[result.val+index];
  726. }else{
  727. val=this.charArr[result.val-index];
  728. }
  729. }else{
  730. if (this.increment){
  731. val=Number(result.val)+index;
  732. }else{
  733. val=Number(result.val)-index;
  734. }
  735. if (val.toString().length<size){
  736. val = (Array(size).join('0') + val).slice(-size);
  737. }
  738. }
  739. return this.currentEl.code.substr(0,this.currentEl.code.length-size)+val;
  740. };
  741. let list = [];
  742. for (let i=1;i<=count;i++){
  743. let obj = Object.assign({},this.currentEl);
  744. obj.eqId = undefined;
  745. obj.updateCoords = undefined;
  746. obj.code = codeTran(i);
  747. list.push(obj);
  748. }
  749. this.$set(this.buildEqInfo,"list",list);
  750. },
  751. pitchEq(el,index){
  752. this.$set(this.buildEqInfo,"current",index);
  753. this.$set(this.buildEqInfo,"currentEqId",el.id);
  754. },
  755. switchEq(el){
  756. if (this.buildEqInfo.currentEqId===el.id)return;
  757. let obj = this.buildEqInfo.list[this.buildEqInfo.current];
  758. obj.id = el.id;
  759. obj.w = el.w;
  760. obj.h = el.h;
  761. obj.describe = el.describe;
  762. obj.grid = el.grid;
  763. obj.layer = el.layer;
  764. obj.color = el.color;
  765. obj.width = el.w;
  766. obj.depth = el.h;
  767. this.$set(this.buildEqInfo,"currentEqId",el.id);
  768. },
  769. openBuildEquipmentGroup(){
  770. if (this.isNotEdit || !this.currentEl.eqId){
  771. window.toast.error("未开启编辑或未选中设备");
  772. return;
  773. }
  774. setTimeout(()=>{
  775. this.getChildren(this.currentEl);
  776. $("#buildGroup").modal("show");
  777. },100);
  778. },
  779. delCoords(){
  780. this.elements.some((el,index)=>{
  781. if (this.currentEl.name === el.name &&
  782. this.currentEl.x === el.x && this.currentEl.y === el.y){
  783. this.$set(this.elements[index],"removeSign",true);
  784. return true;
  785. }
  786. })
  787. },
  788. copyEle(){
  789. if (this.currentEl!=null && JSON.stringify(this.currentEl)!=="{}"){
  790. $('#clipboardDiv').text(JSON.stringify(this.currentEl));
  791. }
  792. },
  793. delEquipment(){
  794. this.equipmentElements.some((el,index)=>{
  795. if (this.currentEl.eqId === el.eqId){
  796. this.$set(this.equipmentElements[index],"removeSign",true);
  797. return true;
  798. }
  799. })
  800. },
  801. delElement(){
  802. if (this.currentEl.eqId)this.delEquipment();
  803. else this.delCoords();
  804. },
  805. addCoords(){
  806. if (this.isNotEdit)return;
  807. this.elements.push({"x":200,"y":200,"width":2,"height":2,"name":"","coords":"居中","border":["left","top","right","bottom"],"color":"white","index":1})
  808. },
  809. clickEditOrSave(){
  810. if(this.isNotEdit){this.isNotEdit = false;return;}
  811. let equipments = [];
  812. let delEquipments = [];
  813. let elements = [];
  814. this.equipmentElements.forEach(equipment=>{
  815. if (equipment.removeSign){
  816. delEquipments.push(equipment.eqId);
  817. }else if (equipment.updateCoords){
  818. equipments.push({
  819. id:equipment.eqId,
  820. info:JSON.stringify({x:equipment.x,y:equipment.y,id:equipment.id,turn:equipment.turn})
  821. });
  822. }
  823. });
  824. this.elements.forEach(el=>{
  825. if (!el.removeSign){
  826. elements.push(el);
  827. }
  828. });
  829. $.ajax({
  830. url : this.baseUrl+"api/base/warehouse/saveScene",
  831. type : "POST",
  832. headers:{'Content-Type':'application/json;charset=utf8'},
  833. data:JSON.stringify({id:this.selected,warehouse:JSON.stringify(elements),equipment:equipments,delEquipments:delEquipments}),
  834. success : (res,status)=>{
  835. if (res.code===200){
  836. this.isNotEdit = true;
  837. window.toast.success("场景更改保存成功");
  838. }else window.toast.error(res.message);
  839. },
  840. error : (err,status)=>{
  841. window.tempTip.show("加载失败");
  842. },
  843. complete:(req,status)=>{
  844. if (status==='timeout'){
  845. window.toast.error("服务器响应超时");
  846. }
  847. },
  848. timeout:10000,
  849. })
  850. },
  851. //备选设备拖拽按下事件
  852. eqDown(equipment){
  853. if (this.isNotEdit)return;
  854. if (this.currentEq.obj!==null)return;
  855. let wid = (this.turn ? equipment.w : equipment.h)*this.ratio;
  856. let hei = (this.turn ? equipment.h : equipment.w)*this.ratio;
  857. let div = document.createElement("div");
  858. div.style.width = wid+'px';
  859. div.style.height = hei+'px';
  860. div.style.backgroundColor = equipment.color;
  861. div.style.zIndex = '999';
  862. div.style.position = 'fixed';
  863. div.style.left = event.clientX+'px';
  864. div.style.top = event.clientY+'px';
  865. div.style.border = '1px #0070C0 solid';
  866. div.style.opacity = '0.5';
  867. document.getElementById("container").append(div);
  868. this.currentEq.el = div;
  869. this.currentEq.obj = equipment;
  870. },
  871. //备选设备拖拽移动事件
  872. eqMove(){
  873. if (this.isNotEdit)return;
  874. if (this.currentEq.obj===null)return;
  875. let x = event.clientX;
  876. let y = event.clientY;
  877. setTimeout(()=>{
  878. this.currentEq.el.style.left = x+'px';
  879. this.currentEq.el.style.top = y+'px';
  880. },10);
  881. },
  882. //备选设备拖拽松开事件
  883. eqUp(){
  884. if (this.isNotEdit)return;
  885. if (this.currentEq.obj===null)return;
  886. this.currentEq.el.remove();
  887. setTimeout(()=>{
  888. this.currentEq.el.remove();
  889. this.currentEq.el = null;
  890. },20);
  891. let content = document.getElementById("canvasApp");
  892. let toolWid = document.getElementById("tool").offsetWidth;
  893. let x = event.clientX-toolWid+content.scrollLeft;
  894. let y = event.clientY+content.scrollTop;
  895. if (x>=0 && y>=0){
  896. let children = [];
  897. for (let i=0;i<this.currentEq.obj.layer;i++)children.push({});
  898. let newEquipment = Object.assign({children:children,x:x,y:y}, this.currentEq.obj);
  899. newEquipment.turn = this.turn;
  900. newEquipment.width = newEquipment.w;
  901. newEquipment.depth = newEquipment.h;
  902. this.showAddModal(newEquipment);
  903. }
  904. this.currentEq.obj = null;
  905. },
  906. showAddModal(equipment){
  907. this.equipmentElements.push(equipment);
  908. this.current = this.equipmentElements[this.equipmentElements.length-1];
  909. setTimeout(()=>{
  910. $("#detailInfo").modal("show");
  911. },20);
  912. },
  913. //场景拖拽按下事件
  914. contentOnmousedown(event){
  915. if (!this.isNotEdit || this.clientCoords.x!==undefined)return;
  916. this.clientCoords = {
  917. x:event.clientX,
  918. y:event.clientY
  919. };
  920. },
  921. //场景拖拽移动事件
  922. contentOnmousemove(event){
  923. if (this.clientCoords.x===undefined)return;
  924. let diffX = event.clientX-this.clientCoords.x-2;
  925. let diffY = event.clientY-this.clientCoords.y-2;
  926. let content = document.getElementById("canvasApp");
  927. setTimeout(()=>{
  928. content.scrollTo(content.scrollLeft+diffX,content.scrollTop+diffY);
  929. },10);
  930. },
  931. //场景拖拽松开事件
  932. contentOnmouseup(){
  933. this.clientCoords = {};
  934. },
  935. onActivated(element){
  936. if (this.isNotEdit)return;
  937. this.currentEl = element;
  938. },
  939. //场景大小调整事件
  940. onResizing(newRect){
  941. if (this.isNotEdit)return;
  942. this.currentEl.width=this.accDiv(newRect.width,this.ratio);
  943. this.currentEl.height=this.accDiv(newRect.height,this.ratio);
  944. },
  945. accDiv(arg1,arg2){
  946. let t1=0,t2=0,r1,r2;
  947. try{t1=arg1.toString().split(".")[1].length}catch(e){}
  948. try{t2=arg2.toString().split(".")[1].length}catch(e){}
  949. with(Math){
  950. r1=Number(arg1.toString().replace(".",""))
  951. r2=Number(arg2.toString().replace(".",""))
  952. return this.accMul((r1/r2),pow(10,t2-t1));
  953. }
  954. },
  955. accMul(arg1,arg2){
  956. let m=0,s1=arg1.toString(),s2=arg2.toString();
  957. try{m+=s1.split(".")[1].length}catch(e){}
  958. try{m+=s2.split(".")[1].length}catch(e){}
  959. return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)
  960. },
  961. //场景拖拽事件
  962. onDragging(newRect){
  963. if (this.isNotEdit)return;
  964. this.currentEl.x=newRect.left;
  965. this.currentEl.y=newRect.top;
  966. $("#canvas").focus();
  967. },
  968. equipmentDrag(newRect){
  969. if (this.isNotEdit)return;
  970. this.currentEl.x=newRect.left;
  971. this.currentEl.y=newRect.top;
  972. this.currentEl.updateCoords = true;
  973. $("#canvas").focus();
  974. },
  975. //文本类属性改变
  976. changeText(key){
  977. this.currentEl[key] = event.target.value;
  978. },
  979. //数值类属性改变
  980. changeNumber(key){
  981. let val = event.target.value;
  982. this.currentEl[key] = val ? parseFloat(val) : 0;
  983. },
  984. _getObjFirstKey(obj){
  985. for(let key in obj){
  986. return key;
  987. }
  988. return null;
  989. },
  990. /**
  991. * 构建库位的默认值信息
  992. * */
  993. _locationAttrDefault(){
  994. this.buildPool.usage = this._getObjFirstKey(this.locationAttr.usage);
  995. this.buildPool.handling = this._getObjFirstKey(this.locationAttr.handling);
  996. this.buildPool.attribute = this._getObjFirstKey(this.locationAttr.attribute);
  997. this.buildPool.category = this._getObjFirstKey(this.locationAttr.category);
  998. this.buildPool.demand = this._getObjFirstKey(this.locationAttr.demand);
  999. this.buildPool.mixFlag = true;
  1000. this.buildPool.mixLotFlag = false;
  1001. this.buildPool.loseIdFlag = true;
  1002. },
  1003. /**
  1004. * 批量构建库位时的操作
  1005. * */
  1006. nextDetailBatch(index){
  1007. if (!this.current.children || this.current.children.length===0){
  1008. window.toast.error("设备信息尚未加载完毕,请稍后重试!");
  1009. return;
  1010. }
  1011. this.batchSign = true;
  1012. this.currentEqChildIndex = index-1;
  1013. setTimeout(function (){
  1014. let parentDom = document.getElementById("locationAttr").firstChild.firstChild;
  1015. let childDom = document.getElementById("locationModal").firstChild.firstChild;
  1016. childDom.style.minWidth = parentDom.offsetWidth+'px';
  1017. childDom.style.minHeight = parentDom.offsetHeight+'px';
  1018. $("#locationModal").modal("show");
  1019. },20);
  1020. this._locationAttrDefault();
  1021. },
  1022. //子设备选定时的库位加载
  1023. nextDetail(index){
  1024. if (!this.current.eqId) {
  1025. window.tempTip.index = 1050;
  1026. window.tempTip.inputVal("子设备编码", (val)=> {
  1027. this.$set(this.current.children[index-1], 'code', val);
  1028. })
  1029. return;
  1030. }
  1031. this.batchSign = false;
  1032. this.currentEqChildIndex = index-1;
  1033. let children = this.current.children[index-1];
  1034. this.isLoadLocation = true;
  1035. this._locationAttrDefault();
  1036. setTimeout(function (){
  1037. let parentDom = document.getElementById("detailInfo").firstChild.firstChild;
  1038. let childDom = document.getElementById("locationModal").firstChild.firstChild;
  1039. childDom.style.minWidth = (parentDom.offsetWidth+200)+'px';
  1040. childDom.style.minHeight = parentDom.offsetHeight+'px';
  1041. $("#locationModal").modal("show");
  1042. },20);
  1043. this.current.children.forEach(item=>{
  1044. item.row = Number(item.row);
  1045. item.column = Number(item.column);
  1046. });
  1047. $.ajax({
  1048. url : this.baseUrl+"api/base/location/get",
  1049. type : "post",
  1050. dataType : "JSON",
  1051. data : {id:children.id},
  1052. success : (res)=>{
  1053. switch (res.code){
  1054. case 200:
  1055. this.locations = res.data[0];
  1056. this.locationMapping = res.data[1] ? res.data[1] : {};
  1057. this.isLoadLocation = false;
  1058. break;
  1059. default:
  1060. window.toast.error(res.message);
  1061. }
  1062. },
  1063. error : (err)=>{
  1064. window.tempTip.setIndex(999);
  1065. window.tempTip.show("网络错误");
  1066. },
  1067. timeout:3000,
  1068. })
  1069. },
  1070. showDetail(equipment){
  1071. this._getLocationAttr();
  1072. if (!this.isNotEdit)return;
  1073. this.current = equipment;
  1074. setTimeout(()=>{
  1075. $("#detailInfo").modal("show");
  1076. this.contentOnmouseup();
  1077. },20);
  1078. this.getChildren(this.current);
  1079. },
  1080. getChildren(equipment){
  1081. if (equipment.children && equipment.children.length>0){
  1082. return;
  1083. }
  1084. $.ajax({
  1085. url : this.baseUrl+"api/base/equipment/getChildren",
  1086. type : "post",
  1087. dataType : "JSON",
  1088. data : {id:equipment.eqId},
  1089. success : (res)=>{
  1090. switch (res.code){
  1091. case 200:
  1092. res.data.forEach(eq=>{
  1093. let tab = eq.location_tab.split("-");
  1094. eq.row = Number(tab[0]);
  1095. eq.column = Number(tab[1]);
  1096. });
  1097. this.$set(equipment,"children",res.data);
  1098. break;
  1099. default:
  1100. window.toast.error("服务器错误");
  1101. }
  1102. },
  1103. error : (err)=>{
  1104. window.tempTip.setIndex(999);
  1105. window.tempTip.show("网络错误");
  1106. },
  1107. timeout:3000,
  1108. })
  1109. },
  1110. saveOrUpdate(){
  1111. this.error = {};
  1112. let error = this._checkEquipmentData(this.current);
  1113. if (JSON.stringify(error)!=="{}"){
  1114. console.log(error)
  1115. this.error = error;return;
  1116. }
  1117. this.exeSave(this.current);
  1118. },
  1119. exeSave(equipment){
  1120. let params = this._formatEquipmentData(equipment);
  1121. params.warehouseDetailId = this.selected;
  1122. $.ajax({
  1123. url : this.baseUrl+"api/base/equipment/saveOrUpdate",
  1124. type : "post",
  1125. dataType : "JSON",
  1126. headers:{'Content-Type':'application/json;charset=utf8'},
  1127. data : JSON.stringify(params),
  1128. success : (res)=>{
  1129. switch (res.code){
  1130. case 200:
  1131. equipment.eqId = res.data[0];
  1132. let locCount = 0;
  1133. equipment.children.forEach((item,index)=>{
  1134. item.id = res.data[1][index];
  1135. if (item.row && Number(item.row) > 0){
  1136. locCount += Number(item.row) * Number(item.column)
  1137. }
  1138. });
  1139. equipment.exist = locCount;
  1140. this.$forceUpdate();
  1141. $("#detailInfo").modal("hide");
  1142. window.toast.success("保存成功");
  1143. break;
  1144. case 701:
  1145. this.error = res.data;
  1146. break;
  1147. case 414:
  1148. this.error = {code:"设备编码重复"};
  1149. window.toast.error(this.error.code);
  1150. break;
  1151. default:
  1152. window.toast.error("服务器错误:"+res.message);
  1153. }
  1154. },
  1155. error : (err)=>{
  1156. console.error(err);
  1157. window.tempTip.setIndex(999);
  1158. window.tempTip.show("网络错误");
  1159. },
  1160. timeout:3000,
  1161. })
  1162. },
  1163. _checkEquipmentData(equipment){
  1164. console.log(equipment)
  1165. let error = {};
  1166. if (!equipment.code)error.code = "设备编号未填写";
  1167. if (equipment.layer !== equipment.children.length)error.children = "设备绑定错误";
  1168. for (let i=0;i<equipment.layer;i++){
  1169. if (!equipment.children[i].height)error["children["+i+"].height"] = "设备高度不得为空"
  1170. //if (!equipment.children[i].area)error["children["+i+"].area"] = "设备折算面积不得为空"
  1171. if (!equipment.children[i].column && equipment.children[i].column!=0)error["children["+i+"].column"] = "库位列数不得为空"
  1172. if (!equipment.children[i].row && equipment.children[i].row!=0)error["children["+i+"].row"] = "库位行数不得为空"
  1173. }
  1174. return error;
  1175. },
  1176. _formatEquipmentData(equipment){
  1177. let eq = {};
  1178. eq.id = equipment.eqId;
  1179. eq.code = equipment.code;
  1180. eq.repositoryId = equipment.repository;
  1181. eq.info = JSON.stringify({'x':equipment.x,'y':equipment.y,'id':equipment.id,'turn':!!equipment.turn});
  1182. eq.depth = equipment.depth;
  1183. eq.width = equipment.width;
  1184. eq.children = equipment.children;
  1185. return eq;
  1186. },
  1187. removeLocationBind(){
  1188. if (this.isLoadLocation)return;
  1189. this.isLoadLocation = true;
  1190. $.ajax({
  1191. url : this.baseUrl+"api/base/location/removeLocationBind",
  1192. type : "post",
  1193. dataType : "JSON",
  1194. data : {id:this.current.children[this.currentEqChildIndex].id},
  1195. success : (res)=>{
  1196. switch (res.code){
  1197. case 200:
  1198. this.current.children[this.currentEqChildIndex].row = 0;
  1199. this.current.children[this.currentEqChildIndex].column = 0;
  1200. this.locations = [];
  1201. window.toast.success("解除成功!");
  1202. break;
  1203. default:
  1204. window.toast.error("库位无法释放,解除失败");
  1205. }
  1206. },
  1207. error : (err)=>{
  1208. window.tempTip.setIndex(999);
  1209. window.tempTip.show("网络错误");
  1210. },
  1211. complete:()=>{
  1212. this.isLoadLocation = false;
  1213. },
  1214. timeout:3000,
  1215. })
  1216. },
  1217. locationBatchBind(){
  1218. $("#loading").show();
  1219. let arr = this.batchEquipment[this.batchEquipmentSign];
  1220. let request = [];
  1221. let failTipList = {};
  1222. arr.forEach(index=>{
  1223. let eq = this.equipmentElements[index];
  1224. if (!eq){
  1225. window.toast.error("异常设备选择");
  1226. }else if (!eq.children || eq.children.length===0 || !eq.children[this.currentEqChildIndex]){
  1227. failTipList[eq.code]="详情尚未加载完毕";
  1228. }else{
  1229. let item = eq.children[this.currentEqChildIndex];
  1230. let code = eq.code+'-'+(this.currentEqChildIndex+1);
  1231. request.push(Object.assign({id:item.id,code:code},
  1232. this.buildPool))
  1233. }
  1234. });
  1235. $.ajax({
  1236. url : this.baseUrl+"api/base/location/locationBatchBound",
  1237. type : "post",
  1238. dataType : "JSON",
  1239. data : JSON.stringify(request),
  1240. headers:{'Content-Type':'application/json;charset=utf8'},
  1241. success : (res)=>{
  1242. switch (res.code){
  1243. case 200:
  1244. $("#locationModal").modal('hide');
  1245. window.toast.success("构建完毕!");
  1246. this.failTipList = Object.assign(failTipList,res.data);
  1247. if (JSON.stringify(this.failTipList)!=="{}"){
  1248. $("#failTipList").modal("show");
  1249. }
  1250. let ele = document.querySelectorAll("#locationAttr span.el-center")[this.current.layer-1-this.currentEqChildIndex];
  1251. ele.className += " bg-success";
  1252. break;
  1253. default:
  1254. window.toast.error(res.message);
  1255. }
  1256. },
  1257. error : (err)=>{
  1258. window.tempTip.setIndex(999);
  1259. window.tempTip.show("网络错误");
  1260. },
  1261. complete:(req,status)=>{
  1262. $("#loading").hide();
  1263. if (status==='timeout'){
  1264. window.toast.error("库位批量构建失败,响应超时");
  1265. }
  1266. },
  1267. timeout:3000,
  1268. });
  1269. },
  1270. locationBind(){
  1271. if (this.batchSign){
  1272. this.locationBatchBind();
  1273. return;
  1274. }
  1275. if (this.isLoadLocation)return;
  1276. let eq = this.current.children[this.currentEqChildIndex];
  1277. let code = this.current.code+'-'+(this.currentEqChildIndex+1);
  1278. this.isLoadLocation = true;
  1279. $.ajax({
  1280. url : this.baseUrl+"api/base/location/locationBind",
  1281. type : "post",
  1282. dataType : "JSON",
  1283. headers:{'Content-Type':'application/json;charset=utf8'},
  1284. data : JSON.stringify(Object.assign({id:eq.id,code:code},this.buildPool)),
  1285. success : (res)=>{
  1286. switch (res.code){
  1287. case 200:
  1288. this.locations = res.data;
  1289. window.toast.success("构建成功!");
  1290. this.current.children[this.currentEqChildIndex].row = Number(this.buildPool.row);
  1291. this.current.children[this.currentEqChildIndex].column = Number(this.buildPool.column);
  1292. this._locationAttrDefault();
  1293. $("#locationModal").modal("hide");
  1294. this.$forceUpdate();
  1295. break;
  1296. default:
  1297. window.toast.error(res.message);
  1298. }
  1299. },
  1300. error : (err)=>{
  1301. window.tempTip.setIndex(999);
  1302. window.tempTip.show("网络错误");
  1303. },
  1304. complete:(req,status)=>{
  1305. this.isLoadLocation = false;
  1306. if (status==='timeout'){
  1307. window.toast.error("库位建立失败,响应超时");
  1308. }
  1309. },
  1310. timeout:3000,
  1311. })
  1312. },
  1313. showAddWarehouseDetail(){
  1314. if (this.ws.length>0){
  1315. $("#warehouseDetail").modal("show");
  1316. return;
  1317. }
  1318. $.ajax({
  1319. url : this.baseUrl+"api/base/warehouse/getList",
  1320. type : "get",
  1321. dataType : "JSON",
  1322. success : (res)=>{
  1323. switch (res.code){
  1324. case 200:
  1325. this.ws = res.data;
  1326. $("#warehouseDetail").modal("show");
  1327. break;
  1328. default:
  1329. window.toast.error("仓库获取失败");
  1330. }
  1331. },
  1332. error : (err)=>{
  1333. window.tempTip.setIndex(999);
  1334. window.tempTip.show("网络错误");
  1335. },
  1336. complete:(req,status)=>{
  1337. this.isLoadLocation = false;
  1338. if (status==='timeout'){
  1339. window.toast.error("获取仓库超时");
  1340. }
  1341. },
  1342. timeout:3000,
  1343. })
  1344. },
  1345. addWarehouseDetail(){
  1346. $.ajax({
  1347. url : this.baseUrl+"api/base/warehouse/detail",
  1348. type : "post",
  1349. dataType : "JSON",
  1350. headers:{'Content-Type':'application/json;charset=utf8'},
  1351. data : JSON.stringify(this.warehouseDetail),
  1352. success : (res)=>{
  1353. switch (res.code){
  1354. case 200:
  1355. window.toast.success("仓库新建成功");
  1356. this.warehouses = res.data;
  1357. $("#warehouseDetail").modal("hide");
  1358. break;
  1359. default:
  1360. window.toast.error(res.message);
  1361. }
  1362. },
  1363. error : (err)=>{
  1364. window.tempTip.setIndex(999);
  1365. window.tempTip.show("网络错误");
  1366. },
  1367. timeout:3000,
  1368. })
  1369. },
  1370. openRepository(){
  1371. $.ajax({
  1372. url : this.baseUrl+"api/base/repository/group",
  1373. type : "get",
  1374. dataType : "JSON",
  1375. data:{id:this.selected},
  1376. success : (res)=>{
  1377. switch (res.code){
  1378. case 200:
  1379. this.group = res.data;
  1380. $("#repository").modal("show");
  1381. break;
  1382. default:
  1383. window.toast.error("获取区域失败");
  1384. }
  1385. },
  1386. error : (err)=>{
  1387. window.tempTip.setIndex(999);
  1388. window.tempTip.show("网络错误");
  1389. },
  1390. complete:(req,status)=>{
  1391. this.isLoadLocation = false;
  1392. if (status==='timeout'){
  1393. window.toast.error("获取区域超时");
  1394. }
  1395. },
  1396. timeout:3000,
  1397. })
  1398. },
  1399. addRepository(){
  1400. this.repository.warehouseDetailId = this.selected;
  1401. $.ajax({
  1402. url : this.baseUrl+"api/base/repository/addRepository",
  1403. type : "post",
  1404. dataType : "JSON",
  1405. headers:{'Content-Type':'application/json;charset=utf8'},
  1406. data:JSON.stringify(this.repository),
  1407. success : (res)=>{
  1408. switch (res.code){
  1409. case 200:
  1410. this.repositories.push(res.data);
  1411. $("#repository").modal("hide");
  1412. this.repository = {};
  1413. break;
  1414. default:
  1415. window.toast.error("库区建立失败");
  1416. }
  1417. },
  1418. error : (err)=>{
  1419. window.tempTip.setIndex(999);
  1420. window.tempTip.show("网络错误");
  1421. },
  1422. complete:(req,status)=>{
  1423. this.isLoadLocation = false;
  1424. if (status==='timeout'){
  1425. window.toast.error("建立库区超时");
  1426. }
  1427. },
  1428. timeout:3000,
  1429. })
  1430. },
  1431. /**
  1432. * 批量构建设备库位时的选中操作
  1433. * */
  1434. batchEquipmentSelected(arr,index){
  1435. this.current = this.equipmentElements[arr[0]];
  1436. this.batchEquipmentSign = index;
  1437. arr.forEach(i=>{
  1438. this.getChildren(this.equipmentElements[i]);
  1439. })
  1440. this._getLocationAttr();
  1441. },
  1442. },
  1443. filters:{
  1444. qty(code){
  1445. let inv = vue.locationMapping[code];
  1446. if(!inv)return 0;
  1447. return inv.QTY;
  1448. },
  1449. qtyOver(code){
  1450. let inv = vue.locationMapping[code];
  1451. if(!inv)return 0;
  1452. return inv.QTYALLOCATED + inv.QTYMVIN + inv.QTYMVOUT + inv.QTYONHOLD + inv.QTYPA + inv.QTYRPIN + inv.QTYRPOUT;
  1453. },
  1454. childStyle(code){
  1455. let inv = vue.locationMapping[code];
  1456. if (!inv)return '';
  1457. let qty = inv.QTY;
  1458. let other = inv.QTYALLOCATED + inv.QTYMVIN + inv.QTYMVOUT + inv.QTYONHOLD + inv.QTYPA + inv.QTYRPIN + inv.QTYRPOUT;
  1459. return (qty>0 || other>0) ?
  1460. 'color: #fff;background-color: #38c172;border-color: #38c172;' : '';
  1461. },
  1462. formatCount(tab){
  1463. let arr = tab.split("-");
  1464. return arr[0]*arr[1];
  1465. }
  1466. }
  1467. });
  1468. </script>
  1469. </html>