index.blade.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. @extends('layouts.app')
  2. @section('title')菜单@endsection
  3. @section('content')
  4. <div class="container-fluid d-none" id="container" @drop="drop($event)" @dragover="dragover($event, false)">
  5. @include("maintenance.menu._modal")
  6. <div class="card" id="content">
  7. <div class="card-body">
  8. <button class="btn btn-outline-info mb-1 mr-3" @click="openModal()"><span class="fa fa-plus"></span>&nbsp;新&nbsp;&nbsp;增</button>
  9. <button class="btn border border-2 mb-1 mr-3" :class="isSaveSort ? 'btn-success' : 'text-secondary'" :disabled="!isSaveSort" @click="sort()"> 保 存 </button>
  10. <div class="btn-group pull-right">
  11. <button class="btn border btn-primary" @click="expand(true)">展开全部</button>
  12. <button class="btn border btn-primary" @click="expand(false)">收起全部</button>
  13. </div>
  14. <div class="row text-nowrap">
  15. <ul class="list-group col-9 offset-1" style="cursor: move;">
  16. <li class="list-group-item" v-for="menu in menus" draggable="true" :id="'menu-'+menu.id"
  17. :data-order="menu.sequence" :data-id="menu.id" :data-parent="menu.parent_id" :data-level="menu.level"
  18. @drop="drop($event)" @dragover="dragover($event)" @dragstart.stop="dragstart(menu.id)">
  19. <span class="fa fa-angle-right pull-left cursor-pointer font-weight-bold" @click="slide(menu.id,$event)" style="margin-top: 0.2em">&nbsp;</span>
  20. <span v-show="menu.font" :class="'fa '+menu.font" :style="menu.font_style"></span>@{{ menu.name }}
  21. <span class="fa fa-close pull-right text-danger" style="cursor: pointer" @click="delMenu(menu.id)"></span>
  22. <span class="fa fa-edit pull-right text-primary mr-2" style="cursor: pointer" @click="openModal(menu)"></span>
  23. <div class="row up" v-if="menu.child.length>0" :id="'slide-'+menu.id">
  24. <ul class="list-group col-9 offset-1">
  25. <li class="list-group-item" v-for="menu2 in menu.child" draggable="true" :id="'menu-'+menu2.id"
  26. :data-order="menu2.sequence" :data-id="menu2.id" :data-parent="menu2.parent_id" :data-level="menu2.level"
  27. @drop="drop($event)" @dragover="dragover($event,dragoverId!=menu.id)" @dragstart.stop="dragstart(menu2.id)">
  28. <span class="fa fa-angle-right pull-left cursor-pointer font-weight-bold" @click="slide(menu2.id,$event)" style="margin-top: 0.2em">&nbsp;</span>
  29. @{{ menu2.name }}
  30. <span class="fa fa-close pull-right text-danger" style="cursor: pointer" @click="delMenu(menu2.id)"></span>
  31. <span class="fa fa-edit pull-right text-primary mr-2" style="cursor: pointer" @click="openModal(menu2)"></span>
  32. <div class="row up" v-if="menu2.child.length>0" :id="'slide-'+menu2.id">
  33. <ul class="list-group col-9 offset-1">
  34. <li class="list-group-item" v-for="menu3 in menu2.child" draggable="true" :id="'menu-'+menu3.id"
  35. :data-order="menu3.sequence" :data-id="menu3.id" :data-parent="menu3.parent_id" :data-level="menu3.level"
  36. @drop="drop($event)" @dragover="dragover($event,dragoverId!=menu2.id && dragoverId!=menu.id)" @dragstart.stop="dragstart(menu3.id)">
  37. <span class="fa fa-angle-right pull-left cursor-pointer font-weight-bold" @click="slide(menu3.id,$event)" style="margin-top: 0.2em">&nbsp;</span>
  38. @{{ menu3.name }}
  39. <span class="fa fa-close pull-right text-danger" style="cursor: pointer" @click="delMenu(menu3.id)"></span>
  40. <span class="fa fa-edit pull-right text-primary mr-2" style="cursor: pointer" @click="openModal(menu3)"></span>
  41. <div class="row up" v-if="menu3.child.length>0" :id="'slide-'+menu3.id">
  42. <ul class="list-group col-9 offset-1">
  43. <li class="list-group-item" v-for="menu4 in menu3.child" draggable="true" :id="'menu-'+menu4.id"
  44. :data-order="menu4.sequence" :data-id="menu4.id" :data-parent="menu4.parent_id" :data-level="menu4.level"
  45. @drop="drop($event)" @dragover="dragover($event,dragoverId!=menu3.id && dragoverId!=menu2.id && dragoverId!=menu.id)" @dragstart.stop="dragstart(menu4.id)">
  46. @{{ menu4.name }}
  47. <span class="fa fa-close pull-right text-danger" style="cursor: pointer" @click="delMenu(menu4.id)"></span>
  48. <span class="fa fa-edit pull-right text-primary mr-2" style="cursor: pointer" @click="openModal(menu4)"></span>
  49. </li>
  50. </ul>
  51. </div>
  52. </li>
  53. </ul>
  54. </div>
  55. </li>
  56. </ul>
  57. </div>
  58. </li>
  59. </ul>
  60. </div>
  61. <li id="dragover-container" class="border-dashed-red" v-show="isDragover" @drop="drop($event)" @dragover="dragover($event,false)">
  62. <div class='w-100 text-center text-secondary'>拖拽至此</div>
  63. </li>
  64. </div>
  65. </div>
  66. </div>
  67. @endsection
  68. @section('lastScript')
  69. <script>
  70. new Vue({
  71. el:"#container",
  72. data:{
  73. menus:[],
  74. unit:{},
  75. errors:{},
  76. dragoverId:"",
  77. isDragover : false,
  78. isSaveSort : false,
  79. menuList:[],
  80. icons:[],
  81. filterIcons:[],
  82. menu:{},
  83. },
  84. mounted(){
  85. let menus = [@foreach($menus as $menu)@json($menu),@endforeach];
  86. let menuMap = {};
  87. menus.forEach(menu=>{
  88. menu["child"] = [];
  89. menuMap["_"+menu.id] = menu;
  90. });
  91. menus.forEach(menu=>{
  92. if (menu.parent_id){
  93. menuMap["_"+menu.parent_id].child.push(menu);
  94. delete menuMap["_"+menu.id];
  95. }
  96. });
  97. this.menus = menuMap;
  98. this._formatSelected();
  99. setTimeout(function(){
  100. $(".up").slideUp();
  101. $("#container").removeClass("d-none");
  102. },0);
  103. },
  104. methods:{
  105. expand(isExpand){
  106. if (isExpand) $(".up").slideDown();
  107. else $(".up").slideUp();
  108. },
  109. slide(id,e){
  110. $("#slide-"+id).slideToggle();
  111. if (e.target.className.indexOf('right')===-1)e.target.className = "fa fa-angle-right pull-left cursor-pointer font-weight-bold";
  112. else e.target.className = "fa fa-angle-down pull-left cursor-pointer font-weight-bold";
  113. },
  114. delMenu(id){
  115. window.tempTip.confirm("确认要删除此菜单及其子级吗?",()=>{
  116. let url = "{{url('maintenance/menu/delete')}}";
  117. let ids = [id];
  118. let nodes = document.getElementById("menu-"+id).getElementsByTagName("LI");
  119. for (let i=0;i<nodes.length;i++){
  120. let id = nodes[i].getAttribute("data-id");
  121. if (id)ids.push(id);
  122. }
  123. window.tempTip.postBasicRequest(url,{ids:ids},()=>{
  124. document.getElementById("menu-"+id).remove();
  125. this.sort();
  126. return "删除成功";
  127. })
  128. });
  129. },
  130. seekIcon(e){
  131. let val = e.target.value;
  132. let arr = [];
  133. this.icons.forEach(icon=>{
  134. if (!val)arr.push(icon);
  135. else if (icon.indexOf(val)!==-1)arr.push(icon);
  136. });
  137. this.filterIcons = arr;
  138. },
  139. selectedIcon(icon){
  140. this.$set(this.menu,"font",icon);
  141. },
  142. _formatSelected(){
  143. new Promise(()=>{
  144. this.menuList = this._mergeArray(this.menus);
  145. this._getIcons()
  146. });
  147. },
  148. _getIcons(){
  149. let url = "{{url('')}}"+"/js/utilities/icons.json";
  150. let request = new XMLHttpRequest();
  151. request.open("get", url);
  152. request.send(null);
  153. request.onload = ()=>{
  154. if (request.status == 200) {
  155. this.icons = JSON.parse(request.responseText);
  156. this.filterIcons = JSON.parse(request.responseText);
  157. }
  158. }
  159. },
  160. _mergeArray(obj,arr=[]){
  161. for (let key in obj){
  162. let name = "";
  163. for (let i=1;i<obj[key]["level"];i++){
  164. name += "&nbsp;&nbsp;&nbsp;";
  165. }
  166. if (obj[key]['level']!==1)name += "└─&nbsp;";
  167. name += obj[key]["name"];
  168. arr.push({name:name,id:obj[key]["id"],level:obj[key]["level"],parent_id:obj[key]["parent_id"]});
  169. if (obj[key].child)arr = this._mergeArray(obj[key].child,arr);
  170. }
  171. return arr;
  172. },
  173. openModal(menu=null){
  174. this.menu=Object.assign({},menu);
  175. if (this.menu){
  176. if (!this.menu.parent_id)this.menu.parent_id = "";
  177. if (this.menu.font_style && this.menu.font_style.slice(0,6)==='color:'){
  178. this.menu.font_style = this.menu.font_style.slice(6);
  179. if (this.menu.font_style[this.menu.font_style.length-1]===';'){
  180. this.menu.font_style = this.menu.font_style.slice(0,this.menu.font_style.length-1);
  181. }
  182. }
  183. }
  184. else this.menu={parent_id:""};
  185. $("#modal").modal("show");
  186. },
  187. submitMenu(){
  188. let url="{{url('maintenance/menu/save')}}";
  189. let msg=this.menu.id ? "成功修改菜单“"+this.menu.name+"”" : "成功新增菜单“"+this.menu.name+"”";
  190. let pa = null;
  191. let level = 0;
  192. if(this.menu.parent_id){
  193. pa = this.menu.parent_id;
  194. level = document.getElementById("menu-"+this.menu.parent_id).getAttribute("data-level");
  195. }
  196. let params = {
  197. name : this.menu.name,
  198. parent_id : pa,
  199. level : Number(level)+1,
  200. route:this.menu.route,
  201. font:this.menu.font,
  202. font_style:this.menu.font_style ? 'color:'+this.menu.font_style+";" : null,
  203. };
  204. if (this.menu.id){
  205. params = {
  206. id:this.menu.id,
  207. name : this.menu.name,
  208. route:this.menu.route,
  209. font:this.menu.font,
  210. font_style:this.menu.font_style ? 'color:'+this.menu.font_style+";" : null,
  211. };
  212. }
  213. window.tempTip.postBasicRequest(url,params,(res)=>{
  214. if (params.id){
  215. let menu = this.seekNode(this.menu.id,this.menu.parent_id);
  216. menu.name = params.name;
  217. menu.route = params.route;
  218. menu.font = params.font;
  219. menu.font_style = params.font_style;
  220. }else this.insert(res);
  221. //$("#modal").modal("hide");
  222. return msg;
  223. },true);
  224. },
  225. dragover(e, isAllow = true){
  226. e.preventDefault();
  227. e.stopPropagation();
  228. if (isAllow) e.currentTarget.after(document.getElementById("dragover-container"))
  229. },
  230. dragstart(id){
  231. $("#menu-"+id).after($("#dragover-container"));
  232. this.dragoverId = id;
  233. this.isDragover = true;
  234. },
  235. drop(e){
  236. e.preventDefault();
  237. e.stopPropagation();
  238. $("#dragover-container").after($("#menu-"+this.dragoverId));
  239. this.handleDrag(this.dragoverId);
  240. this.dragoverId = "";
  241. this.isDragover = false;
  242. this.isSaveSort = true;
  243. },
  244. handleDrag(id){
  245. return new Promise(()=>{
  246. let params = {};
  247. let dom = document.getElementById("menu-"+id);
  248. let oldParent = dom.getAttribute("data-parent");
  249. let parent = dom.parentElement;
  250. let newParent = function () {
  251. while (parent && parent.tagName!=='LI')parent = parent.parentElement;
  252. return parent ? parent.getAttribute("data-id") : null;
  253. }();
  254. if (oldParent!==newParent){
  255. dom.setAttribute("data-parent",newParent);
  256. params.id = id;
  257. params.parent_id = newParent;
  258. let oldLevel = dom.getAttribute("data-level");
  259. let newLevel = parent ? Number(parent.getAttribute("data-level"))+1 : 1;
  260. let diff = oldLevel-newLevel;
  261. if (diff!=0){
  262. dom.setAttribute("data-level",newLevel);
  263. params.level = newLevel;
  264. let child = dom.getElementsByTagName("LI");
  265. if (child.length>0){
  266. params.diff = diff;
  267. params.child = [];
  268. for (let i=0;i<child.length;i++){
  269. params.child.push(child[i].getAttribute("data-id"));
  270. let level = child[i].getAttribute("data-level")-diff;
  271. child[i].setAttribute("data-level",level);
  272. }
  273. }
  274. }
  275. if (JSON.stringify(params)!=='{}'){
  276. window.tempTip.postBasicRequest("{{url('maintenance/menu/update')}}",params,()=>{});
  277. }
  278. }
  279. });
  280. },
  281. sort(){
  282. let nodes = document.getElementById("content").getElementsByTagName("LI");
  283. let update = [["id","sequence"]];
  284. let index = 1;
  285. let arr = [];
  286. for (let i=0;i<nodes.length;i++){
  287. let id = nodes[i].getAttribute("data-id");
  288. let parent_id = nodes[i].getAttribute("data-parent");
  289. if (!id)continue;
  290. let oldOrder = nodes[i].getAttribute("data-order");
  291. if (oldOrder != index){
  292. nodes[i].setAttribute("data-order",index);
  293. update.push({id:id,sequence:index});
  294. }
  295. index++;
  296. //重置列表
  297. let name = "";
  298. let level = Number(nodes[i].getAttribute("data-level"));
  299. for (let j=1;j<level;j++){
  300. name += "&nbsp;&nbsp;&nbsp;";
  301. }
  302. if (level!==1)name += "└─&nbsp;";
  303. for (let j=0;j<nodes[i].childNodes.length;j++){
  304. if (nodes[i].childNodes[j].nodeName==='#text' && nodes[i].childNodes[j].nodeValue!=' '){
  305. name += nodes[i].childNodes[j].nodeValue;
  306. break;
  307. }
  308. }
  309. arr.push({name:name,id:id,level:level,parent_id:parent_id});
  310. }
  311. this.menuList = arr;
  312. if (update.length > 1){
  313. let url = "{{url('maintenance/menu/sort')}}";
  314. window.tempTip.postBasicRequest(url,{"update":update},()=>{
  315. this.isSaveSort = false;
  316. });
  317. }else this.isSaveSort = false;
  318. },
  319. insert(menu){
  320. menu.child = [];
  321. if (!menu.parent_id){
  322. this.$set(this.menus,"_"+menu.id,menu);
  323. setTimeout(()=>{this.sort();},100);
  324. return;
  325. }
  326. let arr = [];
  327. let parent = document.getElementById("menu-"+menu.parent_id);
  328. while (parent){
  329. let parent_id = parent.getAttribute("data-id");
  330. if (parent_id)arr.push(parent_id);
  331. parent = parent.parentElement;
  332. }
  333. if (arr.length===1){
  334. this.menus["_"+menu.parent_id].child.push(menu);
  335. setTimeout(()=>{this.sort();},100);
  336. return;
  337. }
  338. let menus = this.menus["_"+arr[arr.length-1]];
  339. for (let i=arr.length-1;i>=0;i--){
  340. menus.child.some((menu,j)=>{
  341. if (menu.id==arr[i]){
  342. menus = menus.child[j];
  343. return true;
  344. }
  345. });
  346. }
  347. menus.child.push(menu);
  348. setTimeout(()=>{this.sort();},100);
  349. },
  350. seekNode(id,parentId){
  351. if (!parentId)return this.menus["_"+id];
  352. let arr = [];
  353. let parent = document.getElementById("menu-"+parentId);
  354. while (parent){
  355. let parent_id = parent.getAttribute("data-id");
  356. if (parent_id)arr.push(parent_id);
  357. parent = parent.parentElement;
  358. }
  359. if (arr.length===1){
  360. let menus;
  361. this.menus["_"+parentId].child.some((menu,j)=>{
  362. if (menu.id==id){
  363. menus = this.menus["_"+parentId].child[j];
  364. return true;
  365. }
  366. });
  367. return menus;
  368. }
  369. let menus = this.menus["_"+arr[arr.length-1]];
  370. for (let i=arr.length-1;i>=0;i--){
  371. menus.child.some((menu,j)=>{
  372. if (menu.id==arr[i]){
  373. menus = menus.child[j];
  374. return true;
  375. }
  376. });
  377. }
  378. menus.child.some((menu,j)=>{
  379. if (menu.id==id){
  380. menus = menus.child[j];
  381. return true;
  382. }
  383. });
  384. return menus;
  385. },
  386. seekMenu(e){
  387. let val = e.target.value;
  388. let menuMap = {};
  389. for (let i=0;i<this.menuList.length;i++){
  390. menuMap['_'+this.menuList[i].id] = i;
  391. }
  392. this.menuList.forEach((menu,index)=>{
  393. if (menu.name.indexOf(val)===-1)this.$set(this.menuList[index],"hide",true);
  394. else {
  395. this.$set(this.menuList[index],"hide",false);
  396. if (menu.parent_id){
  397. let tar = menuMap['_'+menu.parent_id];
  398. while (tar!==undefined){
  399. this.$set(this.menuList[tar],"hide",false);
  400. tar = menuMap['_'+this.menuList[tar].parent_id];
  401. }
  402. }
  403. }
  404. });
  405. },
  406. }
  407. });
  408. </script>
  409. @endsection