ruoyi.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // 日期格式化
  2. export function parseTime(time: any, pattern?: string) {
  3. if (arguments.length === 0 || !time) {
  4. return null;
  5. }
  6. const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}';
  7. let date;
  8. if (typeof time === 'object') {
  9. date = time;
  10. } else {
  11. if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
  12. time = parseInt(time);
  13. } else if (typeof time === 'string') {
  14. time = time
  15. .replace(new RegExp(/-/gm), '/')
  16. .replace('T', ' ')
  17. .replace(new RegExp(/\.[\d]{3}/gm), '');
  18. }
  19. if (typeof time === 'number' && time.toString().length === 10) {
  20. time = time * 1000;
  21. }
  22. date = new Date(time);
  23. }
  24. const formatObj: { [key: string]: any } = {
  25. y: date.getFullYear(),
  26. m: date.getMonth() + 1,
  27. d: date.getDate(),
  28. h: date.getHours(),
  29. i: date.getMinutes(),
  30. s: date.getSeconds(),
  31. a: date.getDay()
  32. };
  33. return format.replace(/{(y|m|d|h|i|s|a)+}/g, (result: string, key: string) => {
  34. let value = formatObj[key];
  35. // Note: getDay() returns 0 on Sunday
  36. if (key === 'a') {
  37. return ['日', '一', '二', '三', '四', '五', '六'][value];
  38. }
  39. if (result.length > 0 && value < 10) {
  40. value = '0' + value;
  41. }
  42. return value || 0;
  43. });
  44. }
  45. /**
  46. * 添加日期范围
  47. * @param params
  48. * @param dateRange
  49. * @param propName
  50. */
  51. export const addDateRange = (params: any, dateRange: any[], propName?: string) => {
  52. const search = params;
  53. search.params = typeof search.params === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
  54. dateRange = Array.isArray(dateRange) ? dateRange : [];
  55. if (typeof propName === 'undefined') {
  56. search.params['beginTime'] = dateRange[0];
  57. search.params['endTime'] = dateRange[1];
  58. } else {
  59. search.params['begin' + propName] = dateRange[0];
  60. search.params['end' + propName] = dateRange[1];
  61. }
  62. return search;
  63. };
  64. // 回显数据字典
  65. export const selectDictLabel = (datas: any, value: number | string) => {
  66. if (value === undefined) {
  67. return '';
  68. }
  69. const actions = [];
  70. Object.keys(datas).some((key) => {
  71. if (datas[key].value == '' + value) {
  72. actions.push(datas[key].label);
  73. return true;
  74. }
  75. });
  76. if (actions.length === 0) {
  77. actions.push(value);
  78. }
  79. return actions.join('');
  80. };
  81. // 回显数据字典(字符串数组)
  82. export const selectDictLabels = (datas: any, value: any, separator: any) => {
  83. if (value === undefined || value.length === 0) {
  84. return '';
  85. }
  86. if (Array.isArray(value)) {
  87. value = value.join(',');
  88. }
  89. const actions: any[] = [];
  90. const currentSeparator = undefined === separator ? ',' : separator;
  91. const temp = value.split(currentSeparator);
  92. Object.keys(value.split(currentSeparator)).some((val) => {
  93. let match = false;
  94. Object.keys(datas).some((key) => {
  95. if (datas[key].value == '' + temp[val]) {
  96. actions.push(datas[key].label + currentSeparator);
  97. match = true;
  98. }
  99. });
  100. if (!match) {
  101. actions.push(temp[val] + currentSeparator);
  102. }
  103. });
  104. return actions.join('').substring(0, actions.join('').length - 1);
  105. };
  106. // 字符串格式化(%s )
  107. export function sprintf(str: string) {
  108. if (arguments.length !== 0) {
  109. let flag = true,
  110. i = 1;
  111. str = str.replace(/%s/g, function () {
  112. const arg = arguments[i++];
  113. if (typeof arg === 'undefined') {
  114. flag = false;
  115. return '';
  116. }
  117. return arg;
  118. });
  119. return flag ? str : '';
  120. }
  121. }
  122. // 转换字符串,undefined,null等转化为""
  123. export const parseStrEmpty = (str: any) => {
  124. if (!str || str == 'undefined' || str == 'null') {
  125. return '';
  126. }
  127. return str;
  128. };
  129. // 数据合并
  130. export const mergeRecursive = (source: any, target: any) => {
  131. for (const p in target) {
  132. try {
  133. if (target[p].constructor == Object) {
  134. source[p] = mergeRecursive(source[p], target[p]);
  135. } else {
  136. source[p] = target[p];
  137. }
  138. } catch (e) {
  139. source[p] = target[p];
  140. }
  141. }
  142. return source;
  143. };
  144. /**
  145. * 构造树型结构数据
  146. * @param {*} data 数据源
  147. * @param {*} id id字段 默认 'id'
  148. * @param {*} parentId 父节点字段 默认 'parentId'
  149. * @param {*} children 孩子节点字段 默认 'children'
  150. */
  151. export const handleTree = <T>(data: any[], id?: string, parentId?: string, children?: string): T[] => {
  152. const config: {
  153. id: string;
  154. parentId: string;
  155. childrenList: string;
  156. } = {
  157. id: id || 'id',
  158. parentId: parentId || 'parentId',
  159. childrenList: children || 'children'
  160. };
  161. const childrenListMap: any = {};
  162. const nodeIds: any = {};
  163. const tree: T[] = [];
  164. for (const d of data) {
  165. const parentId = d[config.parentId];
  166. if (childrenListMap[parentId] == null) {
  167. childrenListMap[parentId] = [];
  168. }
  169. nodeIds[d[config.id]] = d;
  170. childrenListMap[parentId].push(d);
  171. }
  172. for (const d of data) {
  173. const parentId = d[config.parentId];
  174. if (nodeIds[parentId] == null) {
  175. tree.push(d);
  176. }
  177. }
  178. const adaptToChildrenList = (o: any) => {
  179. if (childrenListMap[o[config.id]] !== null) {
  180. o[config.childrenList] = childrenListMap[o[config.id]];
  181. }
  182. if (o[config.childrenList]) {
  183. for (const c of o[config.childrenList]) {
  184. adaptToChildrenList(c);
  185. }
  186. }
  187. };
  188. for (const t of tree) {
  189. adaptToChildrenList(t);
  190. }
  191. return tree;
  192. };
  193. // 验证是否为blob格式
  194. export const blobValidate = (data: any) => {
  195. return data.type !== 'application/json';
  196. };
  197. /**
  198. * 将字节转成B KB MB GB
  199. * @param byte number
  200. * @returns string
  201. */
  202. export const changeByte = (byte: number) => {
  203. let size = '';
  204. if (byte < 0.1 * 1024) {
  205. // 小于0.1KB,则转化成B
  206. size = `${byte.toFixed(2)}B`;
  207. } else if (byte < 0.1 * 1024 * 1024) {
  208. // 小于0.1MB,则转化成KB
  209. size = `${(byte / 1024).toFixed(2)}KB`;
  210. } else if (byte < 0.1 * 1024 * 1024 * 1024) {
  211. // 小于0.1GB,则转化成MB
  212. size = `${(byte / (1024 * 1024)).toFixed(2)}MB`;
  213. } else {
  214. // 其他转化成GB
  215. size = `${(byte / (1024 * 1024 * 1024)).toFixed(2)}GB`;
  216. }
  217. const sizeStr = `${size}`; // 转成字符串
  218. const index = sizeStr.indexOf('.'); // 获取小数点处的索引
  219. const dou = sizeStr.substr(index + 1, 2); // 获取小数点后两位的值
  220. // eslint-disable-next-line eqeqeq
  221. if (dou == '00') {
  222. // 判断后两位是否为00,如果是则删除00
  223. return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2);
  224. }
  225. return size;
  226. };
  227. export function calculateTransparency(color: string, alpha: number): string {
  228. // 将颜色转换为RGBA或HSLA格式
  229. const colorType = color.startsWith('#') ? 'rgba' : 'hsla';
  230. const r = parseInt(color.substring(1, 3), 16);
  231. const g = parseInt(color.substring(3, 5), 16);
  232. const b = parseInt(color.substring(5, 7), 16);
  233. const a = alpha / 100; // 将百分比转换为小数
  234. if (colorType === 'rgba') {
  235. return `${colorType}(${r}, ${g}, ${b}, ${a})`;
  236. } else {
  237. // 假设颜色是六位数的HSLA格式
  238. const l = parseInt(color.substring(7, 9), 16);
  239. return `${colorType}(${r}, ${g}%, ${l}%, ${a})`;
  240. }
  241. }
  242. export const dataURLtoBlob = (base64Buf: string): Blob => {
  243. const arr = base64Buf.split(',');
  244. const typeItem = arr[0];
  245. const mime = typeItem.match(/:(.*?);/)![1];
  246. const bstr = atob(arr[1]);
  247. const u8arr = new Uint8Array(bstr.length);
  248. for (let i = 0; i < bstr.length; i++) {
  249. u8arr[i] = bstr.charCodeAt(i);
  250. }
  251. return new Blob([u8arr], { type: mime });
  252. };
  253. export const fileExt = (fileName: string) => {
  254. // 获取文件后缀, 从后面到第一个点取 不包括.
  255. return fileName.slice(fileName.lastIndexOf('.') + 1);
  256. };
  257. // 获取随机数
  258. export const getRandomNumber = (min: number, max: number): number => {
  259. return Math.floor(Math.random() * (max - min + 1)) + min;
  260. };
  261. // 获取随机颜色
  262. export const getRandomColor = (): string => {
  263. const letters = '0123456789ABCDEF';
  264. let color = '#';
  265. for (let i = 0; i < 6; i++) {
  266. color += letters[Math.floor(Math.random() * 16)];
  267. }
  268. return color;
  269. };
  270. // 判断地址url是否是一个url连接
  271. export const isUrl = (url: string): boolean => {
  272. const pattern = /^(?:https?:\/\/)?(?:www\.)?[^\s.]+\.[^\s]{2,}$/i;
  273. return pattern.test(url);
  274. };
  275. // 获取一个唯一的uuid共20位
  276. export const getUuid = (): string => {
  277. return new Date().getTime().toString(16) + Math.random().toString(16).slice(2);
  278. };
  279. // 正整数阿拉伯数字转换成中文数字
  280. export const numberToChinese = (num: number): string => {
  281. const chineseNums = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
  282. const chineseUnits = ['', '十', '百', '千', '万', '亿'];
  283. if (num === 0) {
  284. return chineseNums[0];
  285. }
  286. let result = '';
  287. let count = 0;
  288. while (num > 0) {
  289. const digit = num % 10;
  290. if (digit !== 0) {
  291. result = chineseNums[digit] + chineseUnits[count] + result;
  292. } else if (result[0] !== chineseNums[0]) {
  293. result = chineseNums[digit] + result;
  294. }
  295. num = Math.floor(num / 10);
  296. count++;
  297. }
  298. return result;
  299. };
  300. export const getProperty = (obj: any, path: string) => {
  301. const properties = path.split('.');
  302. let value = obj;
  303. for (const prop of properties) {
  304. // eslint-disable-next-line no-prototype-builtins
  305. if (value && Object.prototype.hasOwnProperty.call(value, prop)) {
  306. value = value[prop];
  307. } else {
  308. return undefined;
  309. }
  310. }
  311. return value;
  312. };
  313. // 正整数生成7位数字多余前面补0
  314. export const generateNumber = (num: number, lan = 7): string => {
  315. return num.toString().padStart(lan, '0');
  316. };
  317. // 获取文件后缀名
  318. export const getFileSuffix = (fileName: string): string => {
  319. if (!fileName) return '';
  320. const lastDotIndex = fileName.lastIndexOf('.');
  321. return lastDotIndex !== -1 ? fileName.substring(lastDotIndex + 1) : '';
  322. };
  323. export const recursiveDecode = (input: string, maxDepth: number = 10): string => {
  324. if (typeof input !== 'string' || input.length === 0) return input;
  325. let prev: string = input;
  326. for (let i = 0; i < maxDepth; i++) {
  327. let decoded: string;
  328. try {
  329. // 先替换 '+' 为 ' '(常见 form 编码场景),再解码
  330. decoded = decodeURIComponent(prev.replace(/\+/g, ' '));
  331. } catch (e) {
  332. // 非法序列或无法解码,停止
  333. break;
  334. }
  335. if (decoded === prev) break;
  336. prev = decoded;
  337. }
  338. return prev;
  339. };
  340. // 递归解码对象的类型
  341. type RecursiveDecodeResult<T> = T extends string
  342. ? string
  343. : T extends Array<infer U>
  344. ? Array<RecursiveDecodeResult<U>>
  345. : T extends object
  346. ? { [K in keyof T]: RecursiveDecodeResult<T[K]> }
  347. : T;
  348. export const recursiveDecodeURIComponent = <T>(obj: T): RecursiveDecodeResult<T> => {
  349. if (typeof obj === 'string') {
  350. return recursiveDecode(obj) as RecursiveDecodeResult<T>;
  351. } else if (Array.isArray(obj)) {
  352. return obj.map((item) => recursiveDecodeURIComponent(item)) as RecursiveDecodeResult<T>;
  353. } else if (typeof obj === 'object' && obj !== null) {
  354. const decodedObj: Record<string, any> = {};
  355. for (const key in obj) {
  356. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  357. decodedObj[key] = recursiveDecodeURIComponent((obj as Record<string, any>)[key]);
  358. }
  359. }
  360. return decodedObj as RecursiveDecodeResult<T>;
  361. }
  362. return obj as RecursiveDecodeResult<T>;
  363. };
  364. // 或者使用更简单的类型定义,保持函数简洁
  365. export const recursiveDecodeURIComponentSimple = (obj: any): any => {
  366. if (typeof obj === 'string') {
  367. return recursiveDecode(obj);
  368. } else if (Array.isArray(obj)) {
  369. return obj.map((item) => recursiveDecodeURIComponentSimple(item));
  370. } else if (typeof obj === 'object' && obj !== null) {
  371. const decodedObj: Record<string, any> = {};
  372. for (const key in obj) {
  373. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  374. decodedObj[key] = recursiveDecodeURIComponentSimple(obj[key]);
  375. }
  376. }
  377. return decodedObj;
  378. }
  379. return obj;
  380. };
  381. // 将url提取参数
  382. export const getUrlParams = (url: string): Record<string, string> => {
  383. const params: Record<string, string> = {};
  384. const queryString = url.split('?')[1];
  385. if (!queryString) {
  386. return params;
  387. }
  388. const pairs = queryString.split('&');
  389. for (const pair of pairs) {
  390. const [key, value] = pair.split('=');
  391. params[decodeURIComponent(key)] = decodeURIComponent(value || '');
  392. }
  393. return params;
  394. }
  395. // 预览图片方法
  396. export const previewImage = (urls: string | string[], current?: string) => {
  397. const urlList = Array.isArray(urls) ? urls : [urls];
  398. uni.previewImage({
  399. urls: urlList,
  400. current: current || urlList[0],
  401. });
  402. };