nodeList.blade.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. @extends('user.layouts')
  2. @section('css')
  3. <script src="//at.alicdn.com/t/font_682457_e6aq10jsbq0yhkt9.js" type="text/javascript"></script>
  4. <link href="/assets/global/fonts/font-awesome/font-awesome.min.css" type="text/css" rel="stylesheet">
  5. <link href="/assets/global/vendor/webui-popover/webui-popover.min.css" type="text/css" rel="stylesheet">
  6. <link href="/assets/global/vendor/jvectormap/jquery-jvectormap.min.css" type="text/css" rel="stylesheet">
  7. @endsection
  8. @section('content')
  9. <div class="page-content container-fluid">
  10. <div class="row">
  11. <!-- <div class="col-md-3">-->
  12. <!-- <div class="row map">-->
  13. <!-- <div class="col-md-12">-->
  14. <!-- <div class="card card-block p-20 bg-indigo-500">-->
  15. <!-- <div class="counter counter-lg counter-inverse">-->
  16. <!-- <div class="counter-label text-uppercase font-size-16">{{trans('user.account.level')}}</div>-->
  17. <!-- <div class="counter-number-group">-->
  18. <!-- <span class="counter-icon"><i class="icon wb-user-circle" aria-hidden="true"></i></span>-->
  19. <!-- <span class="counter-number ml-10">{{Auth::getUser()->level}}</span>-->
  20. <!-- </div>-->
  21. <!-- <div class="counter-label text-uppercase font-size-16">{{Auth::getUser()->level_name}}</div>-->
  22. <!-- </div>-->
  23. <!-- </div>-->
  24. <!-- </div>-->
  25. <!--@if(Auth::getUser()->group_id)-->
  26. <!-- <div class="col-md-12">-->
  27. <!-- <div class="card card-block p-20 bg-indigo-500">-->
  28. <!-- <div class="counter counter-lg counter-inverse">-->
  29. <!-- <div class="counter-label text-uppercase font-size-16">{{trans('user.account.group')}}</div>-->
  30. <!-- <div class="counter-number-group">-->
  31. <!-- <span class="counter-icon"><i class="icon wb-globe" aria-hidden="true"></i></span>-->
  32. <!-- <span class="counter-number ml-10">{{Auth::getUser()->group->name}}</span>-->
  33. <!-- </div>-->
  34. <!-- </div>-->
  35. <!-- </div>-->
  36. <!-- </div>-->
  37. <!--@endif-->
  38. <!-- <div class="col-md-12">-->
  39. <!-- <div class="card card-block p-20 bg-indigo-500">-->
  40. <!-- <div class="counter counter-lg counter-inverse">-->
  41. <!-- <div class="counter-label text-uppercase font-size-16">{{trans('user.account.speed_limit')}}</div>-->
  42. <!-- <div class="counter-number-group">-->
  43. <!-- <span class="counter-icon"><i class="icon wb-signal" aria-hidden="true"></i></span>-->
  44. <!-- <span class="counter-number ml-10">{{Auth::getUser()->speed_limit ?? trans('common.unlimited')}}</span>-->
  45. <!-- </div>-->
  46. <!-- <div class="counter-label font-size-16">Mbps</div>-->
  47. <!-- </div>-->
  48. <!-- </div>-->
  49. <!-- </div>-->
  50. <!-- </div>-->
  51. <!--</div>-->
  52. <h3>请复制节点链接后, 然后粘贴到软件即可。请使用我们推荐的软件!!</h3>
  53. {{-- <div class="col-xxl-3 col-xl-4 col-sm-6">--}}
  54. {{-- <div class="card card-inverse card-shadow bg-white node">--}}
  55. {{-- <div class="card-block p-30 row">--}}
  56. {{-- <div class="col-4">--}}
  57. {{-- <svg class="w-p100 text-center" aria-hidden="true">--}}
  58. {{-- </svg>--}}
  59. {{-- </div>--}}
  60. {{-- <div class="col-8 text-break text-right">--}}
  61. {{-- <p class="font-size-20 blue-600">--}}
  62. {{-- {{$node_txt}}--}}
  63. {{-- </p>--}}
  64. {{-- <blockquote>--}}
  65. {{-- </blockquote>--}}
  66. {{-- </div>--}}
  67. {{-- </div>--}}
  68. {{-- </div>--}}
  69. {{-- </div>--}}
  70. <div class="col-xxl-3 col-xl-4 col-sm-6">
  71. <div class="card card-inverse card-shadow bg-white node">
  72. <div class="card-block p-30 row">
  73. <div class="col-4">
  74. <svg class="w-p100 text-center" aria-hidden="true">
  75. <!-- SVG内容 -->
  76. </svg>
  77. </div>
  78. <div class="col-8 text-break text-right">
  79. <p class="font-size-20 blue-600">
  80. {{-- {{$node_txt}} --}}
  81. </p>
  82. <blockquote>
  83. </blockquote>
  84. <!-- 按钮触发模态框 -->
  85. <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
  86. 复制所有节点
  87. </button>
  88. </div>
  89. </div>
  90. </div>
  91. </div>
  92. <!-- 模态框结构 -->
  93. <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  94. <div class="modal-dialog" role="document">
  95. <div class="modal-content">
  96. <div class="modal-header">
  97. <h5 class="modal-title" id="exampleModalLabel">详细内容</h5>
  98. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  99. <span aria-hidden="true">&times;</span>
  100. </button>
  101. </div>
  102. <div class="modal-body">
  103. <!-- 这里放你想展示的内容 -->
  104. <p>
  105. <textarea id="modalContent" class="form-control" rows="12" readonly="readonly">{{$node_txt}}</textarea>
  106. </p>
  107. </div>
  108. <div class="modal-footer">
  109. <!-- 生成二维码按钮 -->
  110. {{-- <button type="button" class="btn btn-primary" onclick="generateQRCode()">生成二维码</button>--}}
  111. <!-- 复制按钮 -->
  112. <button type="button" class="btn btn-primary" onclick="copyToClipboard()">一键复制</button>
  113. <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
  114. </div>
  115. </div>
  116. </div>
  117. </div>
  118. <!-- 模态框结构 - 显示二维码 -->
  119. <div class="modal fade" id="qrModal" tabindex="-1" role="dialog" aria-labelledby="qrModalLabel" aria-hidden="true">
  120. <div class="modal-dialog" role="document">
  121. <div class="modal-content">
  122. <div class="modal-header">
  123. <h5 class="modal-title" id="qrModalLabel">二维码</h5>
  124. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  125. <span aria-hidden="true">&times;</span>
  126. </button>
  127. </div>
  128. <div class="modal-body text-center">
  129. <!-- 显示二维码的地方 -->
  130. <div id="qrcode"></div>
  131. <img id="qrcodeImage" src="" alt="QR Code as Base64" />
  132. </div>
  133. <div class="modal-footer">
  134. <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
  135. </div>
  136. </div>
  137. </div>
  138. </div>
  139. @foreach($nodeList as $node)
  140. <div class="col-xxl-3 col-xl-4 col-sm-6">
  141. <div class="card card-inverse card-shadow bg-white node">
  142. <div class="card-block p-30 row">
  143. <div class="col-4">
  144. <svg class="w-p100 text-center" aria-hidden="true">
  145. <use xlink:href="@if($node->country_code)#icon-{{$node->country_code}}@else #icon-un @endif"></use>
  146. </svg>
  147. </div>
  148. <div class="col-8 text-break text-right">
  149. <p class="font-size-20 blue-600">
  150. <!--<span class="badge badge-pill up m-0 badge-default">{{$node->level_table->name}}</span>-->
  151. <!--@if($node->offline)-->
  152. <!-- <i class="red-600 icon wb-warning" data-content="{{trans('user.node.unstable')}}"-->
  153. <!-- data-trigger="hover" data-toggle="popover" data-placement="top"></i>-->
  154. <!--@endif-->
  155. @if($node->traffic_rate != 1)
  156. <i class="green-600 icon wb-info-circle" data-content="{{trans('user.node.rate', ['ratio' => $node->traffic_rate])}}"
  157. data-trigger="hover" data-toggle="popover" data-placement="top"></i>
  158. @endif
  159. {{$node->name}}
  160. </p>
  161. <blockquote>
  162. @foreach($node->labels as $label)
  163. <span class="badge badge-pill font-size-10 up m-0 badge-info">{{$label->name}}</span>
  164. @endforeach
  165. <br>
  166. <!--{{$node->description}}-->
  167. </blockquote>
  168. <p class="font-size-14">
  169. <button class="btn btn-sm btn-outline-info" onclick="getInfo('{{$node->id}}','code')">
  170. <i id="code{{$node->id}}" class="icon fa-code"></i>
  171. </button>
  172. <!--<button class="btn btn-sm btn-outline-info" onclick="getInfo('{{$node->id}}','qrcode')">-->
  173. <!-- <i id="qrcode{{$node->id}}" class="icon fa-qrcode"></i>-->
  174. <!--</button>-->
  175. <!--<button class="btn btn-sm btn-outline-info" onclick="getInfo('{{$node->id}}','text')">-->
  176. <!-- <i id="text{{$node->id}}" class="icon fa-list"></i>-->
  177. <!--</button>-->
  178. </p>
  179. </div>
  180. </div>
  181. </div>
  182. </div>
  183. @endforeach
  184. </div>
  185. </div>
  186. @endsection
  187. @section('javascript')
  188. <script src="/assets/global/vendor/matchheight/jquery.matchHeight-min.js" type="text/javascript"></script>
  189. <script src="/assets/global/js/Plugin/matchheight.js" type="text/javascript"></script>
  190. <script src="/assets/custom/jquery-qrcode/qrcode.js" type="text/javascript"></script>
  191. <script src="/assets/global/js/Plugin/webui-popover.js" type="text/javascript"></script>
  192. <script src="/assets/global/vendor/jvectormap/jquery-jvectormap.min.js"></script>
  193. <script src="/assets/custom/maps/jquery-jvectormap-world-mill-cn.js"></script>
  194. <script type="text/javascript">
  195. function copyToClipboard() {
  196. var textarea = document.getElementById("modalContent");
  197. textarea.select();
  198. textarea.setSelectionRange(0, 99999); // 对于移动设备的选择范围
  199. document.execCommand("copy");
  200. alert("内容已复制到剪贴板!");
  201. }
  202. function generateQRCode() {
  203. var content = document.getElementById("modalContent").value;
  204. // 检查内容是否为空
  205. if (!content || content.trim() === "") {
  206. alert("内容不能为空!");
  207. return;
  208. }
  209. // 对内容进行Base64编码
  210. var encodedContent = btoa(content);
  211. //console.error(encodedContent);
  212. // 清除之前生成的二维码
  213. document.getElementById("qrcode").innerHTML = "";
  214. // 创建一个隐藏的 canvas 用于生成 Base64 URL
  215. var canvas = document.createElement('canvas');
  216. canvas.width = 256;
  217. canvas.height = 256;
  218. try {
  219. // 生成二维码到隐藏的 canvas 中
  220. var qrCode = new QRCode(canvas, {
  221. text: encodedContent, // 使用Base64编码后的内容
  222. width: 256, // 二维码的宽度
  223. height: 256, // 二维码的高度
  224. correctLevel: QRCode.CorrectLevel.H // 使用最高的纠错级别
  225. });
  226. // 等待二维码生成后,将其转换为 Base64 URL
  227. setTimeout(function() {
  228. var base64URL = canvas.toDataURL("image/png");
  229. // 在页面上显示Base64二维码图片
  230. var imgElement = document.getElementById("qrcodeImage");
  231. imgElement.src = base64URL;
  232. // 输出到控制台或进一步处理
  233. console.log(base64URL);
  234. }, 500); // 等待二维码生成(延迟时间可以根据实际情况调整)
  235. } catch (error) {
  236. console.error("二维码生成失败:", error);
  237. alert("二维码生成失败,请检查内容格式。");
  238. }
  239. // 关闭当前模态框
  240. $('#exampleModal').modal('hide');
  241. // 打开二维码模态框
  242. $('#qrModal').modal('show');
  243. }
  244. $(function() {
  245. $('#world-map').vectorMap({
  246. map: 'world_mill',
  247. scaleColors: ['#C8EEFF', '#0071A4'],
  248. normalizeFunction: 'polynomial',
  249. zoomAnimate: true,
  250. hoverOpacity: 0.7,
  251. hoverColor: false,
  252. regionStyle: {
  253. initial: {
  254. fill: '#3E8EF7',
  255. },
  256. hover: {
  257. fill: '#589FFC',
  258. },
  259. selected: {
  260. fill: '#0B69E3',
  261. },
  262. selectedHover: {
  263. fill: '#589FFC',
  264. },
  265. },
  266. markerStyle: {
  267. initial: {
  268. r: 3,
  269. fill: '#FF4C52',
  270. 'stroke-width': 0,
  271. },
  272. hover: {
  273. r: 6,
  274. stroke: '#FF4C52',
  275. 'stroke-width': 0,
  276. },
  277. },
  278. backgroundColor: '#fff',
  279. markers: [
  280. @foreach($nodesGeo as $name => $geo)
  281. {
  282. latLng: [{{$name}}], name: '{{$geo}}',
  283. },
  284. @endforeach
  285. ],
  286. });
  287. $('.node').matchHeight();
  288. $('.map').matchHeight();
  289. });
  290. function getInfo(id, type) {
  291. const oldClass = $('#' + type + id).attr('class');
  292. $.ajax({
  293. method: 'POST',
  294. url: '{{route('node')}}',
  295. data: {_token: '{{csrf_token()}}', id: id, type: type},
  296. beforeSend: function() {
  297. $('#' + type + id).removeAttr('class').addClass('icon wb-loop icon-spin');
  298. },
  299. success: function(ret) {
  300. if (ret.status === 'success') {
  301. switch (type) {
  302. case 'code':
  303. swal.fire({
  304. html: '<textarea class="form-control" rows="8" readonly="readonly">' + ret.data + '</textarea>' +
  305. '<a href="' + ret.data + '" class="btn btn-danger btn-block mt-10">{{trans('common.open')}}' + ret.title + '</a>',
  306. showConfirmButton: false,
  307. });
  308. break;
  309. case 'qrcode':
  310. swal.fire({
  311. title: '{{trans('user.scan_qrcode')}}',
  312. html: '<div id="qrcode"></div>',
  313. onBeforeOpen: () => {
  314. $('#qrcode').qrcode({text: ret.data});
  315. },
  316. showConfirmButton: false,
  317. });
  318. break;
  319. case 'text':
  320. swal.fire({
  321. title: '{{trans('user.node.info')}}',
  322. html: '<textarea class="form-control" rows="12" readonly="readonly">' + ret.data + '</textarea>',
  323. showConfirmButton: false,
  324. });
  325. break;
  326. default:
  327. swal.fire({title: ret.title, text: ret.data, icon: 'error'});
  328. }
  329. }
  330. },
  331. complete: function() {
  332. $('#' + type + id).removeAttr('class').addClass(oldClass);
  333. },
  334. });
  335. }
  336. </script>
  337. @endsection