conversation.ui.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. let lastPageID = '';
  2. let aiReactionsEffect = null;
  3. let aiPanel = zui.AIPanel.shared;
  4. let lastParamsID = ($.parseLink($.apps.getAppUrl()).vars || []).map(x => x[1]).join();
  5. const takeOverFlag = 'aiapp-conversation.takeOverToggles';
  6. const toggleEleClass = 'aiapp-conversation-toggle';
  7. function openInAIPanel(chat, params)
  8. {
  9. if(!aiPanel) return;
  10. if(typeof params === 'string') try {params = JSON.parse(params);} catch {}
  11. params = params || {};
  12. if(typeof params !== 'object') return;
  13. const options = {};
  14. if(params.postMessage)
  15. {
  16. options.postMessage = params.postMessage;
  17. delete params.postMessage;
  18. }
  19. if(!chat || chat === 'NEW') options.chat = params;
  20. else if(typeof chat === 'string') options.chat = chat;
  21. aiPanel.open(options);
  22. }
  23. function injectEmbedStyle()
  24. {
  25. const $$ = window.parent.$;
  26. if($$('body').hasClass('ai-embed-injected')) return;
  27. $$('body').addClass('ai-embed-injected');
  28. $$('head').append([
  29. '<style>',
  30. '.ai-panel-root[z-mode="embed"] {left: var(--zt-menu-width)!important;}',
  31. '.hide-menu .ai-panel-root[z-mode="embed"] {left: var(--zt-menu-fold-width)!important; display: none}',
  32. 'body[data-app="aiapp"] .ai-panel-root[z-mode="embed"] {display: block}',
  33. '.ai-panel.is-embed {min-width: 1200px; margin: calc(var(--zt-header-height) + 12px) auto 0; position: static; height: calc(100% - var(--zt-header-height) - 28px);}',
  34. '@media (min-width: 1400px) {.ai-panel.is-embed {padding: 0 2.5rem}}',
  35. '@media (min-width: 1720px) {.ai-panel.is-embed {max-width: 1720px;}}',
  36. '.ai-panel.is-embed .ai-chats-panel {box-shadow: 0 0 0 1px rgba(var(--color-border-rgb), 1), var(--shadow); outline: none; width: 100%!important; backdrop-filter: none; height: calc(100% - 32px)!important; position: relative; transition: none; border-radius: var(--radius); bottom: auto!important}',
  37. '.ai-panel.is-embed .ai-panel-header {display: none}',
  38. '.ai-panel-root[z-last-mode="embed"].is-mode-changing .ai-panel {opacity: 0; transition: none}',
  39. '</style>'
  40. ].join('\n'));
  41. }
  42. function showToggleInParent(event)
  43. {
  44. event.stopPropagation();
  45. event.preventDefault();
  46. const $$ = window.parent.$;
  47. const $toggle = $(this);
  48. let id = $toggle.attr('id') || $toggle.data('takeOverToggleID');
  49. if(!id)
  50. {
  51. id = zui.nextGid();
  52. $toggle.data('takeOverToggleID', id);
  53. }
  54. const isMessageBar = id === 'messageBar';
  55. const toggleID = isMessageBar ? id : `${toggleEleClass}_${id}`;
  56. let $trigger = $$(toggleID);
  57. if(!$trigger.length)
  58. {
  59. const data = $toggle.data();
  60. if(data.call === 'fetchMessage' && !data.params) data.params = 'false, options.fetcher';
  61. $trigger = $$(`<div id="${toggleID}" class="state ${toggleEleClass}"></div>`)
  62. .attr('zui-toggle-dropdown', $toggle.attr('zui-toggle-dropdown'))
  63. .css({position: 'fixed', cursor: 'pointer'});
  64. Object.keys(data).forEach(key => $trigger.attr(`data-${key}`, data[key]));
  65. $trigger.appendTo($$('body'));
  66. $trigger.on('hidden', () =>
  67. {
  68. $trigger.next('.dropdown-menu').remove();
  69. $trigger.remove();
  70. });
  71. if(isMessageBar)
  72. {
  73. const $menu = $toggle.next('.dropdown-menu');
  74. const $$menu = $$('<menu></menu>').attr('class', $menu.attr('class')).attr('style', $menu.attr('style')).addClass(toggleEleClass).html($menu.html());
  75. $trigger.after($$menu);
  76. }
  77. }
  78. const boundRect = $toggle[0].getBoundingClientRect();
  79. $trigger.css({left: boundRect.left + $$('#menu').width(), top: boundRect.top, width: boundRect.width, height: boundRect.height});
  80. $trigger.trigger('click');
  81. }
  82. function takeOverToggles()
  83. {
  84. const $toolbar = $('#toolbar > .toolbar');
  85. if($toolbar.data(takeOverFlag)) return;
  86. $toolbar.data(takeOverFlag, true);
  87. $toolbar.children('[zui-toggle-dropdown]').on('click.takeOverToggles', showToggleInParent);
  88. }
  89. window.initAIConversations = function(chat, initialParams)
  90. {
  91. aiPanel = aiPanel || zui.AIPanel.shared;
  92. if(!aiPanel)
  93. {
  94. $('#noZaiConfigTip').removeClass('hidden');
  95. return;
  96. }
  97. aiPanel.toggleEmbed(true);
  98. $('#noZaiConfigTip').remove();
  99. const currentPageID = getPageInfo().id;
  100. lastPageID = currentPageID;
  101. aiReactionsEffect = aiPanel.reactions.state$.subscribe((state) => {
  102. if(!state.zentaoPage || lastPageID === state.zentaoPage.id) return;
  103. lastPageID = state.zentaoPage.id;
  104. aiPanel.toggleEmbed(lastPageID === currentPageID);
  105. });
  106. if(initialParams || chat) setTimeout(() => openInAIPanel(chat, initialParams), 600);
  107. injectEmbedStyle();
  108. takeOverToggles();
  109. }
  110. window.onPageUnmount = function()
  111. {
  112. if(aiReactionsEffect)
  113. {
  114. aiReactionsEffect();
  115. aiReactionsEffect = null;
  116. }
  117. if(aiPanel) aiPanel.toggleEmbed(false);
  118. $('#toolbar > .toolbar').data(takeOverFlag, false).children('[zui-toggle-dropdown]').off('click.takeOverToggles');
  119. window.parent.$('.aiapp-conversation-toggle').remove();
  120. };
  121. window.beforePageLoad = function(options)
  122. {
  123. if(options.id !== 'page') return;
  124. const link = $.parseLink(options.url);
  125. if(link.moduleName !== 'aiapp' || link.methodName !== 'conversation') return;
  126. const paramsID = link.vars.map(x => x[1]).join();
  127. if(paramsID === lastParamsID) return false;
  128. lastParamsID = paramsID;
  129. const params = link.vars[1][1];
  130. if(params) params = atob(params);
  131. openInAIPanel(link.vars[0][1], params);
  132. return false;
  133. };