index.html 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <link id="app-favicon" rel="icon" type="image/svg+xml" href="/vite.svg" />
  6. <meta
  7. name="viewport"
  8. content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
  9. />
  10. <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
  11. <meta http-equiv="Pragma" content="no-cache" />
  12. <meta http-equiv="Expires" content="0" />
  13. <title></title>
  14. <!-- 运行时配置(DMS 栏目等);部署后可改,无需重新构建。须在应用脚本之前加载。 -->
  15. <script src="/config.js"></script>
  16. <script>
  17. let globalThis = window;
  18. // 注意:下面这些 VITE_ 占位符由 vite 构建时替换,少配一个会原样留在产物里。
  19. // 新版聊天协议后端基础地址(POST /api/chat,SSE)
  20. globalThis.VITE_CHAT_API = "%VITE_CHAT_API%" || "";
  21. // DMS 数据管理服务(会话/问答记录/反馈)
  22. globalThis.VITE_DMS_API = "%VITE_DMS_API%" || "";
  23. // 后端网关(取 IP / NLS token 等 /proxy/verify/…)
  24. globalThis.VITE_GATEWAY_API = "%VITE_GATEWAY_API%" || "";
  25. globalThis.__ZHAOSHANG_LLM_MODELS = ["zhaoshang", "zhaoshang_staging", "zhaoshang_safe"];
  26. globalThis.__isZhaoshangLLM = function (model) {
  27. return globalThis.__ZHAOSHANG_LLM_MODELS.indexOf(model || globalThis.llmModel || "") > -1;
  28. };
  29. function getQueryObj(querykey) {
  30. if (!querykey || typeof querykey !== "string") {
  31. /* console.warn("Invalid querykey provided to getQueryObj"); */
  32. return "";
  33. }
  34. var hash = location.hash;
  35. if (!hash || hash.indexOf("?") === -1) {
  36. /* console.warn("No query parameters found in URL hash"); */
  37. return "";
  38. }
  39. var queryString = hash.split("?")[1];
  40. if (!queryString) {
  41. /* console.warn('No query string found after "?" in URL hash'); */
  42. return "";
  43. }
  44. var arr = queryString.split("#")[0].split("&");
  45. var resObj = {};
  46. arr.forEach(function (item) {
  47. if (item) {
  48. var splitItem = item.split("=");
  49. var key = splitItem[0];
  50. var value = splitItem[1] || "";
  51. if (key) {
  52. resObj[key] = decodeURIComponent(value);
  53. }
  54. }
  55. });
  56. return resObj.hasOwnProperty(querykey) ? resObj[querykey] : null;
  57. }
  58. function addVersionInfo() {
  59. var version = "%VITE_VERSION%";
  60. window.humanCardVersion = version;
  61. var mode = "%MODE%";
  62. window.humanCardEnv = mode;
  63. /* console.log("%c@@@version===>", "color:green;font-size:15px", version, mode); */
  64. document.title += " Ver. " + version;
  65. if (mode === "development") {
  66. document.title += " " + mode.toUpperCase();
  67. }
  68. }
  69. function updateFavicon() {
  70. var favicon =
  71. document.querySelector("#app-favicon") || document.querySelector('link[rel="icon"]');
  72. if (!favicon) {
  73. favicon = document.createElement("link");
  74. favicon.id = "app-favicon";
  75. favicon.rel = "icon";
  76. document.head.appendChild(favicon);
  77. }
  78. var isZhaoshang = globalThis.__isZhaoshangLLM(globalThis.llmModel);
  79. favicon.type = isZhaoshang ? "image/x-icon" : "image/svg+xml";
  80. favicon.href = isZhaoshang ? "/qs_favicon.ico" : "/vite.svg";
  81. }
  82. (function initSystem() {
  83. var requestedPolicyMode = getQueryObj("mode");
  84. var isZhaoshangMode =
  85. requestedPolicyMode === "zhaoshang" ||
  86. requestedPolicyMode === "zhaoshang_staging" ||
  87. requestedPolicyMode === "zhaoshang_safe" ||
  88. /^zhaoshang_staging_\d+$/.test(requestedPolicyMode || "");
  89. globalThis.policyMode = isZhaoshangMode ? requestedPolicyMode : "zhaoshang";
  90. {
  91. globalThis.card_id = 317;
  92. globalThis.orgTitle = "营商助手";
  93. globalThis.llmModel = globalThis.policyMode;
  94. globalThis.greeting =
  95. "您好!我是青浦区营商助手”智”小青。我新上岗不久,还在努力学习提升中,请多理解包涵。请问有什么可以帮助您?";
  96. const credit_code = getQueryObj("credit_code");
  97. if (credit_code) {
  98. globalThis.transmission = { credit_code };
  99. }
  100. // 惠企政策库由 src/main.ts → ensurePolicyLibrary() 加载
  101. // (config.dms.policyRemotePath → 本地兜底;上传用 upload-policy-library.mjs)
  102. }
  103. document.title = globalThis.orgTitle;
  104. updateFavicon();
  105. // 下面四行是**加载遮罩的收尾信号,删不得**:BusinessAssistant.vue 的 initSequence() 靠
  106. // globalThis.hasSequence(或等 sequenceLoaded 事件)来隐藏 #loading-cover,
  107. // 少了它页面会永远卡在"正在初始化,请稍候..."。
  108. globalThis.hasSequence = true;
  109. document.dispatchEvent(new CustomEvent("dataLoaded"));
  110. document.dispatchEvent(new CustomEvent("sequenceLoaded"));
  111. addVersionInfo();
  112. })();
  113. (function () {
  114. // eruda 移动端调试面板:只在 URL 带 ?eruda=true(或 localStorage 的 active-eruda 开关)时加载
  115. var src = "//cdn.jsdelivr.net/npm/eruda";
  116. if (!/eruda=true/.test(window.location) && localStorage.getItem("active-eruda") != "true")
  117. return;
  118. document.write("<scr" + 'ipt src="' + src + '"></scr' + "ipt>");
  119. document.write("<scr" + "ipt>eruda.init();</scr" + "ipt>");
  120. })();
  121. </script>
  122. </head>
  123. <body>
  124. <div id="app"></div>
  125. <div id="loading-cover">
  126. <div id="cover">
  127. <!-- <div id="circle" data-text="&nbsp;"></div> -->
  128. <div id="result-text">正在初始化,请稍候...</div>
  129. </div>
  130. </div>
  131. <div id="error-info" style="display: none; opacity: 0">
  132. <div id="error-tips"></div>
  133. <div id="error-reload">重试</div>
  134. </div>
  135. <script>
  136. (function initLoadingAnimation() {
  137. var circle = document.querySelector("#circle");
  138. if (!circle) {
  139. return;
  140. }
  141. var text = circle.dataset.text;
  142. var characters = text.split("");
  143. var deltaAngle = 360 / characters.length;
  144. var distanceFromCenter = 110;
  145. characters.forEach(function (character, index) {
  146. var span = document.createElement("span");
  147. span.innerText = character;
  148. var rotateY = "rotateY(" + index * deltaAngle + "deg)";
  149. var translateZ = "translateZ(" + distanceFromCenter + "px)";
  150. span.style.transform = rotateY + " " + translateZ;
  151. circle.appendChild(span);
  152. });
  153. })();
  154. </script>
  155. <script type="module" src="/src/main.ts"></script>
  156. <style>
  157. body {
  158. margin: 0px;
  159. background: #fff;
  160. }
  161. #loading-cover {
  162. width: 100%;
  163. height: 100%;
  164. position: fixed;
  165. top: 0;
  166. left: 0;
  167. z-index: 100;
  168. font-size: 14px;
  169. backdrop-filter: blur(40px);
  170. -webkit-backdrop-filter: blur(40px);
  171. background: rgba(0, 0, 0, 0.1);
  172. display: flex;
  173. justify-content: center;
  174. align-items: center;
  175. color: #232323;
  176. font-family:
  177. -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
  178. "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
  179. "Noto Color Emoji";
  180. }
  181. #cover {
  182. display: flex;
  183. flex-direction: column;
  184. }
  185. #circle {
  186. position: relative;
  187. transform-style: preserve-3d;
  188. animation: rotate-animation 8s linear infinite;
  189. }
  190. #circle span {
  191. position: absolute;
  192. top: 0;
  193. left: 0;
  194. }
  195. .blur-effect {
  196. animation: add-blur-effect 1s ease-in-out forwards !important;
  197. }
  198. #error-info {
  199. display: flex;
  200. flex-direction: column;
  201. justify-content: center;
  202. align-items: center;
  203. width: 100vw;
  204. height: 100vh;
  205. position: fixed;
  206. top: 0;
  207. left: 0;
  208. z-index: 101;
  209. transition: all 0.5s ease-in-out;
  210. }
  211. #error-tips {
  212. display: inline-flex;
  213. padding: 18px 32px;
  214. justify-content: center;
  215. align-items: center;
  216. border-radius: 20px;
  217. background: rgba(11, 12, 14, 0.8);
  218. font-family: Inter;
  219. font-size: 16px;
  220. font-style: normal;
  221. font-weight: 400;
  222. line-height: normal;
  223. color: #ffffff;
  224. transform: translateY(-100%);
  225. }
  226. #error-reload {
  227. display: flex;
  228. width: 162.5px;
  229. padding: 10px 16px;
  230. justify-content: center;
  231. align-items: center;
  232. border-radius: 14px;
  233. background: linear-gradient(95deg, rgba(74, 114, 255, 0.96) -6.43%, #925eff 98.24%);
  234. color: #fff;
  235. font-family: PingFang HK;
  236. font-size: 16px;
  237. font-style: normal;
  238. font-weight: 500;
  239. line-height: 24px;
  240. transform: translateY(500%);
  241. }
  242. @keyframes add-blur-effect {
  243. 0% {
  244. filter: blur(0px);
  245. -webkit-filter: blur(0px);
  246. }
  247. 50% {
  248. filter: blur(20px);
  249. -webkit-filter: blur(20px);
  250. }
  251. 100% {
  252. filter: blur(0px);
  253. -webkit-filter: blur(0px);
  254. }
  255. }
  256. @keyframes rotate-animation {
  257. 0% {
  258. transform: rotateY(360deg) rotateX(-12deg) rotateZ(12deg);
  259. }
  260. 50% {
  261. transform: rotateY(180deg) rotateX(12deg) rotateZ(-12deg);
  262. }
  263. 100% {
  264. transform: rotateY(0) rotateX(-12deg) rotateZ(12deg);
  265. }
  266. }
  267. </style>
  268. </body>
  269. </html>