index.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. import { getUrlType } from './meta';
  2. // 加载第三方库
  3. export const loadLib = (() => {
  4. const cache: Record<string, Promise<void>> = {};
  5. const load = (
  6. lib: string,
  7. success: () => void,
  8. err: () => void,
  9. maxReq = 0
  10. ) => {
  11. const el = document.createElement("script");
  12. el.src = lib;
  13. document.body.appendChild(el);
  14. el.onload = success;
  15. el.onerror = () => {
  16. if (maxReq > 0) {
  17. load(lib, success, err, --maxReq);
  18. } else {
  19. err();
  20. }
  21. };
  22. };
  23. return (lib: string) => {
  24. if (!cache[lib]) {
  25. cache[lib] = new Promise((resolve, reject) => {
  26. load(lib, resolve, reject, 3);
  27. });
  28. }
  29. return cache[lib];
  30. };
  31. })();
  32. export const getSizeStr = (size: number) => {
  33. let mb = size;
  34. if (mb < 1024) {
  35. return `${mb.toFixed(2)}BYTE`;
  36. }
  37. mb /= 1024;
  38. if (mb < 1024) {
  39. return `${mb.toFixed(2)}KB`;
  40. }
  41. mb /= 1024;
  42. if (mb < 1024) {
  43. return `${mb.toFixed(2)}MB`;
  44. }
  45. mb /= 1024;
  46. if (mb < 1024) {
  47. return `${mb.toFixed(2)}GB`;
  48. }
  49. mb /= 1024;
  50. return `${mb.toFixed(2)}TB`;
  51. };
  52. // 日期格式化
  53. export const formatDate = (date: Date, fmt: string = 'yyyy-MM-dd hh:mm') => {
  54. const map = {
  55. 'M+': date.getMonth() + 1, //月份
  56. 'd+': date.getDate(), //日
  57. 'h+': date.getHours(), //小时
  58. 'm+': date.getMinutes(), //分
  59. 's+': date.getSeconds(), //秒
  60. 'q+': Math.floor((date.getMonth() + 3) / 3), //季度
  61. S: date.getMilliseconds() //毫秒
  62. }
  63. if (/(y+)/.test(fmt)) {
  64. fmt = fmt.replace(
  65. RegExp.$1,
  66. date
  67. .getFullYear()
  68. .toString()
  69. .substr(4 - RegExp.$1.length)
  70. )
  71. }
  72. ;(Object.keys(map) as Array<keyof typeof map>).forEach(k => {
  73. if (new RegExp('(' + k + ')').test(fmt)) {
  74. const val = map[k].toString()
  75. fmt = fmt.replace(
  76. RegExp.$1,
  77. RegExp.$1.length === 1 ? val : ('00' + val).substr(val.length)
  78. )
  79. }
  80. })
  81. return fmt
  82. }
  83. export const togetherCallback = (cbs: (() => void)[]) => () => together(cbs)
  84. export const together = (cbs: (() => void)[]) => {
  85. cbs.forEach(cb => cb())
  86. }
  87. export const getFileUrl = (file: LocalFile | string) =>
  88. typeof file === 'string'
  89. ? file
  90. : file.url
  91. export const getFileName = (file: any): string => {
  92. return typeof file === 'string'
  93. ? file.substring(file.lastIndexOf('/') + 1)
  94. : file.blob instanceof File ? file.blob.name : getUrlType(file.url)
  95. }
  96. export const asyncTimeout = (mis: number = 0) => new Promise(resolve => setTimeout(resolve, mis))
  97. export const jsonToForm = (data: { [key in string]: any }) => {
  98. const formData = new FormData()
  99. for (const [key, val] of Object.entries(data)) {
  100. if (Array.isArray(val)) {
  101. for (let i = 0; i < val.length; i++) {
  102. formData.append(`${key}`, val[i])
  103. }
  104. } else {
  105. formData.append(key, val)
  106. }
  107. }
  108. return formData
  109. }
  110. // 防抖
  111. export const debounce = <T extends (...args: any) => any>(
  112. fn: T,
  113. delay: number = 160
  114. ) => {
  115. let timeout: any;
  116. return function (...args: Parameters<T>) {
  117. clearTimeout(timeout);
  118. timeout = setTimeout(() => {
  119. fn.apply(null, args);
  120. }, delay);
  121. };
  122. };
  123. // 防抖
  124. export const debounceStack = <T extends (...args: any) => any>(
  125. fn: T,
  126. success: (data: ReturnType<T> extends Promise<infer P> ? P : ReturnType<T>) => void,
  127. delay: number = 160
  128. ) => {
  129. let dsToken = 0
  130. return debounce(async (...args: Parameters<T>) => {
  131. ++dsToken
  132. const currentToken = dsToken
  133. const result = await fn.apply(null, args);
  134. if (currentToken === dsToken) {
  135. success(result)
  136. }
  137. }, delay)
  138. };
  139. // 四舍五入保留指定位数
  140. export const round = (num: number, index: number = 2) => {
  141. const s = Math.pow(10, index)
  142. return Math.round(num * s) / s
  143. }
  144. export * from './store-help'
  145. export * from "./stack";
  146. export * from "./loading";
  147. export * from "./route";
  148. export * from "./asyncBus";
  149. export * from './mount'
  150. export * from './watch'
  151. export * from './diff'
  152. export * from './params'
  153. export * from './file-serve'
  154. export * from './video-cover'
  155. export * from './meta'
  156. function randomWord(randomFlag: boolean, min: number, max?: number) {
  157. let str = "";
  158. let range = min;
  159. const arr = [
  160. "0",
  161. "1",
  162. "2",
  163. "3",
  164. "4",
  165. "5",
  166. "6",
  167. "7",
  168. "8",
  169. "9",
  170. "a",
  171. "b",
  172. "c",
  173. "d",
  174. "e",
  175. "f",
  176. "g",
  177. "h",
  178. "i",
  179. "j",
  180. "k",
  181. "l",
  182. "m",
  183. "n",
  184. "o",
  185. "p",
  186. "q",
  187. "r",
  188. "s",
  189. "t",
  190. "u",
  191. "v",
  192. "w",
  193. "x",
  194. "y",
  195. "z",
  196. "A",
  197. "B",
  198. "C",
  199. "D",
  200. "E",
  201. "F",
  202. "G",
  203. "H",
  204. "I",
  205. "J",
  206. "K",
  207. "L",
  208. "M",
  209. "N",
  210. "O",
  211. "P",
  212. "Q",
  213. "R",
  214. "S",
  215. "T",
  216. "U",
  217. "V",
  218. "W",
  219. "X",
  220. "Y",
  221. "Z",
  222. ];
  223. // 随机产生
  224. if (randomFlag && max) {
  225. range = Math.round(Math.random() * (max - min)) + min;
  226. }
  227. for (let i = 0; i < range; i++) {
  228. const pos = Math.round(Math.random() * (arr.length - 1));
  229. str += arr[pos];
  230. }
  231. return str;
  232. }
  233. import { Base64 } from "js-base64";
  234. /**
  235. * 密码加密
  236. * @param {String} pwd
  237. */
  238. export function encodePwd(str: string, strv: string): string[];
  239. export function encodePwd(str: string): string;
  240. export function encodePwd(str: string, strv = "") {
  241. str = Base64.encode(str);
  242. const NUM = 2;
  243. const front = randomWord(false, 8);
  244. const middle = randomWord(false, 8);
  245. const end = randomWord(false, 8);
  246. const str1 = str.substring(0, NUM);
  247. const str2 = str.substring(NUM);
  248. if (strv) {
  249. const strv1 = strv.substring(0, NUM);
  250. const strv2 = strv.substring(NUM);
  251. return [
  252. front + str2 + middle + str1 + end,
  253. front + strv2 + middle + strv1 + end,
  254. ];
  255. }
  256. return front + str2 + middle + str1 + end;
  257. }
  258. /**
  259. * 判断是否为 Firefox 且版本小于 targetVersion(如 "115.9")
  260. * @param {string} targetVersion - 目标版本字符串,例如 "115.9"
  261. * @returns {boolean}
  262. */
  263. export function isFirefoxBelow(targetVersion = "115.9") {
  264. // 尝试使用 navigator.userAgentData (更现代) 如果可用且包含 brands
  265. // 注意:userAgentData.brand/version 可能随浏览器策略返回受限信息
  266. const navigator = window.navigator as any
  267. if (navigator.userAgentData && Array.isArray(navigator.userAgentData.brands)) {
  268. // brands 形如 [{brand: "Chromium", version: "116"}, ...] 或可能被 UA 凭空
  269. for (const b of navigator.userAgentData.brands) {
  270. if (typeof b.brand === "string" && /firefox/i.test(b.brand)) {
  271. const ver = b.version || "";
  272. return compareVersionStrings(ver, targetVersion) < 0;
  273. }
  274. }
  275. }
  276. // 回退到 userAgent 字符串
  277. const ua = navigator.userAgent || "";
  278. // Firefox 的 UA 通常包含 "Firefox/<version>"
  279. const m = ua.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/i);
  280. if (m && m[1]) {
  281. const ver = m[1];
  282. return compareVersionStrings(ver, targetVersion) < 0;
  283. }
  284. // 不是 Firefox 或版本未知
  285. return false;
  286. }
  287. /**
  288. * 比较两个版本字符串(如 "115.9.1" 与 "115.9")
  289. * 返回:
  290. * -1 如果 v1 < v2
  291. * 0 如果 v1 == v2
  292. * 1 如果 v1 > v2
  293. */
  294. function compareVersionStrings(v1: string, v2: string) {
  295. const seg1 = String(v1).split('.').map(s => parseInt(s, 10) || 0);
  296. const seg2 = String(v2).split('.').map(s => parseInt(s, 10) || 0);
  297. const len = Math.max(seg1.length, seg2.length);
  298. for (let i = 0; i < len; i++) {
  299. const a = seg1[i] || 0;
  300. const b = seg2[i] || 0;
  301. if (a < b) return -1;
  302. if (a > b) return 1;
  303. }
  304. return 0;
  305. }