index.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import { config } from "../../config";
  2. import { service } from "../service";
  3. import { basename, extname, filename, parse, parseObject, pathJoin, uuid } from "../utils";
  4. import { useStore } from "../store";
  5. // 上传进度回调结果类型
  6. export type OnProgressUpdateResult = {
  7. progress: number;
  8. totalBytesSent: number;
  9. totalBytesExpectedToSend: number;
  10. };
  11. // 上传任务类型定义
  12. export type UploadTask = {
  13. abort(): void;
  14. };
  15. // 上传选项类型定义
  16. export type UploadOptions = {
  17. onProgressUpdate?: (result: OnProgressUpdateResult) => void; // 上传进度回调
  18. onTask?: (task: UploadTask) => void; // 上传任务回调
  19. };
  20. // 上传模式类型
  21. export type UploadMode = {
  22. mode: "local" | "cloud"; // 上传模式:本地或云端
  23. type: string; // 云服务类型
  24. };
  25. // 上传请求的参数类型
  26. export type UploadRequestOptions = {
  27. url: string;
  28. preview?: string;
  29. data: any;
  30. };
  31. // 云上传返回数据类型
  32. export type CloudUploadResponse = {
  33. uploadUrl?: string;
  34. url?: string;
  35. host?: string;
  36. credentials?: any;
  37. OSSAccessKeyId?: string;
  38. policy?: string;
  39. signature?: string;
  40. publicDomain?: string;
  41. token?: string;
  42. fields?: any;
  43. };
  44. // 本地上传返回数据类型
  45. export type LocalUploadResponse = {
  46. code: number;
  47. message?: string;
  48. data: string;
  49. };
  50. // 获取上传模式(本地/云端及云类型)
  51. async function getUploadMode(): Promise<UploadMode> {
  52. const res = await service.base.comm.uploadMode({});
  53. return parse<UploadMode>(res)!;
  54. }
  55. /**
  56. * 路径上传
  57. * @param path 文件路径
  58. */
  59. export async function upload(path: string) {
  60. return uploadFile({
  61. path,
  62. size: 0,
  63. name: "",
  64. type: "image/png"
  65. });
  66. }
  67. /**
  68. * 文件上传
  69. * @param file 文件信息 ChooseImageTempFile
  70. * @param options 上传选项
  71. */
  72. export async function uploadFile(
  73. file: ChooseImageTempFile,
  74. options: UploadOptions | null = null
  75. ): Promise<string> {
  76. const { user } = useStore();
  77. // 获取上传模式和类型
  78. const { mode, type } = await getUploadMode();
  79. // 判断是否本地上传
  80. const isLocal = mode == "local";
  81. // 判断是否是云上传
  82. const isCloud = mode == "cloud";
  83. // 获取文件路径
  84. const filePath = file.path;
  85. // 获取文件名
  86. let fileName = file.name;
  87. // 如果文件名不存在,则使用文件路径的文件名
  88. if (fileName == "" || fileName == null) {
  89. fileName = basename(filePath);
  90. }
  91. // 获取文件扩展名
  92. let ext = extname(fileName);
  93. if (ext == "") {
  94. ext = "png";
  95. }
  96. // 生成唯一key: 原文件名_uuid.扩展名
  97. let key = `${filename(fileName)}_${uuid()}.${ext}`;
  98. // 云上传需要加上时间戳路径
  99. if (isCloud) {
  100. key = `app/${Date.now()}/${key}`;
  101. }
  102. // 支持多种上传方式
  103. return new Promise((resolve, reject) => {
  104. /**
  105. * 实际上传文件的函数
  106. * @param param0 上传参数
  107. */
  108. function next({ url, preview, data }: UploadRequestOptions) {
  109. // 发起上传请求
  110. const task = uni.uploadFile({
  111. url,
  112. filePath,
  113. name: "file",
  114. header: {
  115. // 本地上传带token
  116. Authorization: isLocal ? user.token : null
  117. },
  118. formData: {
  119. ...(data as UTSJSONObject),
  120. key
  121. },
  122. success(res) {
  123. if (isLocal) {
  124. // 本地上传返回处理
  125. const { code, data, message } = parseObject<LocalUploadResponse>(res.data)!;
  126. if (code == 1000) {
  127. resolve(data);
  128. } else {
  129. reject(message);
  130. }
  131. } else {
  132. // 云上传直接拼接url
  133. resolve(pathJoin(preview ?? url, key!));
  134. }
  135. },
  136. fail(err) {
  137. console.error(err);
  138. reject(err);
  139. }
  140. });
  141. // 上传任务回调
  142. if (options?.onTask != null) {
  143. options.onTask!({
  144. abort: () => {
  145. task.abort();
  146. }
  147. } as UploadTask);
  148. }
  149. // 上传进度回调
  150. if (options?.onProgressUpdate != null) {
  151. task.onProgressUpdate((result) => {
  152. const { progress, totalBytesSent, totalBytesExpectedToSend } = result;
  153. options.onProgressUpdate!({
  154. progress,
  155. totalBytesSent,
  156. totalBytesExpectedToSend
  157. });
  158. });
  159. }
  160. }
  161. // 本地上传
  162. if (isLocal) {
  163. next({
  164. url: config.baseUrl + "/app/base/comm/upload",
  165. data: {}
  166. });
  167. } else {
  168. // 云上传
  169. const data = {} as UTSJSONObject;
  170. // AWS需要提前传key
  171. if (type == "aws") {
  172. data.key = key;
  173. }
  174. // 获取云上传参数
  175. service.base.comm
  176. .upload(data)
  177. .then((res) => {
  178. const d = parse<CloudUploadResponse>(res)!;
  179. switch (type) {
  180. // 腾讯云COS
  181. case "cos":
  182. next({
  183. url: d.url!,
  184. data: d.credentials!
  185. });
  186. break;
  187. // 阿里云OSS
  188. case "oss":
  189. next({
  190. url: d.host!,
  191. data: {
  192. OSSAccessKeyId: d.OSSAccessKeyId,
  193. policy: d.policy,
  194. signature: d.signature
  195. }
  196. });
  197. break;
  198. // 七牛云
  199. case "qiniu":
  200. next({
  201. url: d.uploadUrl!,
  202. preview: d.publicDomain,
  203. data: {
  204. token: d.token
  205. }
  206. });
  207. break;
  208. // 亚马逊AWS
  209. case "aws":
  210. next({
  211. url: d.url!,
  212. data: d.fields!
  213. });
  214. break;
  215. }
  216. })
  217. .catch(reject);
  218. }
  219. });
  220. }