web-core-tcm 0.0.6 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/package.json +20 -3
  2. package/src/{coreApi/api → api}/algorithm/index.ts +6 -0
  3. package/src/api/authorization/alova/implement/index.ts +1 -0
  4. package/src/{coreApi/api → api}/authorization/alova/index.ts +5 -0
  5. package/src/api/authorization/index.ts +2 -0
  6. package/src/api/check/alova/implement/index.ts +1 -0
  7. package/src/{coreApi/api → api}/check/alova/index.ts +5 -0
  8. package/src/{coreApi/api → api}/check/check.ts +1 -1
  9. package/src/api/check/index.ts +2 -0
  10. package/src/{coreApi/api → api}/config/index.ts +2 -0
  11. package/src/api/doctor/alova/implement/index.ts +1 -0
  12. package/src/{coreApi/api → api}/doctor/alova/index.ts +5 -0
  13. package/src/api/doctor/index.ts +2 -0
  14. package/src/api/index.ts +12 -0
  15. package/src/api/metric/implement/index.ts +1 -0
  16. package/src/api/metric/index.ts +2 -0
  17. package/src/api/oauth/alova/implement/index.ts +1 -0
  18. package/src/{coreApi/api → api}/oauth/alova/index.ts +5 -0
  19. package/src/api/oauth/index.ts +2 -0
  20. package/src/api/outpatient/alova/implement/index.ts +1 -0
  21. package/src/{coreApi/api → api}/outpatient/alova/index.ts +5 -0
  22. package/src/api/outpatient/index.ts +2 -0
  23. package/src/api/patient/alova/implement/index.ts +2 -0
  24. package/src/{coreApi/api → api}/patient/alova/index.ts +6 -0
  25. package/src/api/patient/index.ts +4 -0
  26. package/src/api/prescription/alova/implement/index.ts +2 -0
  27. package/src/{coreApi/api → api}/prescription/alova/index.ts +5 -0
  28. package/src/api/prescription/index.ts +3 -0
  29. package/src/api/scientist/alova/implement/index.ts +1 -0
  30. package/src/{coreApi/api → api}/scientist/alova/index.ts +5 -0
  31. package/src/api/scientist/index.ts +2 -0
  32. package/src/index.ts +2 -0
  33. package/src/layouts/UserLayout.vue +106 -0
  34. package/src/pages/LoginPage.vue +32 -0
  35. package/src/proto/Images.proto +7 -0
  36. package/src/proto/WaveMap.proto +10 -0
  37. package/src/proto/index.ts +2 -0
  38. package/src/proto/types/Images_pb.ts +48 -0
  39. package/src/proto/types/WaveMap_pb.ts +59 -0
  40. package/src/router/index.ts +37 -0
  41. package/src/router/routes.ts +14 -0
  42. package/src/util/RichTextUtil.ts +5 -0
  43. package/src/util/datetime.ts +43 -0
  44. package/src/util/export.ts +46 -0
  45. package/src/util/helper.js +58 -0
  46. package/src/util/image.ts +28 -0
  47. package/src/util/number.ts +146 -0
  48. package/src/util/s256.js +30 -0
  49. package/src/util/secret.ts +60 -0
  50. package/src/util/string.ts +121 -0
  51. /package/src/{coreApi/api → api}/algorithm/comprehensiveAlgorithm.ts +0 -0
  52. /package/src/{coreApi/api → api}/algorithm/inquiriesAlgorithm.ts +0 -0
  53. /package/src/{coreApi/api → api}/algorithm/inspectionsAlgorithm.ts +0 -0
  54. /package/src/{coreApi/api → api}/algorithm/lisemsAlgorithm.ts +0 -0
  55. /package/src/{coreApi/api → api}/algorithm/pulsationsAlgorithm.ts +0 -0
  56. /package/src/{coreApi/api → api}/authorization/alova/apiDefinitions.ts +0 -0
  57. /package/src/{coreApi/api → api}/authorization/alova/createApis.ts +0 -0
  58. /package/src/{coreApi/api → api}/authorization/alova/globals.d.ts +0 -0
  59. /package/src/{coreApi/api → api}/authorization/alova/implement/authorization.ts +0 -0
  60. /package/src/{coreApi/api → api}/authorization/authorization.ts +0 -0
  61. /package/src/{coreApi/api → api}/check/alova/apiDefinitions.ts +0 -0
  62. /package/src/{coreApi/api → api}/check/alova/createApis.ts +0 -0
  63. /package/src/{coreApi/api → api}/check/alova/globals.d.ts +0 -0
  64. /package/src/{coreApi/api → api}/check/alova/implement/check.ts +0 -0
  65. /package/src/{coreApi/api → api}/config/alova/index.ts +0 -0
  66. /package/src/{coreApi/api → api}/device/device.js +0 -0
  67. /package/src/{coreApi/api → api}/doctor/alova/apiDefinitions.ts +0 -0
  68. /package/src/{coreApi/api → api}/doctor/alova/createApis.ts +0 -0
  69. /package/src/{coreApi/api → api}/doctor/alova/globals.d.ts +0 -0
  70. /package/src/{coreApi/api → api}/doctor/alova/implement/doctor.ts +0 -0
  71. /package/src/{coreApi/api → api}/doctor/doctor.ts +0 -0
  72. /package/src/{coreApi/api → api}/metric/implement/metric.ts +0 -0
  73. /package/src/{coreApi/api → api}/metric/metric.ts +0 -0
  74. /package/src/{coreApi/api → api}/oauth/alova/apiDefinitions.ts +0 -0
  75. /package/src/{coreApi/api → api}/oauth/alova/createApis.ts +0 -0
  76. /package/src/{coreApi/api → api}/oauth/alova/globals.d.ts +0 -0
  77. /package/src/{coreApi/api → api}/oauth/alova/implement/oauth.ts +0 -0
  78. /package/src/{coreApi/api → api}/oauth/oauth.ts +0 -0
  79. /package/src/{coreApi/api → api}/outpatient/alova/apiDefinitions.ts +0 -0
  80. /package/src/{coreApi/api → api}/outpatient/alova/createApis.ts +0 -0
  81. /package/src/{coreApi/api → api}/outpatient/alova/globals.d.ts +0 -0
  82. /package/src/{coreApi/api → api}/outpatient/alova/implement/outpatient.ts +0 -0
  83. /package/src/{coreApi/api → api}/outpatient/outpatient.ts +0 -0
  84. /package/src/{coreApi/api → api}/patient/alova/apiDefinitions.ts +0 -0
  85. /package/src/{coreApi/api → api}/patient/alova/createApis.ts +0 -0
  86. /package/src/{coreApi/api → api}/patient/alova/globals.d.ts +0 -0
  87. /package/src/{coreApi/api → api}/patient/alova/implement/meta.ts +0 -0
  88. /package/src/{coreApi/api → api}/patient/alova/implement/patient.ts +0 -0
  89. /package/src/{coreApi/api → api}/patient/core.ts +0 -0
  90. /package/src/{coreApi/api → api}/patient/meta.ts +0 -0
  91. /package/src/{coreApi/api → api}/patient/patient.ts +0 -0
  92. /package/src/{coreApi/api → api}/prescription/alova/apiDefinitions.ts +0 -0
  93. /package/src/{coreApi/api → api}/prescription/alova/createApis.ts +0 -0
  94. /package/src/{coreApi/api → api}/prescription/alova/globals.d.ts +0 -0
  95. /package/src/{coreApi/api → api}/prescription/alova/implement/herbal.ts +0 -0
  96. /package/src/{coreApi/api → api}/prescription/alova/implement/prescription.ts +0 -0
  97. /package/src/{coreApi/api → api}/prescription/herbal.ts +0 -0
  98. /package/src/{coreApi/api → api}/prescription/prescription.ts +0 -0
  99. /package/src/{coreApi/api → api}/scientist/alova/apiDefinitions.ts +0 -0
  100. /package/src/{coreApi/api → api}/scientist/alova/createApis.ts +0 -0
  101. /package/src/{coreApi/api → api}/scientist/alova/globals.d.ts +0 -0
  102. /package/src/{coreApi/api → api}/scientist/alova/implement/scientist.ts +0 -0
  103. /package/src/{coreApi/api → api}/scientist/scientist.ts +0 -0
