MWI Price History Viewer Modified - 银河牛牛商城中物品价格走势小助手

(网页版和手机版均适配,API数据获取可能需翻墙)支持1天、3天、7天、14天、30天价格走势图;“更新价格数据Update Data”按钮一次性获取近30日数据(约720条),不弹出图表;图表弹窗基于全量数据进行数据清洗、移动平均计算及趋势线显示(默认隐藏);记录用户选择的日期范围和图例显示状态;网页版为悬浮窗,手机版为弹窗全屏旋转90°展示,右上角有退出按钮。

  1. // ==UserScript==
  2. // @name MWI Price History Viewer Modified - 银河牛牛商城中物品价格走势小助手
  3. // @namespace http://tampermonkey.net/
  4. // @version test0.9.2
  5. // @description (网页版和手机版均适配,API数据获取可能需翻墙)支持1天、3天、7天、14天、30天价格走势图;“更新价格数据Update Data”按钮一次性获取近30日数据(约720条),不弹出图表;图表弹窗基于全量数据进行数据清洗、移动平均计算及趋势线显示(默认隐藏);记录用户选择的日期范围和图例显示状态;网页版为悬浮窗,手机版为弹窗全屏旋转90°展示,右上角有退出按钮。
  6. // @author TaichiSlippers & Fitzmaz
  7. // @license MIT
  8. // @match https://www.milkywayidle.com/*
  9. // @grant GM_addStyle
  10. // @grant GM_getResourceURL
  11. // @require https://cdn.jsdelivr.net/npm/chart.js@4.4.3/dist/chart.umd.min.js
  12. // @require https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js
  13. // @require https://cdn.jsdelivr.net/npm/chartjs-plugin-crosshair@2.0.0/dist/chartjs-plugin-crosshair.min.js
  14. // @require https://cdn.jsdelivr.net/npm/sql.js-httpvfs@0.8.12/dist/index.js
  15. // @resource wasm https://cdn.jsdelivr.net/npm/sql.js-httpvfs@0.8.12/dist/sql-wasm.wasm
  16. // @resource worker https://cdn.jsdelivr.net/npm/sql.js-httpvfs@0.8.12/dist/sqlite.worker.js
  17. // ==/UserScript==
  18. (function () {
  19. 'use strict';
  20. // 手机端正则检测
  21. function isMobileDevice() {
  22. const ua = navigator.userAgent || navigator.vendor || window.opera;
  23. const mobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
  24. const aspectRatio = window.innerHeight / window.innerWidth;
  25. return mobileUA || (aspectRatio >= 1.2);
  26. }
  27. // 保存/加载用户设置:日期范围
  28. function loadRangeSetting() {
  29. return localStorage.getItem("MWI_PriceHistory_Range") || "3";
  30. }
  31. function saveRangeSetting(range) {
  32. localStorage.setItem("MWI_PriceHistory_Range", range);
  33. }
  34. // 保存/加载图例显示状态(四条曲线),默认:ask、bid、ma 显示,trend 隐藏
  35. function loadDatasetVisibility() {
  36. const def = { ask: true, bid: true, ma: true, trend: false };
  37. try {
  38. const vis = JSON.parse(localStorage.getItem("MWI_PriceHistory_DatasetVisibility"));
  39. return Object.assign(def, vis);
  40. } catch (e) {
  41. return def;
  42. }
  43. }
  44. function saveDatasetVisibility(visibility) {
  45. localStorage.setItem("MWI_PriceHistory_DatasetVisibility", JSON.stringify(visibility));
  46. }
  47. // 常量定义
  48. const MWI_DATA_ASK = 'MWI_DATA_ASK';
  49. const MWI_DATA_BID = 'MWI_DATA_BID';
  50. const SpecialItemNames = {
  51. "large_artisans_crate": "Large Artisan's Crate",
  52. "medium_artisans_crate": "Medium Artisan's Crate",
  53. "sorcerers_sole": "Sorcerer's Sole",
  54. "small_artisans_crate": "Small Artisan's Crate",
  55. "purples_gift": "Purple's Gift",
  56. "collectors_boots": "Collector's Boots",
  57. "natures_veil": "Nature's Veil",
  58. "red_chefs_hat": "Red Chef's Hat",
  59. "acrobats_ribbon": "Acrobat's Ribbon",
  60. "bishops_codex": "Bishop's Codex",
  61. "bishops_scroll": "Bishop's Scroll",
  62. "knights_aegis": "Knight's Aegis",
  63. "knights_ingot": "Knight's Ingot",
  64. "magicians_cloth": "Magician's Cloth",
  65. "magicians_hat": "Magician's Hat",
  66. "crushed_philosophers_stone": "Crushed Philosopher's Stone",
  67. "philosophers_stone": "Philosopher's Stone"
  68. };
  69. // 中英物品名称对照字典(示例部分)
  70. const itemNames = {
  71. "/items/coin": "\u91d1\u5e01",
  72. "/items/task_token": "\u4efb\u52a1\u4ee3\u5e01",
  73. "/items/chimerical_token": "\u5947\u5e7b\u4ee3\u5e01",
  74. "/items/sinister_token": "\u9634\u68ee\u4ee3\u5e01",
  75. "/items/enchanted_token": "\u79d8\u6cd5\u4ee3\u5e01",
  76. "/items/cowbell": "\u725b\u94c3",
  77. "/items/bag_of_10_cowbells": "\u725b\u94c3\u888b (10\u4e2a)",
  78. "/items/purples_gift": "\u5c0f\u7d2b\u725b\u7684\u793c\u7269",
  79. "/items/small_meteorite_cache": "\u5c0f\u9668\u77f3\u8231",
  80. "/items/medium_meteorite_cache": "\u4e2d\u9668\u77f3\u8231",
  81. "/items/large_meteorite_cache": "\u5927\u9668\u77f3\u8231",
  82. "/items/small_artisans_crate": "\u5c0f\u5de5\u5320\u5323",
  83. "/items/medium_artisans_crate": "\u4e2d\u5de5\u5320\u5323",
  84. "/items/large_artisans_crate": "\u5927\u5de5\u5320\u5323",
  85. "/items/small_treasure_chest": "\u5c0f\u5b9d\u7bb1",
  86. "/items/medium_treasure_chest": "\u4e2d\u5b9d\u7bb1",
  87. "/items/large_treasure_chest": "\u5927\u5b9d\u7bb1",
  88. "/items/chimerical_chest": "\u5947\u5e7b\u5b9d\u7bb1",
  89. "/items/sinister_chest": "\u9634\u68ee\u5b9d\u7bb1",
  90. "/items/enchanted_chest": "\u79d8\u6cd5\u5b9d\u7bb1",
  91. "/items/blue_key_fragment": "\u84dd\u8272\u94a5\u5319\u788e\u7247",
  92. "/items/green_key_fragment": "\u7eff\u8272\u94a5\u5319\u788e\u7247",
  93. "/items/purple_key_fragment": "\u7d2b\u8272\u94a5\u5319\u788e\u7247",
  94. "/items/white_key_fragment": "\u767d\u8272\u94a5\u5319\u788e\u7247",
  95. "/items/orange_key_fragment": "\u6a59\u8272\u94a5\u5319\u788e\u7247",
  96. "/items/brown_key_fragment": "\u68d5\u8272\u94a5\u5319\u788e\u7247",
  97. "/items/stone_key_fragment": "\u77f3\u5934\u94a5\u5319\u788e\u7247",
  98. "/items/dark_key_fragment": "\u9ed1\u6697\u94a5\u5319\u788e\u7247",
  99. "/items/burning_key_fragment": "\u71c3\u70e7\u94a5\u5319\u788e\u7247",
  100. "/items/chimerical_entry_key": "\u5947\u5e7b\u94a5\u5319",
  101. "/items/chimerical_chest_key": "\u5947\u5e7b\u5b9d\u7bb1\u94a5\u5319",
  102. "/items/sinister_entry_key": "\u9634\u68ee\u94a5\u5319",
  103. "/items/sinister_chest_key": "\u9634\u68ee\u5b9d\u7bb1\u94a5\u5319",
  104. "/items/enchanted_entry_key": "\u79d8\u6cd5\u94a5\u5319",
  105. "/items/enchanted_chest_key": "\u79d8\u6cd5\u5b9d\u7bb1\u94a5\u5319",
  106. "/items/donut": "\u751c\u751c\u5708",
  107. "/items/blueberry_donut": "\u84dd\u8393\u751c\u751c\u5708",
  108. "/items/blackberry_donut": "\u9ed1\u8393\u751c\u751c\u5708",
  109. "/items/strawberry_donut": "\u8349\u8393\u751c\u751c\u5708",
  110. "/items/mooberry_donut": "\u54de\u8393\u751c\u751c\u5708",
  111. "/items/marsberry_donut": "\u706b\u661f\u8393\u751c\u751c\u5708",
  112. "/items/spaceberry_donut": "\u592a\u7a7a\u8393\u751c\u751c\u5708",
  113. "/items/cupcake": "\u7eb8\u676f\u86cb\u7cd5",
  114. "/items/blueberry_cake": "\u84dd\u8393\u86cb\u7cd5",
  115. "/items/blackberry_cake": "\u9ed1\u8393\u86cb\u7cd5",
  116. "/items/strawberry_cake": "\u8349\u8393\u86cb\u7cd5",
  117. "/items/mooberry_cake": "\u54de\u8393\u86cb\u7cd5",
  118. "/items/marsberry_cake": "\u706b\u661f\u8393\u86cb\u7cd5",
  119. "/items/spaceberry_cake": "\u592a\u7a7a\u8393\u86cb\u7cd5",
  120. "/items/gummy": "\u8f6f\u7cd6",
  121. "/items/apple_gummy": "\u82f9\u679c\u8f6f\u7cd6",
  122. "/items/orange_gummy": "\u6a59\u5b50\u8f6f\u7cd6",
  123. "/items/plum_gummy": "\u674e\u5b50\u8f6f\u7cd6",
  124. "/items/peach_gummy": "\u6843\u5b50\u8f6f\u7cd6",
  125. "/items/dragon_fruit_gummy": "\u706b\u9f99\u679c\u8f6f\u7cd6",
  126. "/items/star_fruit_gummy": "\u6768\u6843\u8f6f\u7cd6",
  127. "/items/yogurt": "\u9178\u5976",
  128. "/items/apple_yogurt": "\u82f9\u679c\u9178\u5976",
  129. "/items/orange_yogurt": "\u6a59\u5b50\u9178\u5976",
  130. "/items/plum_yogurt": "\u674e\u5b50\u9178\u5976",
  131. "/items/peach_yogurt": "\u6843\u5b50\u9178\u5976",
  132. "/items/dragon_fruit_yogurt": "\u706b\u9f99\u679c\u9178\u5976",
  133. "/items/star_fruit_yogurt": "\u6768\u6843\u9178\u5976",
  134. "/items/milking_tea": "\u6324\u5976\u8336",
  135. "/items/foraging_tea": "\u91c7\u6458\u8336",
  136. "/items/woodcutting_tea": "\u4f10\u6728\u8336",
  137. "/items/cooking_tea": "\u70f9\u996a\u8336",
  138. "/items/brewing_tea": "\u51b2\u6ce1\u8336",
  139. "/items/alchemy_tea": "\u70bc\u91d1\u8336",
  140. "/items/enhancing_tea": "\u5f3a\u5316\u8336",
  141. "/items/cheesesmithing_tea": "\u5976\u916a\u953b\u9020\u8336",
  142. "/items/crafting_tea": "\u5236\u4f5c\u8336",
  143. "/items/tailoring_tea": "\u7f1d\u7eab\u8336",
  144. "/items/super_milking_tea": "\u8d85\u7ea7\u6324\u5976\u8336",
  145. "/items/super_foraging_tea": "\u8d85\u7ea7\u91c7\u6458\u8336",
  146. "/items/super_woodcutting_tea": "\u8d85\u7ea7\u4f10\u6728\u8336",
  147. "/items/super_cooking_tea": "\u8d85\u7ea7\u70f9\u996a\u8336",
  148. "/items/super_brewing_tea": "\u8d85\u7ea7\u51b2\u6ce1\u8336",
  149. "/items/super_alchemy_tea": "\u8d85\u7ea7\u70bc\u91d1\u8336",
  150. "/items/super_enhancing_tea": "\u8d85\u7ea7\u5f3a\u5316\u8336",
  151. "/items/super_cheesesmithing_tea": "\u8d85\u7ea7\u5976\u916a\u953b\u9020\u8336",
  152. "/items/super_crafting_tea": "\u8d85\u7ea7\u5236\u4f5c\u8336",
  153. "/items/super_tailoring_tea": "\u8d85\u7ea7\u7f1d\u7eab\u8336",
  154. "/items/ultra_milking_tea": "\u7a76\u6781\u6324\u5976\u8336",
  155. "/items/ultra_foraging_tea": "\u7a76\u6781\u91c7\u6458\u8336",
  156. "/items/ultra_woodcutting_tea": "\u7a76\u6781\u4f10\u6728\u8336",
  157. "/items/ultra_cooking_tea": "\u7a76\u6781\u70f9\u996a\u8336",
  158. "/items/ultra_brewing_tea": "\u7a76\u6781\u51b2\u6ce1\u8336",
  159. "/items/ultra_alchemy_tea": "\u7a76\u6781\u70bc\u91d1\u8336",
  160. "/items/ultra_enhancing_tea": "\u7a76\u6781\u5f3a\u5316\u8336",
  161. "/items/ultra_cheesesmithing_tea": "\u7a76\u6781\u5976\u916a\u953b\u9020\u8336",
  162. "/items/ultra_crafting_tea": "\u7a76\u6781\u5236\u4f5c\u8336",
  163. "/items/ultra_tailoring_tea": "\u7a76\u6781\u7f1d\u7eab\u8336",
  164. "/items/gathering_tea": "\u91c7\u96c6\u8336",
  165. "/items/gourmet_tea": "\u7f8e\u98df\u8336",
  166. "/items/wisdom_tea": "\u7ecf\u9a8c\u8336",
  167. "/items/processing_tea": "\u52a0\u5de5\u8336",
  168. "/items/efficiency_tea": "\u6548\u7387\u8336",
  169. "/items/artisan_tea": "\u5de5\u5320\u8336",
  170. "/items/catalytic_tea": "\u50ac\u5316\u8336",
  171. "/items/blessed_tea": "\u798f\u6c14\u8336",
  172. "/items/stamina_coffee": "\u8010\u529b\u5496\u5561",
  173. "/items/intelligence_coffee": "\u667a\u529b\u5496\u5561",
  174. "/items/defense_coffee": "\u9632\u5fa1\u5496\u5561",
  175. "/items/attack_coffee": "\u653b\u51fb\u5496\u5561",
  176. "/items/power_coffee": "\u529b\u91cf\u5496\u5561",
  177. "/items/ranged_coffee": "\u8fdc\u7a0b\u5496\u5561",
  178. "/items/magic_coffee": "\u9b54\u6cd5\u5496\u5561",
  179. "/items/super_stamina_coffee": "\u8d85\u7ea7\u8010\u529b\u5496\u5561",
  180. "/items/super_intelligence_coffee": "\u8d85\u7ea7\u667a\u529b\u5496\u5561",
  181. "/items/super_defense_coffee": "\u8d85\u7ea7\u9632\u5fa1\u5496\u5561",
  182. "/items/super_attack_coffee": "\u8d85\u7ea7\u653b\u51fb\u5496\u5561",
  183. "/items/super_power_coffee": "\u8d85\u7ea7\u529b\u91cf\u5496\u5561",
  184. "/items/super_ranged_coffee": "\u8d85\u7ea7\u8fdc\u7a0b\u5496\u5561",
  185. "/items/super_magic_coffee": "\u8d85\u7ea7\u9b54\u6cd5\u5496\u5561",
  186. "/items/ultra_stamina_coffee": "\u7a76\u6781\u8010\u529b\u5496\u5561",
  187. "/items/ultra_intelligence_coffee": "\u7a76\u6781\u667a\u529b\u5496\u5561",
  188. "/items/ultra_defense_coffee": "\u7a76\u6781\u9632\u5fa1\u5496\u5561",
  189. "/items/ultra_attack_coffee": "\u7a76\u6781\u653b\u51fb\u5496\u5561",
  190. "/items/ultra_power_coffee": "\u7a76\u6781\u529b\u91cf\u5496\u5561",
  191. "/items/ultra_ranged_coffee": "\u7a76\u6781\u8fdc\u7a0b\u5496\u5561",
  192. "/items/ultra_magic_coffee": "\u7a76\u6781\u9b54\u6cd5\u5496\u5561",
  193. "/items/wisdom_coffee": "\u7ecf\u9a8c\u5496\u5561",
  194. "/items/lucky_coffee": "\u5e78\u8fd0\u5496\u5561",
  195. "/items/swiftness_coffee": "\u8fc5\u6377\u5496\u5561",
  196. "/items/channeling_coffee": "\u541f\u5531\u5496\u5561",
  197. "/items/critical_coffee": "\u66b4\u51fb\u5496\u5561",
  198. "/items/poke": "\u7834\u80c6\u4e4b\u523a",
  199. "/items/impale": "\u900f\u9aa8\u4e4b\u523a",
  200. "/items/puncture": "\u7834\u7532\u4e4b\u523a",
  201. "/items/penetrating_strike": "\u8d2f\u5fc3\u4e4b\u523a",
  202. "/items/scratch": "\u722a\u5f71\u65a9",
  203. "/items/cleave": "\u5206\u88c2\u65a9",
  204. "/items/maim": "\u8840\u5203\u65a9",
  205. "/items/crippling_slash": "\u81f4\u6b8b\u65a9",
  206. "/items/smack": "\u91cd\u78be",
  207. "/items/sweep": "\u91cd\u626b",
  208. "/items/stunning_blow": "\u91cd\u9524",
  209. "/items/quick_shot": "\u5feb\u901f\u5c04\u51fb",
  210. "/items/aqua_arrow": "\u6d41\u6c34\u7bad",
  211. "/items/flame_arrow": "\u70c8\u7130\u7bad",
  212. "/items/rain_of_arrows": "\u7bad\u96e8",
  213. "/items/silencing_shot": "\u6c89\u9ed8\u4e4b\u7bad",
  214. "/items/steady_shot": "\u7a33\u5b9a\u5c04\u51fb",
  215. "/items/pestilent_shot": "\u75ab\u75c5\u5c04\u51fb",
  216. "/items/penetrating_shot": "\u8d2f\u7a7f\u5c04\u51fb",
  217. "/items/water_strike": "\u6d41\u6c34\u51b2\u51fb",
  218. "/items/ice_spear": "\u51b0\u67aa\u672f",
  219. "/items/frost_surge": "\u51b0\u971c\u7206\u88c2",
  220. "/items/mana_spring": "\u6cd5\u529b\u55b7\u6cc9",
  221. "/items/entangle": "\u7f20\u7ed5",
  222. "/items/toxic_pollen": "\u5267\u6bd2\u7c89\u5c18",
  223. "/items/natures_veil": "\u81ea\u7136\u83cc\u5e55",
  224. "/items/fireball": "\u706b\u7403",
  225. "/items/flame_blast": "\u7194\u5ca9\u7206\u88c2",
  226. "/items/firestorm": "\u706b\u7130\u98ce\u66b4",
  227. "/items/smoke_burst": "\u70df\u7206\u706d\u5f71",
  228. "/items/minor_heal": "\u521d\u7ea7\u81ea\u6108\u672f",
  229. "/items/heal": "\u81ea\u6108\u672f",
  230. "/items/quick_aid": "\u5feb\u901f\u6cbb\u7597\u672f",
  231. "/items/rejuvenate": "\u7fa4\u4f53\u6cbb\u7597\u672f",
  232. "/items/taunt": "\u5632\u8bbd",
  233. "/items/provoke": "\u6311\u8845",
  234. "/items/toughness": "\u575a\u97e7",
  235. "/items/elusiveness": "\u95ea\u907f",
  236. "/items/precision": "\u7cbe\u786e",
  237. "/items/berserk": "\u72c2\u66b4",
  238. "/items/elemental_affinity": "\u5143\u7d20\u589e\u5e45",
  239. "/items/frenzy": "\u72c2\u901f",
  240. "/items/spike_shell": "\u5c16\u523a\u9632\u62a4",
  241. "/items/arcane_reflection": "\u5965\u672f\u53cd\u5c04",
  242. "/items/vampirism": "\u5438\u8840",
  243. "/items/revive": "\u590d\u6d3b",
  244. "/items/insanity": "\u75af\u72c2",
  245. "/items/invincible": "\u65e0\u654c",
  246. "/items/fierce_aura": "\u7269\u7406\u5149\u73af",
  247. "/items/aqua_aura": "\u6d41\u6c34\u5149\u73af",
  248. "/items/sylvan_aura": "\u81ea\u7136\u5149\u73af",
  249. "/items/flame_aura": "\u706b\u7130\u5149\u73af",
  250. "/items/speed_aura": "\u901f\u5ea6\u5149\u73af",
  251. "/items/critical_aura": "\u66b4\u51fb\u5149\u73af",
  252. "/items/gobo_stabber": "\u54e5\u5e03\u6797\u957f\u5251",
  253. "/items/gobo_slasher": "\u54e5\u5e03\u6797\u5173\u5200",
  254. "/items/gobo_smasher": "\u54e5\u5e03\u6797\u72fc\u7259\u68d2",
  255. "/items/spiked_bulwark": "\u5c16\u523a\u76fe",
  256. "/items/werewolf_slasher": "\u72fc\u4eba\u5173\u5200",
  257. "/items/griffin_bulwark": "\u72ee\u9e6b\u91cd\u76fe",
  258. "/items/gobo_shooter": "\u54e5\u5e03\u6797\u5f39\u5f13",
  259. "/items/vampiric_bow": "\u5438\u8840\u5f13",
  260. "/items/cursed_bow": "\u5492\u6028\u4e4b\u5f13",
  261. "/items/gobo_boomstick": "\u54e5\u5e03\u6797\u706b\u68cd",
  262. "/items/cheese_bulwark": "\u5976\u916a\u91cd\u76fe",
  263. "/items/verdant_bulwark": "\u7fe0\u7eff\u91cd\u76fe",
  264. "/items/azure_bulwark": "\u851a\u84dd\u91cd\u76fe",
  265. "/items/burble_bulwark": "\u6df1\u7d2b\u91cd\u76fe",
  266. "/items/crimson_bulwark": "\u7edb\u7ea2\u91cd\u76fe",
  267. "/items/rainbow_bulwark": "\u5f69\u8679\u91cd\u76fe",
  268. "/items/holy_bulwark": "\u795e\u5723\u91cd\u76fe",
  269. "/items/wooden_bow": "\u6728\u5f13",
  270. "/items/birch_bow": "\u6866\u6728\u5f13",
  271. "/items/cedar_bow": "\u96ea\u677e\u5f13",
  272. "/items/purpleheart_bow": "\u7d2b\u5fc3\u5f13",
  273. "/items/ginkgo_bow": "\u94f6\u674f\u5f13",
  274. "/items/redwood_bow": "\u7ea2\u6749\u5f13",
  275. "/items/arcane_bow": "\u795e\u79d8\u5f13",
  276. "/items/stalactite_spear": "\u77f3\u949f\u957f\u67aa",
  277. "/items/granite_bludgeon": "\u82b1\u5c97\u5ca9\u5927\u68d2",
  278. "/items/regal_sword": "\u541b\u738b\u4e4b\u5251",
  279. "/items/chaotic_flail": "\u6df7\u6c8c\u8fde\u67b7",
  280. "/items/soul_hunter_crossbow": "\u7075\u9b42\u730e\u624b\u5f29",
  281. "/items/sundering_crossbow": "\u88c2\u7a7a\u4e4b\u5f29",
  282. "/items/frost_staff": "\u51b0\u971c\u6cd5\u6756",
  283. "/items/infernal_battlestaff": "\u70bc\u72f1\u6cd5\u6756",
  284. "/items/jackalope_staff": "\u9e7f\u89d2\u5154\u4e4b\u6756",
  285. "/items/cheese_sword": "\u5976\u916a\u5251",
  286. "/items/verdant_sword": "\u7fe0\u7eff\u5251",
  287. "/items/azure_sword": "\u851a\u84dd\u5251",
  288. "/items/burble_sword": "\u6df1\u7d2b\u5251",
  289. "/items/crimson_sword": "\u7edb\u7ea2\u5251",
  290. "/items/rainbow_sword": "\u5f69\u8679\u5251",
  291. "/items/holy_sword": "\u795e\u5723\u5251",
  292. "/items/cheese_spear": "\u5976\u916a\u957f\u67aa",
  293. "/items/verdant_spear": "\u7fe0\u7eff\u957f\u67aa",
  294. "/items/azure_spear": "\u851a\u84dd\u957f\u67aa",
  295. "/items/burble_spear": "\u6df1\u7d2b\u957f\u67aa",
  296. "/items/crimson_spear": "\u7edb\u7ea2\u957f\u67aa",
  297. "/items/rainbow_spear": "\u5f69\u8679\u957f\u67aa",
  298. "/items/holy_spear": "\u795e\u5723\u957f\u67aa",
  299. "/items/cheese_mace": "\u5976\u916a\u9489\u5934\u9524",
  300. "/items/verdant_mace": "\u7fe0\u7eff\u9489\u5934\u9524",
  301. "/items/azure_mace": "\u851a\u84dd\u9489\u5934\u9524",
  302. "/items/burble_mace": "\u6df1\u7d2b\u9489\u5934\u9524",
  303. "/items/crimson_mace": "\u7edb\u7ea2\u9489\u5934\u9524",
  304. "/items/rainbow_mace": "\u5f69\u8679\u9489\u5934\u9524",
  305. "/items/holy_mace": "\u795e\u5723\u9489\u5934\u9524",
  306. "/items/wooden_crossbow": "\u6728\u5f29",
  307. "/items/birch_crossbow": "\u6866\u6728\u5f29",
  308. "/items/cedar_crossbow": "\u96ea\u677e\u5f29",
  309. "/items/purpleheart_crossbow": "\u7d2b\u5fc3\u5f29",
  310. "/items/ginkgo_crossbow": "\u94f6\u674f\u5f29",
  311. "/items/redwood_crossbow": "\u7ea2\u6749\u5f29",
  312. "/items/arcane_crossbow": "\u795e\u79d8\u5f29",
  313. "/items/wooden_water_staff": "\u6728\u5236\u6c34\u6cd5\u6756",
  314. "/items/birch_water_staff": "\u6866\u6728\u6c34\u6cd5\u6756",
  315. "/items/cedar_water_staff": "\u96ea\u677e\u6c34\u6cd5\u6756",
  316. "/items/purpleheart_water_staff": "\u7d2b\u5fc3\u6c34\u6cd5\u6756",
  317. "/items/ginkgo_water_staff": "\u94f6\u674f\u6c34\u6cd5\u6756",
  318. "/items/redwood_water_staff": "\u7ea2\u6749\u6c34\u6cd5\u6756",
  319. "/items/arcane_water_staff": "\u795e\u79d8\u6c34\u6cd5\u6756",
  320. "/items/wooden_nature_staff": "\u6728\u5236\u81ea\u7136\u6cd5\u6756",
  321. "/items/birch_nature_staff": "\u6866\u6728\u81ea\u7136\u6cd5\u6756",
  322. "/items/cedar_nature_staff": "\u96ea\u677e\u81ea\u7136\u6cd5\u6756",
  323. "/items/purpleheart_nature_staff": "\u7d2b\u5fc3\u81ea\u7136\u6cd5\u6756",
  324. "/items/ginkgo_nature_staff": "\u94f6\u674f\u81ea\u7136\u6cd5\u6756",
  325. "/items/redwood_nature_staff": "\u7ea2\u6749\u81ea\u7136\u6cd5\u6756",
  326. "/items/arcane_nature_staff": "\u795e\u79d8\u81ea\u7136\u6cd5\u6756",
  327. "/items/wooden_fire_staff": "\u6728\u706b\u6cd5\u6756",
  328. "/items/birch_fire_staff": "\u6866\u6728\u706b\u6cd5\u6756",
  329. "/items/cedar_fire_staff": "\u96ea\u677e\u706b\u6cd5\u6756",
  330. "/items/purpleheart_fire_staff": "\u7d2b\u5fc3\u706b\u6cd5\u6756",
  331. "/items/ginkgo_fire_staff": "\u94f6\u674f\u706b\u6cd5\u6756",
  332. "/items/redwood_fire_staff": "\u7ea2\u6749\u706b\u6cd5\u6756",
  333. "/items/arcane_fire_staff": "\u795e\u79d8\u706b\u6cd5\u6756",
  334. "/items/eye_watch": "\u638c\u4e0a\u76d1\u5de5",
  335. "/items/snake_fang_dirk": "\u86c7\u7259\u77ed\u5251",
  336. "/items/vision_shield": "\u89c6\u89c9\u76fe",
  337. "/items/gobo_defender": "\u54e5\u5e03\u6797\u9632\u5fa1\u8005",
  338. "/items/vampire_fang_dirk": "\u5438\u8840\u9b3c\u77ed\u5251",
  339. "/items/knights_aegis": "\u9a91\u58eb\u76fe",
  340. "/items/treant_shield": "\u6811\u4eba\u76fe",
  341. "/items/manticore_shield": "\u874e\u72ee\u76fe",
  342. "/items/tome_of_healing": "\u6cbb\u7597\u4e4b\u4e66",
  343. "/items/tome_of_the_elements": "\u5143\u7d20\u4e4b\u4e66",
  344. "/items/watchful_relic": "\u8b66\u6212\u9057\u7269",
  345. "/items/bishops_codex": "\u4e3b\u6559\u6cd5\u5178",
  346. "/items/cheese_buckler": "\u5976\u916a\u5706\u76fe",
  347. "/items/verdant_buckler": "\u7fe0\u7eff\u5706\u76fe",
  348. "/items/azure_buckler": "\u851a\u84dd\u5706\u76fe",
  349. "/items/burble_buckler": "\u6df1\u7d2b\u5706\u76fe",
  350. "/items/crimson_buckler": "\u7edb\u7ea2\u5706\u76fe",
  351. "/items/rainbow_buckler": "\u5f69\u8679\u5706\u76fe",
  352. "/items/holy_buckler": "\u795e\u5723\u5706\u76fe",
  353. "/items/wooden_shield": "\u6728\u76fe",
  354. "/items/birch_shield": "\u6866\u6728\u76fe",
  355. "/items/cedar_shield": "\u96ea\u677e\u76fe",
  356. "/items/purpleheart_shield": "\u7d2b\u5fc3\u76fe",
  357. "/items/ginkgo_shield": "\u94f6\u674f\u76fe",
  358. "/items/redwood_shield": "\u7ea2\u6749\u76fe",
  359. "/items/arcane_shield": "\u795e\u79d8\u76fe",
  360. "/items/sinister_cape": "\u9634\u68ee\u6597\u7bf7",
  361. "/items/chimerical_quiver": "\u5947\u5e7b\u7bad\u888b",
  362. "/items/enchanted_cloak": "\u79d8\u6cd5\u62ab\u98ce",
  363. "/items/red_culinary_hat": "\u7ea2\u8272\u53a8\u5e08\u5e3d",
  364. "/items/snail_shell_helmet": "\u8717\u725b\u58f3\u5934\u76d4",
  365. "/items/vision_helmet": "\u89c6\u89c9\u5934\u76d4",
  366. "/items/fluffy_red_hat": "\u84ec\u677e\u7ea2\u5e3d\u5b50",
  367. "/items/acrobatic_hood": "\u6742\u6280\u5e08\u515c\u5e3d",
  368. "/items/magicians_hat": "\u9b54\u672f\u5e08\u5e3d",
  369. "/items/cheese_helmet": "\u5976\u916a\u5934\u76d4",
  370. "/items/verdant_helmet": "\u7fe0\u7eff\u5934\u76d4",
  371. "/items/azure_helmet": "\u851a\u84dd\u5934\u76d4",
  372. "/items/burble_helmet": "\u6df1\u7d2b\u5934\u76d4",
  373. "/items/crimson_helmet": "\u7edb\u7ea2\u5934\u76d4",
  374. "/items/rainbow_helmet": "\u5f69\u8679\u5934\u76d4",
  375. "/items/holy_helmet": "\u795e\u5723\u5934\u76d4",
  376. "/items/rough_hood": "\u7c97\u7cd9\u515c\u5e3d",
  377. "/items/reptile_hood": "\u722c\u884c\u52a8\u7269\u515c\u5e3d",
  378. "/items/gobo_hood": "\u54e5\u5e03\u6797\u515c\u5e3d",
  379. "/items/beast_hood": "\u91ce\u517d\u515c\u5e3d",
  380. "/items/umbral_hood": "\u6697\u5f71\u515c\u5e3d",
  381. "/items/cotton_hat": "\u68c9\u5e3d",
  382. "/items/linen_hat": "\u4e9a\u9ebb\u5e3d",
  383. "/items/bamboo_hat": "\u7af9\u5e3d",
  384. "/items/silk_hat": "\u4e1d\u5e3d",
  385. "/items/radiant_hat": "\u5149\u8f89\u5e3d",
  386. "/items/dairyhands_top": "\u6324\u5976\u5de5\u4e0a\u8863",
  387. "/items/foragers_top": "\u91c7\u6458\u8005\u4e0a\u8863",
  388. "/items/lumberjacks_top": "\u4f10\u6728\u5de5\u4e0a\u8863",
  389. "/items/cheesemakers_top": "\u5976\u916a\u5e08\u4e0a\u8863",
  390. "/items/crafters_top": "\u5de5\u5320\u4e0a\u8863",
  391. "/items/tailors_top": "\u88c1\u7f1d\u4e0a\u8863",
  392. "/items/chefs_top": "\u53a8\u5e08\u4e0a\u8863",
  393. "/items/brewers_top": "\u996e\u54c1\u5e08\u4e0a\u8863",
  394. "/items/alchemists_top": "\u70bc\u91d1\u5e08\u4e0a\u8863",
  395. "/items/enhancers_top": "\u5f3a\u5316\u5e08\u4e0a\u8863",
  396. "/items/gator_vest": "\u9cc4\u9c7c\u9a6c\u7532",
  397. "/items/turtle_shell_body": "\u9f9f\u58f3\u80f8\u7532",
  398. "/items/colossus_plate_body": "\u5de8\u50cf\u80f8\u7532",
  399. "/items/demonic_plate_body": "\u6076\u9b54\u80f8\u7532",
  400. "/items/marine_tunic": "\u6d77\u6d0b\u76ae\u8863",
  401. "/items/revenant_tunic": "\u4ea1\u7075\u76ae\u8863",
  402. "/items/griffin_tunic": "\u72ee\u9e6b\u76ae\u8863",
  403. "/items/icy_robe_top": "\u51b0\u971c\u888d\u670d",
  404. "/items/flaming_robe_top": "\u70c8\u7130\u888d\u670d",
  405. "/items/luna_robe_top": "\u6708\u795e\u888d\u670d",
  406. "/items/royal_water_robe_top": "\u7687\u5bb6\u6c34\u7cfb\u888d\u670d",
  407. "/items/royal_nature_robe_top": "\u7687\u5bb6\u81ea\u7136\u7cfb\u888d\u670d",
  408. "/items/royal_fire_robe_top": "\u7687\u5bb6\u706b\u7cfb\u888d\u670d",
  409. "/items/cheese_plate_body": "\u5976\u916a\u80f8\u7532",
  410. "/items/verdant_plate_body": "\u7fe0\u7eff\u80f8\u7532",
  411. "/items/azure_plate_body": "\u851a\u84dd\u80f8\u7532",
  412. "/items/burble_plate_body": "\u6df1\u7d2b\u80f8\u7532",
  413. "/items/crimson_plate_body": "\u7edb\u7ea2\u80f8\u7532",
  414. "/items/rainbow_plate_body": "\u5f69\u8679\u80f8\u7532",
  415. "/items/holy_plate_body": "\u795e\u5723\u80f8\u7532",
  416. "/items/rough_tunic": "\u7c97\u7cd9\u76ae\u8863",
  417. "/items/reptile_tunic": "\u722c\u884c\u52a8\u7269\u76ae\u8863",
  418. "/items/gobo_tunic": "\u54e5\u5e03\u6797\u76ae\u8863",
  419. "/items/beast_tunic": "\u91ce\u517d\u76ae\u8863",
  420. "/items/umbral_tunic": "\u6697\u5f71\u76ae\u8863",
  421. "/items/cotton_robe_top": "\u68c9\u5e03\u888d\u670d",
  422. "/items/linen_robe_top": "\u4e9a\u9ebb\u888d\u670d",
  423. "/items/bamboo_robe_top": "\u7af9\u888d\u670d",
  424. "/items/silk_robe_top": "\u4e1d\u7ef8\u888d\u670d",
  425. "/items/radiant_robe_top": "\u5149\u8f89\u888d\u670d",
  426. "/items/dairyhands_bottoms": "\u6324\u5976\u5de5\u4e0b\u88c5",
  427. "/items/foragers_bottoms": "\u91c7\u6458\u8005\u4e0b\u88c5",
  428. "/items/lumberjacks_bottoms": "\u4f10\u6728\u5de5\u4e0b\u88c5",
  429. "/items/cheesemakers_bottoms": "\u5976\u916a\u5e08\u4e0b\u88c5",
  430. "/items/crafters_bottoms": "\u5de5\u5320\u4e0b\u88c5",
  431. "/items/tailors_bottoms": "\u88c1\u7f1d\u4e0b\u88c5",
  432. "/items/chefs_bottoms": "\u53a8\u5e08\u4e0b\u88c5",
  433. "/items/brewers_bottoms": "\u996e\u54c1\u5e08\u4e0b\u88c5",
  434. "/items/alchemists_bottoms": "\u70bc\u91d1\u5e08\u4e0b\u88c5",
  435. "/items/enhancers_bottoms": "\u5f3a\u5316\u5e08\u4e0b\u88c5",
  436. "/items/turtle_shell_legs": "\u9f9f\u58f3\u817f\u7532",
  437. "/items/colossus_plate_legs": "\u5de8\u50cf\u817f\u7532",
  438. "/items/demonic_plate_legs": "\u6076\u9b54\u817f\u7532",
  439. "/items/marine_chaps": "\u822a\u6d77\u76ae\u88e4",
  440. "/items/revenant_chaps": "\u4ea1\u7075\u76ae\u88e4",
  441. "/items/griffin_chaps": "\u72ee\u9e6b\u76ae\u88e4",
  442. "/items/icy_robe_bottoms": "\u51b0\u971c\u888d\u88d9",
  443. "/items/flaming_robe_bottoms": "\u70c8\u7130\u888d\u88d9",
  444. "/items/luna_robe_bottoms": "\u6708\u795e\u888d\u88d9",
  445. "/items/royal_water_robe_bottoms": "\u7687\u5bb6\u6c34\u7cfb\u888d\u88d9",
  446. "/items/royal_nature_robe_bottoms": "\u7687\u5bb6\u81ea\u7136\u7cfb\u888d\u88d9",
  447. "/items/royal_fire_robe_bottoms": "\u7687\u5bb6\u706b\u7cfb\u888d\u88d9",
  448. "/items/cheese_plate_legs": "\u5976\u916a\u817f\u7532",
  449. "/items/verdant_plate_legs": "\u7fe0\u7eff\u817f\u7532",
  450. "/items/azure_plate_legs": "\u851a\u84dd\u817f\u7532",
  451. "/items/burble_plate_legs": "\u6df1\u7d2b\u817f\u7532",
  452. "/items/crimson_plate_legs": "\u7edb\u7ea2\u817f\u7532",
  453. "/items/rainbow_plate_legs": "\u5f69\u8679\u817f\u7532",
  454. "/items/holy_plate_legs": "\u795e\u5723\u817f\u7532",
  455. "/items/rough_chaps": "\u7c97\u7cd9\u76ae\u88e4",
  456. "/items/reptile_chaps": "\u722c\u884c\u52a8\u7269\u76ae\u88e4",
  457. "/items/gobo_chaps": "\u54e5\u5e03\u6797\u76ae\u88e4",
  458. "/items/beast_chaps": "\u91ce\u517d\u76ae\u88e4",
  459. "/items/umbral_chaps": "\u6697\u5f71\u76ae\u88e4",
  460. "/items/cotton_robe_bottoms": "\u68c9\u888d\u88d9",
  461. "/items/linen_robe_bottoms": "\u4e9a\u9ebb\u888d\u88d9",
  462. "/items/bamboo_robe_bottoms": "\u7af9\u888d\u88d9",
  463. "/items/silk_robe_bottoms": "\u4e1d\u7ef8\u888d\u88d9",
  464. "/items/radiant_robe_bottoms": "\u5149\u8f89\u888d\u88d9",
  465. "/items/enchanted_gloves": "\u9644\u9b54\u624b\u5957",
  466. "/items/pincer_gloves": "\u87f9\u94b3\u624b\u5957",
  467. "/items/panda_gloves": "\u718a\u732b\u624b\u5957",
  468. "/items/magnetic_gloves": "\u78c1\u529b\u624b\u5957",
  469. "/items/dodocamel_gauntlets": "\u6e21\u6e21\u9a7c\u62a4\u624b",
  470. "/items/sighted_bracers": "\u7784\u51c6\u62a4\u8155",
  471. "/items/chrono_gloves": "\u65f6\u7a7a\u624b\u5957",
  472. "/items/cheese_gauntlets": "\u5976\u916a\u62a4\u624b",
  473. "/items/verdant_gauntlets": "\u7fe0\u7eff\u62a4\u624b",
  474. "/items/azure_gauntlets": "\u851a\u84dd\u62a4\u624b",
  475. "/items/burble_gauntlets": "\u6df1\u7d2b\u62a4\u624b",
  476. "/items/crimson_gauntlets": "\u7edb\u7ea2\u62a4\u624b",
  477. "/items/rainbow_gauntlets": "\u5f69\u8679\u62a4\u624b",
  478. "/items/holy_gauntlets": "\u795e\u5723\u62a4\u624b",
  479. "/items/rough_bracers": "\u7c97\u7cd9\u62a4\u8155",
  480. "/items/reptile_bracers": "\u722c\u884c\u52a8\u7269\u62a4\u8155",
  481. "/items/gobo_bracers": "\u54e5\u5e03\u6797\u62a4\u8155",
  482. "/items/beast_bracers": "\u91ce\u517d\u62a4\u8155",
  483. "/items/umbral_bracers": "\u6697\u5f71\u62a4\u8155",
  484. "/items/cotton_gloves": "\u68c9\u624b\u5957",
  485. "/items/linen_gloves": "\u4e9a\u9ebb\u624b\u5957",
  486. "/items/bamboo_gloves": "\u7af9\u624b\u5957",
  487. "/items/silk_gloves": "\u4e1d\u624b\u5957",
  488. "/items/radiant_gloves": "\u5149\u8f89\u624b\u5957",
  489. "/items/collectors_boots": "\u6536\u85cf\u5bb6\u9774",
  490. "/items/shoebill_shoes": "\u9cb8\u5934\u9e73\u978b",
  491. "/items/black_bear_shoes": "\u9ed1\u718a\u978b",
  492. "/items/grizzly_bear_shoes": "\u68d5\u718a\u978b",
  493. "/items/polar_bear_shoes": "\u5317\u6781\u718a\u978b",
  494. "/items/centaur_boots": "\u534a\u4eba\u9a6c\u9774",
  495. "/items/sorcerer_boots": "\u5deb\u5e08\u9774",
  496. "/items/cheese_boots": "\u5976\u916a\u9774",
  497. "/items/verdant_boots": "\u7fe0\u7eff\u9774",
  498. "/items/azure_boots": "\u851a\u84dd\u9774",
  499. "/items/burble_boots": "\u6df1\u7d2b\u9774",
  500. "/items/crimson_boots": "\u7edb\u7ea2\u9774",
  501. "/items/rainbow_boots": "\u5f69\u8679\u9774",
  502. "/items/holy_boots": "\u795e\u5723\u9774",
  503. "/items/rough_boots": "\u7c97\u7cd9\u9774",
  504. "/items/reptile_boots": "\u722c\u884c\u52a8\u7269\u9774",
  505. "/items/gobo_boots": "\u54e5\u5e03\u6797\u9774",
  506. "/items/beast_boots": "\u91ce\u517d\u9774",
  507. "/items/umbral_boots": "\u6697\u5f71\u9774",
  508. "/items/cotton_boots": "\u68c9\u9774",
  509. "/items/linen_boots": "\u4e9a\u9ebb\u9774",
  510. "/items/bamboo_boots": "\u7af9\u9774",
  511. "/items/silk_boots": "\u4e1d\u9774",
  512. "/items/radiant_boots": "\u5149\u8f89\u9774",
  513. "/items/small_pouch": "\u5c0f\u888b\u5b50",
  514. "/items/medium_pouch": "\u4e2d\u888b\u5b50",
  515. "/items/large_pouch": "\u5927\u888b\u5b50",
  516. "/items/giant_pouch": "\u5de8\u5927\u888b\u5b50",
  517. "/items/gluttonous_pouch": "\u8d2a\u98df\u4e4b\u888b",
  518. "/items/guzzling_pouch": "\u66b4\u996e\u4e4b\u56ca",
  519. "/items/necklace_of_efficiency": "\u6548\u7387\u9879\u94fe",
  520. "/items/fighter_necklace": "\u6218\u58eb\u9879\u94fe",
  521. "/items/ranger_necklace": "\u5c04\u624b\u9879\u94fe",
  522. "/items/wizard_necklace": "\u5deb\u5e08\u9879\u94fe",
  523. "/items/necklace_of_wisdom": "\u7ecf\u9a8c\u9879\u94fe",
  524. "/items/necklace_of_speed": "\u901f\u5ea6\u9879\u94fe",
  525. "/items/philosophers_necklace": "\u8d24\u8005\u9879\u94fe",
  526. "/items/earrings_of_gathering": "\u91c7\u96c6\u8033\u73af",
  527. "/items/earrings_of_essence_find": "\u7cbe\u534e\u53d1\u73b0\u8033\u73af",
  528. "/items/earrings_of_armor": "\u62a4\u7532\u8033\u73af",
  529. "/items/earrings_of_regeneration": "\u6062\u590d\u8033\u73af",
  530. "/items/earrings_of_resistance": "\u6297\u6027\u8033\u73af",
  531. "/items/earrings_of_rare_find": "\u7a00\u6709\u53d1\u73b0\u8033\u73af",
  532. "/items/earrings_of_critical_strike": "\u66b4\u51fb\u8033\u73af",
  533. "/items/philosophers_earrings": "\u8d24\u8005\u8033\u73af",
  534. "/items/ring_of_gathering": "\u91c7\u96c6\u6212\u6307",
  535. "/items/ring_of_essence_find": "\u7cbe\u534e\u53d1\u73b0\u6212\u6307",
  536. "/items/ring_of_armor": "\u62a4\u7532\u6212\u6307",
  537. "/items/ring_of_regeneration": "\u6062\u590d\u6212\u6307",
  538. "/items/ring_of_resistance": "\u6297\u6027\u6212\u6307",
  539. "/items/ring_of_rare_find": "\u7a00\u6709\u53d1\u73b0\u6212\u6307",
  540. "/items/ring_of_critical_strike": "\u66b4\u51fb\u6212\u6307",
  541. "/items/philosophers_ring": "\u8d24\u8005\u6212\u6307",
  542. "/items/basic_task_badge": "\u57fa\u7840\u4efb\u52a1\u5fbd\u7ae0",
  543. "/items/advanced_task_badge": "\u9ad8\u7ea7\u4efb\u52a1\u5fbd\u7ae0",
  544. "/items/expert_task_badge": "\u4e13\u5bb6\u4efb\u52a1\u5fbd\u7ae0",
  545. "/items/celestial_brush": "\u661f\u7a7a\u5237\u5b50",
  546. "/items/cheese_brush": "\u5976\u916a\u5237\u5b50",
  547. "/items/verdant_brush": "\u7fe0\u7eff\u5237\u5b50",
  548. "/items/azure_brush": "\u851a\u84dd\u5237\u5b50",
  549. "/items/burble_brush": "\u6df1\u7d2b\u5237\u5b50",
  550. "/items/crimson_brush": "\u7edb\u7ea2\u5237\u5b50",
  551. "/items/rainbow_brush": "\u5f69\u8679\u5237\u5b50",
  552. "/items/holy_brush": "\u795e\u5723\u5237\u5b50",
  553. "/items/celestial_shears": "\u661f\u7a7a\u526a\u5200",
  554. "/items/cheese_shears": "\u5976\u916a\u526a\u5200",
  555. "/items/verdant_shears": "\u7fe0\u7eff\u526a\u5200",
  556. "/items/azure_shears": "\u851a\u84dd\u526a\u5200",
  557. "/items/burble_shears": "\u6df1\u7d2b\u526a\u5200",
  558. "/items/crimson_shears": "\u7edb\u7ea2\u526a\u5200",
  559. "/items/rainbow_shears": "\u5f69\u8679\u526a\u5200",
  560. "/items/holy_shears": "\u795e\u5723\u526a\u5200",
  561. "/items/celestial_hatchet": "\u661f\u7a7a\u65a7\u5934",
  562. "/items/cheese_hatchet": "\u5976\u916a\u65a7\u5934",
  563. "/items/verdant_hatchet": "\u7fe0\u7eff\u65a7\u5934",
  564. "/items/azure_hatchet": "\u851a\u84dd\u65a7\u5934",
  565. "/items/burble_hatchet": "\u6df1\u7d2b\u65a7\u5934",
  566. "/items/crimson_hatchet": "\u7edb\u7ea2\u65a7\u5934",
  567. "/items/rainbow_hatchet": "\u5f69\u8679\u65a7\u5934",
  568. "/items/holy_hatchet": "\u795e\u5723\u65a7\u5934",
  569. "/items/celestial_hammer": "\u661f\u7a7a\u9524\u5b50",
  570. "/items/cheese_hammer": "\u5976\u916a\u9524\u5b50",
  571. "/items/verdant_hammer": "\u7fe0\u7eff\u9524\u5b50",
  572. "/items/azure_hammer": "\u851a\u84dd\u9524\u5b50",
  573. "/items/burble_hammer": "\u6df1\u7d2b\u9524\u5b50",
  574. "/items/crimson_hammer": "\u7edb\u7ea2\u9524\u5b50",
  575. "/items/rainbow_hammer": "\u5f69\u8679\u9524\u5b50",
  576. "/items/holy_hammer": "\u795e\u5723\u9524\u5b50",
  577. "/items/celestial_chisel": "\u661f\u7a7a\u51ff\u5b50",
  578. "/items/cheese_chisel": "\u5976\u916a\u51ff\u5b50",
  579. "/items/verdant_chisel": "\u7fe0\u7eff\u51ff\u5b50",
  580. "/items/azure_chisel": "\u851a\u84dd\u51ff\u5b50",
  581. "/items/burble_chisel": "\u6df1\u7d2b\u51ff\u5b50",
  582. "/items/crimson_chisel": "\u7edb\u7ea2\u51ff\u5b50",
  583. "/items/rainbow_chisel": "\u5f69\u8679\u51ff\u5b50",
  584. "/items/holy_chisel": "\u795e\u5723\u51ff\u5b50",
  585. "/items/celestial_needle": "\u661f\u7a7a\u9488",
  586. "/items/cheese_needle": "\u5976\u916a\u9488",
  587. "/items/verdant_needle": "\u7fe0\u7eff\u9488",
  588. "/items/azure_needle": "\u851a\u84dd\u9488",
  589. "/items/burble_needle": "\u6df1\u7d2b\u9488",
  590. "/items/crimson_needle": "\u7edb\u7ea2\u9488",
  591. "/items/rainbow_needle": "\u5f69\u8679\u9488",
  592. "/items/holy_needle": "\u795e\u5723\u9488",
  593. "/items/celestial_spatula": "\u661f\u7a7a\u9505\u94f2",
  594. "/items/cheese_spatula": "\u5976\u916a\u9505\u94f2",
  595. "/items/verdant_spatula": "\u7fe0\u7eff\u9505\u94f2",
  596. "/items/azure_spatula": "\u851a\u84dd\u9505\u94f2",
  597. "/items/burble_spatula": "\u6df1\u7d2b\u9505\u94f2",
  598. "/items/crimson_spatula": "\u7edb\u7ea2\u9505\u94f2",
  599. "/items/rainbow_spatula": "\u5f69\u8679\u9505\u94f2",
  600. "/items/holy_spatula": "\u795e\u5723\u9505\u94f2",
  601. "/items/celestial_pot": "\u661f\u7a7a\u58f6",
  602. "/items/cheese_pot": "\u5976\u916a\u58f6",
  603. "/items/verdant_pot": "\u7fe0\u7eff\u58f6",
  604. "/items/azure_pot": "\u851a\u84dd\u58f6",
  605. "/items/burble_pot": "\u6df1\u7d2b\u58f6",
  606. "/items/crimson_pot": "\u7edb\u7ea2\u58f6",
  607. "/items/rainbow_pot": "\u5f69\u8679\u58f6",
  608. "/items/holy_pot": "\u795e\u5723\u58f6",
  609. "/items/celestial_alembic": "\u661f\u7a7a\u84b8\u998f\u5668",
  610. "/items/cheese_alembic": "\u5976\u916a\u84b8\u998f\u5668",
  611. "/items/verdant_alembic": "\u7fe0\u7eff\u84b8\u998f\u5668",
  612. "/items/azure_alembic": "\u851a\u84dd\u84b8\u998f\u5668",
  613. "/items/burble_alembic": "\u6df1\u7d2b\u84b8\u998f\u5668",
  614. "/items/crimson_alembic": "\u7edb\u7ea2\u84b8\u998f\u5668",
  615. "/items/rainbow_alembic": "\u5f69\u8679\u84b8\u998f\u5668",
  616. "/items/holy_alembic": "\u795e\u5723\u84b8\u998f\u5668",
  617. "/items/celestial_enhancer": "\u661f\u7a7a\u5f3a\u5316\u5668",
  618. "/items/cheese_enhancer": "\u5976\u916a\u5f3a\u5316\u5668",
  619. "/items/verdant_enhancer": "\u7fe0\u7eff\u5f3a\u5316\u5668",
  620. "/items/azure_enhancer": "\u851a\u84dd\u5f3a\u5316\u5668",
  621. "/items/burble_enhancer": "\u6df1\u7d2b\u5f3a\u5316\u5668",
  622. "/items/crimson_enhancer": "\u7edb\u7ea2\u5f3a\u5316\u5668",
  623. "/items/rainbow_enhancer": "\u5f69\u8679\u5f3a\u5316\u5668",
  624. "/items/holy_enhancer": "\u795e\u5723\u5f3a\u5316\u5668",
  625. "/items/milk": "\u725b\u5976",
  626. "/items/verdant_milk": "\u7fe0\u7eff\u725b\u5976",
  627. "/items/azure_milk": "\u851a\u84dd\u725b\u5976",
  628. "/items/burble_milk": "\u6df1\u7d2b\u725b\u5976",
  629. "/items/crimson_milk": "\u7edb\u7ea2\u725b\u5976",
  630. "/items/rainbow_milk": "\u5f69\u8679\u725b\u5976",
  631. "/items/holy_milk": "\u795e\u5723\u725b\u5976",
  632. "/items/cheese": "\u5976\u916a",
  633. "/items/verdant_cheese": "\u7fe0\u7eff\u5976\u916a",
  634. "/items/azure_cheese": "\u851a\u84dd\u5976\u916a",
  635. "/items/burble_cheese": "\u6df1\u7d2b\u5976\u916a",
  636. "/items/crimson_cheese": "\u7edb\u7ea2\u5976\u916a",
  637. "/items/rainbow_cheese": "\u5f69\u8679\u5976\u916a",
  638. "/items/holy_cheese": "\u795e\u5723\u5976\u916a",
  639. "/items/log": "\u539f\u6728",
  640. "/items/birch_log": "\u767d\u6866\u539f\u6728",
  641. "/items/cedar_log": "\u96ea\u677e\u539f\u6728",
  642. "/items/purpleheart_log": "\u7d2b\u5fc3\u539f\u6728",
  643. "/items/ginkgo_log": "\u94f6\u674f\u539f\u6728",
  644. "/items/redwood_log": "\u7ea2\u6749\u539f\u6728",
  645. "/items/arcane_log": "\u795e\u79d8\u539f\u6728",
  646. "/items/lumber": "\u6728\u677f",
  647. "/items/birch_lumber": "\u767d\u6866\u6728\u677f",
  648. "/items/cedar_lumber": "\u96ea\u677e\u6728\u677f",
  649. "/items/purpleheart_lumber": "\u7d2b\u5fc3\u6728\u677f",
  650. "/items/ginkgo_lumber": "\u94f6\u674f\u6728\u677f",
  651. "/items/redwood_lumber": "\u7ea2\u6749\u6728\u677f",
  652. "/items/arcane_lumber": "\u795e\u79d8\u6728\u677f",
  653. "/items/rough_hide": "\u7c97\u7cd9\u517d\u76ae",
  654. "/items/reptile_hide": "\u722c\u884c\u52a8\u7269\u76ae",
  655. "/items/gobo_hide": "\u54e5\u5e03\u6797\u76ae",
  656. "/items/beast_hide": "\u91ce\u517d\u76ae",
  657. "/items/umbral_hide": "\u6697\u5f71\u76ae",
  658. "/items/rough_leather": "\u7c97\u7cd9\u76ae\u9769",
  659. "/items/reptile_leather": "\u722c\u884c\u52a8\u7269\u76ae\u9769",
  660. "/items/gobo_leather": "\u54e5\u5e03\u6797\u76ae\u9769",
  661. "/items/beast_leather": "\u91ce\u517d\u76ae\u9769",
  662. "/items/umbral_leather": "\u6697\u5f71\u76ae\u9769",
  663. "/items/cotton": "\u68c9\u82b1",
  664. "/items/flax": "\u4e9a\u9ebb",
  665. "/items/bamboo_branch": "\u7af9\u5b50",
  666. "/items/cocoon": "\u8695\u8327",
  667. "/items/radiant_fiber": "\u5149\u8f89\u7ea4\u7ef4",
  668. "/items/cotton_fabric": "\u68c9\u82b1\u5e03\u6599",
  669. "/items/linen_fabric": "\u4e9a\u9ebb\u5e03\u6599",
  670. "/items/bamboo_fabric": "\u7af9\u5b50\u5e03\u6599",
  671. "/items/silk_fabric": "\u4e1d\u7ef8",
  672. "/items/radiant_fabric": "\u5149\u8f89\u5e03\u6599",
  673. "/items/egg": "\u9e21\u86cb",
  674. "/items/wheat": "\u5c0f\u9ea6",
  675. "/items/sugar": "\u7cd6",
  676. "/items/blueberry": "\u84dd\u8393",
  677. "/items/blackberry": "\u9ed1\u8393",
  678. "/items/strawberry": "\u8349\u8393",
  679. "/items/mooberry": "\u54de\u6885",
  680. "/items/marsberry": "\u706b\u661f\u6885",
  681. "/items/spaceberry": "\u592a\u7a7a\u6885",
  682. "/items/apple": "\u82f9\u679c",
  683. "/items/orange": "\u6a59\u5b50",
  684. "/items/plum": "\u674e\u5b50",
  685. "/items/peach": "\u6843\u5b50",
  686. "/items/dragon_fruit": "\u706b\u9f99\u679c",
  687. "/items/star_fruit": "\u6768\u6843",
  688. "/items/arabica_coffee_bean": "\u4f4e\u7ea7\u5496\u5561\u8c46",
  689. "/items/robusta_coffee_bean": "\u4e2d\u7ea7\u5496\u5561\u8c46",
  690. "/items/liberica_coffee_bean": "\u9ad8\u7ea7\u5496\u5561\u8c46",
  691. "/items/excelsa_coffee_bean": "\u7279\u7ea7\u5496\u5561\u8c46",
  692. "/items/fieriosa_coffee_bean": "\u706b\u5c71\u5496\u5561\u8c46",
  693. "/items/spacia_coffee_bean": "\u592a\u7a7a\u5496\u5561\u8c46",
  694. "/items/green_tea_leaf": "\u7eff\u8336\u53f6",
  695. "/items/black_tea_leaf": "\u9ed1\u8336\u53f6",
  696. "/items/burble_tea_leaf": "\u7d2b\u8336\u53f6",
  697. "/items/moolong_tea_leaf": "\u54de\u9f99\u8336\u53f6",
  698. "/items/red_tea_leaf": "\u7ea2\u8336\u53f6",
  699. "/items/emp_tea_leaf": "\u865a\u7a7a\u8336\u53f6",
  700. "/items/catalyst_of_coinification": "\u70b9\u91d1\u50ac\u5316\u5242",
  701. "/items/catalyst_of_decomposition": "\u5206\u89e3\u50ac\u5316\u5242",
  702. "/items/catalyst_of_transmutation": "\u8f6c\u5316\u50ac\u5316\u5242",
  703. "/items/prime_catalyst": "\u81f3\u9ad8\u50ac\u5316\u5242",
  704. "/items/snake_fang": "\u86c7\u7259",
  705. "/items/shoebill_feather": "\u9cb8\u5934\u9e73\u7fbd\u6bdb",
  706. "/items/snail_shell": "\u8717\u725b\u58f3",
  707. "/items/crab_pincer": "\u87f9\u94b3",
  708. "/items/turtle_shell": "\u4e4c\u9f9f\u58f3",
  709. "/items/marine_scale": "\u6d77\u6d0b\u9cde\u7247",
  710. "/items/treant_bark": "\u6811\u76ae",
  711. "/items/centaur_hoof": "\u534a\u4eba\u9a6c\u8e44",
  712. "/items/luna_wing": "\u6708\u795e\u7ffc",
  713. "/items/gobo_rag": "\u54e5\u5e03\u6797\u62b9\u5e03",
  714. "/items/goggles": "\u62a4\u76ee\u955c",
  715. "/items/magnifying_glass": "\u653e\u5927\u955c",
  716. "/items/eye_of_the_watcher": "\u89c2\u5bdf\u8005\u4e4b\u773c",
  717. "/items/icy_cloth": "\u51b0\u971c\u7ec7\u7269",
  718. "/items/flaming_cloth": "\u70c8\u7130\u7ec7\u7269",
  719. "/items/sorcerers_sole": "\u9b54\u6cd5\u5e08\u978b\u5e95",
  720. "/items/chrono_sphere": "\u65f6\u7a7a\u7403",
  721. "/items/frost_sphere": "\u51b0\u971c\u7403",
  722. "/items/panda_fluff": "\u718a\u732b\u7ed2",
  723. "/items/black_bear_fluff": "\u9ed1\u718a\u7ed2",
  724. "/items/grizzly_bear_fluff": "\u68d5\u718a\u7ed2",
  725. "/items/polar_bear_fluff": "\u5317\u6781\u718a\u7ed2",
  726. "/items/red_panda_fluff": "\u5c0f\u718a\u732b\u7ed2",
  727. "/items/magnet": "\u78c1\u94c1",
  728. "/items/stalactite_shard": "\u949f\u4e73\u77f3\u788e\u7247",
  729. "/items/living_granite": "\u82b1\u5c97\u5ca9",
  730. "/items/colossus_core": "\u5de8\u50cf\u6838\u5fc3",
  731. "/items/vampire_fang": "\u5438\u8840\u9b3c\u4e4b\u7259",
  732. "/items/werewolf_claw": "\u72fc\u4eba\u4e4b\u722a",
  733. "/items/revenant_anima": "\u4ea1\u8005\u4e4b\u9b42",
  734. "/items/soul_fragment": "\u7075\u9b42\u788e\u7247",
  735. "/items/infernal_ember": "\u5730\u72f1\u4f59\u70ec",
  736. "/items/demonic_core": "\u6076\u9b54\u6838\u5fc3",
  737. "/items/griffin_leather": "\u72ee\u9e6b\u4e4b\u76ae",
  738. "/items/manticore_sting": "\u874e\u72ee\u4e4b\u523a",
  739. "/items/jackalope_antler": "\u9e7f\u89d2\u5154\u4e4b\u89d2",
  740. "/items/dodocamel_plume": "\u6e21\u6e21\u9a7c\u4e4b\u7fce",
  741. "/items/griffin_talon": "\u72ee\u9e6b\u4e4b\u722a",
  742. "/items/acrobats_ribbon": "\u6742\u6280\u5e08\u5f69\u5e26",
  743. "/items/magicians_cloth": "\u9b54\u672f\u5e08\u7ec7\u7269",
  744. "/items/chaotic_chain": "\u6df7\u6c8c\u9501\u94fe",
  745. "/items/cursed_ball": "\u8bc5\u5492\u4e4b\u7403",
  746. "/items/royal_cloth": "\u7687\u5bb6\u7ec7\u7269",
  747. "/items/knights_ingot": "\u9a91\u58eb\u4e4b\u952d",
  748. "/items/bishops_scroll": "\u4e3b\u6559\u5377\u8f74",
  749. "/items/regal_jewel": "\u541b\u738b\u5b9d\u77f3",
  750. "/items/sundering_jewel": "\u88c2\u7a7a\u5b9d\u77f3",
  751. "/items/butter_of_proficiency": "\u7cbe\u901a\u4e4b\u6cb9",
  752. "/items/thread_of_expertise": "\u4e13\u7cbe\u4e4b\u7ebf",
  753. "/items/branch_of_insight": "\u6d1e\u5bdf\u4e4b\u679d",
  754. "/items/gluttonous_energy": "\u8d2a\u98df\u80fd\u91cf",
  755. "/items/guzzling_energy": "\u66b4\u996e\u80fd\u91cf",
  756. "/items/milking_essence": "\u6324\u5976\u7cbe\u534e",
  757. "/items/foraging_essence": "\u91c7\u6458\u7cbe\u534e",
  758. "/items/woodcutting_essence": "\u4f10\u6728\u7cbe\u534e",
  759. "/items/cheesesmithing_essence": "\u5976\u916a\u953b\u9020\u7cbe\u534e",
  760. "/items/crafting_essence": "\u5236\u4f5c\u7cbe\u534e",
  761. "/items/tailoring_essence": "\u7f1d\u7eab\u7cbe\u534e",
  762. "/items/cooking_essence": "\u70f9\u996a\u7cbe\u534e",
  763. "/items/brewing_essence": "\u51b2\u6ce1\u7cbe\u534e",
  764. "/items/alchemy_essence": "\u70bc\u91d1\u7cbe\u534e",
  765. "/items/enhancing_essence": "\u5f3a\u5316\u7cbe\u534e",
  766. "/items/swamp_essence": "\u6cbc\u6cfd\u7cbe\u534e",
  767. "/items/aqua_essence": "\u6d77\u6d0b\u7cbe\u534e",
  768. "/items/jungle_essence": "\u4e1b\u6797\u7cbe\u534e",
  769. "/items/gobo_essence": "\u54e5\u5e03\u6797\u7cbe\u534e",
  770. "/items/eyessence": "\u773c\u7cbe\u534e",
  771. "/items/sorcerer_essence": "\u6cd5\u5e08\u7cbe\u534e",
  772. "/items/bear_essence": "\u718a\u718a\u7cbe\u534e",
  773. "/items/golem_essence": "\u9b54\u50cf\u7cbe\u534e",
  774. "/items/twilight_essence": "\u66ae\u5149\u7cbe\u534e",
  775. "/items/abyssal_essence": "\u5730\u72f1\u7cbe\u534e",
  776. "/items/chimerical_essence": "\u5947\u5e7b\u7cbe\u534e",
  777. "/items/sinister_essence": "\u9634\u68ee\u7cbe\u534e",
  778. "/items/enchanted_essence": "\u79d8\u6cd5\u7cbe\u534e",
  779. "/items/task_crystal": "\u4efb\u52a1\u6c34\u6676",
  780. "/items/star_fragment": "\u661f\u5149\u788e\u7247",
  781. "/items/pearl": "\u73cd\u73e0",
  782. "/items/amber": "\u7425\u73c0",
  783. "/items/garnet": "\u77f3\u69b4\u77f3",
  784. "/items/jade": "\u7fe1\u7fe0",
  785. "/items/amethyst": "\u7d2b\u6c34\u6676",
  786. "/items/moonstone": "\u6708\u4eae\u77f3",
  787. "/items/sunstone": "\u592a\u9633\u77f3",
  788. "/items/philosopher's_stone": "\u8d24\u8005\u4e4b\u77f3",
  789. "/items/crushed_pearl": "\u73cd\u73e0\u788e\u7247",
  790. "/items/crushed_amber": "\u7425\u73c0\u788e\u7247",
  791. "/items/crushed_garnet": "\u77f3\u69b4\u77f3\u788e\u7247",
  792. "/items/crushed_jade": "\u7fe1\u7fe0\u788e\u7247",
  793. "/items/crushed_amethyst": "\u7d2b\u6c34\u6676\u788e\u7247",
  794. "/items/crushed_moonstone": "\u6708\u4eae\u77f3\u788e\u7247",
  795. "/items/crushed_sunstone": "\u592a\u9633\u77f3\u788e\u7247",
  796. "/items/crushed_philosopher's_stone": "\u8d24\u8005\u4e4b\u77f3\u788e\u7247",
  797. "/items/shard_of_protection": "\u4fdd\u62a4\u788e\u7247",
  798. "/items/mirror_of_protection": "\u4fdd\u62a4\u4e4b\u955c"
  799. };
  800. function getEnglishName(itemName) {
  801. return itemName.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
  802. }
  803. function getItemDisplayName(itemName) {
  804. const key = "/items/" + itemName;
  805. const chinese = itemNames[key] || "";
  806. const english = getEnglishName(itemName);
  807. return chinese ? `${chinese} / ${english}` : english;
  808. }
  809. function getColumn(itemName, row) {
  810. const filters = [
  811. itemName => itemName.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '),
  812. itemName => SpecialItemNames[itemName]
  813. ];
  814. for (const filter of filters) {
  815. const column = filter(itemName);
  816. if (row.hasOwnProperty(column)) {
  817. return column;
  818. }
  819. }
  820. }
  821. // 按钮的字儿
  822. const en = {
  823. "show_btn_title": "Price History",
  824. "update_btn_title": "Update Data",
  825. "update_btn_title_downloading": "Update Data (downloading...)",
  826. "update_btn_title_succeeded": "Update Data (succeeded)",
  827. "update_btn_title_failed": "Update Data (failed)"
  828. };
  829. const zh = {
  830. "show_btn_title": "价格走势图",
  831. "update_btn_title": "更新价格数据",
  832. "update_btn_title_downloading": "更新价格数据 (下载中...)",
  833. "update_btn_title_succeeded": "更新价格数据成功",
  834. "update_btn_title_failed": "更新价格数据失败"
  835. };
  836. function loadTranslations() {
  837. const lang = (navigator.language || navigator.userLanguage).substring(0, 2);
  838. return lang === 'zh' ? zh : en;
  839. }
  840. const Strings = loadTranslations();
  841. // IndexedDB 封装类
  842. class LargeLocalStorage {
  843. constructor() {
  844. this.db = null;
  845. this.dbName = 'LargeLocalStorage';
  846. this.storeName = 'data';
  847. }
  848. open() {
  849. return new Promise((resolve, reject) => {
  850. const request = indexedDB.open(this.dbName, 1);
  851. request.onupgradeneeded = (event) => {
  852. const db = event.target.result;
  853. if (!db.objectStoreNames.contains(this.storeName)) {
  854. db.createObjectStore(this.storeName);
  855. }
  856. };
  857. request.onsuccess = (event) => {
  858. this.db = event.target.result;
  859. resolve(this.db);
  860. };
  861. request.onerror = (error) => {
  862. reject(error);
  863. };
  864. });
  865. }
  866. close() {
  867. if (this.db) this.db.close();
  868. }
  869. async setItem(key, value) {
  870. if (!this.db) await this.open();
  871. return new Promise((resolve, reject) => {
  872. const transaction = this.db.transaction(this.storeName, 'readwrite');
  873. const store = transaction.objectStore(this.storeName);
  874. store.put(value, key);
  875. transaction.oncomplete = () => {
  876. resolve();
  877. };
  878. transaction.onerror = (error) => {
  879. reject(error);
  880. };
  881. });
  882. }
  883. async getItem(key) {
  884. if (!this.db) await this.open();
  885. return new Promise((resolve, reject) => {
  886. const transaction = this.db.transaction(this.storeName, 'readonly');
  887. const store = transaction.objectStore(this.storeName);
  888. const getRequest = store.get(key);
  889. getRequest.onsuccess = (event) => {
  890. resolve(event.target.result);
  891. };
  892. getRequest.onerror = (error) => {
  893. reject(error);
  894. };
  895. });
  896. }
  897. }
  898. const storage = new LargeLocalStorage();
  899. // 数据库相关
  900. const dbUrl = 'https://raw.githubusercontent.com/holychikenz/MWIApi/main/market.db';
  901. let worker = null;
  902. let itemName = null;
  903. let myChart = null;
  904. // 全量数据存储:近30天数据
  905. let fullAskData = null;
  906. let fullBidData = null;
  907. function extractItemName(href) {
  908. const match = href.match(/#(.+)$/);
  909. return match ? match[1] : null;
  910. }
  911. // 添加 CSS:统一背景为 #191c2b,文字为白色;手机端全屏时旋转90°并平移
  912. function addCss() {
  913. let modalStyles = `
  914. .modal {
  915. display: none;
  916. position: fixed;
  917. z-index: 9999;
  918. left: 0;
  919. top: 0;
  920. width: 100%;
  921. height: 100%;
  922. overflow: auto;
  923. background-color: rgba(0,0,0,0.8);
  924. display: flex;
  925. align-items: center;
  926. justify-content: center;
  927. }
  928. .modal-content {
  929. background-color: #191c2b;
  930. color: #FFFFFF;
  931. padding: 20px;
  932. border: 1px solid #888;
  933. width: 75%;
  934. position: relative;
  935. }
  936. #timeRangeSelect {
  937. margin-bottom: 10px;
  938. background-color: #191c2b;
  939. color: #FFFFFF;
  940. border: 1px solid #fff;
  941. }
  942. #timeRangeSelect option {
  943. background-color: #191c2b;
  944. color: #FFFFFF;
  945. }
  946. #myChart {
  947. background-color: #191c2b;
  948. }
  949. `;
  950. if (isMobileDevice()) {
  951. modalStyles += `
  952. .modal-content.mobile {
  953. width: 100vh;
  954. height: 100vw;
  955. padding: 10px;
  956. transform: rotate(90deg) translate(0, -100%);
  957. transform-origin: top left;
  958. position: absolute;
  959. top: 0;
  960. left: 0;
  961. }
  962. #closeModalButton {
  963. position: absolute;
  964. top: 10px;
  965. right: 10px;
  966. font-size: 2em;
  967. background: transparent;
  968. border: none;
  969. color: #FFFFFF;
  970. z-index: 100;
  971. }
  972. `;
  973. }
  974. GM_addStyle(modalStyles);
  975. }
  976. // 创建弹窗;手机端时添加 .mobile 类和右上角关闭按钮
  977. function createModal() {
  978. const modal = document.createElement('div');
  979. modal.id = 'myModal';
  980. modal.className = 'modal';
  981. modal.style.display = 'none';
  982. modal.onclick = function () {
  983. modal.style.display = 'none';
  984. destroyChart();
  985. };
  986. const modalContent = document.createElement('div');
  987. modalContent.className = 'modal-content';
  988. if (isMobileDevice()) {
  989. modalContent.classList.add('mobile');
  990. const closeBtn = document.createElement('button');
  991. closeBtn.id = 'closeModalButton';
  992. closeBtn.textContent = '✕';
  993. closeBtn.onclick = function (e) {
  994. e.stopPropagation();
  995. modal.style.display = 'none';
  996. destroyChart();
  997. };
  998. modalContent.appendChild(closeBtn);
  999. }
  1000. modalContent.onclick = function (e) {
  1001. e.stopPropagation();
  1002. };
  1003. // 下拉菜单
  1004. const timeRangeSelect = document.createElement('select');
  1005. timeRangeSelect.id = 'timeRangeSelect';
  1006. const ranges = [
  1007. { value: '1', text: '1天' },
  1008. { value: '3', text: '3天' },
  1009. { value: '7', text: '7天' },
  1010. { value: '14', text: '14天' },
  1011. { value: '30', text: '30天' }
  1012. ];
  1013. ranges.forEach(opt => {
  1014. const option = document.createElement('option');
  1015. option.value = opt.value;
  1016. option.textContent = opt.text;
  1017. timeRangeSelect.appendChild(option);
  1018. });
  1019. timeRangeSelect.addEventListener('change', () => {
  1020. const days = parseInt(timeRangeSelect.value);
  1021. saveRangeSetting(timeRangeSelect.value);
  1022. updateChartFromStoredData(days);
  1023. });
  1024. modalContent.appendChild(timeRangeSelect);
  1025. // 物品名称显示区域
  1026. const itemNameDisplay = document.createElement('span');
  1027. itemNameDisplay.id = 'itemNameDisplay';
  1028. itemNameDisplay.style.marginLeft = '10px';
  1029. itemNameDisplay.style.fontWeight = 'bold';
  1030. itemNameDisplay.textContent = '';
  1031. modalContent.appendChild(itemNameDisplay);
  1032. // canvas 用于绘图
  1033. const chartCanvas = document.createElement('canvas');
  1034. chartCanvas.id = 'myChart';
  1035. modalContent.appendChild(chartCanvas);
  1036. modal.appendChild(modalContent);
  1037. document.body.appendChild(modal);
  1038. return modal;
  1039. }
  1040. function destroyChart() {
  1041. if (myChart) {
  1042. myChart.destroy();
  1043. myChart = null;
  1044. }
  1045. }
  1046. // 计算全局趋势线参数(基于30日全量合并数据)
  1047. function computeGlobalTrendline(fullData, column) {
  1048. const n = fullData.length;
  1049. if (n === 0) return { slope: 0, intercept: 0 };
  1050. let sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
  1051. fullData.forEach(point => {
  1052. const x = new Date(point.time * 1000).getTime();
  1053. const y = (point.bid_price != null) ? ((point.ask_price + point.bid_price) / 2) : point.ask_price;
  1054. sumX += x;
  1055. sumY += y;
  1056. sumXY += x * y;
  1057. sumX2 += x * x;
  1058. });
  1059. const meanX = sumX / n;
  1060. const meanY = sumY / n;
  1061. const slope = (sumXY - n * meanX * meanY) / (sumX2 - n * meanX * meanX);
  1062. const intercept = meanY - slope * meanX;
  1063. return { slope, intercept };
  1064. }
  1065. // 数据清洗逻辑:遍历合并数据,置 0 为 null;若价格异常(>2.5×或<0.6×前一个有效值且与趋势预测值也异常),则替换为前值
  1066. function cleanData(mergedData, globalTrend, avgVal) {
  1067. mergedData.sort((a, b) => a.time - b.time);
  1068. let cleaned = [];
  1069. let prevAsk = null, prevBid = null;
  1070. mergedData.forEach(point => {
  1071. let newAsk = point.ask_price;
  1072. let newBid = point.bid_price;
  1073. if (newAsk === 0) newAsk = null;
  1074. if (newBid === 0) newBid = null;
  1075. const t = new Date(point.time * 1000).getTime();
  1076. const trendVal = globalTrend.slope * t + globalTrend.intercept;
  1077. if (newAsk == null) {
  1078. newAsk = prevAsk;
  1079. } else if (prevAsk != null) {
  1080. if ((newAsk > 2.5 * prevAsk || newAsk < 0.6 * prevAsk) &&
  1081. (newAsk > 2.5 * trendVal || newAsk < 0.6 * trendVal)) {
  1082. newAsk = prevAsk;
  1083. }
  1084. }
  1085. if (newAsk != null) prevAsk = newAsk;
  1086. if (newBid == null) {
  1087. newBid = prevBid;
  1088. } else if (prevBid != null) {
  1089. if ((newBid > 2.5 * prevBid || newBid < 0.6 * prevBid) &&
  1090. (newBid > 2.5 * trendVal || newBid < 0.6 * trendVal)) {
  1091. newBid = prevBid;
  1092. }
  1093. }
  1094. if (newBid != null) prevBid = newBid;
  1095. cleaned.push({ time: point.time, ask_price: newAsk, bid_price: newBid });
  1096. });
  1097. return cleaned;
  1098. }
  1099. // 根据所选天数过滤数据、清洗、并绘制图表
  1100. async function updateChartFromStoredData(days) {
  1101. try {
  1102. const currentTime = Math.floor(Date.now() / 1000);
  1103. const timeFilter = currentTime - (days * 24 * 60 * 60);
  1104. const filteredAsk = fullAskData.filter(row => row.time >= timeFilter);
  1105. const filteredBid = fullBidData.filter(row => row.time >= timeFilter);
  1106. const column = getColumn(itemName, filteredAsk[0]);
  1107. if (!column) {
  1108. alert('Invalid itemName');
  1109. return;
  1110. }
  1111. let mergedData = filteredAsk.map(askRow => {
  1112. const bidRow = filteredBid.find(b => b.time === askRow.time);
  1113. return { time: askRow.time, ask_price: askRow[column], bid_price: bidRow ? bidRow[column] : null };
  1114. });
  1115. let globalMergedData = fullAskData.map(askRow => {
  1116. const bidRow = fullBidData.find(b => b.time === askRow.time);
  1117. return { time: askRow.time, ask_price: askRow[column], bid_price: bidRow ? bidRow[column] : null };
  1118. });
  1119. let askValuesAll = globalMergedData.map(row => row.ask_price).filter(v => v !== 0 && v != null);
  1120. let bidValuesAll = globalMergedData.map(row => row.bid_price).filter(v => v !== 0 && v != null);
  1121. const avgAsk = askValuesAll.reduce((s, v) => s + v, 0) / askValuesAll.length;
  1122. const avgBid = bidValuesAll.reduce((s, v) => s + v, 0) / bidValuesAll.length;
  1123. const avgCombined = (avgAsk + avgBid) / 2;
  1124. const globalTrend = computeGlobalTrendline(globalMergedData, column);
  1125. const cleanedData = cleanData(mergedData, globalTrend, avgCombined);
  1126. renderChart(cleanedData, days);
  1127. } catch (error) {
  1128. alert('Error updating chart');
  1129. }
  1130. }
  1131. // 计算趋势线(基于清洗后数据),采用线性回归
  1132. function computeTrendline(data) {
  1133. const n = data.length;
  1134. if (n === 0) return null;
  1135. let sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
  1136. data.forEach(point => {
  1137. const x = new Date(point.time * 1000).getTime();
  1138. const y = (point.bid_price != null) ? ((point.ask_price + point.bid_price) / 2) : point.ask_price;
  1139. sumX += x;
  1140. sumY += y;
  1141. sumXY += x * y;
  1142. sumX2 += x * x;
  1143. });
  1144. const meanX = sumX / n;
  1145. const meanY = sumY / n;
  1146. const slope = (sumXY - n * meanX * meanY) / (sumX2 - n * meanX * meanX);
  1147. const intercept = meanY - slope * meanX;
  1148. const firstTime = new Date(data[0].time * 1000).getTime();
  1149. const lastTime = new Date(data[n - 1].time * 1000).getTime();
  1150. return [
  1151. { x: firstTime, y: slope * firstTime + intercept },
  1152. { x: lastTime, y: slope * lastTime + intercept }
  1153. ];
  1154. }
  1155. // 绘制图表,并添加 MA(5) 与趋势线;同时加载用户记录的图例显示状态
  1156. function renderChart(data, days) {
  1157. if (!document.getElementById('myModal')) {
  1158. addCss();
  1159. createModal();
  1160. }
  1161. const modal = document.getElementById('myModal');
  1162. modal.style.display = 'flex';
  1163. const itemDisplayElem = document.getElementById('itemNameDisplay');
  1164. if (itemDisplayElem && itemName) {
  1165. itemDisplayElem.textContent = getItemDisplayName(itemName);
  1166. }
  1167. const times = data.map(row => new Date(row.time * 1000));
  1168. const askPrices = data.map(row => row.ask_price);
  1169. const bidPrices = data.map(row => row.bid_price);
  1170. const baseValues = data.map(row => (row.bid_price != null) ? ((row.ask_price + row.bid_price) / 2) : row.ask_price);
  1171. const maValues = [];
  1172. const windowSize = 5;
  1173. for (let i = 0; i < baseValues.length; i++) {
  1174. if (i < windowSize - 1) {
  1175. maValues.push(null);
  1176. } else {
  1177. let sum = 0, count = 0;
  1178. for (let j = i - windowSize + 1; j <= i; j++) {
  1179. if (baseValues[j] != null) {
  1180. sum += baseValues[j];
  1181. count++;
  1182. }
  1183. }
  1184. maValues.push(count > 0 ? sum / count : null);
  1185. }
  1186. }
  1187. const trendlineData = computeTrendline(data);
  1188. const ctx = document.getElementById('myChart').getContext('2d');
  1189. let timeUnit, timeFormat;
  1190. if (days <= 3) {
  1191. timeUnit = 'hour';
  1192. timeFormat = 'HH:mm';
  1193. } else {
  1194. timeUnit = 'day';
  1195. timeFormat = 'MM/dd';
  1196. }
  1197. const visibility = loadDatasetVisibility();
  1198. destroyChart();
  1199. myChart = new Chart(ctx, {
  1200. type: 'line',
  1201. data: {
  1202. labels: times,
  1203. datasets: [
  1204. {
  1205. label: '卖一价 Ask',
  1206. data: askPrices,
  1207. borderColor: 'rgba(255, 99, 132, 1)',
  1208. fill: false,
  1209. hidden: !visibility.ask
  1210. },
  1211. {
  1212. label: '买一价 Bid',
  1213. data: bidPrices,
  1214. borderColor: 'rgba(54, 162, 235, 1)',
  1215. fill: false,
  1216. hidden: !visibility.bid
  1217. },
  1218. {
  1219. label: '移动平均价',
  1220. data: maValues,
  1221. borderColor: 'rgba(75, 192, 192, 1)',
  1222. fill: false,
  1223. pointRadius: 0,
  1224. hidden: !visibility.ma
  1225. },
  1226. {
  1227. label: '趋势线',
  1228. data: trendlineData,
  1229. borderColor: 'orange',
  1230. fill: false,
  1231. borderDash: [5, 5],
  1232. pointRadius: 0,
  1233. hidden: !visibility.trend
  1234. }
  1235. ]
  1236. },
  1237. options: {
  1238. responsive: true,
  1239. scales: {
  1240. x: {
  1241. type: 'time',
  1242. time: {
  1243. unit: timeUnit,
  1244. tooltipFormat: timeFormat,
  1245. displayFormats: { hour: 'HH:mm', day: 'MM/dd' }
  1246. },
  1247. title: { display: false },
  1248. grid: { color: "rgba(255,255,255,0.2)" },
  1249. ticks: { color: "#FFFFFF" }
  1250. },
  1251. y: {
  1252. title: { display: true, text: '价格', color: "#FFFFFF" },
  1253. grid: { color: "rgba(255,255,255,0.2)" },
  1254. ticks: { color: "#FFFFFF" }
  1255. }
  1256. },
  1257. plugins: {
  1258. tooltip: { mode: 'interpolate', intersect: false, bodyColor: "#FFFFFF", titleColor: "#FFFFFF" },
  1259. crosshair: { line: { color: '#ff6666', width: 1 } },
  1260. legend: {
  1261. display: true,
  1262. labels: { color: "#FFFFFF" },
  1263. onClick: function (e, legendItem, legend) {
  1264. Chart.defaults.plugins.legend.onClick(e, legendItem, legend);
  1265. const ci = legend.chart;
  1266. const newVisibility = {
  1267. ask: !ci.getDatasetMeta(0).hidden,
  1268. bid: !ci.getDatasetMeta(1).hidden,
  1269. ma: !ci.getDatasetMeta(2).hidden,
  1270. trend: !ci.getDatasetMeta(3).hidden
  1271. };
  1272. saveDatasetVisibility(newVisibility);
  1273. ci.update();
  1274. }
  1275. }
  1276. }
  1277. }
  1278. });
  1279. }
  1280. // 显示图表弹窗(默认使用保存的日期范围,如果无则为3天)
  1281. async function showPopup() {
  1282. if (!document.getElementById('myModal')) {
  1283. addCss();
  1284. createModal();
  1285. }
  1286. const timeRangeSelect = document.getElementById('timeRangeSelect');
  1287. if (!timeRangeSelect) {
  1288. return;
  1289. }
  1290. timeRangeSelect.value = loadRangeSetting();
  1291. fullAskData = await storage.getItem(MWI_DATA_ASK);
  1292. fullBidData = await storage.getItem(MWI_DATA_BID);
  1293. if (!fullAskData || !fullBidData) {
  1294. alert('请先更新市场数据');
  1295. return;
  1296. }
  1297. const days = parseInt(timeRangeSelect.value);
  1298. updateChartFromStoredData(days);
  1299. }
  1300. // 更新数据:获取近30日数据(约720条)
  1301. async function updateData() {
  1302. if (!worker) {
  1303. return;
  1304. }
  1305. const updateBtn = document.querySelector('button.updateDataBtn');
  1306. if (updateBtn) {
  1307. updateBtn.disabled = true;
  1308. updateBtn.textContent = Strings.update_btn_title_downloading;
  1309. }
  1310. const timeFilter = Math.floor(Date.now() / 1000) - (30 * 24 * 60 * 60);
  1311. try {
  1312. const query1 = `SELECT * FROM ask a WHERE a.time >= ?`;
  1313. const ask = await worker.db.query(query1, [timeFilter]);
  1314. await storage.setItem(MWI_DATA_ASK, ask);
  1315. const query2 = `SELECT * FROM bid b WHERE b.time >= ?`;
  1316. const bid = await worker.db.query(query2, [timeFilter]);
  1317. await storage.setItem(MWI_DATA_BID, bid);
  1318. fullAskData = ask;
  1319. fullBidData = bid;
  1320. if (updateBtn) {
  1321. updateBtn.textContent = Strings.update_btn_title_succeeded;
  1322. updateBtn.disabled = false;
  1323. }
  1324. } catch (error) {
  1325. if (updateBtn) {
  1326. updateBtn.textContent = Strings.update_btn_title_failed;
  1327. updateBtn.disabled = false;
  1328. }
  1329. }
  1330. }
  1331. // MutationObserver:监听当前物品节点变化,更新 itemName
  1332. function handleCurrentItemNode(mutationsList) {
  1333. for (let mutation of mutationsList) {
  1334. if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  1335. mutation.addedNodes.forEach(node => {
  1336. if (node.classList && [...node.classList].some(c => c.startsWith('MarketplacePanel_currentItem'))) {
  1337. const useElement = node.querySelector('use');
  1338. if (useElement) {
  1339. itemName = extractItemName(useElement.getAttribute('href'));
  1340. }
  1341. }
  1342. });
  1343. }
  1344. }
  1345. }
  1346. // MutationObserver:监听市场按钮容器,添加“价格走势图”与“更新价格数据”按钮
  1347. function handleMarketNavButtonContainerNode(mutationsList) {
  1348. for (let mutation of mutationsList) {
  1349. if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  1350. mutation.addedNodes.forEach(node => {
  1351. if (node.classList && [...node.classList].some(c => c.startsWith('MarketplacePanel_marketNavButtonContainer'))) {
  1352. const buttons = node.querySelectorAll('button');
  1353. if (buttons.length > 0) {
  1354. const lastButton = buttons[buttons.length - 1];
  1355. const showButton = lastButton.cloneNode(true);
  1356. showButton.textContent = Strings.show_btn_title;
  1357. showButton.onclick = showPopup;
  1358. node.appendChild(showButton);
  1359. const updateButton = lastButton.cloneNode(true);
  1360. updateButton.textContent = Strings.update_btn_title;
  1361. updateButton.classList.add('updateDataBtn');
  1362. updateButton.onclick = function () {
  1363. updateData();
  1364. };
  1365. node.appendChild(updateButton);
  1366. }
  1367. }
  1368. });
  1369. }
  1370. }
  1371. }
  1372. async function createWorker() {
  1373. const workerUrl = GM_getResourceURL("worker");
  1374. const wasmUrl = GM_getResourceURL("wasm");
  1375. const config = {
  1376. from: "inline",
  1377. config: {
  1378. serverMode: "full",
  1379. url: dbUrl,
  1380. requestChunkSize: 4096,
  1381. },
  1382. };
  1383. worker = await createDbWorker([config], workerUrl, wasmUrl);
  1384. }
  1385. function initializeObservers() {
  1386. const targetNode = document.querySelector('div[class*="MarketplacePanel_marketListings"]');
  1387. if (targetNode) {
  1388. const observerCurrentItem = new MutationObserver(handleCurrentItemNode);
  1389. const observerMarketNavButtonContainer = new MutationObserver(handleMarketNavButtonContainerNode);
  1390. observerCurrentItem.observe(targetNode, { childList: true, subtree: true });
  1391. observerMarketNavButtonContainer.observe(targetNode, { childList: true, subtree: true });
  1392. } else {
  1393. setTimeout(initializeObservers, 1000);
  1394. }
  1395. }
  1396. // 初始化:启动 MutationObserver 与 Worker
  1397. initializeObservers();
  1398. createWorker();
  1399. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址