index.blade.php 71 KB

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