@@ -0,0 +1,46 @@
1
+ function pulsation2csv(data: { [key: string]: number[] }): void {
2
+ const keys = Object.keys(data);
3
+
4
+ const maxLength = Math.max(...keys.map((key) => data[key]!.length));
5
+
6
+ // 填充所有数组到最大长度,可以填充空字符串或其他默认值
7
+ keys.forEach((key) => {
8
+ while (data[key]!.length < maxLength) {
9
+ data[key]!.push(0); // 或者填入其他默认值
10
+ }
11
+ });
12
+
13
+ let csvContent = '';
14
+
15
+ // 添加自定义表头
16
+ csvContent += keys.join(',') + '\n';
17
+
18
+ // 遍历数据数组,将每一行转换为CSV格式
19
+ for (let i = 0; i < maxLength; i++) {
20
+ let row = '';
21
+ keys.forEach((key) => {
22
+ row += `"${data[key]![i]}"`;
23
+ row += ',';
24
+ });
25
+ csvContent += row.slice(0, -1) + '\n'; // 去掉最后一个逗号
26
+ }
27
+
28
+ // 创建一个 Blob 对象
29
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
30
+
31
+ // 创建一个可下载的链接
32
+ const url = window.URL.createObjectURL(blob);
33
+ const link = document.createElement('a');
34
+ link.href = url;
35
+ link.setAttribute('download', 'data.csv'); // 文件名
36
+ document.body.appendChild(link);
37
+
38
+ // 模拟点击事件以下载文件
39
+ link.click();
40
+
41
+ // 清理
42
+ document.body.removeChild(link);
43
+ window.URL.revokeObjectURL(url);
44
+ }
45
+
46
+ export { pulsation2csv };
@@ -0,0 +1,58 @@
1
+ /** token操作助手对象 */
2
+ export const tokenHelper = {
3
+ set: (val) => {
4
+ //判断是electron还算web
5
+ if (getPlatform() === 'electron') {
6
+ window.electronAPI.setStoreItem('token', val);
7
+ } else {
8
+ window.localStorage.setItem('token', val);
9
+ }
10
+ },
11
+ get: () => {
12
+ if (getPlatform() === 'electron') {
13
+ return window.electronAPI.getStoreItem('token');
14
+ } else {
15
+ return window.localStorage.getItem('token') ;
16
+ }
17
+ },
18
+ remove: () => {
19
+ //判断是不是electron
20
+ if (getPlatform() === 'electron') {
21
+ window.electronAPI.setStoreItem('token', '');
22
+ } else {
23
+ window.localStorage.removeItem('token');
24
+ }
25
+ },
26
+ };
27
+ export const storageHelper = {
28
+ setItem: (key, val) => {
29
+ //判断是electron还是spa,目前都是spa,electron也是spa的分离模式,所以第一个判断不会生效,留作后续。
30
+ if (getPlatform() === 'electron') {
31
+ window.electronAPI.setStoreItem(key, val);
32
+ } else {
33
+ window.localStorage.setItem(key, val);
34
+ }
35
+ },
36
+ getItem: (key) => {
37
+ if (getPlatform() === 'electron') {
38
+ return window.electronAPI.getStoreItem(key);
39
+ } else {
40
+ return window.localStorage.getItem(key);
41
+ }
42
+ },
43
+ removeItem: (key) => {
44
+ if (getPlatform() === 'electron') {
45
+ return window.electronAPI.removeStoreItem(key);
46
+ } else {
47
+ return window.localStorage.removeItem(key);
48
+ }
49
+ },
50
+ };
51
+ export const getPlatform = () => {
52
+ try {
53
+ if (window.electronAPI.available()) return 'electron';
54
+ // if(window.electronAPI.available()) return process.env.MODE
55
+ } catch {
56
+ return process.env.MODE;
57
+ }
58
+ };
@@ -0,0 +1,28 @@
1
+ export function arrayBufferToImageBase64(bytes: Uint8Array) {
2
+ // do anything with the byte array here
3
+ let binary = '';
4
+ const len = bytes.byteLength;
5
+ for (let i = 0; i < len; i++) {
6
+ binary += String.fromCharCode(bytes[i] as number);
7
+ }
8
+ return 'data:image/png;base64,' + window.btoa(binary);
9
+ }
10
+ export function base64ToArrayBuffer(base64: string): ArrayBuffer {
11
+ // 移除可能存在的 data URL 前缀
12
+ const base64WithoutPrefix = base64.replace(/^data:\w+\/\w+;base64,/, '');
13
+
14
+ // 解码 base64 字符串
15
+ const binaryString = window.atob(base64WithoutPrefix);
16
+ const len = binaryString.length;
17
+
18
+ // 创建 ArrayBuffer 和 Uint8Array
19
+ const buffer = new ArrayBuffer(len);
20
+ const bytes = new Uint8Array(buffer);
21
+
22
+ // 将字符转换为字节
23
+ for (let i = 0; i < len; i++) {
24
+ bytes[i] = binaryString.charCodeAt(i);
25
+ }
26
+
27
+ return buffer;
28
+ }
@@ -0,0 +1,146 @@
1
+ function buf2hex(buffer: ArrayBuffer) {
2
+ // buffer is an ArrayBuffer
3
+ const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
4
+ return ('00' + bit.toString(16)).slice(-2);
5
+ });
6
+ return hexArr.join('');
7
+ }
8
+
9
+ function hex2int(hex: string) {
10
+ const len = hex.length,
11
+ a = new Array(len);
12
+ let code;
13
+ for (let i = 0; i < len; i++) {
14
+ code = hex.charCodeAt(i);
15
+ if (48 <= code && code < 58) {
16
+ code -= 48;
17
+ } else {
18
+ code = (code & 0xdf) - 65 + 10;
19
+ }
20
+ a[i] = code;
21
+ }
22
+ return a.reduce(function (acc, c) {
23
+ acc = 16 * acc + c;
24
+ return acc;
25
+ }, 0);
26
+ }
27
+ /**
28
+ * 将数组分割成指定长度的数组
29
+ * @param arr 数组
30
+ * @param size 分割长度
31
+ * @returns 分割后的数组
32
+ */
33
+ function chunk(arr: number[], size: number) {
34
+ const objArr = [];
35
+ let index = 0;
36
+ const objArrLen = arr.length / size;
37
+ for (let i = 0; i < objArrLen; i++) {
38
+ const arrTemp = [];
39
+ for (let j = 0; j < size; j++) {
40
+ arrTemp[j] = arr[index++];
41
+ if (index == arr.length) {
42
+ break;
43
+ }
44
+ }
45
+ objArr[i] = arrTemp;
46
+ }
47
+ return objArr;
48
+ }
49
+ // 发送指令字符串转二进制
50
+ function stringToBytes(str: string) {
51
+ const array = new Uint8Array(str.length);
52
+ for (let i = 0, l = str.length; i < l; i++) {
53
+ array[i] = str.charCodeAt(i);
54
+ }
55
+ return array.buffer;
56
+ }
57
+ function numberToChinese(num: number | null): string {
58
+ if (num === null || isNaN(num)) return '无效数字';
59
+
60
+ // 处理负数
61
+ const isNegative = num < 0;
62
+ num = Math.abs(num);
63
+
64
+ // 处理小数部分
65
+ const integerPart = Math.floor(num);
66
+ const decimalPart = num - integerPart;
67
+
68
+ // 中文数字单位
69
+ const chineseNums: string[] = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
70
+ const chineseUnits: string[] = ['', '十', '百', '千'];
71
+ const chineseBigUnits: string[] = ['', '万', '亿', '兆'];
72
+
73
+ // 转换整数部分
74
+ let chineseInteger = '';
75
+ if (integerPart === 0) {
76
+ chineseInteger = '零';
77
+ } else {
78
+ const numStr = integerPart.toString();
79
+ const groupCount = Math.ceil(numStr.length / 4);
80
+ const groups: string[] = [];
81
+
82
+ // 将数字分成四位一组
83
+ for (let i = 0; i < groupCount; i++) {
84
+ const start = Math.max(0, numStr.length - (i + 1) * 4);
85
+ const end = numStr.length - i * 4;
86
+ groups.unshift(numStr.slice(start, end));
87
+ }
88
+
89
+ // 处理每一组
90
+ for (let i = 0; i < groups.length; i++) {
91
+ let groupStr = '';
92
+ const groupNum = groups[i]!;
93
+
94
+ for (let j = 0; j < groupNum.length; j++) {
95
+ const digit = parseInt(groupNum[j]!);
96
+ const pos = groupNum.length - 1 - j;
97
+
98
+ if (digit !== 0) {
99
+ groupStr += chineseNums[digit]! + chineseUnits[pos];
100
+ } else {
101
+ // 处理连续的零
102
+ if (j < groupNum.length - 1 && groupNum[j + 1] !== '0') {
103
+ groupStr += chineseNums[0];
104
+ }
105
+ }
106
+ }
107
+
108
+ // 添加大单位(万、亿等)
109
+ if (groupStr !== '') {
110
+ groupStr += chineseBigUnits[groups.length - 1 - i];
111
+ }
112
+
113
+ chineseInteger += groupStr;
114
+ }
115
+
116
+ // 处理特殊情况(如"一十"简化为"十")
117
+ if (chineseInteger.startsWith('一十')) {
118
+ chineseInteger = chineseInteger.substring(1);
119
+ }
120
+
121
+ // 去除多余的零
122
+ chineseInteger = chineseInteger.replace(/零+/g, '零').replace(/零+$/, '');
123
+ }
124
+
125
+ // 转换小数部分
126
+ let chineseDecimal = '';
127
+ if (decimalPart > 0) {
128
+ chineseDecimal = '点';
129
+ let decimalStr = decimalPart.toString().split('.')[1] || '';
130
+
131
+ // 限制小数位数,避免无限循环小数
132
+ decimalStr = decimalStr.substring(0, 10);
133
+
134
+ for (let i = 0; i < decimalStr.length; i++) {
135
+ const digit = parseInt(decimalStr[i]!);
136
+ chineseDecimal += chineseNums[digit];
137
+ }
138
+ }
139
+
140
+ // 组合结果
141
+ const result = (isNegative ? '负' : '') + chineseInteger + chineseDecimal;
142
+
143
+ return result === '零' ? '零' : result.replace(/^零+/, '');
144
+ }
145
+ //导出方法
146
+ export { buf2hex, hex2int, chunk, stringToBytes, numberToChinese };
@@ -0,0 +1,30 @@
1
+ // 生成随机字符串 (用于 code_verifier)
2
+ import CryptoJS from 'crypto-js';
3
+ export function generateRandomString(length) {
4
+ const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
5
+ let result = '';
6
+
7
+ const randomValues = new Uint8Array(length);
8
+ crypto.getRandomValues(randomValues);
9
+
10
+ for (let i = 0; i < length; i++) {
11
+ result += charset[randomValues[i] % charset.length];
12
+ }
13
+
14
+ return result;
15
+ }
16
+
17
+ // 生成 code_challenge (S256 方法)
18
+ export function generateCodeChallenge(codeVerifier) {
19
+ // 1. 计算 SHA256 哈希
20
+ const hash = CryptoJS.SHA256(codeVerifier);
21
+
22
+ // 2. 转换为 Base64 URL 安全编码
23
+ const base64 = hash.toString(CryptoJS.enc.Base64);
24
+ const base64Url = base64
25
+ .replace(/=/g, '')
26
+ .replace(/\+/g, '-')
27
+ .replace(/\//g, '_');
28
+
29
+ return base64Url;
30
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * 生成OAuth PKCE所需的code_verifier和code_challenge
3
+ * @param method code_challenge_method,目前只支持S256
4
+ * @returns 包含code_verifier和code_challenge的对象
5
+ */
6
+ export async function generatePKCECodes(method: string = 'S256') {
7
+ // 生成code_verifier (随机字符串)
8
+ const codeVerifier = generateCodeVerifier();
9
+
10
+ // 根据method生成code_challenge
11
+ let codeChallenge: string;
12
+ switch (method) {
13
+ case 'S256':
14
+ codeChallenge = await generateCodeChallengeS256(codeVerifier);
15
+ break;
16
+ default:
17
+ throw new Error(`Unsupported code challenge method: ${method}`);
18
+ }
19
+
20
+ return {
21
+ code_verifier: codeVerifier,
22
+ code_challenge: codeChallenge,
23
+ code_challenge_method: method
24
+ };
25
+ }
26
+
27
+ /**
28
+ * 生成code_verifier
29
+ * 根据RFC 7636,code_verifier应该是43-128个字符的随机字符串
30
+ * @returns code_verifier字符串
31
+ */
32
+ function generateCodeVerifier(): string {
33
+ const array = new Uint8Array(32);
34
+ crypto.getRandomValues(array);
35
+ return base64UrlEncode(array);
36
+ }
37
+
38
+ /**
39
+ * 使用S256方法生成code_challenge
40
+ * @param codeVerifier code_verifier字符串
41
+ * @returns code_challenge字符串
42
+ */
43
+ async function generateCodeChallengeS256(codeVerifier: string) {
44
+ const encoder = new TextEncoder();
45
+ const data = encoder.encode(codeVerifier);
46
+ const hash = crypto.subtle.digest('SHA-256', data);
47
+ return await hash.then((buffer) => base64UrlEncode(new Uint8Array(buffer)));
48
+ }
49
+
50
+ /**
51
+ * Base64 URL安全编码
52
+ * @param array 需要编码的字节数组
53
+ * @returns URL安全的Base64编码字符串
54
+ */
55
+ function base64UrlEncode(array: Uint8Array): string {
56
+ return btoa(String.fromCharCode(...array))
57
+ .replace(/\+/g, '-')
58
+ .replace(/\//g, '_')
59
+ .replace(/=/g, '');
60
+ }
@@ -0,0 +1,121 @@
1
+ import pinyin from 'pinyin';
2
+ export function getName(name: string): string {
3
+ if (!name) {
4
+ return ''; // 如果名字不存在或为空,返回空字符串
5
+ }
6
+ const parts = name.split(' ');
7
+ if (parts.length === 2) {
8
+ return `${parts[1]}${parts[0]}`; // 交换名字的顺序
9
+ } else {
10
+ return name; // 标红处理
11
+ }
12
+ }
13
+
14
+ /**
15
+ * 通用拼音筛选函数
16
+ * @param val 搜索关键词
17
+ * @param options 选项数组
18
+ * @returns 筛选后的选项数组
19
+ */
20
+ export function pinyinFilter(
21
+ val: string,
22
+ options: string[]
23
+ ): string[] {
24
+ if (!val) return [];
25
+
26
+ const lowerVal = val.toLowerCase();
27
+
28
+ return options.filter(option => {
29
+ const targetStr = option;
30
+ if (!targetStr) return false;
31
+
32
+ // 1. 直接包含搜索词
33
+ if (targetStr.includes(lowerVal)) return true;
34
+
35
+ // 2. 拼音全拼包含搜索词
36
+ const fullPinyin = pinyin(targetStr, { style: pinyin.STYLE_NORMAL })
37
+ .map(word => word[0]).join('');
38
+ if (fullPinyin.includes(lowerVal)) return true;
39
+
40
+ // 3. 拼音首字母缩写包含搜索词
41
+ const abbr = getPinyinAbbr(targetStr);
42
+ return abbr.includes(lowerVal);
43
+ });
44
+ }
45
+
46
+ /**
47
+ * 通用拼音筛选函数(返回匹配项的索引)
48
+ * @param val 搜索关键词
49
+ * @param options 选项数组
50
+ * @returns 匹配项的索引数组
51
+ */
52
+ export function pinyinFilterIndex(
53
+ val: string,
54
+ options: string[]
55
+ ): number[] {
56
+ if (!val) return [];
57
+
58
+ const lowerVal = val.toLowerCase();
59
+
60
+ return options
61
+ .map((option, index) => ({ option, index })) // 保留原始索引
62
+ .filter(({ option }) => {
63
+ const targetStr = option;
64
+ if (!targetStr) return false;
65
+
66
+ // 1. 直接包含搜索词
67
+ if (targetStr.includes(lowerVal)) return true;
68
+
69
+ // 2. 拼音全拼包含搜索词
70
+ const fullPinyin = pinyin(targetStr, { style: pinyin.STYLE_NORMAL })
71
+ .map(word => word[0]).join('');
72
+ if (fullPinyin.includes(lowerVal)) return true;
73
+
74
+ // 3. 拼音首字母缩写包含搜索词
75
+ const abbr = getPinyinAbbr(targetStr);
76
+ return abbr.includes(lowerVal);
77
+ })
78
+ .map(({ index }) => index); // 提取索引
79
+ }
80
+ // 获取拼音首字母缩写(单独封装以便复用)
81
+ function getPinyinAbbr(chinese: string): string {
82
+ if (!chinese) return '';
83
+ const pinyinArray = pinyin(chinese, {
84
+ style: pinyin.STYLE_NORMAL,
85
+ heteronym: false
86
+ });
87
+ return pinyinArray.map(word => word[0]!.charAt(0)).join('');
88
+ }
89
+
90
+ export function parseIdNumber(idNumber: string) {
91
+ if (!/^\d{17}[\dXx]$/.test(idNumber)) {
92
+ throw new Error('无效的身份证号码');
93
+ }
94
+
95
+ // 提取出生日期
96
+ const birthDateStr = idNumber.substring(6, 14);
97
+ const birthDate = `${birthDateStr.substring(0, 4)}/${birthDateStr.substring(4, 6)}/${birthDateStr.substring(6, 8)}`;
98
+
99
+ // 计算年龄
100
+ const birthYear = parseInt(birthDateStr.substring(0, 4), 10);
101
+ const birthMonth = parseInt(birthDateStr.substring(4, 6), 10) - 1; // 月份从0开始
102
+ const birthDay = parseInt(birthDateStr.substring(6, 8), 10);
103
+
104
+ const today = new Date();
105
+ const age = today.getFullYear() - birthYear -
106
+ (today.getMonth() < birthMonth ||
107
+ (today.getMonth() === birthMonth && today.getDate() < birthDay) ? 1 : 0);
108
+
109
+ // 提取性别(第17位)
110
+ const genderDigit = parseInt(idNumber.substring(16, 17), 10);
111
+ const gender = genderDigit % 2 === 1 ? '男' : '女';
112
+
113
+ return {
114
+ birthDate, // 格式:YYYY-MM-DD
115
+ gender, // '男' 或 '女'
116
+ age // 周岁年龄
117
+ };
118
+ }
119
+ export function isNumber(value: string) {
120
+ return /^\d+$/.test(value);
121
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes