api.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. "use strict";
  2. const common_vendor = require("../common/vendor.js");
  3. const ENV = "prod";
  4. const CONFIG = {
  5. dev: "http://localhost:8081",
  6. // 开发环境
  7. local: "http://192.168.1.171:8081",
  8. prod: "https://www.whzhangsheng.cn/applet-api"
  9. // 生产环境
  10. };
  11. const BASE_URL = CONFIG[ENV];
  12. const getImageUrl = (url) => {
  13. if (!url)
  14. return "";
  15. if (url.startsWith("wxfile://") || url.startsWith("http://tmp/") || url.includes("/tmp/wx")) {
  16. console.warn("[getImageUrl] 检测到微信临时路径,无法显示:", url);
  17. return "";
  18. }
  19. if (url.startsWith("http")) {
  20. return url;
  21. }
  22. if (url.startsWith("/static/images/")) {
  23. return BASE_URL + url.replace("/static/images/", "/images/");
  24. }
  25. return BASE_URL + url;
  26. };
  27. const getToken = () => {
  28. return common_vendor.index.getStorageSync("user_token") || null;
  29. };
  30. const request = (options) => {
  31. return new Promise((resolve, reject) => {
  32. const token = getToken();
  33. const header = options.header || {};
  34. if (token) {
  35. header["Authorization"] = `Bearer ${token}`;
  36. }
  37. const publicApis = [
  38. "/v1/stock/pool/list",
  39. "/v1/order/config"
  40. ];
  41. const isPublicApi = publicApis.some((api) => options.url.includes(api));
  42. common_vendor.index.request({
  43. url: `${BASE_URL}${options.url}`,
  44. method: options.method || "GET",
  45. data: options.data || {},
  46. header,
  47. success: (res) => {
  48. const newToken = res.header["New-Token"] || res.header["new-token"];
  49. if (newToken) {
  50. console.log("检测到新token,自动续期");
  51. common_vendor.index.setStorageSync("user_token", newToken);
  52. }
  53. if (res.statusCode === 200) {
  54. resolve(res.data);
  55. } else if (res.statusCode === 401) {
  56. if (isPublicApi) {
  57. reject(new Error("未授权"));
  58. return;
  59. }
  60. common_vendor.index.showToast({
  61. title: "登录已过期,请重新登录",
  62. icon: "none",
  63. duration: 2e3
  64. });
  65. common_vendor.index.removeStorageSync("user_token");
  66. common_vendor.index.removeStorageSync("user_info");
  67. setTimeout(() => {
  68. common_vendor.index.showModal({
  69. title: "登录提示",
  70. content: "登录已过期,请重新登录",
  71. confirmText: "去登录",
  72. cancelText: "取消",
  73. success: (modalRes) => {
  74. if (modalRes.confirm) {
  75. common_vendor.index.navigateTo({
  76. url: "/pages/login/login"
  77. });
  78. }
  79. }
  80. });
  81. }, 2e3);
  82. reject(new Error("未授权"));
  83. } else {
  84. reject(new Error(res.data.message || "服务暂不可用"));
  85. }
  86. },
  87. fail: () => {
  88. reject(new Error("网络异常"));
  89. }
  90. });
  91. });
  92. };
  93. const wxSilentLoginApi = (params) => {
  94. return request({
  95. url: "/v1/auth/wx/silent-login",
  96. method: "POST",
  97. header: {
  98. "content-type": "application/json"
  99. },
  100. data: params
  101. });
  102. };
  103. const wxPhoneLoginApi = (params) => {
  104. return request({
  105. url: "/v1/auth/wx/phone-verify",
  106. method: "POST",
  107. header: {
  108. "content-type": "application/json"
  109. },
  110. data: params
  111. });
  112. };
  113. const wxCompleteUserInfoApi = (params) => {
  114. return request({
  115. url: "/v1/auth/wx/register",
  116. method: "POST",
  117. header: {
  118. "content-type": "application/json"
  119. },
  120. data: params
  121. });
  122. };
  123. const getUserInfoApi = () => {
  124. return request({
  125. url: "/v1/user/info",
  126. method: "GET"
  127. });
  128. };
  129. const uploadFile = {
  130. url: `${BASE_URL}/v1/file/upload`
  131. };
  132. const updateUserProfile = (data) => {
  133. return request({
  134. url: "/v1/user/profile",
  135. method: "PUT",
  136. header: {
  137. "content-type": "application/json"
  138. },
  139. data
  140. });
  141. };
  142. const getSuggestions = (keyword) => {
  143. return request({
  144. url: "/v1/stock/suggestion",
  145. method: "GET",
  146. data: { keyword }
  147. });
  148. };
  149. const searchStocks = (keyword) => {
  150. return request({
  151. url: "/v1/stock/search",
  152. method: "POST",
  153. header: {
  154. "content-type": "application/json"
  155. },
  156. data: { keyword }
  157. });
  158. };
  159. const getStockQuotes = (codes) => {
  160. return request({
  161. url: "/api/stock/fetch",
  162. method: "GET",
  163. data: { codes }
  164. });
  165. };
  166. const getIndexQuote = (code) => {
  167. return request({
  168. url: "/api/stock/index",
  169. method: "GET",
  170. data: { code }
  171. });
  172. };
  173. const getUserStocks = () => {
  174. return request({
  175. url: "/v1/user/stock/list",
  176. method: "GET"
  177. });
  178. };
  179. const addUserStock = (data) => {
  180. return request({
  181. url: "/v1/user/stock/add",
  182. method: "POST",
  183. header: {
  184. "content-type": "application/json"
  185. },
  186. data
  187. });
  188. };
  189. const deleteUserStock = (stockCode) => {
  190. return request({
  191. url: `/v1/user/stock/delete?stockCode=${encodeURIComponent(stockCode)}`,
  192. method: "DELETE"
  193. });
  194. };
  195. const getStockPoolList = (poolType) => {
  196. return request({
  197. url: "/v1/stock/pool/list",
  198. method: "GET",
  199. data: { poolType }
  200. });
  201. };
  202. const getPaymentConfig = (poolType) => {
  203. return request({
  204. url: "/v1/order/config",
  205. method: "GET",
  206. data: { poolType }
  207. });
  208. };
  209. const createOrder = (data) => {
  210. return request({
  211. url: "/v1/order/create",
  212. method: "POST",
  213. header: {
  214. "content-type": "application/json"
  215. },
  216. data
  217. });
  218. };
  219. const queryOrder = (orderNo) => {
  220. return request({
  221. url: "/v1/order/query",
  222. method: "GET",
  223. data: { orderNo }
  224. });
  225. };
  226. const getUserOrders = () => {
  227. return request({
  228. url: "/v1/order/list",
  229. method: "GET"
  230. });
  231. };
  232. const repayOrder = (orderNo) => {
  233. return request({
  234. url: `/v1/order/repay?orderNo=${encodeURIComponent(orderNo)}`,
  235. method: "POST"
  236. });
  237. };
  238. const checkSubscription = (poolType) => {
  239. return request({
  240. url: "/v1/order/check-subscription",
  241. method: "GET",
  242. data: { poolType }
  243. });
  244. };
  245. const wxPay = (payParams) => {
  246. const totalFee = payParams.total_fee || payParams.totalFee;
  247. console.log("调起支付,参数:", JSON.stringify(payParams), "totalFee:", totalFee);
  248. if (!totalFee) {
  249. console.error("缺少 total_fee 参数,payParams:", payParams);
  250. }
  251. return new Promise((resolve, reject) => {
  252. common_vendor.index.requestPayment({
  253. provider: "wxpay",
  254. timeStamp: payParams.timeStamp,
  255. nonceStr: payParams.nonceStr,
  256. package: payParams.packageValue,
  257. signType: payParams.signType,
  258. paySign: payParams.paySign,
  259. totalFee,
  260. // 开发者工具模拟支付需要
  261. success: (res) => {
  262. resolve(res);
  263. },
  264. fail: (err) => {
  265. console.log("支付失败:", err);
  266. if (err.errMsg && err.errMsg.includes("cancel")) {
  267. reject(new Error("用户取消支付"));
  268. } else {
  269. reject(new Error("支付失败:" + (err.errMsg || JSON.stringify(err))));
  270. }
  271. }
  272. });
  273. });
  274. };
  275. const getStockHistory = (params) => {
  276. return request({
  277. url: "/v1/stock/history/list",
  278. method: "GET",
  279. data: params
  280. });
  281. };
  282. const getStockHistoryStats = (params) => {
  283. return request({
  284. url: "/v1/stock/history/stats",
  285. method: "GET",
  286. data: params
  287. });
  288. };
  289. const searchStockHistory = (keyword, recordDate) => {
  290. const data = { keyword };
  291. if (recordDate) {
  292. data.recordDate = recordDate;
  293. }
  294. return request({
  295. url: "/v1/stock/history/search",
  296. method: "GET",
  297. data
  298. });
  299. };
  300. const submitFeedback = (data) => {
  301. console.log("[submitFeedback] 开始提交反馈,数据:", data);
  302. return request({
  303. url: "/v1/user/feedback/submit",
  304. method: "POST",
  305. header: {
  306. "content-type": "application/json"
  307. },
  308. data
  309. });
  310. };
  311. const uploadFeedbackImage = {
  312. url: `${BASE_URL}/v1/file/upload`
  313. };
  314. exports.BASE_URL = BASE_URL;
  315. exports.addUserStock = addUserStock;
  316. exports.checkSubscription = checkSubscription;
  317. exports.createOrder = createOrder;
  318. exports.deleteUserStock = deleteUserStock;
  319. exports.getImageUrl = getImageUrl;
  320. exports.getIndexQuote = getIndexQuote;
  321. exports.getPaymentConfig = getPaymentConfig;
  322. exports.getStockHistory = getStockHistory;
  323. exports.getStockHistoryStats = getStockHistoryStats;
  324. exports.getStockPoolList = getStockPoolList;
  325. exports.getStockQuotes = getStockQuotes;
  326. exports.getSuggestions = getSuggestions;
  327. exports.getUserInfoApi = getUserInfoApi;
  328. exports.getUserOrders = getUserOrders;
  329. exports.getUserStocks = getUserStocks;
  330. exports.queryOrder = queryOrder;
  331. exports.repayOrder = repayOrder;
  332. exports.searchStockHistory = searchStockHistory;
  333. exports.searchStocks = searchStocks;
  334. exports.submitFeedback = submitFeedback;
  335. exports.updateUserProfile = updateUserProfile;
  336. exports.uploadFeedbackImage = uploadFeedbackImage;
  337. exports.uploadFile = uploadFile;
  338. exports.wxCompleteUserInfoApi = wxCompleteUserInfoApi;
  339. exports.wxPay = wxPay;
  340. exports.wxPhoneLoginApi = wxPhoneLoginApi;
  341. exports.wxSilentLoginApi = wxSilentLoginApi;