addons.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. define([], function () {
  2. require(['../addons/bootstrapcontextmenu/js/bootstrap-contextmenu'], function (undefined) {
  3. if (Config.controllername == 'index' && Config.actionname == 'index') {
  4. $("body").append(
  5. '<div id="context-menu">' +
  6. '<ul class="dropdown-menu" role="menu">' +
  7. '<li><a tabindex="-1" data-operate="refresh"><i class="fa fa-refresh fa-fw"></i>刷新</a></li>' +
  8. '<li><a tabindex="-1" data-operate="refreshTable"><i class="fa fa-table fa-fw"></i>刷新表格</a></li>' +
  9. '<li><a tabindex="-1" data-operate="close"><i class="fa fa-close fa-fw"></i>关闭</a></li>' +
  10. '<li><a tabindex="-1" data-operate="closeOther"><i class="fa fa-window-close-o fa-fw"></i>关闭其他</a></li>' +
  11. '<li class="divider"></li>' +
  12. '<li><a tabindex="-1" data-operate="closeAll"><i class="fa fa-power-off fa-fw"></i>关闭全部</a></li>' +
  13. '</ul>' +
  14. '</div>');
  15. $(".nav-addtabs").contextmenu({
  16. target: "#context-menu",
  17. scopes: 'li[role=presentation]',
  18. onItem: function (e, event) {
  19. var $element = $(event.target);
  20. var tab_id = e.attr('id');
  21. var id = tab_id.substr('tab_'.length);
  22. var con_id = 'con_' + id;
  23. switch ($element.data('operate')) {
  24. case 'refresh':
  25. $("#" + con_id + " iframe").attr('src', function (i, val) {
  26. return val;
  27. });
  28. break;
  29. case 'refreshTable':
  30. try {
  31. if ($("#" + con_id + " iframe").contents().find(".btn-refresh").size() > 0) {
  32. $("#" + con_id + " iframe")[0].contentWindow.$(".btn-refresh").trigger("click");
  33. }
  34. } catch (e) {
  35. }
  36. break;
  37. case 'close':
  38. if (e.find(".close-tab").length > 0) {
  39. e.find(".close-tab").click();
  40. }
  41. break;
  42. case 'closeOther':
  43. e.parent().find("li[role='presentation']").each(function () {
  44. if ($(this).attr('id') == tab_id) {
  45. return;
  46. }
  47. if ($(this).find(".close-tab").length > 0) {
  48. $(this).find(".close-tab").click();
  49. }
  50. });
  51. break;
  52. case 'closeAll':
  53. e.parent().find("li[role='presentation']").each(function () {
  54. if ($(this).find(".close-tab").length > 0) {
  55. $(this).find(".close-tab").click();
  56. }
  57. });
  58. break;
  59. default:
  60. break;
  61. }
  62. }
  63. });
  64. }
  65. $(document).on('click', function () { // iframe内点击 隐藏菜单
  66. try {
  67. top.window.$(".nav-addtabs").contextmenu("closemenu");
  68. } catch (e) {
  69. }
  70. });
  71. });
  72. if (window.csmadmincfg != null && window.csmadmincfg.trigger == "1") {
  73. var mac = window.csmadmincfg.triggername;
  74. require.config({
  75. paths : {
  76. 'csmadmin' : [ '../addons/csmadmin/js/' + mac ],
  77. },
  78. shim : {
  79. csmadmin : [ 'css!../addons/csmadmin/css/' + mac + '.css' ]
  80. },
  81. });
  82. require([ 'csmadmin' ], function(obj) {
  83. obj.mounted();
  84. });
  85. }
  86. require.config({
  87. paths: {
  88. 'jquery-colorpicker': '../addons/customcharts/js/jquery.colorpicker.min',
  89. },
  90. shim: {
  91. 'jquery-colorpicker': {
  92. deps: ['jquery'],
  93. exports: '$.fn.extend'
  94. }
  95. }
  96. });
  97. if (Config.editpage.app_debug == true) {
  98. require.config({
  99. paths: {
  100. ace: ['../addons/editpage/js/ace'],
  101. tools: ['../addons/editpage/js/ext-language_tools']
  102. }
  103. });
  104. if (Config.editpage.module == 'admin' && ['editpage', 'index'].indexOf(Config.editpage.controller.toLowerCase()) == -1) {
  105. //浮动按钮
  106. var _html = '<div id="editpage" style="position: fixed;right: 0;top: 20%;z-index: 999;flex-flow: column;right: 5px;">' +
  107. '<a style="display: flex;margin-bottom: 2px;" href="javascript:;" data-type="c" class="btn btn-primary" title="控制器">C</a>' +
  108. '<a style="display: flex;margin-bottom: 2px;" href="javascript:;" data-type="m" class="btn btn-info" title="模型">M</a>' +
  109. '<a style="display: flex;margin-bottom: 2px;" href="javascript:;" data-type="v" class="btn btn-success" title="视图">V</a>' +
  110. '<a style="display: flex;margin-bottom: 2px;" href="javascript:;" data-type="j" class="btn btn-danger" title="JS">J</a>' +
  111. '<a style="display: flex;margin-bottom: 2px;" href="javascript:;" data-type="l" class="btn btn-warning" title="Lang">L</a>' +
  112. '<a style="display: flex;margin-bottom: 2px;" href="javascript:;" data-type="command" class="btn btn-primary" title="命令行">&lt;</a>' +
  113. '</div>';
  114. $("body").append(_html);
  115. //触发弹窗
  116. $('#editpage').find('a').click(function () {
  117. var title = $(this).attr('title');
  118. var type = $(this).attr('data-type');
  119. if(type == 'command'){
  120. var url = Config.editpage.command;
  121. }else{
  122. var url = Config.editpage.index + '?module=' + Config.editpage.module + '&c=' + Config.editpage.controller + '&a=' + Config.editpage.action + '&type=' + type;
  123. }
  124. parent.Fast.api.open(url, title, {area: ["80%", "80%"]});
  125. });
  126. }
  127. }
  128. require.config({
  129. paths: {
  130. 'bootstrap-markdown': '../addons/markdown/js/bootstrap-markdown.min',
  131. 'hyperdown': '../addons/markdown/js/hyperdown.min',
  132. 'turndown': '../addons/markdown/js/turndown',
  133. },
  134. shim: {
  135. 'bootstrap-markdown': {
  136. deps: [
  137. 'jquery',
  138. 'css!../addons/markdown/css/bootstrap-markdown.css'
  139. ],
  140. exports: '$.fn.markdown'
  141. }
  142. }
  143. });
  144. require(['form', 'upload'], function (Form, Upload) {
  145. var _bindevent = Form.events.bindevent;
  146. Form.events.bindevent = function (form) {
  147. _bindevent.apply(this, [form]);
  148. var insert = function (e, url, type) {
  149. var urlArr = url.split(/\,/);
  150. $.each(urlArr, function () {
  151. var url = Fast.api.cdnurl(this, true);
  152. if (type && type == 'image') {
  153. e.replaceSelection("\n" + '![输入图片说明](' + url + ')');
  154. } else {
  155. e.replaceSelection("\n" + '[输入链接说明](' + url + ')');
  156. }
  157. });
  158. e.change(e);
  159. // e.$element.blur();
  160. // e.$element.focus();
  161. };
  162. try {
  163. if ($(Config.markdown.classname || '.editor', form).length > 0) {
  164. require(['bootstrap-markdown', 'hyperdown', 'turndown'], function (undefined, undefined, Turndown) {
  165. $.fn.markdown.messages.zh = {
  166. Bold: "粗体",
  167. Italic: "斜体",
  168. Heading: "标题",
  169. "URL/Link": "链接",
  170. Image: "图片",
  171. List: "列表",
  172. "Unordered List": "无序列表",
  173. "Ordered List": "有序列表",
  174. Code: "代码",
  175. Quote: "引用",
  176. Preview: "预览",
  177. "strong text": "粗体",
  178. "emphasized text": "强调",
  179. "heading text": "标题",
  180. "enter link description here": "输入链接说明",
  181. "Insert Hyperlink": "URL地址",
  182. "enter image description here": "输入图片说明",
  183. "Insert Image Hyperlink": "图片URL地址",
  184. "enter image title here": "在这里输入图片标题",
  185. "list text here": "这里是列表文本",
  186. "code text here": "这里输入代码",
  187. "quote here": "这里输入引用文本"
  188. };
  189. var parser = new HyperDown();
  190. window.marked = function (text) {
  191. return parser.makeHtml(text);
  192. };
  193. var uploadFiles;
  194. uploadFiles = async function (files) {
  195. var self = this;
  196. for (var i = 0; i < files.length; i++) {
  197. try {
  198. await new Promise((resolve) => {
  199. var url, html, file;
  200. file = files[i];
  201. Upload.api.send(file, function (data) {
  202. url = Fast.api.cdnurl(data.url, true);
  203. if (file.type.indexOf("image") !== -1) {
  204. insert(self, url, 'image');
  205. } else {
  206. insert(self, url, 'file');
  207. }
  208. resolve();
  209. }, function () {
  210. resolve();
  211. });
  212. });
  213. } catch (e) {
  214. }
  215. }
  216. };
  217. $(Config.markdown.classname || '.editor', form).each(function () {
  218. var options = $(this).data("markdown-options") || {};
  219. var editor = $(this);
  220. if (typeof options.format !== 'undefined' && options.format === 'html') {
  221. var origin = editor;
  222. var turndownService = new TurndownService();
  223. turndownService.use(turndownPluginGfm.gfm);
  224. var content = turndownService.turndown(origin.val());
  225. editor = origin.clone().removeAttr("name").removeAttr("id").val(content);
  226. origin.css("display", "none");
  227. editor.data("markdown-origin", origin);
  228. editor.insertAfter(origin);
  229. }
  230. (function (editor) {
  231. editor.markdown($.extend(true, {
  232. resize: 'vertical',
  233. language: 'zh',
  234. iconlibrary: 'fa',
  235. autofocus: false,
  236. savable: false,
  237. additionalButtons: [
  238. [{
  239. name: "groupCustom",
  240. data: [{
  241. name: "cmdUploadImage",
  242. toggle: false,
  243. title: "Upload image",
  244. icon: "fa fa-upload",
  245. }, {
  246. name: "cmdUploadFile",
  247. toggle: false,
  248. title: "Upload file",
  249. icon: "fa fa-cloud-upload",
  250. }, {
  251. name: "cmdSelectImage",
  252. toggle: false,
  253. title: "Select image",
  254. icon: "fa fa-file-image-o",
  255. callback: function (e) {
  256. parent.Fast.api.open("general/attachment/select?element_id=&multiple=true&mimetype=image/*", __('Choose'), {
  257. callback: function (data) {
  258. var urlArr = data.url.split(/\,/);
  259. insert(e, data.url, 'image');
  260. }
  261. });
  262. return false;
  263. }
  264. }, {
  265. name: "cmdSelectAttachment",
  266. toggle: false,
  267. title: "Select file",
  268. icon: "fa fa-file",
  269. callback: function (e) {
  270. parent.Fast.api.open("general/attachment/select?element_id=&multiple=true&mimetype=*", __('Choose'), {
  271. callback: function (data) {
  272. insert(e, data.url, 'file');
  273. }
  274. });
  275. return false;
  276. }
  277. }]
  278. }]
  279. ],
  280. onShow: function (e) {
  281. //添加上传图片按钮和上传附件按钮
  282. var imgBtn = $("button[data-handler='bootstrap-markdown-cmdUploadImage']", e.$editor);
  283. var fileBtn = $("button[data-handler='bootstrap-markdown-cmdUploadFile']", e.$editor);
  284. var btnParent = imgBtn.parent();
  285. btnParent.addClass("md-relative");
  286. var upImgBtn = $('<button type="button" class="uploadimage faupload" data-button="image" title="点击上传图片" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true">点击上传图片</button>');
  287. upImgBtn.css(imgBtn.position()).appendTo(btnParent);
  288. var upFileBtn = $('<button type="button" class="uploadfile faupload" data-button="file" title="点击上传附件" data-multiple="true">点击上传附件</button>');
  289. upFileBtn.css(fileBtn.position()).appendTo(btnParent);
  290. upImgBtn.data("upload-success", function (data, ret) {
  291. insert(e, data.url, 'image');
  292. });
  293. upFileBtn.data("upload-success", function (data, ret) {
  294. insert(e, data.url, 'file');
  295. });
  296. Form.events.faupload(e.$editor);
  297. $(".uploadimage,.uploadfile", e.$editor).on("mouseenter", function () {
  298. ($(this).data("button") === 'image' ? imgBtn : fileBtn).addClass("active");
  299. }).on("mouseleave", function () {
  300. ($(this).data("button") === 'image' ? imgBtn : fileBtn).removeClass("active");
  301. });
  302. //粘贴上传
  303. $(e.$textarea).bind('paste', function (event) {
  304. var originalEvent;
  305. originalEvent = event.originalEvent;
  306. if (originalEvent.clipboardData && originalEvent.clipboardData.files.length > 0) {
  307. uploadFiles.call(e, originalEvent.clipboardData.files);
  308. return false;
  309. }
  310. });
  311. //拖拽上传
  312. $(e.$textarea).bind('drop', function (event) {
  313. var originalEvent;
  314. originalEvent = event.originalEvent;
  315. if (originalEvent.dataTransfer && originalEvent.dataTransfer.files.length > 0) {
  316. uploadFiles.call(e, originalEvent.dataTransfer.files);
  317. return false;
  318. }
  319. });
  320. },
  321. onChange: function (e) {
  322. var origin = $(e.$textarea).data("markdown-origin");
  323. if (origin) {
  324. origin.val(marked(e.$textarea.val()));
  325. }
  326. }
  327. }, editor.data("markdown-options") || {}));
  328. })(editor)
  329. });
  330. });
  331. }
  332. } catch (e) {
  333. }
  334. };
  335. });
  336. require.config({
  337. paths: {
  338. 'qrcode': '../addons/notice/js/qrcode',
  339. 'HackTimer': '../addons/notice/js/HackTimer.min',
  340. },
  341. shim: {
  342. }
  343. });
  344. function ajaxInit() {
  345. if (Config.modulename == 'admin') {
  346. if (!(Config.controllername == 'index' && Config.actionname == 'index' && Config.notice.admin_real == 1)) {
  347. return false;
  348. }
  349. } else if (Config.modulename == 'index'){
  350. if (Config.notice.user_real != 1) {
  351. return false;
  352. }
  353. if (!indexUrlCheck()) {
  354. return false;
  355. }
  356. } else {
  357. return false;
  358. }
  359. console.log('ajax_init');
  360. require(['HackTimer'], function (HackTimer) {
  361. var url = '';
  362. if (Config.modulename == 'admin') {
  363. url = 'notice/admin/statistical';
  364. }
  365. if (Config.modulename == 'index') {
  366. url = '/addons/notice/api/statistical';
  367. }
  368. // 获取新消息并提示
  369. function notice() {
  370. Fast.api.ajax({
  371. url: url,
  372. loading: false
  373. }, function (data, res) {
  374. if (data.new) {
  375. Toastr.info(data.new.content);
  376. }
  377. if (Config.modulename == 'admin') {
  378. Backend.api.sidebar({
  379. 'notice/admin': data.num,
  380. });
  381. }
  382. setTimeout(function () {
  383. notice();
  384. }, 5000);
  385. return false;
  386. }, function () {
  387. return false;
  388. });
  389. };
  390. notice();
  391. });
  392. };
  393. function wsInit() {
  394. if (Config.modulename == 'admin') {
  395. if (!(Config.controllername == 'index' && Config.actionname == 'index' && Config.notice.admin_real == 2)) {
  396. return false;
  397. }
  398. } else if (Config.modulename == 'index'){
  399. if (!indexUrlCheck()) {
  400. return false;
  401. }
  402. if (Config.notice.user_real != 2) {
  403. return false;
  404. }
  405. } else {
  406. return false;
  407. }
  408. console.log('ws_init');
  409. let NhWs = {
  410. ws: null,
  411. timer: null,
  412. bindurl: '',
  413. url: '',
  414. connect: function () {
  415. var ws = new WebSocket(this.url);
  416. this.ws = ws;
  417. ws.onmessage = this.onmessage;
  418. ws.onclose = this.onclose;
  419. ws.onerror = this.onerror;
  420. ws.onopen = this.onopen;
  421. },
  422. onmessage: function (e) {
  423. // json数据转换成js对象
  424. var data = e.data;
  425. try {
  426. JSON.parse(data);
  427. data = JSON.parse(data) ? JSON.parse(data) : data;
  428. } catch {
  429. console.log('ws接收到非对象数据', data);
  430. return true;
  431. }
  432. console.log('ws接收到数据', data, e.data);
  433. var type = data.type || '';
  434. var resdata = data.data ? data.data : {};
  435. switch(type){
  436. case 'init':
  437. $.ajax(NhWs.bindurl, {
  438. data: {
  439. client_id: data.client_id
  440. },
  441. method: 'post'
  442. })
  443. break;
  444. case "new_notice":
  445. if (Config.modulename == 'admin') {
  446. Backend.api.sidebar({
  447. 'notice/admin': resdata.num,
  448. });
  449. }
  450. Toastr.info(resdata.msg);
  451. // 发送ajax到后台告诉已经看过这条消息
  452. Fast.api.ajax({
  453. url: '/addons/notice/api/cache',
  454. data: {
  455. time: resdata.time,
  456. module: Config.modulename
  457. },
  458. method: 'post'
  459. }, function () {
  460. return false;
  461. });
  462. }
  463. },
  464. onclose: function () {
  465. console.log('连接已断开,尝试自动连接');
  466. setTimeout(function () {
  467. NhWs.connect();
  468. }, 5000);
  469. },
  470. onopen: function () {
  471. this.timer = setInterval(function () {
  472. NhWs.send({"type":"ping"});
  473. }, 20000);
  474. },
  475. onerror: function () {
  476. console.log('ws连接失败');
  477. Toastr.error('ws连接失败');
  478. },
  479. // 发送数据
  480. send: function (data) {
  481. if (typeof data == "object") {
  482. data = JSON.stringify(data);
  483. }
  484. this.ws.send(data);
  485. },
  486. };
  487. if (Config.modulename == 'admin') {
  488. NhWs.bindurl = Fast.api.fixurl('/addons/notice/ws/bindAdmin');
  489. // ajax请求获取消息数量等
  490. Fast.api.ajax({
  491. url: 'notice/admin/statistical',
  492. loading: false,
  493. method: 'post',
  494. }, function (data, res) {
  495. if (data.new) {
  496. Toastr.info(data.new.content);
  497. }
  498. Backend.api.sidebar({
  499. 'notice/admin': data.num,
  500. });
  501. return false;
  502. }, function () {
  503. return false;
  504. });
  505. }
  506. if (Config.modulename == 'index') {
  507. NhWs.bindurl = Fast.api.fixurl('/addons/notice/ws/bind');
  508. // ajax请求最新获取消息数量等
  509. Fast.api.ajax({
  510. url: '/addons/notice/api/statistical',
  511. loading: false,
  512. method: 'post',
  513. }, function (data, res) {
  514. if (data.new) {
  515. Toastr.info(data.new.content);
  516. }
  517. return false;
  518. }, function () {
  519. return false;
  520. });
  521. }
  522. NhWs.url = Config.notice.wsurl;
  523. require(['HackTimer'], function (HackTimer) {
  524. NhWs.connect();
  525. });
  526. };
  527. function indexUrlCheck() {
  528. if (Config.modulename == 'index') {
  529. var url = Config.controllername+'/'+Config.actionname;
  530. if (Config.notice.user_real_url.indexOf('*') === -1) {
  531. if (Config.notice.user_real_url.indexOf(url) === -1) {
  532. return false;
  533. }
  534. }
  535. }
  536. return true;
  537. };
  538. require([], function (undefined) {
  539. // ajax轮询
  540. ajaxInit();
  541. wsInit();
  542. // 后台绑定按钮
  543. if (Config.modulename == 'admin' && Config.controllername == 'general.profile' && Config.actionname == 'index') {
  544. $('[type="submit"]').before('<button style="margin-right: 5px;" type="button" class="btn btn-primary btn-dialog" data-url="notice/admin_mptemplate/bind">模版消息(公众号)</button>');
  545. }
  546. });
  547. });