index.blade.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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. .re{transform:rotate(-90deg);
  44. -ms-transform:rotate(-90deg); /* Internet Explorer 9*/
  45. -moz-transform:rotate(-90deg); /* Firefox */
  46. -webkit-transform:rotate(-90deg); /* Safari 和 Chrome */
  47. -o-transform:rotate(-90deg); /* Opera */
  48. filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
  49. font-family: "Microsoft YaHei Light","sans-serif";
  50. }
  51. </style>
  52. </head>
  53. <body>
  54. <div class="container-fluid w-100 h-100" id="container" @mousemove="eqMove()" @mouseup="eqUp()">
  55. <div class="row w-100 h-100">
  56. <div class="col-2 " style="user-select: none;" id="tool">
  57. <div class="dropdown">
  58. <button type="button" class="btn p-0 w-100" id="dropdownMenu"
  59. data-toggle="dropdown">
  60. <h4 class="text-muted mt-1 p1">@{{ name }}&nbsp;&nbsp;<i class="fa fa-exchange text-info"></i></h4>
  61. </button>
  62. <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu">
  63. <li role="presentation" v-for="warehouse in warehouses" v-if="warehouse.id!==selected">
  64. <a role="menuitem" tabindex="-1" style="cursor: pointer" class="ml-3"
  65. @click="selectedWarehouse(warehouse)">@{{ warehouse.name }}</a>
  66. </li>
  67. </ul>
  68. </div>
  69. <p class="font-weight-bold p-0 mb-0 mt-5">位置</p>
  70. <div class="row text-muted small">
  71. <small class="col-6">X</small>
  72. <small class="col-6">Y</small>
  73. </div>
  74. <div class="row m-0 p-0">
  75. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.x"
  76. @blur="changeNumber('x')"></input>
  77. <input type="number" class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.y"
  78. @blur="changeNumber('y')"></input>
  79. </div>
  80. <p class="font-weight-bold p-0 mb-0 mt-3">大小</p>
  81. <div class="row text-muted small">
  82. <small class="col-6">高</small>
  83. <small class="col-6">宽</small>
  84. </div>
  85. <div class="row m-0 p-0">
  86. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.height" @blur="changeNumber('height')"></input>
  87. <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>
  88. </div>
  89. <p class="font-weight-bold p-0 mb-0 mt-3">其他</p>
  90. <div class="row text-muted small">
  91. <small class="col-6">层级</small>
  92. <small class="col-6">颜色</small>
  93. </div>
  94. <div class="row m-0 p-0">
  95. <input type="number" class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.index" @blur="changeNumber('index')"></input>
  96. <input class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.color" @blur="changeText('color')"></input>
  97. </div>
  98. <div class="row text-muted small">
  99. <small class="col-6">名称</small>
  100. <small class="col-6">名称位置</small>
  101. </div>
  102. <div class="row m-0 p-0">
  103. <input class="col-5 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" :value="currentEl.name" @blur="changeText('name')"></input>
  104. <select class="col-5 offset-1 form-control form-control-sm p-0" :disabled="currentEl.x===undefined" v-model="currentEl.coords">
  105. <option value="左上">左上</option>
  106. <option value="左下">左下</option>
  107. <option value="右上">右上</option>
  108. <option value="右下">右下</option>
  109. <option value="居中">居中</option>
  110. <option value="中上">中上</option>
  111. </select>
  112. </div>
  113. <div class="row text-muted small">
  114. <small class="col-6">边框</small>
  115. </div>
  116. <div class="m-0 small">
  117. <div class="form-check">
  118. <label class="form-check-label">
  119. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="top" :disabled="currentEl.x===undefined">上
  120. </label>
  121. </div>
  122. <div class="form-check">
  123. <label class="form-check-label">
  124. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="bottom" :disabled="currentEl.x===undefined">下
  125. </label>
  126. </div>
  127. <div class="form-check">
  128. <label class="form-check-label">
  129. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="left" :disabled="currentEl.x===undefined">左
  130. </label>
  131. </div>
  132. <div class="form-check">
  133. <label class="form-check-label">
  134. <input type="checkbox" class="form-check-input" v-model="currentEl.border" value="right" :disabled="currentEl.x===undefined">右
  135. </label>
  136. </div>
  137. </div>
  138. <p class="font-weight-bold p-0 mb-0 mt-5 h5">全局</p>
  139. <div class="row text-muted">
  140. <div class="col-4">缩放</div>
  141. <div class="input-group input-group-sm col-8 m-0">
  142. <input type="number" class="form-control" step="1" v-model="scale"></input>
  143. <div class="input-group-append">
  144. <span class="input-group-text">%</span>
  145. </div>
  146. </div>
  147. </div>
  148. <div class="row mt-3">
  149. <h5 class="font-weight-bold ml-3">设备</h5>
  150. <div class="form-check ml-3">
  151. <label class="form-check-label">
  152. <input type="checkbox" class="form-check-input" v-model="grid">网格
  153. </label>
  154. </div>
  155. </div>
  156. <div style="height: 250px;overflow-y: auto;overflow-x: hidden" class="w-100">
  157. <div class="row" v-for="equipment in equipments" @mousedown="eqDown(equipment)">
  158. <div class="col-5">
  159. <div style="border: 1px #0070C0 solid" :style="[{backgroundColor:equipment.color},{width:equipment.h+'px'},{height:equipment.w+'px'}]"></div>
  160. </div>
  161. <div class="col-7 p1">
  162. @{{ equipment.describe }}
  163. </div>
  164. </div>
  165. </div>
  166. <button class="btn btn-info col-10 text-white" style="position:absolute;bottom: 20px;cursor: pointer">保存更改</button>
  167. </div>
  168. <div class="col-10 p-0">
  169. <div class="w-100 bg-secondary" id="canvasApp" style="height: 100vh;overflow: auto;user-select: none;">
  170. <div id="canvas" :style="[{width:container.width*(scale/100)+'px'},{height:container.height*(scale/100)+'px'},{transform: 'scale('+(scale/100)+')'}]"
  171. style="position: relative;transform-origin: 0 0" class="bg-white"
  172. @mousedown="contentOnmousedown" @mousemove="contentOnmousemove" @mouseup="contentOnmouseup">
  173. <vue-drag-resize v-for="(element,index) in elements"
  174. @activated="onActivated(element)"
  175. @dragging="onDragging"
  176. @resizing="onResizing"
  177. :style="[{backgroundColor:element.color},
  178. element.border.indexOf('left')===-1 ? {borderLeft:'none'} : {},
  179. element.border.indexOf('right')===-1 ? {borderRight:'none'} : {},
  180. element.border.indexOf('top')===-1 ? {borderTop:'none'} : {},
  181. element.border.indexOf('bottom')===-1 ? {borderBottom:'none'} : {}]"
  182. style="border-width:1px;border-color: #000000;border-style: solid"
  183. :key="index" :prevent-active-behavior="isNotEdit"
  184. :parent-limitation="true" :w="element.width" :h="element.height"
  185. :x="element.x" :y="element.y" :z="element.index">
  186. <div :class="coordsMapping[element.coords]">@{{ element.name }}</div>
  187. </vue-drag-resize>
  188. <vue-drag-resize style="border-width:1px;border-color: #0070C0;border-style: dashed;cursor: pointer"
  189. v-for="(element,index) in equipmentElements"
  190. :is-resizable="false" :snap-to-grid="grid" :grid-x="40" :grid-y="30"
  191. :style="[{backgroundColor:element.color}]"
  192. :key="'eq-'+index" :prevent-active-behavior="isNotEdit"
  193. :parent-limitation="true" :w="element.width" :h="element.height"
  194. :x="element.x" :y="element.y" :z="90">
  195. <div class="h-100 re w-100 el-center">@{{ element.name }}</div>
  196. </vue-drag-resize>
  197. </div>
  198. </div>
  199. </div>
  200. </div>
  201. @include("equipment._detailInfo")
  202. @include("equipment._location")
  203. </div>
  204. </body>
  205. <script src="{{ mix('js/app.js') }}"></script>
  206. <script type="text/javascript">
  207. var vue = new Vue({
  208. el:"#container",
  209. data:{
  210. warehouses:[{id:1,name:"松江泗砖仓库一层"},{id:2,name:"九干"}], //仓库描述
  211. selected:"", //当前选中的仓库ID
  212. container:{width:1950,height:1125}, //容器初始大小
  213. name:"", //当前选中的仓库NAME
  214. isNotEdit:false, //是否允许编辑
  215. currentEl:{}, //当前选中的元素
  216. coordsMapping:{ //元素信息映射
  217. "居中":"h-100 w-100 el-center",
  218. "中上":"text-center",
  219. "左上":"",
  220. "左下":"el-left-bottom",
  221. "右上":"text-right",
  222. "右下":"el-right-bottom",
  223. },
  224. elements:[ //场景元素池
  225. {
  226. x:0,
  227. y:0,
  228. width:22.5,
  229. height:30,
  230. name:"test",
  231. coords:"居中",
  232. border:["left","top","right","bottom"],
  233. color:"white",
  234. index:1,
  235. },
  236. ],
  237. clientCoords:{}, //坐标系记录
  238. scale:100, //缩放值
  239. equipments:[ //备选设备池
  240. {id:1,w:22.5,h:45,color:"RGB(252,228,214)",describe:"4层高位货架,可设八个标准托盘位"},
  241. {id:2,w:22.5,h:45,color:"RGB(255,255,255)",describe:"5层高位货架,可设十个标准托盘位"},
  242. {id:3,w:22.5,h:45,color:"RGB(169,208,142)",describe:"叉车通道,可设三个标准托盘位"},
  243. {id:4,w:22.5,h:45,color:"RGB(221,235,247)",describe:"叉车通道,可设六个标准托盘位"},
  244. {id:5,w:22.5,h:30,color:"RGB(255,255,0)",describe:"半组货架,可设四层高四个标准托盘位"},
  245. {id:6,w:22.5,h:30,color:"RGB(189,215,238)",describe:"叉车通道,顶上两个托盘位"},
  246. {id:7,w:22.5,h:30,color:"RGB(255,255,5)",describe:"半组货架,可设五层高五个标准托盘位"},
  247. ],
  248. currentEq:{ //选中的设备
  249. el:null,
  250. obj:null,
  251. },
  252. equipmentElements:[ //设备元素池
  253. ],
  254. grid:true, //设备拖拽是否开启网格
  255. isLoadLocation:false, //开启加载库位
  256. },
  257. mounted() {
  258. $("#detailInfo").modal("show");
  259. let record = localStorage.getItem("equipment:warehouse");
  260. if (record){
  261. let recordObj = JSON.parse(record);
  262. this.selected = recordObj.id;
  263. this.name = recordObj.name;
  264. }else{
  265. if (this.warehouses.length>0)this.selectedWarehouse(this.warehouses[0]);
  266. }
  267. },
  268. methods:{
  269. //备选设备拖拽按下事件
  270. eqDown(equipment){
  271. if (this.currentEq.obj!==null)return;
  272. let div = document.createElement("div");
  273. div.style.width = equipment.w+'px';
  274. div.style.height = equipment.h+'px';
  275. div.style.backgroundColor = equipment.color;
  276. div.style.zIndex = '999';
  277. div.style.position = 'fixed';
  278. div.style.left = event.clientX+'px';
  279. div.style.top = event.clientY+'px';
  280. div.style.border = '1px #0070C0 solid';
  281. div.style.opacity = '0.5';
  282. document.getElementById("container").append(div);
  283. this.currentEq.el = div;
  284. this.currentEq.obj = equipment;
  285. },
  286. //备选设备拖拽移动事件
  287. eqMove(){
  288. if (this.currentEq.obj===null)return;
  289. let x = event.clientX;
  290. let y = event.clientY;
  291. setTimeout(()=>{
  292. this.currentEq.el.style.left = x+'px';
  293. this.currentEq.el.style.top = y+'px';
  294. },10);
  295. },
  296. //备选设备拖拽松开事件
  297. eqUp(){
  298. if (this.currentEq.obj===null)return;
  299. this.currentEq.el.remove();
  300. this.currentEq.el = null;
  301. let content = document.getElementById("canvasApp");
  302. let toolWid = document.getElementById("tool").offsetWidth;
  303. let x = event.clientX-toolWid+content.scrollLeft;
  304. let y = event.clientY+content.scrollTop;
  305. if (x>=0 && y>=0){
  306. this.equipmentElements.push({
  307. x:x, y:y,
  308. width:this.currentEq.obj.w,
  309. height:this.currentEq.obj.h,
  310. name:"test",
  311. color:this.currentEq.obj.color,
  312. });
  313. }
  314. this.currentEq.obj = null;
  315. },
  316. //场景拖拽按下事件
  317. contentOnmousedown(event){
  318. if (!this.isNotEdit || this.clientCoords.x!==undefined)return;
  319. this.clientCoords = {
  320. x:event.clientX,
  321. y:event.clientY
  322. };
  323. },
  324. //场景拖拽移动事件
  325. contentOnmousemove(event){
  326. if (this.clientCoords.x===undefined)return;
  327. let diffX = event.clientX-this.clientCoords.x-2;
  328. let diffY = event.clientY-this.clientCoords.y-2;
  329. let content = document.getElementById("canvasApp");
  330. setTimeout(()=>{
  331. content.scrollTo(content.scrollLeft+diffX,content.scrollTop+diffY);
  332. },10);
  333. },
  334. //场景拖拽松开事件
  335. contentOnmouseup(){
  336. this.clientCoords = {};
  337. },
  338. onActivated(element){
  339. if (this.isNotEdit)return;
  340. this.currentEl = element;
  341. },
  342. //场景大小调整事件
  343. onResizing(newRect){
  344. if (this.isNotEdit)return;
  345. this.currentEl.width=newRect.width;
  346. this.currentEl.height=newRect.height;
  347. },
  348. //场景拖拽事件
  349. onDragging(newRect){
  350. if (this.isNotEdit)return;
  351. this.currentEl.x=newRect.left;
  352. this.currentEl.y=newRect.top;
  353. },
  354. //仓库切换
  355. selectedWarehouse(warehouse){
  356. this.selected = warehouse.id;
  357. this.name = warehouse.name;
  358. localStorage.setItem("equipment:warehouse", JSON.stringify(warehouse));
  359. },
  360. //文本类属性改变
  361. changeText(key){
  362. this.currentEl[key] = event.target.value;
  363. },
  364. //数值类属性改变
  365. changeNumber(key){
  366. this.currentEl[key] = event.target.value ? parseFloat(event.target.value) : 0;
  367. },
  368. //子设备选定时的库位加载
  369. nextDetail(layer){
  370. let parentDom = document.getElementById("detailInfo").firstChild.firstChild;
  371. let childDom = document.getElementById("locationModal").firstChild.firstChild;
  372. childDom.style.minWidth = parentDom.offsetWidth+'px';
  373. childDom.style.minHeight = parentDom.offsetHeight+'px';
  374. $("#locationModal").modal("show");
  375. this.isLoadLocation = true;
  376. setTimeout(()=>{
  377. this.isLoadLocation = false;
  378. },2000);
  379. //开启隐去现DIV动画,加载新DIV,加载数据
  380. //请求加载
  381. //关闭动画
  382. },
  383. },
  384. });
  385. </script>
  386. </html>