base.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // 基础服务 - 对应 supermart-mini/service/base.js
  2. import { Platform } from "react-native";
  3. import { get, getToken, post } from "./http";
  4. const apis = {
  5. PAGE_CONFIG: "/api/app/page/getByPageId",
  6. MESSAGE: "/api/app/message",
  7. TRACK: "/api/track",
  8. FEEDBACK: "/api/app/feedback/submit",
  9. PARAM_CONFIG: "/param/paramConfig",
  10. };
  11. export interface BannerItem {
  12. id: string;
  13. cover: string;
  14. path?: { url: string };
  15. }
  16. export interface TabItem {
  17. title: string;
  18. cover: string;
  19. path?: { url: string };
  20. }
  21. export interface PageConfig {
  22. components: Array<{
  23. elements: any[];
  24. }>;
  25. }
  26. // 获取页面配置
  27. export const getPageConfig = async (
  28. pageId: string,
  29. ): Promise<PageConfig | null> => {
  30. const res = await get<PageConfig>(apis.PAGE_CONFIG, { pageId });
  31. return res.data;
  32. };
  33. // 获取消息列表
  34. export const getMessages = async (
  35. current: number,
  36. size: number,
  37. type?: string,
  38. ) => {
  39. const params: any = { current, size };
  40. if (type) params.type = type;
  41. const res = await get(apis.MESSAGE, params);
  42. return res.success ? res.data : null;
  43. };
  44. // 获取消息列表(分页)
  45. export const getMessageList = async (
  46. current: number,
  47. size: number,
  48. type?: string,
  49. ) => {
  50. const params: any = { current, size };
  51. if (type) params.type = type;
  52. const res = await get(apis.MESSAGE, params);
  53. return res.success ? res.data : { records: [], total: 0 };
  54. };
  55. // 获取参数配置
  56. export const getParamConfig = async (code: string) => {
  57. const res = await get(apis.PARAM_CONFIG, { code });
  58. return res.data;
  59. };
  60. // 提交反馈
  61. export const submitFeedback = async (data: any) => {
  62. const res = await post(apis.FEEDBACK, data);
  63. return res.data;
  64. };
  65. // 追踪
  66. export const track = async () => {
  67. const res = await get(apis.TRACK);
  68. return res.data;
  69. };
  70. // 上传文件
  71. export const uploadFile = async (
  72. fileUri: string,
  73. folder = "avatar",
  74. ): Promise<string | null> => {
  75. try {
  76. // iOS ImagePicker 可能返回各种格式的路径,统一处理
  77. let processedUri = decodeURI(fileUri);
  78. if (Platform.OS === "ios") {
  79. // 确保有 file:// 前缀
  80. if (!processedUri.startsWith("file://") && !processedUri.startsWith("http")) {
  81. processedUri = `file://${processedUri}`;
  82. }
  83. }
  84. const formData = new FormData();
  85. // 获取文件名
  86. const fileName = processedUri.split("/").pop() || `avatar_${Date.now()}.jpg`;
  87. // 创建文件对象 (React Native 格式)
  88. const fileObj = {
  89. uri: processedUri,
  90. type: "image/jpeg",
  91. name: fileName,
  92. } as any;
  93. formData.append("file", fileObj);
  94. formData.append("appId", "supermart-acetoys");
  95. formData.append("folder", folder);
  96. // 获取 token
  97. const token = getToken();
  98. console.log("[uploadFile] token:", token ? "有" : "无", "uri:", processedUri.substring(0, 50));
  99. // 构建 track header(与 Vue 原项目 http.js 一致)
  100. const track = JSON.stringify({
  101. os: Platform.OS === "ios" ? 5 : 6,
  102. version: "1.0.5",
  103. deviceCode: "",
  104. bundleId: "com.wonderful.mart",
  105. channel: "wonderful",
  106. });
  107. const response = await fetch("https://mm.acefig.com/api/oss/file/upload", {
  108. method: "POST",
  109. headers: {
  110. // 不设置 Content-Type,让 fetch 自动处理 multipart/form-data 边界
  111. Authentication: token || "",
  112. track: track,
  113. },
  114. body: formData,
  115. });
  116. console.log("[uploadFile] 响应状态:", response.status);
  117. // 检查响应状态
  118. if (!response.ok) {
  119. const errorText = await response.text();
  120. console.error("[uploadFile] 上传失败 状态:", response.status, "内容:", errorText);
  121. return null;
  122. }
  123. const text = await response.text();
  124. console.log("[uploadFile] 响应内容:", text?.substring(0, 200));
  125. if (!text) {
  126. console.error("[uploadFile] 上传响应为空");
  127. return null;
  128. }
  129. const result = JSON.parse(text);
  130. // code 可能是数字或字符串
  131. if ((result.code === 0 || result.code === "0") && result.data?.url) {
  132. console.log("[uploadFile] 成功:", result.data.url);
  133. return result.data.url;
  134. }
  135. console.error("[uploadFile] 上传返回错误:", JSON.stringify(result));
  136. return null;
  137. } catch (error) {
  138. console.error("[uploadFile] 上传文件异常:", error);
  139. return null;
  140. }
  141. };
  142. export default {
  143. getPageConfig,
  144. getMessages,
  145. getMessageList,
  146. getParamConfig,
  147. submitFeedback,
  148. track,
  149. uploadFile,
  150. };