api.js 8.6 KB

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