Greasy Fork is available in English.

论坛快捷回帖

使用自定义内容或本扩展预定义的回帖内容,快捷回复支持的论坛的发帖!

Installer dette scriptet?
Skaperens foreslåtte skript

Du vil kanskje også like QQ群管理者.

Installer dette scriptet
  1. // ==UserScript==
  2. // @name 论坛快捷回帖
  3. // @namespace bmqy.net
  4. // @version 3.7.4
  5. // @author bmqy
  6. // @description 使用自定义内容或本扩展预定义的回帖内容,快捷回复支持的论坛的发帖!
  7. // @license ISC
  8. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTM4IDc5LjE1OTgyNCwgMjAxNi8wOS8xNC0wMTowOTowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1NjY1Njk3Ni1hNmQ2LWQ1NDAtYTBlZC0yOTc4MzRkMTk3N2EiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RUMzMzI0MjVFQUFBMTFFNzg2NzE4QUI1NzM0QThGNTciIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RUMzMzI0MjRFQUFBMTFFNzg2NzE4QUI1NzM0QThGNTciIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6M2NjNjZkNGUtYzdhMC0wNTQwLWFiODEtZjJmYzJiMmM5MTE3IiBzdFJlZjpkb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6YzNjZGU3YmUtZWFhYS0xMWU3LTllYTUtYTJlMzRjY2Y4N2EyIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+6Z3FfgAACS1JREFUeNrkWwtMV1UYPyA+UBJ84fvJw3yRQgoiKjqblqWu16ZpaTVzWVsUtVorazKd09aLmWnWZlauh5k6sxZWA0FKFCEVEXyBLQ0V1CRQpO/D39XT2b3//7nnD/jg237zfy73nnu+75zzfb/vO1e/2tpa0ZTFXzRxafIGCLgZBpmbmyvKy8t1b28ZEhJSNXToUL272Qfc6IiPj9dVfj5hWGxsrHbfAYZWblS5cOGCzm1PEuYQVgcGBnq8MSMjo+7fhISEawaYN2+eyM7Ovlm38iTCB4QlhH+NfIA3q93AMorwJXTZovMAz/ytEgWiCd8QbiMUE/5oSmFwAOFrQme0MwlnbyUD9CT0dfhbH8y8/PctbjovLS31u5EM0JwwkHA/4S3Cr4SdhLE294Zi5gdI1zh8ZbngFX4pKSn+15MIdSKEYQ+PhjIRhNbSPdVY1rJ0g8OLUa7nEY7pvLiqqkpMmTJFhIaG1jSWAdjS4YRIAjOaEVC2l5fnzjAFkNqtCJ/D66uyjjmdjvKpqamipKSkNjw8vMGocHtCPwJz0TGEwZjtti774dXgh98dCR85bAmWQTDuXkKFneJZWVkiJydHJCcnX2XA9WWAMMzwSEIcZrqvQT+1CGWFhGws/zIrdMOQvGybOVBgxkHe4oQVhG3yrFuK+5oMtYWygzG7d8AA7QwUPgOFef+mE/LRtuPjGwhb4Sh5FUzD+1WJgCH/4kZSUlJgWlrapfz8/Iu+ZIO8ZxPxwggYwN9wdnmGdmCG+fchF30wxd0FXHYwwB7CfYQSbtCyb0bKV5qmw7yk3yTc1cCz61Z4C0y3uZ6PlVFi7e+goKDzpvUAzqzeh+d1M7vZ0uwWN1BUGQQHKwtT4KmEI3XholUrUVNTI06dOmVUEOGUctV1ml0duZuLHlJ7H5Q/bF04d+6cmDFjRl2K79YATDGX2dxXBOq5DcoWi+sj7HumSO39UP5/viQzM9O4JPY84rgsTE1TGnGGPcntXPHB7wPY80X1VRPsSphhw7CSfeg/Dt76HLh6ro8GYIccCK4wFf96yzHYR13SMQDH9A5yJQpRwER4kB8SZhFOI2wxm/sYDtb0MOIRTuSg/AGHHGMyeMlQkLJZnlaJbIDeyt8yHV6ik9l9i4TlUcIPMMCzhNe5JEf4xKDfGCjGChY43FODsliodC3SkwH8FQ4vy3nDmUoiTCSMI3xKOAlKu4DwGXxKcyXJ8dPodwhWT56He06DKMkSr+sDTip/6w4DXXZJUtiPLHQoTz2HdHYs2GUCDH8R979ro4AlXzC11xgDr9xJUjvWM4tBfTwxMTEeytYCZRopqyrsR5h99LcpX/HsbYYX3yG9Rwb7nVc0V4QnRyn3eUzxbXVC+tbpLW8B9qjHpXYH7B83Mgwe9wTaQXCGv4NcTQZXT/PgPBcRxvtggIMga/JKDtfxAWU2YWW4gQHKUJxsQ/iOMBe/LRmFkpcnecmHVP2Y4vT8bSpIjkXR35T2veDeV6lnZGSkWLZsmVN/d0ph70WHmRwCB1vqQYnxBqvPEn73bl1HqBogy+ZBdiobEU9bFxYWipUrV9r11RJkaj9+P+bwzq4IZzlenHOsD9tgu9KOUvIHRwPsB2uT42oBBrMG6MxGsJHBqARx8SIYcBIe0KuEt63ihY087IMB8hBZLOmLPMerAY7KWRXC2grQWVbsAUKqg5d+kPAPVlELDxxiI4hQD8JycaUUXqXs4U0Ie6ZyCLoIyRkP1DFAtQ3RGIlrvAWWQlHVCUwgvAwWZlVzKxwG9w7hCZS49kH5VeiT4/ds8IHReLeJnLVhsfG69QCmqjOldjRWwnl4Z57lN+DwMlAmmwolFkuMrMShOMrkp6dEmycg55gNujxcorJnhIsDDxtCNNlbRLOr7e1W2F+YNGCBwSZg9kYjyZmJcCdnXVul36UgQUnwI5ukv43B4JZiwDKPHy3MT6/Us36OKp11VkARCJGldAiY3RHFy273MoAt8Pjfo6Dpj/x9OZzf38jehoM9FsPYasgMA7kxIUSnJBbYBav1hLcVcNpm/8QZDGAP8n+u1/OJzk+EZwj3ICT9LK2OfAxWlTZSAcStlCqVKz9sW69bwG75xBkOYjqWdRflOqfJ88DbJ6LOF+XQxzQfCJGaWI3SNUCWTSkqxGAQaxyuP4Qy20hUndYJ5wo0FzZaGxohQ2kPUvty4tsFCCXWeR77g34eUlUn2YUwp7IwXo5Pa/bRHzF8p4EB8hHaW6DdB5Fpr7cVcFSptDYz3IsH5JcZir8PfOCQ4rwDwVi9boFLcGIe94+GXLJZhiYyzvC58zYTEKdjAJZ0m2JHM4NBbK4HA7Tz4dldNltKywC5SIZkQtTbYAD7PCQ8bgqtpqKG12BdAxSDzsoPmuTox4VzFVdXNvnwbHelXalrgHLdhEJD1vugABtwteGzATY8okjXAALFy/ogRKuwFdxKOQorZYbvTbZJgzf4YoBIQ4fEucBrQv+cgfftWiRdaQbv6wTlFym1Cy7ObtMhQnIcL5dYIBOicHRksg34zOA9DFAolafdwHq897DLfc5EbQS2aYyNw2ZqvADESNsAx0AmoqUVM8zQAAKUNwtp7iisiGwUXHZr9tESkzAAfcSg3dXLcwuRmQo3BqhBOIxWCNFKH5zaUWCt5v2dEYJjsCUGQGHdz9srofxi3YqQXULxuA0hqhH1LwFQrj+W8nC0exqywB/hB3I8vVAnr5e/z4uAZ82vB4U7imsfVY5Fv6xwkEFflSiCFKDW8IsO/9AxQCFIkUWCWqN+94LLAfphKUciuRmB330MjfcnYvpOVKcOwADVbpec7lKSWeBc5AobPDwXAoWjUPcbgtkNNlC2Wprd7VC6GEbwec/pCJ8FzBHXzvh4iX4lrhx8rkZ9rwUUjsMMR6BtctJ7ErO7Cz5oPwxQ2RBORzevT1E8KT87H6UtywDtDcZQA+V4q2VidguVPKTBxM0J7BLs16eU6+wcu7jMzooRXtORrx/EVmt0cWOAWsw2f8nBHzF003zG+gJ8B1DkkuU1jgEqK7W3F/sD/miSj8r4mKwXyIr1VUkJQmc6GF5jfkWqHzOhr5/1YXFeXp6oqKgw6asHuDgXP60jsRv+/+QHBweLqKgo8Z8AAwDLxAqw4SNMdgAAAABJRU5ErkJggg==
  9. // @homepage https://github.com/bmqy/bbs_quickreply#readme
  10. // @homepageURL https://github.com/bmqy/bbs_quickreply#readme
  11. // @source https://github.com/bmqy/bbs_quickreply.git
  12. // @supportURL https://github.com/bmqy/bbs_quickreply/issues
  13. // @match *://*/thread*.*
  14. // @match *://*/forum.php?mod==viewthread*
  15. // @match *://*/forum.php?mod=viewthread*
  16. // @match *://*/forum/forum.php?mod=viewthread*
  17. // @match *://*/forum/thread*
  18. // @match *://*/bbs/forum.php?mod=viewthread*
  19. // @match *://*/bbs/thread*.*
  20. // @match *://*/forum.php?mod=post*
  21. // @match *://www.nodeseek.com/post*
  22. // @match *://linux.do/*
  23. // @match *://meta.appinn.net/*
  24. // @match *://www.v2ex.com/t/*
  25. // @match *://discuss.flarum.org/*
  26. // @match *://www.nodeloc.com/*
  27. // @require https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js
  28. // @require data:application/javascript,%3Bwindow.Vue%3DVue%3B
  29. // @require https://cdn.jsdelivr.net/npm/element-plus@2.3.6/dist/index.full.min.js
  30. // @require https://cdn.jsdelivr.net/npm/@element-plus/icons-vue@2.1.0/dist/index.iife.min.js
  31. // @resource element-plus/dist/index.css https://cdn.jsdelivr.net/npm/element-plus@2.3.6/dist/index.css
  32. // @connect quickreply.bmqy.net
  33. // @connect generativelanguage.googleapis.com
  34. // @connect dashscope.aliyuncs.com
  35. // @connect api.moonshot.cn
  36. // @connect api.openai.com
  37. // @connect *
  38. // @grant GM_getResourceText
  39. // @grant GM_getValue
  40. // @grant GM_info
  41. // @grant GM_listValues
  42. // @grant GM_setValue
  43. // @grant GM_xmlhttpRequest
  44. // @grant unsafeWindow
  45. // ==/UserScript==
  46.  
  47. (e=>{const a=document.createElement("style");a.dataset.source="vite-plugin-monkey",a.textContent=e,document.head.append(a)})(' .quickReplyBox[data-v-904ce70d]{position:relative}.quickReplyBox .el-form[data-v-904ce70d]{text-align:left}.quickReplyBox .reply-form-inline .el-form-item[data-v-904ce70d]{margin-bottom:15px}.el-dialog__footer a{text-decoration:none}.el-tabs__nav-next,.el-tabs__nav-prev{height:44px;display:flex;justify-content:center;align-items:center}.el-dialog{display:flex;flex-direction:column;margin:0!important;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);max-height:calc(100% - 30px);max-width:1300px}.el-dialog__header{margin-right:0!important}.el-dialog__body{flex:1;overflow:auto;padding:0}.quickReplyBox .el-input__inner{margin-bottom:0;background-color:transparent;border:0;outline:none}#reply-control.open{height:calc(var(--composer-height) + 65px)!important}#reply-control .reply-area{height:calc(100% - 91px)!important}.app-dialog-foot[data-v-904ce70d]{color:#909399;font-size:14px}.quickReplyBoxTitle[data-v-904ce70d]{margin-right:10px;font-weight:700;color:red}.el-form-item--mini.el-form-item[data-v-904ce70d],.el-form-item--small.el-form-item[data-v-904ce70d]{margin-bottom:10px}.el-select[data-v-904ce70d]{width:300px}.el-dialog__footer{background-color:#fff}.app-margin-right-30[data-v-54a1a6de]{margin-right:30px}.my-list-tabs[data-v-54a1a6de]{border-radius:var(--el-card-border-radius);border:1px solid var(--el-card-border-color)}.list-left[data-v-54a1a6de]{padding-right:15px;display:flex;flex:1;align-items:stretch;justify-content:start}.list-number[data-v-54a1a6de]{margin-right:5px;color:#909399}.list-title[data-v-54a1a6de]{flex:1;font-weight:400}.list-right[data-v-54a1a6de]{min-width:70px}.list-right .el-badge.item[data-v-54a1a6de]{margin-right:30px}.list li[data-v-54a1a6de]{margin-bottom:5px;padding-bottom:5px;font-size:13px;line-height:30px;display:flex;align-items:flex-start;justify-content:space-between;border-bottom:1px solid #ebeef5}.list li[data-v-54a1a6de]:hover{background-color:#f5f5f5}.quickReplyLoginBox .tips[data-v-54a1a6de]{margin-left:50px;text-align:left;font-size:12px}.addReplyBox[data-v-54a1a6de]{margin-top:15px;padding-top:10px;border-top:1px dashed #ccc}.box-card .el-card__header[data-v-54a1a6de]{padding:10px 20px}.box-card .el-card__header span[data-v-54a1a6de]{font-size:14px}.clearfix[data-v-54a1a6de]:before,.clearfix[data-v-54a1a6de]:after{display:table;content:""}.clearfix[data-v-54a1a6de]:after{clear:both}.el-pagination[data-v-54a1a6de]{padding:15px 5px 0}.setBox .el-input__inner{margin-bottom:0;background-color:transparent;border:0;outline:none}.setBox .el-checkbox{white-space:wrap}.box-card .el-card__header[data-v-66d8ae03]{padding:10px 20px}.box-card .el-card__header span[data-v-66d8ae03]{font-size:14px}.setAIBox .el-input__inner{margin-bottom:0;background-color:transparent;border:0;outline:none}.margin-left{margin-left:15px} ');
  48.  
  49. (function (vue, ElementPlus, ElementPlusIconsVue) {
  50. 'use strict';
  51.  
  52. function _interopNamespaceDefault(e) {
  53. const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
  54. if (e) {
  55. for (const k in e) {
  56. if (k !== 'default') {
  57. const d = Object.getOwnPropertyDescriptor(e, k);
  58. Object.defineProperty(n, k, d.get ? d : {
  59. enumerable: true,
  60. get: () => e[k]
  61. });
  62. }
  63. }
  64. }
  65. n.default = e;
  66. return Object.freeze(n);
  67. }
  68.  
  69. const ElementPlusIconsVue__namespace = /*#__PURE__*/_interopNamespaceDefault(ElementPlusIconsVue);
  70.  
  71. const cssLoader = (e) => {
  72. const t = GM_getResourceText(e), o = document.createElement("style");
  73. return o.innerText = t, document.head.append(o), t;
  74. };
  75. cssLoader("element-plus/dist/index.css");
  76. var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  77. var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
  78. var _GM_listValues = /* @__PURE__ */ (() => typeof GM_listValues != "undefined" ? GM_listValues : void 0)();
  79. var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  80. var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
  81. var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
  82. const _export_sfc = (sfc, props) => {
  83. const target = sfc.__vccOpts || sfc;
  84. for (const [key, val] of props) {
  85. target[key] = val;
  86. }
  87. return target;
  88. };
  89. const _hoisted_1$3 = { class: "quickReplyBox" };
  90. const _hoisted_2$2 = {
  91. slot: "label",
  92. class: "quickReplyBoxTitle"
  93. };
  94. const _sfc_main$3 = {
  95. __name: "App",
  96. setup(__props) {
  97. const { proxy } = vue.getCurrentInstance();
  98. const list = vue.ref([]);
  99. const currentReply = vue.ref("");
  100. const currentPlatform = vue.ref("discuz");
  101. const fwin_replyLoaded = vue.ref(false);
  102. const submitNow = vue.ref(false);
  103. const hasEditor = vue.ref(false);
  104. const lastClickElement = vue.ref(false);
  105. const setShow = vue.ref(false);
  106. const useAI = vue.ref("");
  107. const loadingAIReply = vue.ref(false);
  108. const aiNameList = vue.ref({
  109. gemini: "Gemini Pro",
  110. qianwen: "通义千问-turbo",
  111. kimi: "Kimi",
  112. chatgpt: "ChatGPT"
  113. });
  114. const constVar = vue.ref({
  115. email: "",
  116. qq: "",
  117. wechat: "",
  118. url: "",
  119. base64: false
  120. });
  121. vue.onBeforeMount(() => {
  122. checkPlatform();
  123. getList();
  124. submitNow.value = proxy.$storage.getUserInfo("submitNow") || false;
  125. useAI.value = proxy.$storage.getUserInfo("useAI") || "";
  126. updateConstVar();
  127. updateAIModel();
  128. });
  129. function checkPlatform() {
  130. if (location.host.indexOf("nodeseek") > -1) {
  131. currentPlatform.value = "nodeseek";
  132. } else if (location.host.indexOf("v2ex") > -1) {
  133. currentPlatform.value = "v2ex";
  134. } else {
  135. let $generator = document.head.querySelector("meta[name=generator]");
  136. if ($generator) {
  137. if ($generator.content.indexOf("Discuz") > -1) {
  138. currentPlatform.value = "discuz";
  139. } else if ($generator.content.indexOf("Discourse") > -1) {
  140. currentPlatform.value = "discourse";
  141. }
  142. } else {
  143. let $html = document.body.innerHTML;
  144. if ($html.indexOf("flarum-loading") > -1) {
  145. currentPlatform.value = "flarum";
  146. }
  147. }
  148. }
  149. }
  150. async function getList() {
  151. let myListStorage = proxy.$storage.get();
  152. list.value = myListStorage && myListStorage.length > 0 ? myListStorage : [];
  153. currentReply.value = "";
  154. }
  155. function openSet() {
  156. setShow.value = true;
  157. }
  158. function closeSet() {
  159. setShow.value = false;
  160. }
  161. function updateAIModel() {
  162. useAI.value = proxy.$storage.getUserInfo("useAI") || "";
  163. let chatgptModel = proxy.$storage.getUserInfo("chatgptModel") || "gpt-3.5-turbo";
  164. if (useAI.value === "chatgpt") {
  165. aiNameList.value["chatgpt"] = `ChatGPT (${chatgptModel})`;
  166. }
  167. }
  168. function updateConstVar() {
  169. constVar.value = proxy.$storage.getUserInfo("constVar") || constVar.value;
  170. }
  171. function updateMyList(data) {
  172. let myListStorage = data || [];
  173. list.value = myListStorage;
  174. }
  175. async function getAIReply() {
  176. let title2 = "";
  177. if (loadingAIReply.value)
  178. return false;
  179. loadingAIReply.value = true;
  180. if (currentPlatform.value == "discuz") {
  181. title2 = document.querySelector("#thread_subject").innerText;
  182. } else if (currentPlatform.value == "discourse") {
  183. if (document.querySelector("#topic-title h1>a")) {
  184. title2 = document.querySelector("#topic-title h1>a").innerText;
  185. } else {
  186. title2 = document.querySelector("h1.header-title a").innerText;
  187. }
  188. } else if (currentPlatform.value == "nodeseek") {
  189. title2 = document.querySelector("h1>a.post-title-link").innerText;
  190. } else if (currentPlatform.value == "v2ex") {
  191. title2 = document.querySelector("#Main .header>h1").innerText;
  192. }
  193. if (!title2) {
  194. proxy.$message.error("无法获取帖子标题,请检查脚本是否支持此论坛");
  195. return false;
  196. }
  197. await proxy.$api.getAIReply(title2).then((res) => {
  198. currentReply.value = res;
  199. enterReply();
  200. }).catch((err) => {
  201. proxy.$message.error(err);
  202. }).finally(() => {
  203. loadingAIReply.value = false;
  204. });
  205. }
  206. function enterPostReply() {
  207. let $postmessage = document.querySelector("#postmessage");
  208. $postmessage.value = currentReply.value;
  209. }
  210. function enterEditorReply() {
  211. let $editorTextarea = document.querySelector("#e_textarea");
  212. let $editorIframe = document.querySelector("#e_iframe").contentWindow.document.body;
  213. $editorIframe.style.background = "";
  214. $editorIframe.innerHTML = currentReply.value || window.bbcode2html(`${$editorTextarea.value}`);
  215. }
  216. function fastreBindClick() {
  217. document.querySelector("body").addEventListener(
  218. "click",
  219. (e) => {
  220. let theElement = `fastre&${e.target.href}`;
  221. if (lastClickElement.value != theElement && e.target.className == "fastre") {
  222. lastClickElement.value = theElement;
  223. fwin_replyLoaded.value = false;
  224. }
  225. },
  226. true
  227. );
  228. }
  229. function replyfastBindClick() {
  230. document.querySelector("body").addEventListener(
  231. "click",
  232. (e) => {
  233. let theElement = `replyfast&${e.target.href}`;
  234. if (lastClickElement.value != theElement && e.target.className == "replyfast") {
  235. lastClickElement.value = theElement;
  236. fwin_replyLoaded.value = false;
  237. }
  238. },
  239. true
  240. );
  241. }
  242. function flbcBindClick() {
  243. document.querySelector("body").addEventListener(
  244. "click",
  245. (e) => {
  246. let theElement = `flbc&${e.target.href}`;
  247. if (lastClickElement.value != theElement && e.target.className == "flbc") {
  248. lastClickElement.value = theElement;
  249. fwin_replyLoaded.value = false;
  250. }
  251. },
  252. true
  253. );
  254. }
  255. function checkEditor() {
  256. hasEditor.value = document.querySelector("#e_iframe");
  257. }
  258. function postReplyMutationObserver() {
  259. let mos = new MutationObserver(function(mutations, observer) {
  260. for (const mutation in mutations) {
  261. if (Object.hasOwnProperty.call(mutations, mutation)) {
  262. const element = mutations[mutation];
  263. if (element.target.id == "subjecthide") {
  264. fwin_replyLoaded.value = true;
  265. }
  266. }
  267. }
  268. });
  269. if (document.querySelector("#append_parent")) {
  270. mos.observe(document.querySelector("#append_parent"), {
  271. attributes: true,
  272. childList: true,
  273. subtree: true
  274. });
  275. }
  276. }
  277. function enterReply() {
  278. currentReply.value = currentReply.value.replace("{email}", constVar.value.base64 ? proxy.$tools.encodeStr(constVar.value.email) : constVar.value.email);
  279. currentReply.value = currentReply.value.replace("{qq}", constVar.value.base64 ? proxy.$tools.encodeStr(constVar.value.qq) : constVar.value.qq);
  280. currentReply.value = currentReply.value.replace("{wechat}", constVar.value.base64 ? proxy.$tools.encodeStr(constVar.value.wechat) : constVar.value.wechat);
  281. currentReply.value = currentReply.value.replace("{url}", constVar.value.base64 ? proxy.$tools.encodeStr(constVar.value.url) : constVar.value.url);
  282. if (fwin_replyLoaded.value) {
  283. enterPostReply();
  284. } else if (hasEditor.value) {
  285. enterEditorReply();
  286. } else if (currentPlatform.value == "nodeseek") {
  287. enterMarkdownItReply();
  288. } else if (currentPlatform.value == "discourse") {
  289. enterDiscourseEmberReply();
  290. } else if (currentPlatform.value == "v2ex") {
  291. enterReplyContentReply();
  292. } else if (currentPlatform.value == "flarum") {
  293. enterFlarumTextEditorReply();
  294. } else {
  295. enterFastPostReply();
  296. }
  297. }
  298. function enterMarkdownItReply() {
  299. _unsafeWindow.editor && _unsafeWindow.editor.setMarkdown && _unsafeWindow.editor.setMarkdown(currentReply.value);
  300. if (submitNow.value && !useAI.value && currentReply.value) {
  301. document.querySelector(".md-editor button.submit").click();
  302. }
  303. }
  304. function enterDiscourseEmberReply() {
  305. let $emberTextarea = document.querySelector("textarea.ember-text-area.d-editor-input");
  306. if ($emberTextarea) {
  307. $emberTextarea.value = currentReply.value;
  308. $emberTextarea.dispatchEvent(new Event("change"));
  309. }
  310. if (submitNow.value && !useAI.value && currentReply.value) {
  311. document.querySelector(".submit-panel button.btn.create").click();
  312. currentReply.value = "";
  313. }
  314. }
  315. function enterReplyContentReply() {
  316. let $replyContent = document.querySelector("textarea#reply_content");
  317. if ($replyContent) {
  318. $replyContent.value = currentReply.value;
  319. }
  320. if (submitNow.value && !useAI.value && currentReply.value) {
  321. document.querySelector('#reply-box input[type="submit"]').click();
  322. currentReply.value = "";
  323. }
  324. }
  325. function enterFlarumTextEditorReply() {
  326. let $textEditor = document.querySelector("textarea.FormControl.TextEditor-editor");
  327. if ($textEditor) {
  328. $textEditor.value = currentReply.value;
  329. $textEditor.dispatchEvent(new Event("change"));
  330. }
  331. if (submitNow.value && !useAI.value && currentReply.value) {
  332. document.querySelector(".item-submit button.Button").click();
  333. currentReply.value = "";
  334. }
  335. }
  336. function enterFastPostReply() {
  337. try {
  338. let $fastpostmessage = document.querySelector(
  339. "#fastpostmessage"
  340. );
  341. $fastpostmessage.style.background = "";
  342. $fastpostmessage.value = currentReply.value;
  343. if (submitNow.value && !useAI.value && currentReply.value) {
  344. document.querySelector("button#fastpostsubmit").click();
  345. }
  346. } catch (err) {
  347. console.log("请检查发帖权限!");
  348. }
  349. }
  350. const title = vue.computed(() => {
  351. return `${proxy.$app.getName()}`;
  352. });
  353. const tips = vue.computed(() => {
  354. return `${proxy.$app.getName()},控制面板:
  355. - 分享、收藏更多精彩回帖;
  356. - 登录账号(登录后可打开脚本菜单同步你的回帖,在任何设备上恢复并使用);
  357. - AI及更多功能,请点击油猴图标打开脚本菜单开启或关闭;`;
  358. });
  359. vue.onMounted(() => {
  360. checkEditor();
  361. postReplyMutationObserver();
  362. enterReply();
  363. fastreBindClick();
  364. replyfastBindClick();
  365. flbcBindClick();
  366. });
  367. vue.watch(fwin_replyLoaded, (n) => {
  368. if (n) {
  369. let $floatlayout_reply = document.querySelector(
  370. "#floatlayout_reply"
  371. );
  372. $floatlayout_reply.insertBefore(
  373. proxy.$el,
  374. $floatlayout_reply.childNodes[0]
  375. );
  376. enterPostReply();
  377. } else {
  378. let $fastposteditor = document.querySelector(
  379. "#fastposteditor"
  380. );
  381. $fastposteditor.insertBefore(
  382. proxy.$el,
  383. $fastposteditor.childNodes[0]
  384. );
  385. }
  386. });
  387. return (_ctx, _cache) => {
  388. const _component_el_option = vue.resolveComponent("el-option");
  389. const _component_el_select = vue.resolveComponent("el-select");
  390. const _component_el_form_item = vue.resolveComponent("el-form-item");
  391. const _component_el_button = vue.resolveComponent("el-button");
  392. const _component_el_button_group = vue.resolveComponent("el-button-group");
  393. const _component_el_form = vue.resolveComponent("el-form");
  394. const _component_app_set = vue.resolveComponent("app-set");
  395. const _component_el_link = vue.resolveComponent("el-link");
  396. const _component_el_dialog = vue.resolveComponent("el-dialog");
  397. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
  398. vue.createVNode(vue.Transition, { name: "el-fade-in-linear" }, {
  399. default: vue.withCtx(() => [
  400. vue.createVNode(_component_el_form, {
  401. inline: true,
  402. class: "reply-form-inline"
  403. }, {
  404. default: vue.withCtx(() => [
  405. vue.createVNode(_component_el_form_item, null, {
  406. default: vue.withCtx(() => [
  407. vue.createElementVNode("div", _hoisted_2$2, vue.toDisplayString(`${vue.unref(title)}: `), 1),
  408. vue.createVNode(_component_el_select, {
  409. modelValue: vue.unref(currentReply),
  410. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.isRef(currentReply) ? currentReply.value = $event : null),
  411. placeholder: "请选择",
  412. "no-data-text": "这里啥都没有...",
  413. onChange: enterReply
  414. }, {
  415. default: vue.withCtx(() => [
  416. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(list), (item, index) => {
  417. return vue.openBlock(), vue.createBlock(_component_el_option, {
  418. key: index,
  419. label: item,
  420. value: item
  421. }, null, 8, ["label", "value"]);
  422. }), 128))
  423. ]),
  424. _: 1
  425. }, 8, ["modelValue"])
  426. ]),
  427. _: 1
  428. }),
  429. vue.createVNode(_component_el_form_item, null, {
  430. default: vue.withCtx(() => [
  431. vue.createVNode(_component_el_button_group, null, {
  432. default: vue.withCtx(() => [
  433. vue.createVNode(_component_el_button, {
  434. type: "primary",
  435. class: "btnQuickReplySet",
  436. icon: "tools",
  437. onClick: openSet,
  438. title: vue.unref(tips)
  439. }, null, 8, ["title"]),
  440. vue.unref(useAI) != "" ? (vue.openBlock(), vue.createBlock(_component_el_button, {
  441. key: 0,
  442. type: "success",
  443. class: "btnQuickReplySet",
  444. loading: vue.unref(loadingAIReply),
  445. icon: "magicStick",
  446. onClick: getAIReply,
  447. title: `正在由【${vue.unref(aiNameList)[vue.unref(useAI)]}】为你提供创意回帖
  448.  
  449. Tips:使用AI就像开盲盒,请准备好是否接受结果再提交`
  450. }, null, 8, ["loading", "title"])) : vue.createCommentVNode("", true)
  451. ]),
  452. _: 1
  453. })
  454. ]),
  455. _: 1
  456. })
  457. ]),
  458. _: 1
  459. })
  460. ]),
  461. _: 1
  462. }),
  463. vue.createVNode(_component_el_dialog, {
  464. modelValue: vue.unref(setShow),
  465. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.isRef(setShow) ? setShow.value = $event : null),
  466. onClose: closeSet,
  467. title: _ctx.$app.getName(),
  468. width: "75%",
  469. "show-close": true,
  470. "destroy-on-close": "",
  471. "append-to-body": ""
  472. }, {
  473. default: vue.withCtx(() => [
  474. vue.createVNode(_component_app_set, {
  475. ref: "setPanel",
  476. onUpdateMyList: updateMyList,
  477. onUpdateConstVar: updateConstVar,
  478. onUpdateAIModel: updateAIModel
  479. }, null, 512)
  480. ]),
  481. footer: vue.withCtx(() => [
  482. vue.createVNode(_component_el_link, {
  483. type: "info",
  484. href: "https://github.com/bmqy/bbs_quickreply?tab=readme-ov-file#%E6%9B%B4%E6%96%B0%E6%97%A5%E5%BF%97",
  485. title: "更新日志",
  486. target: "_blank"
  487. }, {
  488. default: vue.withCtx(() => [
  489. vue.createTextVNode(vue.toDisplayString(`ver: ${_ctx.$app.getVersion()}`), 1)
  490. ]),
  491. _: 1
  492. })
  493. ]),
  494. _: 1
  495. }, 8, ["modelValue", "title"])
  496. ]);
  497. };
  498. }
  499. };
  500. const App = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-904ce70d"]]);
  501. const _withScopeId = (n) => (vue.pushScopeId("data-v-54a1a6de"), n = n(), vue.popScopeId(), n);
  502. const _hoisted_1$2 = { class: "setBox" };
  503. const _hoisted_2$1 = {
  504. key: 0,
  505. class: "quickReplyLoginBox"
  506. };
  507. const _hoisted_3 = { style: { "margin-top": "15px" } };
  508. const _hoisted_4 = { key: 1 };
  509. const _hoisted_5 = {
  510. key: 0,
  511. class: "list"
  512. };
  513. const _hoisted_6 = { class: "list-left" };
  514. const _hoisted_7 = { class: "list-number" };
  515. const _hoisted_8 = { class: "list-title" };
  516. const _hoisted_9 = { class: "list-right" };
  517. const _hoisted_10 = {
  518. key: 1,
  519. class: "tips"
  520. };
  521. const _hoisted_11 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("p", null, "未设置快速回帖内容!", -1));
  522. const _hoisted_12 = [
  523. _hoisted_11
  524. ];
  525. const _hoisted_13 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("span", null, "网友分享的", -1));
  526. const _hoisted_14 = { key: 0 };
  527. const _hoisted_15 = { class: "addReplyBox" };
  528. const _sfc_main$2 = {
  529. __name: "Set",
  530. emits: ["updateMyList", "updateConstVar", "updateAIModel"],
  531. setup(__props, { emit }) {
  532. const { proxy } = vue.getCurrentInstance();
  533. const myList = vue.ref([]);
  534. const systemList = vue.ref([]);
  535. const systemListCount = vue.ref(0);
  536. const loading = vue.ref(false);
  537. const isLogin = vue.ref(false);
  538. const realtimeSync = vue.ref(false);
  539. const realtimeBackup = vue.ref(false);
  540. const submitNow = vue.ref(false);
  541. const currentTab = vue.ref("mine");
  542. const showLoginForce = vue.ref(false);
  543. const newReply = vue.ref("");
  544. const windowSize = vue.ref({
  545. width: window.innerWidth,
  546. height: window.innerHeight
  547. });
  548. const queryData = vue.ref({
  549. page: 1,
  550. prop: "replyId",
  551. order: "desc"
  552. });
  553. const constVar = vue.ref({
  554. email: "",
  555. qq: "",
  556. wechat: "",
  557. url: "",
  558. base64: false
  559. });
  560. vue.onBeforeMount(() => {
  561. isLogin.value = proxy.$storage.getUserInfo("userId");
  562. realtimeSync.value = proxy.$storage.getUserInfo("realtimeSync") || false;
  563. realtimeBackup.value = proxy.$storage.getUserInfo("realtimeBackup") || false;
  564. submitNow.value = proxy.$storage.getUserInfo("submitNow") || false;
  565. constVar.value = proxy.$storage.getUserInfo("constVar") || constVar.value;
  566. getMyList();
  567. getSystemList();
  568. });
  569. function getMyList() {
  570. let myListStorage = proxy.$storage.get();
  571. myList.value = myListStorage && myListStorage.length > 0 ? myListStorage : [];
  572. }
  573. async function getSystemList() {
  574. loading.value = true;
  575. let res = await proxy.$api.selectList(queryData.value.page, queryData.value.prop, queryData.value.order);
  576. systemList.value = res.data.totalCount > 0 ? res.data.list : [];
  577. systemListCount.value = res.data.totalCount;
  578. loading.value = false;
  579. }
  580. function currentPageChange(current) {
  581. queryData.value.page = current;
  582. getSystemList();
  583. }
  584. function sortChange(e) {
  585. queryData.value.prop = e.order ? e.prop : "replyId";
  586. queryData.value.order = e.order === "descending" || !e.order ? "desc" : "asc";
  587. getSystemList();
  588. }
  589. function addReply() {
  590. if (newReply.value == "") {
  591. proxy.$message.error("回复内容不能为空!");
  592. return false;
  593. }
  594. if (myList.value.indexOf(newReply.value) != -1) {
  595. proxy.$message.error("该回复已添加过!");
  596. newReply.value = "";
  597. return false;
  598. }
  599. if (myList.value.length >= 10) {
  600. proxy.$message.warning("自定义回复,超出条数上限!");
  601. return false;
  602. }
  603. myList.value.push(newReply.value);
  604. realtimeSync.value && upload();
  605. realtimeBackup.value && uploadAll();
  606. updateMyList();
  607. newReply.value = "";
  608. return true;
  609. }
  610. function updateMyList() {
  611. proxy.$storage.set(myList.value);
  612. emit("updateMyList", myList.value);
  613. }
  614. function delReply(index) {
  615. myList.value.splice(index, 1);
  616. updateMyList();
  617. realtimeSync.value && upload();
  618. realtimeBackup.value && uploadAll();
  619. }
  620. function shareReply(index) {
  621. proxy.$api.replyInsert(myList.value[index]).then((res) => {
  622. proxy.$message.success(res.message);
  623. getSystemList();
  624. }).catch((err) => {
  625. proxy.$message.error(err.message);
  626. });
  627. }
  628. function likeReply(index) {
  629. proxy.$api.likeCountUpdate(systemList.value[index].replyId).then((res) => {
  630. if (res.code == 0) {
  631. systemList.value[index]["likeCount"] = res.data.likeCount;
  632. proxy.$message.success("点赞成功");
  633. } else {
  634. proxy.$message.error(res.message);
  635. }
  636. }).catch((err) => {
  637. proxy.$message.error(err.message);
  638. });
  639. }
  640. function collectReply(index) {
  641. let nStr = systemList.value[index].content;
  642. if (myList.value.indexOf(nStr) != -1) {
  643. proxy.$message.error("该回复已添加过!");
  644. return false;
  645. }
  646. newReply.value = nStr;
  647. proxy.$api.collectCountUpdate(systemList.value[index].replyId).then((res) => {
  648. if (res.code == 0) {
  649. addReply() && proxy.$message.success("收藏成功");
  650. realtimeSync.value && upload();
  651. realtimeBackup.value && uploadAll();
  652. } else {
  653. proxy.$message.error(res.message);
  654. }
  655. }).catch((err) => {
  656. proxy.$message.error(err.message);
  657. });
  658. }
  659. function onLoginSuccess() {
  660. showLoginForce.value = false;
  661. isLogin.value = true;
  662. myList.value.length === 0 && download();
  663. }
  664. function upload() {
  665. proxy.$storage.uploadList();
  666. }
  667. async function download() {
  668. let list = await proxy.$storage.downloadList();
  669. myList.value = list;
  670. updateMyList();
  671. }
  672. function uploadAll() {
  673. proxy.$storage.uploadAll();
  674. }
  675. async function downloadAll() {
  676. let all = await proxy.$storage.downloadAll();
  677. myList.value = all.QuickReply || [];
  678. updateMyList();
  679. }
  680. function loginForce() {
  681. showLoginForce.value = !showLoginForce.value;
  682. currentTab.value = "mine";
  683. }
  684. function loginCancel() {
  685. showLoginForce.value = false;
  686. currentTab.value = "mine";
  687. }
  688. function logout() {
  689. proxy.$storage.setUserInfo("userId", "");
  690. isLogin.value = false;
  691. }
  692. function onRealtimeSyncChange(e) {
  693. realtimeSync.value = e;
  694. proxy.$storage.setUserInfo("realtimeSync", e);
  695. realtimeBackup.value && uploadAll();
  696. }
  697. function onRealtimeBackupChange(e) {
  698. realtimeBackup.value = e;
  699. proxy.$storage.setUserInfo("realtimeBackup", e);
  700. realtimeBackup.value && uploadAll();
  701. }
  702. function onSubmitNowChange(e) {
  703. submitNow.value = e;
  704. proxy.$storage.setUserInfo("submitNow", e);
  705. realtimeBackup.value && uploadAll();
  706. }
  707. function updateAI() {
  708. emit("updateAIModel");
  709. realtimeBackup.value && uploadAll();
  710. }
  711. function constVarChange() {
  712. proxy.$storage.setUserInfo("constVar", constVar.value);
  713. emit("updateConstVar");
  714. realtimeBackup.value && uploadAll();
  715. }
  716. return (_ctx, _cache) => {
  717. const _component_app_login = vue.resolveComponent("app-login");
  718. const _component_el_text = vue.resolveComponent("el-text");
  719. const _component_el_space = vue.resolveComponent("el-space");
  720. const _component_el_button = vue.resolveComponent("el-button");
  721. const _component_el_tooltip = vue.resolveComponent("el-tooltip");
  722. const _component_el_tab_pane = vue.resolveComponent("el-tab-pane");
  723. const _component_el_checkbox = vue.resolveComponent("el-checkbox");
  724. const _component_el_input = vue.resolveComponent("el-input");
  725. const _component_el_form_item = vue.resolveComponent("el-form-item");
  726. const _component_el_switch = vue.resolveComponent("el-switch");
  727. const _component_el_form = vue.resolveComponent("el-form");
  728. const _component_app_set_ai = vue.resolveComponent("app-set-ai");
  729. const _component_el_tabs = vue.resolveComponent("el-tabs");
  730. const _component_el_col = vue.resolveComponent("el-col");
  731. const _component_el_table_column = vue.resolveComponent("el-table-column");
  732. const _component_el_tag = vue.resolveComponent("el-tag");
  733. const _component_el_table = vue.resolveComponent("el-table");
  734. const _component_el_pagination = vue.resolveComponent("el-pagination");
  735. const _component_el_card = vue.resolveComponent("el-card");
  736. const _component_el_row = vue.resolveComponent("el-row");
  737. const _directive_loading = vue.resolveDirective("loading");
  738. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
  739. vue.createVNode(_component_el_card, {
  740. class: "box-card",
  741. shadow: "never"
  742. }, {
  743. default: vue.withCtx(() => [
  744. vue.createVNode(_component_el_row, { gutter: 30 }, {
  745. default: vue.withCtx(() => [
  746. vue.createVNode(_component_el_col, {
  747. span: 9,
  748. md: { span: 9 },
  749. sm: { span: 24 },
  750. xs: { span: 24 }
  751. }, {
  752. default: vue.withCtx(() => [
  753. vue.createVNode(_component_el_tabs, {
  754. type: "border-card",
  755. class: "my-list-tabs",
  756. modelValue: vue.unref(currentTab),
  757. "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => vue.isRef(currentTab) ? currentTab.value = $event : null)
  758. }, {
  759. default: vue.withCtx(() => [
  760. vue.createVNode(_component_el_tab_pane, {
  761. name: "mine",
  762. label: "我在用的"
  763. }, {
  764. default: vue.withCtx(() => [
  765. vue.unref(myList).length === 0 && !vue.unref(isLogin) || vue.unref(showLoginForce) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$1, [
  766. vue.createElementVNode("div", _hoisted_3, [
  767. vue.createVNode(_component_app_login, {
  768. onOnSuccess: onLoginSuccess,
  769. onOnClose: loginCancel
  770. }),
  771. vue.createVNode(_component_el_space, {
  772. direction: "vertical",
  773. alignment: "flex-start"
  774. }, {
  775. default: vue.withCtx(() => [
  776. vue.createElementVNode("div", null, [
  777. vue.createVNode(_component_el_text, { type: "info" }, {
  778. default: vue.withCtx(() => [
  779. vue.createTextVNode("* 登录后,即可在任意设备同步你的配置;")
  780. ]),
  781. _: 1
  782. })
  783. ]),
  784. vue.createElementVNode("div", null, [
  785. vue.createVNode(_component_el_text, { type: "info" }, {
  786. default: vue.withCtx(() => [
  787. vue.createTextVNode("* 云端只负责保存账号及其回复列表,不留存多余信息;")
  788. ]),
  789. _: 1
  790. })
  791. ]),
  792. vue.createElementVNode("div", null, [
  793. vue.createVNode(_component_el_text, { type: "info" }, {
  794. default: vue.withCtx(() => [
  795. vue.createTextVNode("* 忘记密码无法恢复,可重新注册;")
  796. ]),
  797. _: 1
  798. })
  799. ]),
  800. vue.createElementVNode("div", null, [
  801. vue.createVNode(_component_el_text, { type: "info" }, {
  802. default: vue.withCtx(() => [
  803. vue.createTextVNode("* 如不需登录,也可忽略登录界面,直接使用即可;")
  804. ]),
  805. _: 1
  806. })
  807. ])
  808. ]),
  809. _: 1
  810. })
  811. ])
  812. ])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_4, [
  813. !vue.unref(showLoginForce) || vue.unref(myList).length > 0 ? (vue.openBlock(), vue.createElementBlock("ul", _hoisted_5, [
  814. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(myList), (item, index) => {
  815. return vue.openBlock(), vue.createElementBlock("li", { key: index }, [
  816. vue.createElementVNode("div", _hoisted_6, [
  817. vue.createElementVNode("div", _hoisted_7, vue.toDisplayString(`${index + 1}、`), 1),
  818. vue.createElementVNode("div", _hoisted_8, vue.toDisplayString(`${item}`), 1)
  819. ]),
  820. vue.createElementVNode("div", _hoisted_9, [
  821. vue.createVNode(_component_el_tooltip, {
  822. class: "item",
  823. effect: "dark",
  824. content: "分享它",
  825. placement: "top-start"
  826. }, {
  827. default: vue.withCtx(() => [
  828. vue.createVNode(_component_el_button, {
  829. type: "success",
  830. size: "small",
  831. icon: "Share",
  832. circle: "",
  833. onClick: ($event) => shareReply(index)
  834. }, null, 8, ["onClick"])
  835. ]),
  836. _: 2
  837. }, 1024),
  838. vue.createVNode(_component_el_tooltip, {
  839. class: "item",
  840. effect: "dark",
  841. content: "移除",
  842. placement: "top-start"
  843. }, {
  844. default: vue.withCtx(() => [
  845. vue.createVNode(_component_el_button, {
  846. type: "danger",
  847. size: "small",
  848. icon: "DeleteFilled",
  849. circle: "",
  850. onClick: ($event) => delReply(index)
  851. }, null, 8, ["onClick"])
  852. ]),
  853. _: 2
  854. }, 1024)
  855. ])
  856. ]);
  857. }), 128))
  858. ])) : vue.createCommentVNode("", true),
  859. vue.unref(myList).length == 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_10, _hoisted_12)) : vue.createCommentVNode("", true)
  860. ]))
  861. ]),
  862. _: 1
  863. }),
  864. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_tab_pane, {
  865. key: 0,
  866. name: "options",
  867. label: "选项"
  868. }, {
  869. default: vue.withCtx(() => [
  870. vue.createVNode(_component_el_space, {
  871. direction: "vertical",
  872. alignment: "flex-start"
  873. }, {
  874. default: vue.withCtx(() => [
  875. vue.createElementVNode("div", null, [
  876. vue.createVNode(_component_el_checkbox, {
  877. modelValue: vue.unref(realtimeSync),
  878. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.isRef(realtimeSync) ? realtimeSync.value = $event : null),
  879. label: "实时同步,本地回复列表修改后立即上传",
  880. size: "small",
  881. checked: vue.unref(realtimeSync),
  882. onChange: onRealtimeSyncChange
  883. }, null, 8, ["modelValue", "checked"])
  884. ]),
  885. vue.createElementVNode("div", null, [
  886. vue.createVNode(_component_el_checkbox, {
  887. modelValue: vue.unref(realtimeBackup),
  888. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.isRef(realtimeBackup) ? realtimeBackup.value = $event : null),
  889. label: "实时备份,本地回复列表及任一配置修改后立即备份至云端",
  890. size: "small",
  891. checked: vue.unref(realtimeBackup),
  892. onChange: onRealtimeBackupChange
  893. }, null, 8, ["modelValue", "checked"])
  894. ]),
  895. vue.createElementVNode("div", null, [
  896. vue.createVNode(_component_el_checkbox, {
  897. modelValue: vue.unref(submitNow),
  898. "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.isRef(submitNow) ? submitNow.value = $event : null),
  899. label: "立即提交,选择快捷回帖内容后立即提交回帖",
  900. size: "small",
  901. checked: vue.unref(submitNow),
  902. onChange: onSubmitNowChange
  903. }, null, 8, ["modelValue", "checked"])
  904. ]),
  905. vue.createVNode(_component_el_space, {
  906. direction: "vertical",
  907. alignment: "flex-start",
  908. style: { "margin-top": "18px" }
  909. }, {
  910. default: vue.withCtx(() => [
  911. vue.createElementVNode("div", null, [
  912. vue.createVNode(_component_el_text, { type: "info" }, {
  913. default: vue.withCtx(() => [
  914. vue.createTextVNode("* AI和常量只存在本地,不参与同步")
  915. ]),
  916. _: 1
  917. })
  918. ]),
  919. vue.createElementVNode("div", null, [
  920. vue.createVNode(_component_el_text, { type: "info" }, {
  921. default: vue.withCtx(() => [
  922. vue.createTextVNode("* 如需备份所有配置请使用操作中的全量备份、全量恢复")
  923. ]),
  924. _: 1
  925. })
  926. ]),
  927. vue.createElementVNode("div", null, [
  928. vue.createVNode(_component_el_text, { type: "info" }, {
  929. default: vue.withCtx(() => [
  930. vue.createTextVNode("* 全量备份仅为方便多设备同步配置,使用base64存储,请知悉")
  931. ]),
  932. _: 1
  933. })
  934. ])
  935. ]),
  936. _: 1
  937. })
  938. ]),
  939. _: 1
  940. })
  941. ]),
  942. _: 1
  943. })) : vue.createCommentVNode("", true),
  944. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_tab_pane, {
  945. key: 1,
  946. name: "constVar",
  947. label: "常量"
  948. }, {
  949. default: vue.withCtx(() => [
  950. vue.createVNode(_component_el_form, {
  951. model: vue.unref(constVar),
  952. "label-width": "60",
  953. style: { "max-width": "600px" }
  954. }, {
  955. default: vue.withCtx(() => [
  956. vue.createVNode(_component_el_form_item, { label: "邮箱" }, {
  957. default: vue.withCtx(() => [
  958. vue.createVNode(_component_el_input, {
  959. modelValue: vue.unref(constVar).email,
  960. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.unref(constVar).email = $event),
  961. onChange: constVarChange
  962. }, null, 8, ["modelValue"])
  963. ]),
  964. _: 1
  965. }),
  966. vue.createVNode(_component_el_form_item, { label: "QQ" }, {
  967. default: vue.withCtx(() => [
  968. vue.createVNode(_component_el_input, {
  969. modelValue: vue.unref(constVar).qq,
  970. "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => vue.unref(constVar).qq = $event),
  971. onChange: constVarChange
  972. }, null, 8, ["modelValue"])
  973. ]),
  974. _: 1
  975. }),
  976. vue.createVNode(_component_el_form_item, { label: "微信" }, {
  977. default: vue.withCtx(() => [
  978. vue.createVNode(_component_el_input, {
  979. modelValue: vue.unref(constVar).wechat,
  980. "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => vue.unref(constVar).wechat = $event),
  981. onChange: constVarChange
  982. }, null, 8, ["modelValue"])
  983. ]),
  984. _: 1
  985. }),
  986. vue.createVNode(_component_el_form_item, { label: "网址" }, {
  987. default: vue.withCtx(() => [
  988. vue.createVNode(_component_el_input, {
  989. modelValue: vue.unref(constVar).url,
  990. "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => vue.unref(constVar).url = $event),
  991. onChange: constVarChange
  992. }, null, 8, ["modelValue"])
  993. ]),
  994. _: 1
  995. }),
  996. vue.createVNode(_component_el_form_item, { label: "加密" }, {
  997. default: vue.withCtx(() => [
  998. vue.createVNode(_component_el_switch, {
  999. modelValue: vue.unref(constVar).base64,
  1000. "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => vue.unref(constVar).base64 = $event),
  1001. onChange: constVarChange
  1002. }, null, 8, ["modelValue"])
  1003. ]),
  1004. _: 1
  1005. })
  1006. ]),
  1007. _: 1
  1008. }, 8, ["model"]),
  1009. vue.createVNode(_component_el_space, {
  1010. direction: "vertical",
  1011. alignment: "flex-start"
  1012. }, {
  1013. default: vue.withCtx(() => [
  1014. vue.createElementVNode("div", null, [
  1015. vue.createVNode(_component_el_text, { type: "info" }, {
  1016. default: vue.withCtx(() => [
  1017. vue.createTextVNode("* 可在快捷回帖中使用以上常量:{email}、{qq}、{wechat}、{url},例:我的邮箱是{email},我的QQ是{qq};")
  1018. ]),
  1019. _: 1
  1020. })
  1021. ]),
  1022. vue.createElementVNode("div", null, [
  1023. vue.createVNode(_component_el_text, { type: "info" }, {
  1024. default: vue.withCtx(() => [
  1025. vue.createTextVNode("* 开启加密后,只在回帖时显示base64加密后的常量;")
  1026. ]),
  1027. _: 1
  1028. })
  1029. ])
  1030. ]),
  1031. _: 1
  1032. })
  1033. ]),
  1034. _: 1
  1035. })) : vue.createCommentVNode("", true),
  1036. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_tab_pane, {
  1037. key: 2,
  1038. name: "ai",
  1039. label: "AI"
  1040. }, {
  1041. default: vue.withCtx(() => [
  1042. vue.createVNode(_component_app_set_ai, {
  1043. ref: "setAIPanel",
  1044. onUpdateAI: updateAI
  1045. }, null, 512)
  1046. ]),
  1047. _: 1
  1048. })) : vue.createCommentVNode("", true),
  1049. vue.createVNode(_component_el_tab_pane, {
  1050. name: "actions",
  1051. label: "操作"
  1052. }, {
  1053. default: vue.withCtx(() => [
  1054. vue.createVNode(_component_el_space, { wrap: "" }, {
  1055. default: vue.withCtx(() => [
  1056. !vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_button, {
  1057. key: 0,
  1058. type: "success",
  1059. icon: "UserFilled",
  1060. size: "small",
  1061. onClick: loginForce
  1062. }, {
  1063. default: vue.withCtx(() => [
  1064. vue.createTextVNode("登录,登录后即可在任意设备同步你的配置")
  1065. ]),
  1066. _: 1
  1067. })) : vue.createCommentVNode("", true),
  1068. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_button, {
  1069. key: 1,
  1070. type: "danger",
  1071. icon: "SwitchButton",
  1072. size: "small",
  1073. onClick: logout
  1074. }, {
  1075. default: vue.withCtx(() => [
  1076. vue.createTextVNode("注销,注销登录后将不能再同步列表")
  1077. ]),
  1078. _: 1
  1079. })) : vue.createCommentVNode("", true),
  1080. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_button, {
  1081. key: 2,
  1082. type: "primary",
  1083. icon: "Upload",
  1084. size: "small",
  1085. onClick: upload
  1086. }, {
  1087. default: vue.withCtx(() => [
  1088. vue.createTextVNode("上传,上传本地列表会覆盖云端数据")
  1089. ]),
  1090. _: 1
  1091. })) : vue.createCommentVNode("", true),
  1092. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_button, {
  1093. key: 3,
  1094. type: "warning",
  1095. icon: "Download",
  1096. size: "small",
  1097. onClick: download
  1098. }, {
  1099. default: vue.withCtx(() => [
  1100. vue.createTextVNode("下载,下载云端列表会覆盖本地数据")
  1101. ]),
  1102. _: 1
  1103. })) : vue.createCommentVNode("", true),
  1104. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_button, {
  1105. key: 4,
  1106. type: "primary",
  1107. icon: "Upload",
  1108. size: "small",
  1109. onClick: uploadAll
  1110. }, {
  1111. default: vue.withCtx(() => [
  1112. vue.createTextVNode("全量备份,全量备份本地所有配置信息到云端")
  1113. ]),
  1114. _: 1
  1115. })) : vue.createCommentVNode("", true),
  1116. vue.unref(isLogin) ? (vue.openBlock(), vue.createBlock(_component_el_button, {
  1117. key: 5,
  1118. type: "warning",
  1119. icon: "Download",
  1120. size: "small",
  1121. onClick: downloadAll
  1122. }, {
  1123. default: vue.withCtx(() => [
  1124. vue.createTextVNode("全量恢复,全量恢复云端配置信息覆盖本地数据")
  1125. ]),
  1126. _: 1
  1127. })) : vue.createCommentVNode("", true)
  1128. ]),
  1129. _: 1
  1130. })
  1131. ]),
  1132. _: 1
  1133. })
  1134. ]),
  1135. _: 1
  1136. }, 8, ["modelValue"])
  1137. ]),
  1138. _: 1
  1139. }),
  1140. vue.createVNode(_component_el_col, {
  1141. span: 15,
  1142. md: { span: 15 },
  1143. sm: { span: 24 },
  1144. xs: { span: 24 },
  1145. style: vue.normalizeStyle({ "margin-top": vue.unref(windowSize).width < 992 ? "15px" : 0 })
  1146. }, {
  1147. default: vue.withCtx(() => [
  1148. vue.createVNode(_component_el_card, {
  1149. class: "box-card",
  1150. shadow: "never",
  1151. "body-style": { padding: "0 20px 20px" }
  1152. }, {
  1153. header: vue.withCtx(() => [
  1154. _hoisted_13
  1155. ]),
  1156. default: vue.withCtx(() => [
  1157. vue.withDirectives((vue.openBlock(), vue.createBlock(_component_el_table, {
  1158. ref: "filterTable",
  1159. data: vue.unref(systemList),
  1160. size: "small",
  1161. stripe: "",
  1162. onSortChange: sortChange
  1163. }, {
  1164. default: vue.withCtx(() => [
  1165. vue.createVNode(_component_el_table_column, {
  1166. prop: "replyId",
  1167. label: "ID",
  1168. width: "50",
  1169. align: "center"
  1170. }),
  1171. vue.createVNode(_component_el_table_column, {
  1172. prop: "content",
  1173. label: "内容"
  1174. }, {
  1175. default: vue.withCtx((scope) => [
  1176. _ctx.$app.isNew(scope.row.created) ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_14, [
  1177. vue.createTextVNode(vue.toDisplayString(scope.row.content) + " ", 1),
  1178. vue.createVNode(_component_el_tooltip, {
  1179. class: "item",
  1180. effect: "dark",
  1181. content: "7天内新增",
  1182. placement: "top-start"
  1183. }, {
  1184. default: vue.withCtx(() => [
  1185. vue.createVNode(_component_el_tag, {
  1186. type: "primary",
  1187. effect: "dark",
  1188. size: "small",
  1189. round: "",
  1190. style: { "transform": "scale(0.7)" }
  1191. }, {
  1192. default: vue.withCtx(() => [
  1193. vue.createTextVNode(" NEW ")
  1194. ]),
  1195. _: 1
  1196. })
  1197. ]),
  1198. _: 1
  1199. })
  1200. ])) : vue.createCommentVNode("", true)
  1201. ]),
  1202. _: 1
  1203. }),
  1204. vue.createVNode(_component_el_table_column, {
  1205. prop: "likeCount",
  1206. sortable: "custom",
  1207. width: "70",
  1208. align: "center",
  1209. label: "点赞"
  1210. }, {
  1211. default: vue.withCtx((scope) => [
  1212. vue.createVNode(_component_el_tag, {
  1213. type: "info",
  1214. size: "small"
  1215. }, {
  1216. default: vue.withCtx(() => [
  1217. vue.createTextVNode(vue.toDisplayString(scope.row.likeCount), 1)
  1218. ]),
  1219. _: 2
  1220. }, 1024)
  1221. ]),
  1222. _: 1
  1223. }),
  1224. vue.createVNode(_component_el_table_column, {
  1225. label: "操作",
  1226. width: "100",
  1227. align: "center"
  1228. }, {
  1229. default: vue.withCtx((scope) => [
  1230. vue.createVNode(_component_el_tooltip, {
  1231. class: "item",
  1232. effect: "dark",
  1233. content: "给个赞",
  1234. placement: "top-start"
  1235. }, {
  1236. default: vue.withCtx(() => [
  1237. vue.createVNode(_component_el_button, {
  1238. type: "success",
  1239. size: "small",
  1240. icon: "Pointer",
  1241. circle: "",
  1242. onClick: ($event) => likeReply(scope.$index)
  1243. }, null, 8, ["onClick"])
  1244. ]),
  1245. _: 2
  1246. }, 1024),
  1247. vue.createVNode(_component_el_tooltip, {
  1248. class: "item",
  1249. effect: "dark",
  1250. content: "收藏进我的",
  1251. placement: "top-start"
  1252. }, {
  1253. default: vue.withCtx(() => [
  1254. vue.createVNode(_component_el_button, {
  1255. type: "danger",
  1256. size: "small",
  1257. icon: "StarFilled",
  1258. circle: "",
  1259. onClick: ($event) => collectReply(scope.$index)
  1260. }, null, 8, ["onClick"])
  1261. ]),
  1262. _: 2
  1263. }, 1024)
  1264. ]),
  1265. _: 1
  1266. })
  1267. ]),
  1268. _: 1
  1269. }, 8, ["data"])), [
  1270. [_directive_loading, vue.unref(loading)]
  1271. ]),
  1272. vue.createVNode(_component_el_pagination, {
  1273. background: "",
  1274. layout: "prev, pager, next",
  1275. small: vue.unref(windowSize).width <= 640,
  1276. "page-size": 10,
  1277. "pager-count": vue.unref(windowSize).width > 640 ? 5 : 3,
  1278. onCurrentChange: currentPageChange,
  1279. total: vue.unref(systemListCount)
  1280. }, null, 8, ["small", "pager-count", "total"])
  1281. ]),
  1282. _: 1
  1283. })
  1284. ]),
  1285. _: 1
  1286. }, 8, ["style"])
  1287. ]),
  1288. _: 1
  1289. }),
  1290. vue.createElementVNode("div", _hoisted_15, [
  1291. vue.createVNode(_component_el_input, {
  1292. placeholder: "请输入新的回复内容",
  1293. modelValue: vue.unref(newReply),
  1294. "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => vue.isRef(newReply) ? newReply.value = $event : null),
  1295. autosize: { minRows: 1, maxRows: 3 },
  1296. maxlength: "100",
  1297. "show-word-limit": true,
  1298. resize: "none",
  1299. clearable: "",
  1300. class: "input-with-select"
  1301. }, {
  1302. append: vue.withCtx(() => [
  1303. vue.createVNode(_component_el_button, {
  1304. icon: "Plus",
  1305. onClick: addReply
  1306. })
  1307. ]),
  1308. _: 1
  1309. }, 8, ["modelValue"])
  1310. ])
  1311. ]),
  1312. _: 1
  1313. })
  1314. ]);
  1315. };
  1316. }
  1317. };
  1318. const Set = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-54a1a6de"]]);
  1319. const _hoisted_1$1 = { class: "setAIBox" };
  1320. const _sfc_main$1 = {
  1321. __name: "Ai",
  1322. emits: ["updateAI"],
  1323. setup(__props, { emit }) {
  1324. const { proxy } = vue.getCurrentInstance();
  1325. const geminiApiKey = vue.ref("");
  1326. const useGemini = vue.ref(false);
  1327. const qianwenApiKey = vue.ref("");
  1328. const useQianwen = vue.ref(false);
  1329. const kimiApiKey = vue.ref("");
  1330. const useKimi = vue.ref(false);
  1331. const chatgptDomain = vue.ref("");
  1332. const chatgptApiKey = vue.ref("");
  1333. const chatgptModel = vue.ref("gpt-3.5-turbo");
  1334. const chatgptModelList = vue.ref([
  1335. { value: "gpt-4", label: "gpt-4" },
  1336. { value: "gpt-4-0314", label: "gpt-4-0314" },
  1337. { value: "gpt-4-0613", label: "gpt-4-0613" },
  1338. { value: "gpt-4-32k", label: "gpt-4-32k" },
  1339. { value: "gpt-4-32k-0314", label: "gpt-4-32k-0314" },
  1340. { value: "gpt-4-32k-0613", label: "gpt-4-32k-0613" },
  1341. { value: "gpt-4-1106-preview", label: "gpt-4-1106-preview" },
  1342. { value: "gpt-4-vision-preview", label: "gpt-4-vision-preview" },
  1343. { value: "gpt-3.5-turbo", label: "gpt-3.5-turbo" },
  1344. { value: "gpt-3.5-turbo-0301", label: "gpt-3.5-turbo-0301" },
  1345. { value: "gpt-3.5-turbo-0613", label: "gpt-3.5-turbo-0613" },
  1346. { value: "gpt-3.5-turbo-1106", label: "gpt-3.5-turbo-1106" },
  1347. { value: "gpt-3.5-turbo-16k", label: "gpt-3.5-turbo-16k" },
  1348. { value: "gpt-3.5-turbo-16k-0613", label: "gpt-3.5-turbo-16k-0613" }
  1349. ]);
  1350. const useChatgpt = vue.ref(false);
  1351. const useAI = vue.ref("");
  1352. const promptCustom = vue.ref("");
  1353. const usePromptCustom = vue.ref(false);
  1354. vue.onBeforeMount(() => {
  1355. useAI.value = proxy.$storage.getUserInfo("useAI") || "";
  1356. geminiApiKey.value = proxy.$storage.getUserInfo("geminiApiKey") || "";
  1357. useGemini.value = useAI.value == "gemini";
  1358. qianwenApiKey.value = proxy.$storage.getUserInfo("qianwenApiKey") || "";
  1359. useQianwen.value = useAI.value == "qianwen";
  1360. kimiApiKey.value = proxy.$storage.getUserInfo("kimiApiKey") || "";
  1361. useKimi.value = useAI.value == "kimi";
  1362. chatgptDomain.value = proxy.$storage.getUserInfo("chatgptDomain") || "";
  1363. chatgptApiKey.value = proxy.$storage.getUserInfo("chatgptApiKey") || "";
  1364. chatgptModel.value = proxy.$storage.getUserInfo("chatgptModel") || "";
  1365. useChatgpt.value = useAI.value == "chatgpt";
  1366. promptCustom.value = proxy.$storage.getUserInfo("promptCustom") || "";
  1367. usePromptCustom.value = proxy.$storage.getUserInfo("usePromptCustom") || false;
  1368. });
  1369. function onGeminiApiKeyChange(e) {
  1370. proxy.$storage.setUserInfo("geminiApiKey", e);
  1371. emit("updateAI");
  1372. }
  1373. function onGeminiChange(e) {
  1374. useAI.value = e ? "gemini" : "";
  1375. proxy.$storage.setUserInfo("useAI", useAI.value);
  1376. proxy.$storage.setUserInfo("geminiApiKey", geminiApiKey.value || "");
  1377. emit("updateAI");
  1378. }
  1379. function useGeminiBeforeChange() {
  1380. if (!useGemini.value && !geminiApiKey.value) {
  1381. proxy.$message.error("请先填写:gemini api key");
  1382. return false;
  1383. }
  1384. return true;
  1385. }
  1386. function onQianwenApiKeyChange(e) {
  1387. proxy.$storage.setUserInfo("qianwenApiKey", e);
  1388. emit("updateAI");
  1389. }
  1390. function onQianwenChange(e) {
  1391. useAI.value = e ? "qianwen" : "";
  1392. proxy.$storage.setUserInfo("useAI", useAI.value);
  1393. proxy.$storage.setUserInfo("qianwenApiKey", qianwenApiKey.value || "");
  1394. emit("updateAI");
  1395. }
  1396. function useQianwenBeforeChange() {
  1397. if (!useQianwen.value && !qianwenApiKey.value) {
  1398. proxy.$message.error("请先填写:通义千问 api key");
  1399. return false;
  1400. }
  1401. return true;
  1402. }
  1403. function onKimiApiKeyChange(e) {
  1404. proxy.$storage.setUserInfo("kimiApiKey", e);
  1405. emit("updateAI");
  1406. }
  1407. function onKimiChange(e) {
  1408. useAI.value = e ? "kimi" : "";
  1409. proxy.$storage.setUserInfo("useAI", useAI.value);
  1410. proxy.$storage.setUserInfo("kimiApiKey", kimiApiKey.value || "");
  1411. emit("updateAI");
  1412. }
  1413. function useKimiBeforeChange() {
  1414. if (!useKimi.value && !kimiApiKey.value) {
  1415. proxy.$message.error("请先填写:Kimi api key");
  1416. return false;
  1417. }
  1418. return true;
  1419. }
  1420. function onChatgptDomainChange(e) {
  1421. proxy.$storage.setUserInfo("chatgptDomain", e);
  1422. emit("updateAI");
  1423. }
  1424. function onChatgptApiKeyChange(e) {
  1425. proxy.$storage.setUserInfo("chatgptApiKey", e);
  1426. emit("updateAI");
  1427. }
  1428. function onChatgptModelChange(e) {
  1429. proxy.$storage.setUserInfo("chatgptModel", e);
  1430. emit("updateAI");
  1431. }
  1432. function onChatgptChange(e) {
  1433. useAI.value = e ? "chatgpt" : "";
  1434. proxy.$storage.setUserInfo("useAI", useAI.value);
  1435. proxy.$storage.setUserInfo("chatgptDomain", chatgptDomain.value || "");
  1436. proxy.$storage.setUserInfo("chatgptApiKey", chatgptApiKey.value || "");
  1437. proxy.$storage.setUserInfo("chatgptModel", chatgptModel.value || "");
  1438. emit("updateAI");
  1439. }
  1440. function useChatgptBeforeChange() {
  1441. if (!useChatgpt.value && !chatgptDomain.value) {
  1442. proxy.$message.error("请先填写:chatgpt api domain");
  1443. return false;
  1444. }
  1445. return true;
  1446. }
  1447. function onPromptCustomChange(e) {
  1448. proxy.$storage.setUserInfo("promptCustom", e);
  1449. emit("updateAI");
  1450. }
  1451. function onUsePromptCustomChange(e) {
  1452. proxy.$storage.setUserInfo("usePromptCustom", usePromptCustom.value);
  1453. proxy.$storage.setUserInfo("promptCustom", promptCustom.value);
  1454. emit("updateAI");
  1455. }
  1456. function usePromptCustomBeforeChange() {
  1457. if (!usePromptCustom.value && !promptCustom.value) {
  1458. proxy.$message.error("请先填写:自定义 Prompt");
  1459. return false;
  1460. }
  1461. if (!usePromptCustom.value && promptCustom.value.indexOf("{{title}}") == -1) {
  1462. proxy.$message.error("请检查自定义 Prompt 中是否包含变量:{{title}}");
  1463. return false;
  1464. }
  1465. return true;
  1466. }
  1467. vue.watch(useAI, (n, o) => {
  1468. useGemini.value = n == "gemini";
  1469. useQianwen.value = n == "qianwen";
  1470. useKimi.value = n == "kimi";
  1471. useChatgpt.value = n == "chatgpt";
  1472. });
  1473. return (_ctx, _cache) => {
  1474. const _component_el_input = vue.resolveComponent("el-input");
  1475. const _component_el_tooltip = vue.resolveComponent("el-tooltip");
  1476. const _component_el_form_item = vue.resolveComponent("el-form-item");
  1477. const _component_el_switch = vue.resolveComponent("el-switch");
  1478. const _component_el_option = vue.resolveComponent("el-option");
  1479. const _component_el_select = vue.resolveComponent("el-select");
  1480. const _component_el_form = vue.resolveComponent("el-form");
  1481. const _component_el_card = vue.resolveComponent("el-card");
  1482. return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
  1483. vue.createVNode(_component_el_card, {
  1484. class: "box-card",
  1485. shadow: "never"
  1486. }, {
  1487. default: vue.withCtx(() => [
  1488. vue.createVNode(_component_el_form, {
  1489. "label-width": "110",
  1490. "label-position": "left",
  1491. size: "small"
  1492. }, {
  1493. default: vue.withCtx(() => [
  1494. vue.createVNode(_component_el_form_item, { label: "Gemini API Key" }, {
  1495. default: vue.withCtx(() => [
  1496. vue.createVNode(_component_el_tooltip, {
  1497. content: "获取API Key:https://aistudio.google.com/app/apikey",
  1498. placement: "top"
  1499. }, {
  1500. default: vue.withCtx(() => [
  1501. vue.createVNode(_component_el_input, {
  1502. modelValue: vue.unref(geminiApiKey),
  1503. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.isRef(geminiApiKey) ? geminiApiKey.value = $event : null),
  1504. onChange: onGeminiApiKeyChange
  1505. }, null, 8, ["modelValue"])
  1506. ]),
  1507. _: 1
  1508. })
  1509. ]),
  1510. _: 1
  1511. }),
  1512. vue.createVNode(_component_el_form_item, { label: "启用" }, {
  1513. default: vue.withCtx(() => [
  1514. vue.createVNode(_component_el_switch, {
  1515. modelValue: vue.unref(useGemini),
  1516. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.isRef(useGemini) ? useGemini.value = $event : null),
  1517. onChange: onGeminiChange,
  1518. "before-change": useGeminiBeforeChange
  1519. }, null, 8, ["modelValue"])
  1520. ]),
  1521. _: 1
  1522. }),
  1523. vue.createVNode(_component_el_form_item, { label: "通义千问 API Key" }, {
  1524. default: vue.withCtx(() => [
  1525. vue.createVNode(_component_el_tooltip, {
  1526. content: "获取API Key:https://dashscope.console.aliyun.com/apiKey",
  1527. placement: "top"
  1528. }, {
  1529. default: vue.withCtx(() => [
  1530. vue.createVNode(_component_el_input, {
  1531. modelValue: vue.unref(qianwenApiKey),
  1532. "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.isRef(qianwenApiKey) ? qianwenApiKey.value = $event : null),
  1533. onChange: onQianwenApiKeyChange
  1534. }, null, 8, ["modelValue"])
  1535. ]),
  1536. _: 1
  1537. })
  1538. ]),
  1539. _: 1
  1540. }),
  1541. vue.createVNode(_component_el_form_item, { label: "启用" }, {
  1542. default: vue.withCtx(() => [
  1543. vue.createVNode(_component_el_switch, {
  1544. modelValue: vue.unref(useQianwen),
  1545. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.isRef(useQianwen) ? useQianwen.value = $event : null),
  1546. onChange: onQianwenChange,
  1547. "before-change": useQianwenBeforeChange
  1548. }, null, 8, ["modelValue"])
  1549. ]),
  1550. _: 1
  1551. }),
  1552. vue.createVNode(_component_el_form_item, { label: "Kimi API Key" }, {
  1553. default: vue.withCtx(() => [
  1554. vue.createVNode(_component_el_tooltip, {
  1555. content: "获取API Key:https://platform.moonshot.cn/console/api-keys",
  1556. placement: "top"
  1557. }, {
  1558. default: vue.withCtx(() => [
  1559. vue.createVNode(_component_el_input, {
  1560. modelValue: vue.unref(kimiApiKey),
  1561. "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => vue.isRef(kimiApiKey) ? kimiApiKey.value = $event : null),
  1562. onChange: onKimiApiKeyChange
  1563. }, null, 8, ["modelValue"])
  1564. ]),
  1565. _: 1
  1566. })
  1567. ]),
  1568. _: 1
  1569. }),
  1570. vue.createVNode(_component_el_form_item, { label: "启用" }, {
  1571. default: vue.withCtx(() => [
  1572. vue.createVNode(_component_el_switch, {
  1573. modelValue: vue.unref(useKimi),
  1574. "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => vue.isRef(useKimi) ? useKimi.value = $event : null),
  1575. onChange: onKimiChange,
  1576. "before-change": useKimiBeforeChange
  1577. }, null, 8, ["modelValue"])
  1578. ]),
  1579. _: 1
  1580. }),
  1581. vue.createVNode(_component_el_form_item, { label: "Chatgpt Domain" }, {
  1582. default: vue.withCtx(() => [
  1583. vue.createVNode(_component_el_tooltip, {
  1584. content: "请自行寻找可用域名,example: chat.customai.com",
  1585. placement: "top"
  1586. }, {
  1587. default: vue.withCtx(() => [
  1588. vue.createVNode(_component_el_input, {
  1589. modelValue: vue.unref(chatgptDomain),
  1590. "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => vue.isRef(chatgptDomain) ? chatgptDomain.value = $event : null),
  1591. onChange: onChatgptDomainChange
  1592. }, null, 8, ["modelValue"])
  1593. ]),
  1594. _: 1
  1595. })
  1596. ]),
  1597. _: 1
  1598. }),
  1599. vue.createVNode(_component_el_form_item, { label: "Chatgpt API Key" }, {
  1600. default: vue.withCtx(() => [
  1601. vue.createVNode(_component_el_tooltip, {
  1602. content: "按接口规则填写",
  1603. placement: "top"
  1604. }, {
  1605. default: vue.withCtx(() => [
  1606. vue.createVNode(_component_el_input, {
  1607. modelValue: vue.unref(chatgptApiKey),
  1608. "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => vue.isRef(chatgptApiKey) ? chatgptApiKey.value = $event : null),
  1609. onChange: onChatgptApiKeyChange
  1610. }, null, 8, ["modelValue"])
  1611. ]),
  1612. _: 1
  1613. })
  1614. ]),
  1615. _: 1
  1616. }),
  1617. vue.createVNode(_component_el_form_item, { label: "Chatgpt Model" }, {
  1618. default: vue.withCtx(() => [
  1619. vue.createVNode(_component_el_tooltip, {
  1620. content: "默认使用:gpt-3.5-turbo,需接口支持",
  1621. placement: "top"
  1622. }, {
  1623. default: vue.withCtx(() => [
  1624. vue.createVNode(_component_el_select, {
  1625. modelValue: vue.unref(chatgptModel),
  1626. "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => vue.isRef(chatgptModel) ? chatgptModel.value = $event : null),
  1627. placeholder: "Select",
  1628. size: "large",
  1629. style: { "width": "240px" },
  1630. onChange: onChatgptModelChange
  1631. }, {
  1632. default: vue.withCtx(() => [
  1633. (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(vue.unref(chatgptModelList), (item) => {
  1634. return vue.openBlock(), vue.createBlock(_component_el_option, {
  1635. key: item.value,
  1636. label: item.label,
  1637. value: item.value
  1638. }, null, 8, ["label", "value"]);
  1639. }), 128))
  1640. ]),
  1641. _: 1
  1642. }, 8, ["modelValue"])
  1643. ]),
  1644. _: 1
  1645. })
  1646. ]),
  1647. _: 1
  1648. }),
  1649. vue.createVNode(_component_el_form_item, { label: "启用" }, {
  1650. default: vue.withCtx(() => [
  1651. vue.createVNode(_component_el_switch, {
  1652. modelValue: vue.unref(useChatgpt),
  1653. "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => vue.isRef(useChatgpt) ? useChatgpt.value = $event : null),
  1654. onChange: onChatgptChange,
  1655. "before-change": useChatgptBeforeChange
  1656. }, null, 8, ["modelValue"])
  1657. ]),
  1658. _: 1
  1659. }),
  1660. vue.createVNode(_component_el_form_item, { label: "自定义 Prompt" }, {
  1661. default: vue.withCtx(() => [
  1662. vue.createVNode(_component_el_tooltip, {
  1663. content: "自定义提示问语,帮你获得更个性化的回帖内容。必须包含唯一变量:{{title}}",
  1664. placement: "top"
  1665. }, {
  1666. default: vue.withCtx(() => [
  1667. vue.createVNode(_component_el_input, {
  1668. type: "textarea",
  1669. modelValue: vue.unref(promptCustom),
  1670. "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => vue.isRef(promptCustom) ? promptCustom.value = $event : null),
  1671. onChange: onPromptCustomChange,
  1672. placeholder: `默认:${vue.unref(proxy).$app.prompt}`
  1673. }, null, 8, ["modelValue", "placeholder"])
  1674. ]),
  1675. _: 1
  1676. })
  1677. ]),
  1678. _: 1
  1679. }),
  1680. vue.createVNode(_component_el_form_item, { label: "启用" }, {
  1681. default: vue.withCtx(() => [
  1682. vue.createVNode(_component_el_switch, {
  1683. modelValue: vue.unref(usePromptCustom),
  1684. "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => vue.isRef(usePromptCustom) ? usePromptCustom.value = $event : null),
  1685. onChange: onUsePromptCustomChange,
  1686. "before-change": usePromptCustomBeforeChange
  1687. }, null, 8, ["modelValue"])
  1688. ]),
  1689. _: 1
  1690. })
  1691. ]),
  1692. _: 1
  1693. })
  1694. ]),
  1695. _: 1
  1696. })
  1697. ]);
  1698. };
  1699. }
  1700. };
  1701. const AI = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-66d8ae03"]]);
  1702. const _hoisted_1 = { class: "margin-left" };
  1703. const _hoisted_2 = { class: "margin-left" };
  1704. const _sfc_main = {
  1705. __name: "Login",
  1706. emits: ["onSuccess", "onClose"],
  1707. setup(__props, { emit }) {
  1708. const { proxy } = vue.getCurrentInstance();
  1709. const checkName = (rule, value, callback) => {
  1710. if (!/[0-9a-zA-Z@\.]{5,20}/.test(value)) {
  1711. callback("用户名5-20,只能包含字母、数字、“.”、“@”等");
  1712. }
  1713. callback();
  1714. };
  1715. const checkPassword = (rule, value, callback) => {
  1716. if (!/[0-9a-zA-Z\.\-_]{2,20}/.test(value)) {
  1717. callback("密码2-20,只能包含字母、数字、“.”、“-”、“_”等");
  1718. }
  1719. callback();
  1720. };
  1721. const checkRePassword = (rule, value, callback) => {
  1722. if (value !== loginForm.value.password) {
  1723. callback("两次密码不一致");
  1724. }
  1725. callback();
  1726. };
  1727. const registerFormRef = vue.ref();
  1728. const formMode = vue.ref(1);
  1729. const registerRules = vue.ref({
  1730. username: [
  1731. { required: true, message: "用户名不能为空", trigger: "blur" }
  1732. // { validator: checkName, trigger: 'blur'}
  1733. ],
  1734. password: [
  1735. { required: true, message: "密码不能为空", trigger: "blur" },
  1736. { validator: checkPassword, trigger: "blur" }
  1737. ],
  1738. rePassword: [
  1739. { required: true, message: "确认密码不能为空", trigger: "blur" },
  1740. { validator: checkRePassword, trigger: "blur" }
  1741. ]
  1742. });
  1743. const loginFormRef = vue.ref();
  1744. const loginForm = vue.ref({
  1745. username: "",
  1746. password: "",
  1747. rePassword: ""
  1748. });
  1749. const loginRules = vue.ref({
  1750. username: [
  1751. { required: true, message: "用户名不能为空", trigger: "blur" },
  1752. { validator: checkName, trigger: "blur" }
  1753. ],
  1754. password: [
  1755. { required: true, message: "密码不能为空", trigger: "blur" },
  1756. { validator: checkPassword, trigger: "blur" }
  1757. ]
  1758. });
  1759. const loginSuccess = (res) => {
  1760. proxy.$storage.setUserInfo("userId", res.data.userId);
  1761. emit("onSuccess");
  1762. };
  1763. const loginOnSubmit = () => {
  1764. loginFormRef.value.validate(async (valid, fields) => {
  1765. if (valid) {
  1766. proxy.$api.login(loginForm.value).then((res) => {
  1767. if (res.code != 0) {
  1768. proxy.$message.error(res.message);
  1769. return false;
  1770. }
  1771. loginSuccess(res);
  1772. }).catch((err) => {
  1773. proxy.$message.error(err.message);
  1774. });
  1775. }
  1776. });
  1777. };
  1778. const registerOnSubmit = () => {
  1779. registerFormRef.value.validate(async (valid, fields) => {
  1780. if (valid) {
  1781. proxy.$api.register(loginForm.value).then((res) => {
  1782. if (res.code != 0) {
  1783. proxy.$message.error(res.message);
  1784. return false;
  1785. }
  1786. loginSuccess(res);
  1787. }).catch((err) => {
  1788. proxy.$message.error(err.message);
  1789. });
  1790. }
  1791. });
  1792. };
  1793. const close = () => {
  1794. emit("onClose");
  1795. };
  1796. return (_ctx, _cache) => {
  1797. const _component_el_input = vue.resolveComponent("el-input");
  1798. const _component_el_form_item = vue.resolveComponent("el-form-item");
  1799. const _component_el_button = vue.resolveComponent("el-button");
  1800. const _component_el_link = vue.resolveComponent("el-link");
  1801. const _component_el_space = vue.resolveComponent("el-space");
  1802. const _component_el_form = vue.resolveComponent("el-form");
  1803. return vue.openBlock(), vue.createElementBlock("div", null, [
  1804. vue.unref(formMode) === 1 ? (vue.openBlock(), vue.createBlock(_component_el_form, {
  1805. key: 0,
  1806. ref_key: "loginFormRef",
  1807. ref: loginFormRef,
  1808. model: vue.unref(loginForm),
  1809. rules: vue.unref(loginRules),
  1810. "label-width": "120px"
  1811. }, {
  1812. default: vue.withCtx(() => [
  1813. vue.createVNode(_component_el_form_item, {
  1814. label: "用户名:",
  1815. prop: "username",
  1816. required: ""
  1817. }, {
  1818. default: vue.withCtx(() => [
  1819. vue.createVNode(_component_el_input, {
  1820. modelValue: vue.unref(loginForm).username,
  1821. "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.unref(loginForm).username = $event)
  1822. }, null, 8, ["modelValue"])
  1823. ]),
  1824. _: 1
  1825. }),
  1826. vue.createVNode(_component_el_form_item, {
  1827. label: "密码:",
  1828. prop: "password",
  1829. required: ""
  1830. }, {
  1831. default: vue.withCtx(() => [
  1832. vue.createVNode(_component_el_input, {
  1833. modelValue: vue.unref(loginForm).password,
  1834. "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.unref(loginForm).password = $event)
  1835. }, null, 8, ["modelValue"])
  1836. ]),
  1837. _: 1
  1838. }),
  1839. vue.createVNode(_component_el_form_item, null, {
  1840. default: vue.withCtx(() => [
  1841. vue.createVNode(_component_el_button, {
  1842. type: "primary",
  1843. onClick: loginOnSubmit
  1844. }, {
  1845. default: vue.withCtx(() => [
  1846. vue.createTextVNode("登录")
  1847. ]),
  1848. _: 1
  1849. }),
  1850. vue.createElementVNode("div", _hoisted_1, [
  1851. vue.createVNode(_component_el_space, null, {
  1852. default: vue.withCtx(() => [
  1853. vue.createVNode(_component_el_link, {
  1854. href: "javascript:;",
  1855. onClick: _cache[2] || (_cache[2] = ($event) => formMode.value = 0)
  1856. }, {
  1857. default: vue.withCtx(() => [
  1858. vue.createTextVNode("注册")
  1859. ]),
  1860. _: 1
  1861. }),
  1862. vue.createVNode(_component_el_link, {
  1863. href: "javascript:;",
  1864. onClick: close
  1865. }, {
  1866. default: vue.withCtx(() => [
  1867. vue.createTextVNode("关闭")
  1868. ]),
  1869. _: 1
  1870. })
  1871. ]),
  1872. _: 1
  1873. })
  1874. ])
  1875. ]),
  1876. _: 1
  1877. })
  1878. ]),
  1879. _: 1
  1880. }, 8, ["model", "rules"])) : (vue.openBlock(), vue.createBlock(_component_el_form, {
  1881. key: 1,
  1882. ref_key: "registerFormRef",
  1883. ref: registerFormRef,
  1884. model: vue.unref(loginForm),
  1885. rules: vue.unref(registerRules),
  1886. "label-width": "120px"
  1887. }, {
  1888. default: vue.withCtx(() => [
  1889. vue.createVNode(_component_el_form_item, {
  1890. label: "用户名:",
  1891. prop: "username",
  1892. required: ""
  1893. }, {
  1894. default: vue.withCtx(() => [
  1895. vue.createVNode(_component_el_input, {
  1896. modelValue: vue.unref(loginForm).username,
  1897. "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.unref(loginForm).username = $event)
  1898. }, null, 8, ["modelValue"])
  1899. ]),
  1900. _: 1
  1901. }),
  1902. vue.createVNode(_component_el_form_item, {
  1903. label: "密码:",
  1904. prop: "password",
  1905. required: ""
  1906. }, {
  1907. default: vue.withCtx(() => [
  1908. vue.createVNode(_component_el_input, {
  1909. modelValue: vue.unref(loginForm).password,
  1910. "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => vue.unref(loginForm).password = $event)
  1911. }, null, 8, ["modelValue"])
  1912. ]),
  1913. _: 1
  1914. }),
  1915. vue.createVNode(_component_el_form_item, {
  1916. label: "确认密码:",
  1917. prop: "rePassword",
  1918. required: ""
  1919. }, {
  1920. default: vue.withCtx(() => [
  1921. vue.createVNode(_component_el_input, {
  1922. modelValue: vue.unref(loginForm).rePassword,
  1923. "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => vue.unref(loginForm).rePassword = $event)
  1924. }, null, 8, ["modelValue"])
  1925. ]),
  1926. _: 1
  1927. }),
  1928. vue.createVNode(_component_el_form_item, null, {
  1929. default: vue.withCtx(() => [
  1930. vue.createVNode(_component_el_button, {
  1931. type: "primary",
  1932. onClick: registerOnSubmit
  1933. }, {
  1934. default: vue.withCtx(() => [
  1935. vue.createTextVNode("注册")
  1936. ]),
  1937. _: 1
  1938. }),
  1939. vue.createElementVNode("div", _hoisted_2, [
  1940. vue.createVNode(_component_el_space, null, {
  1941. default: vue.withCtx(() => [
  1942. vue.createVNode(_component_el_link, {
  1943. href: "javascript:;",
  1944. onClick: _cache[6] || (_cache[6] = ($event) => formMode.value = 1)
  1945. }, {
  1946. default: vue.withCtx(() => [
  1947. vue.createTextVNode("登录")
  1948. ]),
  1949. _: 1
  1950. }),
  1951. vue.createVNode(_component_el_link, {
  1952. href: "javascript:;",
  1953. onClick: close
  1954. }, {
  1955. default: vue.withCtx(() => [
  1956. vue.createTextVNode("关闭")
  1957. ]),
  1958. _: 1
  1959. })
  1960. ]),
  1961. _: 1
  1962. })
  1963. ])
  1964. ]),
  1965. _: 1
  1966. })
  1967. ]),
  1968. _: 1
  1969. }, 8, ["model", "rules"]))
  1970. ]);
  1971. };
  1972. }
  1973. };
  1974. const Util = {
  1975. install: (app2, options) => {
  1976. app2.config.globalProperties.$storage = {
  1977. key: "QuickReply",
  1978. userStorageKey: "QuickReplyUser",
  1979. set(value) {
  1980. _GM_setValue(this.key, value);
  1981. },
  1982. get() {
  1983. return _GM_getValue(this.key, []);
  1984. },
  1985. getAll() {
  1986. let keyList = _GM_listValues();
  1987. let all = {};
  1988. keyList.forEach((key) => {
  1989. all[key] = _GM_getValue(key, "");
  1990. });
  1991. return all;
  1992. },
  1993. setAll(data) {
  1994. for (let key in data) {
  1995. _GM_setValue(key, data[key]);
  1996. }
  1997. },
  1998. setUserInfo(key, value) {
  1999. let fullKey = `${this.userStorageKey}.${key}`;
  2000. _GM_setValue(fullKey, value);
  2001. },
  2002. getUserInfo(key) {
  2003. let fullKey = `${this.userStorageKey}.${key}`;
  2004. return _GM_getValue(fullKey, "");
  2005. },
  2006. uploadList() {
  2007. let proxy = app2.config.globalProperties;
  2008. let userId = proxy.$storage.getUserInfo("userId");
  2009. let myList = proxy.$storage.get() || [];
  2010. if (!userId) {
  2011. proxy.$message.error("请先登录");
  2012. return false;
  2013. }
  2014. if (myList.length == 0) {
  2015. proxy.$message.error("无可同步数据");
  2016. return false;
  2017. }
  2018. proxy.$api.upQuickReplyList({
  2019. userId,
  2020. list: myList
  2021. }).then((res) => {
  2022. proxy.$message.success("上传成功");
  2023. }).catch((err) => {
  2024. proxy.$message.error(err.message);
  2025. });
  2026. },
  2027. async downloadList() {
  2028. let proxy = app2.config.globalProperties;
  2029. let userId = proxy.$storage.getUserInfo("userId");
  2030. if (!userId) {
  2031. proxy.$message.error("请先登录");
  2032. return false;
  2033. }
  2034. let res = await proxy.$api.downQuickReplyList({
  2035. userId
  2036. });
  2037. if (res.code == 0) {
  2038. if (res.data.length == 0) {
  2039. proxy.$message.error("云端无数据");
  2040. } else {
  2041. proxy.$storage.set(res.data);
  2042. proxy.$message.success("下载成功");
  2043. return res.data;
  2044. }
  2045. } else {
  2046. proxy.$message.error(res.message);
  2047. }
  2048. },
  2049. uploadAll() {
  2050. let proxy = app2.config.globalProperties;
  2051. let userId = proxy.$storage.getUserInfo("userId");
  2052. let options2 = proxy.$storage.getAll();
  2053. if (options2.QuickReply && options2.QuickReply.length > 10) {
  2054. proxy.$message.error("回复列表超出数量限制:10 条");
  2055. return false;
  2056. }
  2057. options2 = JSON.stringify(options2);
  2058. options2 = proxy.$tools.encodeStr(options2);
  2059. if (!userId) {
  2060. proxy.$message.error("请先登录");
  2061. return false;
  2062. }
  2063. proxy.$api.upUserAll({
  2064. userId,
  2065. options: options2
  2066. }).then((res) => {
  2067. proxy.$message.success("备份成功");
  2068. }).catch((err) => {
  2069. proxy.$message.error(err.message);
  2070. });
  2071. },
  2072. async downloadAll() {
  2073. let proxy = app2.config.globalProperties;
  2074. let userId = proxy.$storage.getUserInfo("userId");
  2075. if (!userId) {
  2076. proxy.$message.error("请先登录");
  2077. return false;
  2078. }
  2079. let res = await proxy.$api.downUserAll({
  2080. userId
  2081. });
  2082. if (res.code == 0) {
  2083. proxy.$storage.setAll(res.data);
  2084. proxy.$message.success("恢复成功");
  2085. return res.data;
  2086. } else {
  2087. proxy.$message.error(res.message);
  2088. }
  2089. }
  2090. };
  2091. app2.config.globalProperties.$app = {
  2092. getName() {
  2093. return _GM_info["script"]["name"];
  2094. },
  2095. getVersion: function() {
  2096. return _GM_info["script"]["version"];
  2097. },
  2098. prompt: "请根据帖子标题:{{title}},以回帖的语气生成一条15字左右的简短回复",
  2099. isNew: function(timestamp) {
  2100. if (!timestamp)
  2101. return false;
  2102. let number = 3600 * 24 * 7;
  2103. return parseInt((/* @__PURE__ */ new Date()).getTime() / 1e3) - timestamp <= number;
  2104. }
  2105. };
  2106. app2.config.globalProperties.$tools = {
  2107. encodeStr: function(str) {
  2108. let encoder = new TextEncoder();
  2109. str = encoder.encode(str);
  2110. return btoa(String.fromCharCode.apply(null, str));
  2111. },
  2112. decodeStr: function(str) {
  2113. var byteCharacters = atob(str);
  2114. var byteArray = new Uint8Array(byteCharacters.length);
  2115. for (var i = 0; i < byteCharacters.length; i++) {
  2116. byteArray[i] = byteCharacters.charCodeAt(i);
  2117. }
  2118. var decoder = new TextDecoder();
  2119. return decoder.decode(byteArray);
  2120. }
  2121. };
  2122. }
  2123. };
  2124. const http = function(api, data, method) {
  2125. method = method ? method.toLowerCase() : "post";
  2126. return new Promise((resolve, reject) => {
  2127. let url = `https://quickreply.bmqy.net/api${api}`;
  2128. if (method === "get") {
  2129. url += `?${Object.keys(data).map((key) => key + "=" + encodeURIComponent(data[key])).join("&")}`;
  2130. }
  2131. _GM_xmlhttpRequest({
  2132. method,
  2133. url,
  2134. headers: {
  2135. "Content-Type": "application/json; charset=utf-8"
  2136. },
  2137. data: method === "post" ? `${JSON.stringify(data)}` : "",
  2138. responseType: "json",
  2139. onload: function(xhr) {
  2140. if (xhr.status == 200) {
  2141. resolve(xhr.response);
  2142. } else {
  2143. reject(xhr.response);
  2144. }
  2145. },
  2146. onerror: function(xhr) {
  2147. reject(xhr.response);
  2148. }
  2149. });
  2150. });
  2151. };
  2152. const Api = {
  2153. install: (app2, options) => {
  2154. app2.config.globalProperties.$api = {
  2155. // 获取网友分享的回复
  2156. selectList: async function(page = 0, prop = "replyId", order = "descending") {
  2157. return await http("/selectList", {
  2158. page,
  2159. prop,
  2160. order
  2161. }, "get");
  2162. },
  2163. // 更新收藏数量
  2164. collectCountUpdate: async function(replyId) {
  2165. return await http("/collectCountUpdate", {
  2166. replyId
  2167. });
  2168. },
  2169. // 更新点赞数量
  2170. likeCountUpdate: async function(replyId) {
  2171. return await http("/likeCountUpdate", {
  2172. replyId
  2173. });
  2174. },
  2175. // 添加网友分享的回复
  2176. replyInsert: async function(content) {
  2177. return await http("/replyInsert", {
  2178. content
  2179. });
  2180. },
  2181. // 用户注册
  2182. register: async function(params) {
  2183. return await http("/register", params);
  2184. },
  2185. // 用户登录
  2186. login: async function(params) {
  2187. return await http("/login", params);
  2188. },
  2189. // 上传列表
  2190. upQuickReplyList: async function(params) {
  2191. return await http("/uploadList", params);
  2192. },
  2193. // 下载列表
  2194. downQuickReplyList: async function(params) {
  2195. return await http("/downloadList", params);
  2196. },
  2197. // 上传全量备份
  2198. upUserAll: async function(params) {
  2199. return await http("/uploadAll", params);
  2200. },
  2201. // 下载全量备份
  2202. downUserAll: async function(params) {
  2203. return await http("/downloadAll", params);
  2204. },
  2205. // 获取AI回复
  2206. getAIReply: function(title) {
  2207. return new Promise((resolve, reject) => {
  2208. let proxy = app2.config.globalProperties;
  2209. let useAI = proxy.$storage.getUserInfo("useAI") || "";
  2210. if (!title) {
  2211. reject("参数无效");
  2212. }
  2213. let prompt = proxy.$app.prompt;
  2214. let promptCustom = proxy.$storage.getUserInfo("promptCustom") || "";
  2215. let usePromptCustom = proxy.$storage.getUserInfo("usePromptCustom") || false;
  2216. if (usePromptCustom && promptCustom) {
  2217. prompt = promptCustom;
  2218. }
  2219. prompt = prompt.replace("{{title}}", title);
  2220. if (useAI == "gemini") {
  2221. let geminiApiKey = proxy.$storage.getUserInfo("geminiApiKey") || "";
  2222. if (!geminiApiKey) {
  2223. reject("无效api key");
  2224. }
  2225. let url = `https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent?key=${geminiApiKey}`;
  2226. let data = {
  2227. "contents": [
  2228. {
  2229. "parts": [
  2230. {
  2231. "text": prompt
  2232. }
  2233. ]
  2234. }
  2235. ]
  2236. };
  2237. _GM_xmlhttpRequest({
  2238. method: "POST",
  2239. url,
  2240. headers: {
  2241. "Content-Type": "application/json; charset=utf-8",
  2242. "User-Agent": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36`
  2243. },
  2244. data: `${JSON.stringify(data)}`,
  2245. responseType: "json",
  2246. onload: function(xhr) {
  2247. let { error, candidates } = xhr.response;
  2248. if (error) {
  2249. reject(error.message);
  2250. }
  2251. resolve(candidates[0].content.parts[0].text);
  2252. },
  2253. onerror: function(xhr) {
  2254. reject(xhr.response);
  2255. }
  2256. });
  2257. } else if (useAI == "qianwen") {
  2258. let qianwenApiKey = proxy.$storage.getUserInfo("qianwenApiKey") || "";
  2259. if (!qianwenApiKey) {
  2260. reject("无效api key");
  2261. }
  2262. let url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation";
  2263. let data = {
  2264. "model": "qwen-turbo",
  2265. "parameters": {
  2266. "result_format": "text"
  2267. },
  2268. "input": {
  2269. "prompt": prompt
  2270. }
  2271. };
  2272. _GM_xmlhttpRequest({
  2273. method: "POST",
  2274. url,
  2275. headers: {
  2276. "Content-Type": "application/json; charset=utf-8",
  2277. "User-Agent": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36`,
  2278. "Authorization": `Bearer ${qianwenApiKey}`
  2279. },
  2280. data: `${JSON.stringify(data)}`,
  2281. responseType: "json",
  2282. onload: function(xhr) {
  2283. let { output, code, message } = xhr.response;
  2284. if (code) {
  2285. reject(message);
  2286. }
  2287. let result = output.text;
  2288. result = result.replace(/[\\"]+/g, "");
  2289. resolve(result);
  2290. },
  2291. onerror: function(xhr) {
  2292. reject(xhr.response);
  2293. }
  2294. });
  2295. } else if (useAI == "kimi") {
  2296. let kimiApiKey = proxy.$storage.getUserInfo("kimiApiKey") || "";
  2297. if (!kimiApiKey) {
  2298. reject("无效api key");
  2299. }
  2300. let url = "https://api.moonshot.cn/v1/chat/completions";
  2301. let data = {
  2302. "model": "moonshot-v1-8k",
  2303. "messages": [
  2304. {
  2305. "role": "user",
  2306. "content": prompt
  2307. }
  2308. ]
  2309. };
  2310. _GM_xmlhttpRequest({
  2311. method: "POST",
  2312. url,
  2313. headers: {
  2314. "Content-Type": "application/json; charset=utf-8",
  2315. "User-Agent": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36`,
  2316. "Authorization": `Bearer ${kimiApiKey}`
  2317. },
  2318. data: `${JSON.stringify(data)}`,
  2319. responseType: "json",
  2320. onload: function(xhr) {
  2321. let { choices, error } = xhr.response;
  2322. if (error) {
  2323. reject(error.message);
  2324. }
  2325. let result = choices[0].message.content;
  2326. resolve(result);
  2327. },
  2328. onerror: function(xhr) {
  2329. reject(xhr.response);
  2330. }
  2331. });
  2332. } else if (useAI == "chatgpt") {
  2333. let chatgptDomain = proxy.$storage.getUserInfo("chatgptDomain") || "api.openai.com";
  2334. let chatgptModel = proxy.$storage.getUserInfo("chatgptModel") || "gpt-3.5-turbo";
  2335. let chatgptApiKey = proxy.$storage.getUserInfo("chatgptApiKey") || "";
  2336. if (!chatgptDomain) {
  2337. reject("无效地址");
  2338. }
  2339. let url = `https://${chatgptDomain}/v1/chat/completions`;
  2340. let data = {
  2341. "model": `${chatgptModel}`,
  2342. "messages": [
  2343. {
  2344. "role": "user",
  2345. "content": prompt
  2346. }
  2347. ],
  2348. "stream": false
  2349. };
  2350. let headers = {
  2351. "Content-Type": "application/json; charset=utf-8",
  2352. "User-Agent": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36`
  2353. };
  2354. if (chatgptApiKey) {
  2355. headers["Authorization"] = `Bearer ${chatgptApiKey}`;
  2356. }
  2357. _GM_xmlhttpRequest({
  2358. method: "POST",
  2359. url,
  2360. headers,
  2361. data: `${JSON.stringify(data)}`,
  2362. responseType: "json",
  2363. onload: function(xhr) {
  2364. let { choices, error } = xhr.response;
  2365. if (error) {
  2366. reject(error.message);
  2367. }
  2368. let result = choices[0].message.content;
  2369. resolve(result);
  2370. },
  2371. onerror: function(xhr) {
  2372. reject(xhr.response);
  2373. }
  2374. });
  2375. } else {
  2376. reject("暂未配置AI");
  2377. }
  2378. });
  2379. }
  2380. };
  2381. }
  2382. };
  2383. const app = vue.createApp(App);
  2384. for (const [key, component] of Object.entries(ElementPlusIconsVue__namespace)) {
  2385. app.component(key, component);
  2386. }
  2387. app.component("app-set-ai", AI);
  2388. app.component("app-set", Set);
  2389. app.component("app-login", _sfc_main);
  2390. app.use(ElementPlus);
  2391. app.use(Util);
  2392. app.use(Api);
  2393. app.mount(
  2394. (() => {
  2395. const $fastposteditor = document.querySelector("#fastposteditor");
  2396. const $postbox = document.querySelector("#postbox");
  2397. const $appRoot = document.createElement("div");
  2398. if ($fastposteditor) {
  2399. $fastposteditor.insertBefore($appRoot, $fastposteditor.childNodes[0]);
  2400. }
  2401. if ($postbox) {
  2402. $appRoot.style.paddingTop = "15px";
  2403. $postbox.insertBefore($appRoot, $postbox.childNodes[4]);
  2404. }
  2405. const $editorBody = document.querySelector(".comment-container");
  2406. if ($editorBody) {
  2407. $appRoot.style.padding = "15px 15px 0";
  2408. $editorBody.appendChild($appRoot);
  2409. }
  2410. const $replyControl = document.querySelector("#reply-control");
  2411. if ($replyControl) {
  2412. $appRoot.style.padding = "15px 15px 0";
  2413. $replyControl.insertBefore($appRoot, $replyControl.childNodes[2]);
  2414. }
  2415. const $replyBox = document.querySelector("#reply-box");
  2416. if ($replyBox) {
  2417. $appRoot.style.padding = "15px 15px 0";
  2418. $replyBox.insertBefore($appRoot, $replyBox.childNodes[2]);
  2419. }
  2420. const $composerBox = document.querySelector("#composer");
  2421. if ($composerBox) {
  2422. const $composerInner = $composerBox.querySelector(".Composer");
  2423. $appRoot.style.padding = "15px 15px 0";
  2424. $composerInner.insertBefore($appRoot, $composerInner.childNodes[2]);
  2425. }
  2426. return $appRoot;
  2427. })()
  2428. );
  2429.  
  2430. })(Vue, ElementPlus, ElementPlusIconsVue);