index.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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. <script>
  15. let globalThis = window;
  16. globalThis.modelServer = "%VITE_API%" || "";
  17. globalThis.isKnowledgeApi = "%VITE_USE_KNOWLEDGE_API%" === "true";
  18. // 新版聊天协议后端基础地址(POST /api/chat,SSE)
  19. globalThis.VITE_CHAT_API = "%VITE_CHAT_API%" || "";
  20. // DMS 数据管理服务(会话/问答记录/反馈)。token 由 vite 代理注入,前端不持有
  21. globalThis.VITE_DMS_API = "%VITE_DMS_API%" || "";
  22. globalThis.VITE_IP_API = "%VITE_IP_API%" || "";
  23. // [已移除] globalThis.isQingpuEnv = "MODE" === "qingpu";
  24. // 2026-09-24 用户要求「环境只保留开发和生产」:qingpu 模式已删除,这行本身也是死的
  25. // (写的是字面量 "MODE",永远不会等于 "qingpu";且全仓库没有任何地方读 isQingpuEnv)
  26. globalThis.__ZHAOSHANG_LLM_MODELS = ["zhaoshang", "zhaoshang_staging", "zhaoshang_safe"];
  27. globalThis.__isZhaoshangLLM = function (model) {
  28. return globalThis.__ZHAOSHANG_LLM_MODELS.indexOf(model || globalThis.llmModel || "") > -1;
  29. };
  30. var cardURL = globalThis.modelServer;
  31. function getQueryObj(querykey) {
  32. if (!querykey || typeof querykey !== "string") {
  33. console.warn("Invalid querykey provided to getQueryObj");
  34. return "";
  35. }
  36. var hash = location.hash;
  37. if (!hash || hash.indexOf("?") === -1) {
  38. console.warn("No query parameters found in URL hash");
  39. return "";
  40. }
  41. var queryString = hash.split("?")[1];
  42. if (!queryString) {
  43. console.warn('No query string found after "?" in URL hash');
  44. return "";
  45. }
  46. var arr = queryString.split("#")[0].split("&");
  47. var resObj = {};
  48. arr.forEach(function (item) {
  49. if (item) {
  50. var splitItem = item.split("=");
  51. var key = splitItem[0];
  52. var value = splitItem[1] || "";
  53. if (key) {
  54. resObj[key] = decodeURIComponent(value);
  55. }
  56. }
  57. });
  58. return resObj.hasOwnProperty(querykey) ? resObj[querykey] : null;
  59. }
  60. function addVersionInfo() {
  61. var version = "%VITE_VERSION%";
  62. window.humanCardVersion = version;
  63. var mode = "%MODE%";
  64. window.humanCardEnv = mode;
  65. console.log("%c@@@version===>", "color:green;font-size:15px", version, mode);
  66. document.title += " Ver. " + version;
  67. if (mode === "development") {
  68. document.title += " " + mode.toUpperCase();
  69. }
  70. }
  71. }
  72. function initMessageChannel() {
  73. window.addEventListener("message", () => {
  74. if (event.data && event.data.type === "initMessage") {
  75. // 这里收到父页面发来的大文本
  76. console.log("收到父页面消息:", event.data.text);
  77. localStorage.setItem("initMessage", event.data.text);
  78. // ...你的业务处理...
  79. }
  80. });
  81. window.parent.postMessage(
  82. { type: "ready" },
  83. "%VITE_PARENT_ORIGIN%" // 指定父页面的 origin,务必不要写成 '*',防止安全隐患
  84. );
  85. }
  86. function updateFavicon() {
  87. var favicon =
  88. document.querySelector("#app-favicon") || document.querySelector('link[rel="icon"]');
  89. if (!favicon) {
  90. favicon = document.createElement("link");
  91. favicon.id = "app-favicon";
  92. favicon.rel = "icon";
  93. document.head.appendChild(favicon);
  94. }
  95. var isZhaoshang = globalThis.__isZhaoshangLLM(globalThis.llmModel);
  96. favicon.type = isZhaoshang ? "image/x-icon" : "image/svg+xml";
  97. favicon.href = isZhaoshang ? "/qs_favicon.ico" : "/vite.svg";
  98. }
  99. (function initSystem() {
  100. var requestedPolicyMode = getQueryObj("mode");
  101. var isZhaoshangMode =
  102. requestedPolicyMode === "zhaoshang" ||
  103. requestedPolicyMode === "zhaoshang_staging" ||
  104. requestedPolicyMode === "zhaoshang_safe" ||
  105. /^zhaoshang_staging_\d+$/.test(requestedPolicyMode || "");
  106. globalThis.policyMode = isZhaoshangMode ? requestedPolicyMode : "zhaoshang";
  107. {
  108. globalThis.card_id = 317;
  109. globalThis.orgTitle = "营商助手";
  110. globalThis.llmModel = globalThis.policyMode;
  111. globalThis.greeting =
  112. "您好!我是青浦区营商助手”智”小青。我新上岗不久,还在努力学习提升中,请多理解包涵。请问有什么可以帮助您?";
  113. const credit_code = getQueryObj("credit_code");
  114. if (credit_code) {
  115. globalThis.transmission = { credit_code };
  116. }
  117. // 预下载完整政策列表到内存中
  118. (function () {
  119. var downloadURL = "%VITE_DOWNLOAD_URL%" + "merchant-agent/policies_public.v1.json";
  120. var localFallbackURL = "/merchant-agent/policies_public.v1.json";
  121. function applyPolicies(data, source) {
  122. // 支持 { data: [...] } 和纯数组两种格式
  123. var list = Array.isArray(data) ? data : data.data;
  124. globalThis.policiesPublic = list || [];
  125. console.log(
  126. "%c[zhaoshang] 政策列表加载完成(" +
  127. source +
  128. "):" +
  129. globalThis.policiesPublic.length +
  130. " 条",
  131. "color:green"
  132. );
  133. }
  134. function loadPolicies(source) {
  135. return fetch(source.url)
  136. .then(function (response) {
  137. if (!response.ok) throw new Error("HTTP " + response.status);
  138. return response.json();
  139. })
  140. .then(function (data) {
  141. applyPolicies(data, source.label);
  142. });
  143. }
  144. // 开发环境优先读本地副本:远端那份 327 条全都没有 data.市级政策id,
  145. // 政策详情面板的「政策名称」会因此拼不出地址、点不开;本地这份有 261/262。
  146. // 由 VITE_POLICY_LOCAL_FIRST 控制(仅 .env.development 为 true)
  147. var localFirst = "%VITE_POLICY_LOCAL_FIRST%" === "true";
  148. var sources = localFirst
  149. ? [
  150. { url: localFallbackURL, label: "local" },
  151. { url: downloadURL, label: "remote" },
  152. ]
  153. : [
  154. { url: downloadURL, label: "remote" },
  155. { url: localFallbackURL, label: "local" },
  156. ];
  157. loadPolicies(sources[0]).catch(function (err) {
  158. console.warn(
  159. "[zhaoshang] 政策列表(" + sources[0].label + ")加载失败,尝试另一个来源:",
  160. err
  161. );
  162. loadPolicies(sources[1]).catch(function (fallbackErr) {
  163. console.warn("[zhaoshang] 政策列表两个来源都加载失败:", fallbackErr);
  164. globalThis.policiesPublic = [];
  165. });
  166. });
  167. })();
  168. }
  169. document.title = globalThis.orgTitle;
  170. updateFavicon();
  171. initMessageChannel();
  172. if (globalThis.isKnowledgeApi) {
  173. document.title = globalThis.orgTitle;
  174. globalThis.cardInfo = {
  175. id: 100161,
  176. human_gender: 1,
  177. card_id: 297,
  178. card_name: "政策解读",
  179. name: "政策解读",
  180. background: "",
  181. url: "https://timg.metamaker.cn/mms_threejs_res/1c792f578384242a92f1fb2e1ad8f70d",
  182. human_avatar:
  183. "//img.metamaker.cn/resources/52116488a01573be4d6754d7de9090464a54ccc3.png",
  184. title: "1",
  185. duty: "1",
  186. org: "1",
  187. mobile: "1",
  188. wx_id: "1",
  189. logo: "",
  190. tts_args: {
  191. speed: 30,
  192. volume: 100,
  193. voice_name: "S_x8pOUDlm1",
  194. },
  195. share_conf: {
  196. qrcode: "https://img.metamaker.cn/human_card/b380126e1c138a4c1373f1b6bc8e1a4b.jpg",
  197. share_img: "https://img.metamaker.cn/human_card/3ce6f8c86bd3525d113dde450aeadbd7.jpg",
  198. share_title: "政策解读",
  199. card_img: "https://img.metamaker.cn/human_card/91c4f4e2ccf393168f01761e54802351.jpg",
  200. },
  201. func_sets: {
  202. opt_area: [
  203. {
  204. name: "拨打电话",
  205. type: 1,
  206. alias: "",
  207. check: false,
  208. },
  209. {
  210. name: "复制微信",
  211. type: 2,
  212. alias: "",
  213. check: false,
  214. },
  215. {
  216. name: "查看文档",
  217. type: 3,
  218. alias: "",
  219. check: false,
  220. },
  221. ],
  222. question_guide: {
  223. guess_ask: {
  224. check: false,
  225. value: "",
  226. },
  227. common_problem: {
  228. check: false,
  229. value: [],
  230. },
  231. },
  232. hide_name_brand: 0,
  233. human_interaction: {
  234. welcome: {
  235. check: true,
  236. value: globalThis.greeting,
  237. },
  238. },
  239. },
  240. dialog_sets: {
  241. strict: false,
  242. only_kl: false,
  243. unable_answer: {
  244. text: "很抱歉,我不太理解您的意思,请问您想了解的是什么问题呢?",
  245. check: false,
  246. amount: 1,
  247. },
  248. belief_threshold: 0.88,
  249. },
  250. };
  251. globalThis.hasSequence = true;
  252. document.dispatchEvent(new CustomEvent("dataLoaded"));
  253. document.dispatchEvent(new CustomEvent("sequenceLoaded"));
  254. addVersionInfo();
  255. }
  256. })();
  257. (function () {
  258. var src = "//cdn.jsdelivr.net/npm/eruda";
  259. if (!/eruda=true/.test(window.location) && localStorage.getItem("active-eruda") != "true")
  260. return;
  261. document.write("<scr" + 'ipt src="' + src + '"></scr' + "ipt>");
  262. document.write("<scr" + "ipt>eruda.init();</scr" + "ipt>");
  263. })();
  264. //
  265. document.addEventListener("WeixinJSBridgeReady", () => {
  266. console.log("WeixinJSBridgeReady");
  267. // let video = document.getElementById("human-stream");
  268. // video && video.play();
  269. });
  270. </script>
  271. </head>
  272. <body>
  273. <div id="app"></div>
  274. <div id="loading-cover">
  275. <div id="cover">
  276. <!-- <div id="circle" data-text="&nbsp;"></div> -->
  277. <div id="result-text">正在初始化,请稍候...</div>
  278. <!-- 加载中,请稍候... -->
  279. </div>
  280. </div>
  281. <div id="error-info" style="display: none; opacity: 0">
  282. <div id="error-tips"></div>
  283. <div id="error-reload">重试</div>
  284. </div>
  285. <script>
  286. (function initLoadingAnimation() {
  287. var circle = document.querySelector("#circle");
  288. if (!circle) {
  289. return;
  290. }
  291. var text = circle.dataset.text;
  292. var characters = text.split("");
  293. var deltaAngle = 360 / characters.length;
  294. var distanceFromCenter = 110;
  295. characters.forEach(function (character, index) {
  296. var span = document.createElement("span");
  297. span.innerText = character;
  298. var rotateY = "rotateY(" + index * deltaAngle + "deg)";
  299. var translateZ = "translateZ(" + distanceFromCenter + "px)";
  300. span.style.transform = rotateY + " " + translateZ;
  301. circle.appendChild(span);
  302. });
  303. })();
  304. </script>
  305. <script>
  306. var _hmt = _hmt || [];
  307. (function () {
  308. var hm = document.createElement("script");
  309. hm.src = "https://hm.baidu.com/hm.js?d6307cb011c91628ce6be043f40d510a";
  310. var s = document.getElementsByTagName("script")[0];
  311. s.parentNode.insertBefore(hm, s);
  312. })();
  313. </script>
  314. <script type="module" src="/src/main.ts"></script>
  315. <style>
  316. body {
  317. margin: 0px;
  318. background: #fff;
  319. }
  320. #loading-cover {
  321. width: 100%;
  322. height: 100%;
  323. position: fixed;
  324. top: 0;
  325. left: 0;
  326. z-index: 100;
  327. font-size: 14px;
  328. backdrop-filter: blur(40px);
  329. -webkit-backdrop-filter: blur(40px);
  330. background: rgba(0, 0, 0, 0.1);
  331. display: flex;
  332. justify-content: center;
  333. align-items: center;
  334. color: #232323;
  335. font-family:
  336. -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
  337. "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
  338. "Noto Color Emoji";
  339. }
  340. #cover {
  341. display: flex;
  342. flex-direction: column;
  343. }
  344. #circle {
  345. position: relative;
  346. transform-style: preserve-3d;
  347. animation: rotate-animation 8s linear infinite;
  348. }
  349. #circle span {
  350. position: absolute;
  351. top: 0;
  352. left: 0;
  353. }
  354. .blur-effect {
  355. animation: add-blur-effect 1s ease-in-out forwards !important;
  356. }
  357. #error-info {
  358. display: flex;
  359. flex-direction: column;
  360. justify-content: center;
  361. align-items: center;
  362. width: 100vw;
  363. height: 100vh;
  364. position: fixed;
  365. top: 0;
  366. left: 0;
  367. z-index: 101;
  368. transition: all 0.5s ease-in-out;
  369. }
  370. #error-tips {
  371. display: inline-flex;
  372. padding: 18px 32px;
  373. justify-content: center;
  374. align-items: center;
  375. border-radius: 20px;
  376. background: rgba(11, 12, 14, 0.8);
  377. font-family: Inter;
  378. font-size: 16px;
  379. font-style: normal;
  380. font-weight: 400;
  381. line-height: normal;
  382. color: #ffffff;
  383. transform: translateY(-100%);
  384. }
  385. #error-reload {
  386. display: flex;
  387. width: 162.5px;
  388. padding: 10px 16px;
  389. justify-content: center;
  390. align-items: center;
  391. border-radius: 14px;
  392. background: linear-gradient(95deg, rgba(74, 114, 255, 0.96) -6.43%, #925eff 98.24%);
  393. color: #fff;
  394. /* title/h5_medium */
  395. font-family: PingFang HK;
  396. font-size: 16px;
  397. font-style: normal;
  398. font-weight: 500;
  399. line-height: 24px;
  400. transform: translateY(500%);
  401. }
  402. @keyframes add-blur-effect {
  403. 0% {
  404. filter: blur(0px);
  405. -webkit-filter: blur(0px);
  406. }
  407. 50% {
  408. filter: blur(20px);
  409. -webkit-filter: blur(20px);
  410. }
  411. 100% {
  412. filter: blur(0px);
  413. -webkit-filter: blur(0px);
  414. }
  415. }
  416. @keyframes rotate-animation {
  417. 0% {
  418. transform: rotateY(360deg) rotateX(-12deg) rotateZ(12deg);
  419. }
  420. 50% {
  421. transform: rotateY(180deg) rotateX(12deg) rotateZ(-12deg);
  422. }
  423. 100% {
  424. transform: rotateY(0) rotateX(-12deg) rotateZ(12deg);
  425. }
  426. }
  427. </style>
  428. </body>
  429. </html>