File size: 6,571 Bytes
e85fa50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/**

 * 通用辅助工具函数

 */

/**

 * 生成唯一ID

 * @returns 唯一ID字符串

 */
export const generateId = (): string => {
    return Date.now().toString(36) + Math.random().toString(36).substring(2);
  };
  
  /**

   * 格式化日期为本地字符串

   * @param date 日期对象或日期字符串

   * @param options 格式化选项

   * @returns 格式化后的日期字符串

   */
  export const formatDate = (
    date: Date | string,
    options: Intl.DateTimeFormatOptions = {
      year: 'numeric',
      month: 'long',
      day: 'numeric'
    }
  ): string => {
    const dateObj = date instanceof Date ? date : new Date(date);
    return dateObj.toLocaleDateString('zh-CN', options);
  };
  
  /**

   * 格式化日期和时间为本地字符串

   * @param date 日期对象或日期字符串

   * @returns 格式化后的日期和时间字符串

   */
  export const formatDateTime = (date: Date | string): string => {
    const dateObj = date instanceof Date ? date : new Date(date);
    return dateObj.toLocaleDateString('zh-CN', {
      year: 'numeric',
      month: 'long',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit'
    });
  };
  
  /**

   * 截断文本到指定长度

   * @param text 需要截断的文本

   * @param maxLength 最大长度

   * @param suffix 省略号后缀,默认为"..."

   * @returns 截断后的文本

   */
  export const truncateText = (
    text: string,
    maxLength: number,
    suffix: string = '...'
  ): string => {
    if (text.length <= maxLength) return text;
    return text.substring(0, maxLength) + suffix;
  };
  
  /**

   * 深度克隆对象

   * @param obj 需要克隆的对象

   * @returns 克隆后的对象

   */
  export const deepClone = <T>(obj: T): T => {
    return JSON.parse(JSON.stringify(obj));
  };
  
  /**

   * 按属性对对象数组进行排序

   * @param array 对象数组

   * @param key 排序键

   * @param ascending 是否升序,默认为true

   * @returns 排序后的数组

   */
  export const sortByProperty = <T>(
    array: T[],
    key: keyof T,
    ascending: boolean = true
  ): T[] => {
    return [...array].sort((a, b) => {
      const valueA = a[key];
      const valueB = b[key];
      
      if (valueA === valueB) return 0;
      
      // 处理日期对象
      if (valueA instanceof Date && valueB instanceof Date) {
        return ascending ? valueA.getTime() - valueB.getTime() : valueB.getTime() - valueA.getTime();
      }
      
      // 处理字符串
      if (typeof valueA === 'string' && typeof valueB === 'string') {
        return ascending ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
      }
      
      // 处理数字
      if (typeof valueA === 'number' && typeof valueB === 'number') {
        return ascending ? valueA - valueB : valueB - valueA;
      }
      
      // 默认使用字符串比较
      return ascending
        ? String(valueA).localeCompare(String(valueB))
        : String(valueB).localeCompare(String(valueA));
    });
  };
  
  /**

   * 延迟执行(Promise形式)

   * @param ms 延迟毫秒数

   * @returns Promise

   */
  export const delay = (ms: number): Promise<void> => {
    return new Promise(resolve => setTimeout(resolve, ms));
  };
  
  /**

   * 防抖函数

   * @param func 要执行的函数

   * @param wait 等待时间(毫秒)

   * @returns 防抖处理后的函数

   */
  export function debounce<T extends (...args: any[]) => any>(
    func: T,
    wait: number
  ): (...args: Parameters<T>) => void {
    let timeout: NodeJS.Timeout | null = null;
    
    return function (...args: Parameters<T>) {
      const later = () => {
        timeout = null;
        func(...args);
      };
      
      if (timeout) clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }
  
  /**

   * 节流函数

   * @param func 要执行的函数

   * @param limit 时间限制(毫秒)

   * @returns 节流处理后的函数

   */
  export function throttle<T extends (...args: any[]) => any>(
    func: T,
    limit: number
  ): (...args: Parameters<T>) => void {
    let inThrottle = false;
    
    return function (...args: Parameters<T>) {
      if (!inThrottle) {
        func(...args);
        inThrottle = true;
        setTimeout(() => {
          inThrottle = false;
        }, limit);
      }
    };
  }
  
  /**

   * 过滤对象数组

   * @param array 对象数组

   * @param searchTerm 搜索关键词

   * @param keys 要搜索的属性键数组

   * @returns 过滤后的数组

   */
  export const filterArrayBySearchTerm = <T>(
    array: T[],
    searchTerm: string,
    keys: (keyof T)[]
  ): T[] => {
    if (!searchTerm) return array;
    
    const lowercasedTerm = searchTerm.toLowerCase();
    
    return array.filter(item => {
      return keys.some(key => {
        const value = item[key];
        if (value == null) return false;
        return String(value).toLowerCase().includes(lowercasedTerm);
      });
    });
  };
  
  /**

   * 分组对象数组

   * @param array 对象数组

   * @param key 分组键

   * @returns 分组后的对象

   */
  export const groupBy = <T>(array: T[], key: keyof T): Record<string, T[]> => {
    return array.reduce((result, item) => {
      const groupKey = String(item[key]);
      if (!result[groupKey]) {
        result[groupKey] = [];
      }
      result[groupKey].push(item);
      return result;
    }, {} as Record<string, T[]>);
  };
  
  /**

   * 检查对象是否为空

   * @param obj 要检查的对象

   * @returns 布尔值,指示对象是否为空

   */
  export const isEmptyObject = (obj: Record<string, any>): boolean => {
    return Object.keys(obj).length === 0;
  };
  
  /**

   * 从数组中移除重复项

   * @param array 数组

   * @returns 去重后的数组

   */
  export const removeDuplicates = <T>(array: T[]): T[] => {
    return [...new Set(array)];
  };
  
  /**

   * 从日期对象获取YYYY-MM-DD格式的日期字符串

   * @param date 日期对象

   * @returns 格式化后的日期字符串

   */
  export const getFormattedDate = (date: Date): string => {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  };