diff --git a/.gitignore b/.gitignore index 658ae4b9..7a35f749 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,7 @@ pnpm-lock.yaml .env.local /test.js +/test-*.js repo/ # /docs/zh diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8616b699..e6c56786 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,154 @@ # 更新日志 +### [1.3.75](https://github.com/novlan1/t-comm/compare/v1.3.74...v1.3.75) (2024-04-03) + + +### Features 🎉 + +* **slash:** add slash ([aff4d20](https://github.com/novlan1/t-comm/commit/aff4d208dd43ed0d946a907df8e521aae041f411)) + +### [1.3.74](https://github.com/novlan1/t-comm/compare/v1.3.73...v1.3.74) (2024-04-02) + +### [1.3.73](https://github.com/novlan1/t-comm/compare/v1.3.72...v1.3.73) (2024-04-02) + + +### Features 🎉 + +* **act-id:** add act id map ([ca26316](https://github.com/novlan1/t-comm/commit/ca263161287a1e6683a8229d2521cda79cc0575a)) + +### [1.3.72](https://github.com/novlan1/t-comm/compare/v1.3.71...v1.3.72) (2024-04-02) + + +### Features 🎉 + +* **open-location:** 类型优化 ([0b3ab15](https://github.com/novlan1/t-comm/commit/0b3ab154f084cc1ff95f7e72393236e207c23d1d)) + +### [1.3.71](https://github.com/novlan1/t-comm/compare/v1.3.70...v1.3.71) (2024-04-01) + + +### Features 🎉 + +* **open-location:** 支持iframe ([7d02f6e](https://github.com/novlan1/t-comm/commit/7d02f6ea25cb39820224ceaa8b59b9344ecd35d0)) + +### [1.3.70](https://github.com/novlan1/t-comm/compare/v1.3.69...v1.3.70) (2024-03-31) + + +### Features 🎉 + +* **open-location:** export types ([72ae8c7](https://github.com/novlan1/t-comm/commit/72ae8c7c9343d971580b360e480361772e900f73)) + +### [1.3.69](https://github.com/novlan1/t-comm/compare/v1.3.68...v1.3.69) (2024-03-31) + + +### Features 🎉 + +* **open-location:** add open location ([17647c1](https://github.com/novlan1/t-comm/commit/17647c14d418dd4b3544ea73cdf84421e1653d42)) + +### [1.3.68](https://github.com/novlan1/t-comm/compare/v1.3.67...v1.3.68) (2024-03-30) + + +### Features 🎉 + +* **route-leave-cache:** 支持手动调用 ([ba2443d](https://github.com/novlan1/t-comm/commit/ba2443d2f4e83f7d8cf5f877b8ba13cc2aa5c7b1)) + +### [1.3.67](https://github.com/novlan1/t-comm/compare/v1.3.66...v1.3.67) (2024-03-30) + + +### Features 🎉 + +* **before-route-leave:** add before route leave cache ([f3bd8f7](https://github.com/novlan1/t-comm/commit/f3bd8f7ae91aa1bf7681effba072484a83287c3c)) + +### [1.3.66](https://github.com/novlan1/t-comm/compare/v1.3.65...v1.3.66) (2024-03-29) + + +### Documentation 📖 + +* update uploader docs ([bf3556a](https://github.com/novlan1/t-comm/commit/bf3556a20ef1fc6969320095f4551348308be203)) +* update uploader docs ([4025659](https://github.com/novlan1/t-comm/commit/402565907ffdd59001a92d7caf57349f4bf5457e)) + + +### Features 🎉 + +* **simple-morse:** add simple morse ([7d6bab9](https://github.com/novlan1/t-comm/commit/7d6bab9f350b4d0e8624e7daf9cc8a5d6cc3f8c3)) + +### [1.3.65](https://github.com/novlan1/t-comm/compare/v1.3.64...v1.3.65) (2024-03-29) + + +### Features 🎉 + +* **uploader:** 支持小程序上传 ([641b8f6](https://github.com/novlan1/t-comm/commit/641b8f6a76a06a1fecdd1aca349c5a9398936bb1)) + +### [1.3.64](https://github.com/novlan1/t-comm/compare/v1.3.63...v1.3.64) (2024-03-29) + + +### Features 🎉 + +* **flat:** 补充flat类型 ([59c844b](https://github.com/novlan1/t-comm/commit/59c844b818dfa9f276fa46d8651a9c041621cf55)) +* **flatten:** update flatten type ([1db2e4f](https://github.com/novlan1/t-comm/commit/1db2e4faddb633bfaea6a0c6912b1b975820573a)) +* **launch-game:** update launch game ([55ee0c4](https://github.com/novlan1/t-comm/commit/55ee0c40c221dee342665843574cca1fad57719b)) + +### [1.3.63](https://github.com/novlan1/t-comm/compare/v1.3.62...v1.3.63) (2024-03-15) + + +### Features 🎉 + +* **node-port:** add check valid port ([58cde23](https://github.com/novlan1/t-comm/commit/58cde230b6e97e4e688232643fcba6229ca331a6)) + +### [1.3.62](https://github.com/novlan1/t-comm/compare/v1.3.61...v1.3.62) (2024-03-15) + + +### Code Refactoring ♻️ + +* **path-to-regexp:** update types ([4c2e60c](https://github.com/novlan1/t-comm/commit/4c2e60c32c6d9e6c205c25456c5603ec5760e042)) + +### [1.3.61](https://github.com/novlan1/t-comm/compare/v1.3.60...v1.3.61) (2024-03-15) + + +### Chore 🚀 + +* remove post install script ([00663a0](https://github.com/novlan1/t-comm/commit/00663a01ad939bbb235c8b7c31ed069d835b2f18)) + + +### Features 🎉 + +* **path-regexp:** 导出path-to-regexp ([399050f](https://github.com/novlan1/t-comm/commit/399050fbc00eec066603deded76ef67ce2289089)) + +### [1.3.60](https://github.com/novlan1/t-comm/compare/v1.3.59...v1.3.60) (2024-03-14) + + +### Features 🎉 + +* **version-tip:** 支持第一个大版本 ([3951428](https://github.com/novlan1/t-comm/commit/39514288467e7e68013b8c829fb68ec232c782de)) + +### [1.3.59](https://github.com/novlan1/t-comm/compare/v1.3.58...v1.3.59) (2024-03-13) + + +### Features 🎉 + +* add tam export ([e008a8c](https://github.com/novlan1/t-comm/commit/e008a8c70383ea71e43d7e7e9859c7ca20cf6abc)) +* **version:** support first version ([6d5cbbb](https://github.com/novlan1/t-comm/commit/6d5cbbb2bd274ea0947619a8b735c746602dc225)) + +### [1.3.58](https://github.com/novlan1/t-comm/compare/v1.3.57...v1.3.58) (2024-03-07) + + +### Features 🎉 + +* **version-tip:** support lerna changelog ([694aedc](https://github.com/novlan1/t-comm/commit/694aedcc00475da81d303dd0aec2b86bb2eb81e5)) + +### [1.3.57](https://github.com/novlan1/t-comm/compare/v1.3.56...v1.3.57) (2024-03-06) + + +### Features 🎉 + +* **robot-msg:** add robot msg ([dc0156a](https://github.com/novlan1/t-comm/commit/dc0156a54670513d2aa7b3e2d10711e407aedfb5)) + +### [1.3.56](https://github.com/novlan1/t-comm/compare/v1.3.55...v1.3.56) (2024-03-06) + + +### Features 🎉 + +* **router:** add match params ([3f2a38a](https://github.com/novlan1/t-comm/commit/3f2a38a58dfb1aea368a126e82b4eee0e22043ff)) + ### [1.3.55](https://github.com/novlan1/t-comm/compare/v1.3.54...v1.3.55) (2024-03-01) diff --git a/docs/zh/launch-game.md b/docs/zh/launch-game.md index e752deac..de4cf387 100644 --- a/docs/zh/launch-game.md +++ b/docs/zh/launch-game.md @@ -100,10 +100,6 @@ launchGNGameRoom({ | params | object |

拉起参数

| | params.roomId | string |

房间 Id

| | params.roomPwd | string |

房间 Pwd

| -| [params.context] | object |

上下文,可传入组件实例 this

| -| [params.qrCodeLib] | object |

qrcode

| -| [params.dialogHandler] | object |

弹窗 handler

| -| [params.otherDialogParams] | object |

弹窗的其他参数

| | [params.wxJSLink] | string |

wx js link

| | [params.env] | object |

环境对象

| diff --git a/docs/zh/morse-pwd.md b/docs/zh/morse-pwd.md index ce2bf281..0159237d 100644 --- a/docs/zh/morse-pwd.md +++ b/docs/zh/morse-pwd.md @@ -3,11 +3,11 @@ ## 引入 ```ts -import { MorsePwd } from 't-comm'; +import { MorsePwd , simpleMorse } from 't-comm'; // or -import { MorsePwd } from 't-comm/lib/morse-pwd/index'; +import { MorsePwd , simpleMorse} from 't-comm/lib/morse-pwd/index'; ``` @@ -137,3 +137,29 @@ export default { } ``` + + +## `simpleMorse(param)` + + +**描述**:

简单的摩斯密码,只有点击

+ +**参数**: + + +| 参数名 | 类型 | 描述 | +| --- | --- | --- | +| param | object |

参数

| + + + +**示例** + +```ts +simpleMorse({ + target: 5, // 目标值 + callback: () => console.log('test'), + timeout: 300, // 超时取消 + debug: false, +}) +``` diff --git a/docs/zh/open-location.md b/docs/zh/open-location.md new file mode 100644 index 00000000..2bc8e159 --- /dev/null +++ b/docs/zh/open-location.md @@ -0,0 +1,65 @@ +[[toc]] + +## 引入 + +```ts +import { openLocationInMp, openLocationInH5 } from 't-comm'; + +// or + +import { openLocationInMp, openLocationInH5} from 't-comm/lib/open-location/index'; +``` + + +## `openLocationInMp(param)` + + +**描述**:

打开地图,查看位置

+ +**参数**: + + +| 参数名 | 描述 | +| --- | --- | +| param |

参数

| + +**返回**:

查看Promise

+ +**示例** + +```ts +openLocationInMp({ + lat, + lng, + name, + address, +}); + + +## `openLocationInH5(param)` + + +**描述**:

打开地图,查看位置

+ +**参数**: + + +| 参数名 | 描述 | +| --- | --- | +| param |

参数

| + +**返回**:

查看Promise

+ +**示例** + +```ts +openLocationInH5({ + lat, + lng, + name, + address, + + context: this, + route: '/map' +}); +``` diff --git a/docs/zh/router.md b/docs/zh/router.md index 2dd80d39..1f6a4446 100644 --- a/docs/zh/router.md +++ b/docs/zh/router.md @@ -3,11 +3,19 @@ ## 引入 ```ts -import { findRouteName } from 't-comm'; +import { + findRouteName, + getRouterFuncPath, + getH5CurrentUrl +} from 't-comm'; // or -import { findRouteName} from 't-comm/lib/router/index'; +import { + findRouteName, + getRouterFuncPath, + getH5CurrentUrl +} from 't-comm/lib/router/index'; ``` @@ -35,3 +43,40 @@ const { name, params, meta, path } = findRouteName(rawPath, ALL_ROUTES) || {}; console.log('name', name); ``` + + +## `getRouterFuncPath(route)` + + +**描述**:

根据路由跳转时的参数,提取 path 和其他参数

+ +**参数**: + + +| 参数名 | 描述 | +| --- | --- | +| route |

$router.push 或者 $router.replace 的参数

| + +**返回**:

解析结果

+ + + +## `getH5CurrentUrl(route)` + + +**描述**:

小程序下,获取对应的 H5 路由信息

+ +**参数**: + + +| 参数名 | 类型 | 描述 | +| --- | --- | --- | +| route | Object |

路由信息

| + +**返回**:

H5 Url

+ +**示例** + +```ts +getH5CurrentUrl(this.$route); +``` diff --git a/docs/zh/uni-app.md b/docs/zh/uni-app.md new file mode 100644 index 00000000..c4a1d335 --- /dev/null +++ b/docs/zh/uni-app.md @@ -0,0 +1,30 @@ +[[toc]] + +## 引入 + +```ts +import { getRouteLeaveCache } from 't-comm'; + +// or + +import { getRouteLeaveCache} from 't-comm/lib/uni-app/index'; +``` + + +## `getRouteLeaveCache()` + + +**描述**:

路由离开前记住缓存,返回后不刷新页面

+

比如创建赛事页面,如果前往查看规则,返回后,希望保留之前的表单

+

注意,用了这个 mixin,就不要用 onShow 了,而是用 mounted, +否则可能会重复触发刷新

+ +**参数**: + + +| 参数名 | 类型 | 描述 | +| --- | --- | --- | +| config.refresh | string |

刷新方法

| + +**返回**:

返回对象,包含 beforeRouteLeave 和 activated 方法

+ diff --git a/docs/zh/uploader.md b/docs/zh/uploader.md index a07d6b60..a6f73993 100644 --- a/docs/zh/uploader.md +++ b/docs/zh/uploader.md @@ -15,6 +15,16 @@ import { uploadFile} from 't-comm/lib/uploader/index'; **描述**:

上传文件

+

上传的本质:

+
    +
  1. +

    小程序上传文件是先用 chooseFile 获取一个文件,可以得到 +一个临时路径,然后用 uploadFile 上传该临时路径

    +
  2. +
  3. +

    H5 是 input 获取文件,然后用 FormData 上传 File 对象

    +
  4. +
**参数**: diff --git a/package.json b/package.json index 2db9a341..17557ff9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "t-comm", - "version": "1.3.55", + "version": "1.3.75", "description": "丰富易用的工具库", "main": "lib/index.js", "module": "lib/index.esm.js", @@ -64,8 +64,7 @@ "release:patch": "standard-version --release-as patch -a", "release:alpha": "standard-version --prerelease alpha -a", "release:beta": "standard-version --prerelease beta -a", - "step:build": "node script/gulp/test-task", - "postinstall": "node -e \"try{require('./lib/npm-tip/post-install')}catch(e){}\"" + "step:build": "node script/gulp/test-task" }, "devDependencies": { "@babel/core": "^7.17.2", @@ -92,6 +91,7 @@ "better-docs": "^2.7.2", "chalk": "^4.1.2", "conventional-changelog": "^3.1.25", + "cos-nodejs-sdk-v5": "^2.11.19", "docdash": "^1.2.0", "dotenv": "^16.0.3", "eslint": "^8.25.0", diff --git a/src/base/list/flat.ts b/src/base/list/flat.ts index 83d1a740..1743f41a 100644 --- a/src/base/list/flat.ts +++ b/src/base/list/flat.ts @@ -1,3 +1,9 @@ +type Flat = T extends [infer F, ...infer R] + ? F extends any[] + ? [...Flat, ...Flat] + : [F, ...Flat] + : []; + /** * 递归拉平数组 * @param list 数组 @@ -9,8 +15,8 @@ * * // [1, 2, 3, 4, 5] */ -export function flat(list: Array): Array { - return list.reduce((acc, item) => acc.concat(Array.isArray(item) ? flat(item) : item), []); +export function flat(list: T[]): Flat { + return list.reduce((acc, item) => acc.concat(Array.isArray(item) ? flat(item) : item), [] as any); } @@ -29,9 +35,12 @@ export function flat(list: Array): Array { * // {1: {id: 1, name: 'a'}, 2: {id: 2, name: 'b'}} * */ -export function flatten(list: Array>, key: string): Record { - return list.reduce((acc: Record, item) => { - acc[item[key]] = item; +export function flatten( + list: Array>, + key: string, +): Record> { + return list.reduce((acc: Record>, item) => { + acc[item[key as K]] = item; return acc; - }, {}); + }, {} as any); } diff --git a/src/base/object/sort.ts b/src/base/object/sort.ts index d320afc7..3fc6d6ee 100644 --- a/src/base/object/sort.ts +++ b/src/base/object/sort.ts @@ -1,10 +1,10 @@ -export function sortObjectByKey(obj: any) { +export function sortObjectByKey(obj: Record): Record { if (!obj) { return obj; } - const list = Object.keys(obj).map(key => ({ - value: obj[key], + const list = Object.keys(obj).map((key: string) => ({ + value: obj[key as T], key, })); @@ -13,9 +13,9 @@ export function sortObjectByKey(obj: any) { if (a.key > b.key) return 1; return 0; }); - const result = list.reduce((acc: any, item) => { - acc[item.key] = item.value; + const result = list.reduce((acc: Record, item) => { + acc[item.key as T] = item.value; return acc; - }, {}); + }, {} as any); return result; } diff --git a/src/constant/act-id.ts b/src/constant/act-id.ts new file mode 100644 index 00000000..e25ed042 --- /dev/null +++ b/src/constant/act-id.ts @@ -0,0 +1,3 @@ +export const ACT_ID_MAP = { + GP: '10002', +}; diff --git a/src/constant/index.ts b/src/constant/index.ts index bfd34bae..45d0dbc8 100644 --- a/src/constant/index.ts +++ b/src/constant/index.ts @@ -1 +1,2 @@ +export { ACT_ID_MAP } from './act-id'; export { GID_MAP } from './gid'; diff --git a/src/e2e-test/robot-msg.ts b/src/e2e-test/robot-msg.ts index b7548520..910f5347 100644 --- a/src/e2e-test/robot-msg.ts +++ b/src/e2e-test/robot-msg.ts @@ -1,6 +1,8 @@ import { parseRobotMessage, genRobotMessage } from '../wecom-robot/message'; import { timeStampFormat } from '../time/time'; import { EMOJI_MAP } from './config'; +import type { ITestList } from './types'; + const TRIGGER_MAP = { MANUAL: '手动', @@ -37,18 +39,32 @@ function getFailedTestUnits({ }: { passes: number; tests: number; - testList: Array<{ - fail: number; - title: string; - }> + testList: ITestList; }) { - if (passes == tests) return []; - if (!testList?.length) return []; + if (passes == tests) return {}; + if (!testList?.length) return {}; + + const failedTests = testList.filter(item => !!item.fail); + const failTestTitles = failedTests.map(item => item.title); + + if (!failTestTitles?.length) return {}; + return { + errorTitle: `失败:${failTestTitles.join('、')}`, + errorDetail: getFailedDetail(failedTests), + }; +} - const failedTests = testList.filter(item => !!item.fail).map(item => item.title); +function getFailedDetail(failedTests: Array<{ + err: { + estack?: string; + }; + title: string; +}>) { + return failedTests.map((item) => { + const errMsg = (item.err.estack || '').replace(/[\n]+/g, '; '); - if (!failedTests?.length) return []; - return [`失败:${failedTests.join('、')}`]; + return `${item.title}: ${errMsg}`; + }).filter(item => item); } @@ -70,10 +86,7 @@ export function getE2ETestRobotMessage(data: { passes: number; link: string; - testList: Array<{ - fail: number; - title: string; - }> + testList: ITestList; }> }, notificationList = []) { const { @@ -92,15 +105,16 @@ export function getE2ETestRobotMessage(data: { const time = timeStampFormat(new Date(start).getTime(), 'MM-dd hh:mm:ss'); const title = `>${hasFailed ? EMOJI_MAP.FAIL : EMOJI_MAP.PASS}【自动化测试】`; - const messageList = [ + const errorDetailList: Array> = []; + const messageList: any = [ [ `${title}${parseRobotMessage({ content: `${name}-${comment}`, link: projectLink, })}`, { - content: `${tests}/${passes}`, - label: '全部/成功', + content: `${passes}/${tests}`, + label: '成功/全部', }, { content: `${Math.ceil(duration / 1000)}s`, @@ -130,18 +144,26 @@ export function getE2ETestRobotMessage(data: { link, }); + const failedInfo = getFailedTestUnits({ + testList, + passes, + tests, + }); + if (failedInfo.errorDetail?.length) { + errorDetailList.push(['\n']); + errorDetailList.push(failedInfo.errorDetail); + } + return [ `- ${fileName}`, - `${tests}/${passes}`, - ...getFailedTestUnits({ - testList, - passes, - tests, - }), + `${passes}/${tests}`, + failedInfo?.errorTitle || '', ]; }); messageList.push(...fileMessageList); + messageList.push(...['\n', '\n']); + messageList.push(...errorDetailList); return { message: genRobotMessage(messageList), diff --git a/src/e2e-test/types.ts b/src/e2e-test/types.ts index aca4aab5..19e04e16 100644 --- a/src/e2e-test/types.ts +++ b/src/e2e-test/types.ts @@ -1,2 +1,9 @@ export type IBrowser = any; export type IPage = any; +export type ITestList = Array<{ + fail: number; + title: string; + err: { + estack?: string; + }; +}>; diff --git a/src/git/git-link.ts b/src/git/git-link.ts index 5c5c6786..4869bc49 100644 --- a/src/git/git-link.ts +++ b/src/git/git-link.ts @@ -1,6 +1,7 @@ -export function rmFirstAndLastSlash(str = '') { - return str.replace(/^\/|\/$/g, ''); -} +import { removeFirstAndLastSlash } from '../slash/slash'; + + +export const rmFirstAndLastSlash = removeFirstAndLastSlash; export function getGitCodeLink({ domain, diff --git a/src/index.ts b/src/index.ts index 6b1f06e5..3ef75b54 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,7 +42,9 @@ export * from './mp-ci'; export * from './msdk'; export * from './node'; export * from './node-img'; +export * from './node-port'; export * from './npm-tip'; +export * from './open-location'; export * from './open-source-report'; export * from './pages-statistics'; export * from './path'; @@ -61,6 +63,7 @@ export * from './rtx'; export * from './scheduler'; export * from './share'; export * from './sheet'; +export * from './slash'; export * from './sleep'; export * from './storage'; export * from './tam'; @@ -70,6 +73,7 @@ export * from './tgit'; export * from './throttle'; export * from './time'; export * from './toast'; +export * from './uni-app'; export * from './uploader'; export * from './url'; export * from './v-console'; diff --git a/src/launch-game/game-gp.ts b/src/launch-game/game-gp.ts index d582cbe5..887c3a86 100644 --- a/src/launch-game/game-gp.ts +++ b/src/launch-game/game-gp.ts @@ -5,7 +5,6 @@ import { GAME_SCHEME_PREFIX_MAP, DEFAULT_WX_JS_SDK, } from './helper'; -import type { IBaseLaunchParams } from './types'; /** @@ -13,10 +12,6 @@ import type { IBaseLaunchParams } from './types'; * @param {object} params 拉起参数 * @param {string} params.roomId 房间 Id * @param {string} params.roomPwd 房间 Pwd - * @param {object} [params.context] 上下文,可传入组件实例 this - * @param {object} [params.qrCodeLib] qrcode - * @param {object} [params.dialogHandler] 弹窗 handler - * @param {object} [params.otherDialogParams] 弹窗的其他参数 * @param {string} [params.wxJSLink] wx js link * @param {object} [params.env] 环境对象 * @returns Promise @@ -33,16 +28,13 @@ export function launchGPGameRoom({ roomId = '', roomPwd = '', - context, - qrCodeLib, - dialogHandler, - otherDialogParams, - wxJSLink = DEFAULT_WX_JS_SDK, env = initEnv(), -}: IBaseLaunchParams & { +}: { roomId: string; roomPwd: string; + wxJSLink?: string; + env?: Record; }) { const schemeParam = getGPSchemeParam(roomId, roomPwd); @@ -52,13 +44,8 @@ export function launchGPGameRoom({ roomPwd, }, schemeParam, - - context, - qrCodeLib, - dialogHandler, - otherDialogParams, - schemePrefix: GAME_SCHEME_PREFIX_MAP.GP, + wxJSLink, env, }); diff --git a/src/launch-game/helper.ts b/src/launch-game/helper.ts index 4bd3cbc7..1a46cf43 100644 --- a/src/launch-game/helper.ts +++ b/src/launch-game/helper.ts @@ -77,8 +77,9 @@ export function launchInWX({ console.info('[launchCore wx] res: ', res); if (res.err_msg.indexOf('ok') === -1) { - if (res.err_msg.indexOf('permission') > -1 - || res.err_msg.indexOf('access_denied') > -1 + if ((res.err_msg.indexOf('permission') > -1 + || res.err_msg.indexOf('access_denied') > -1) + && qrCodeLib && dialogHandler ) { showQRcode({ launchParams, @@ -88,10 +89,10 @@ export function launchInWX({ otherDialogParams, }); } else { - reject(); + reject(res); } } else { - resolve(1); + resolve(res); } }, ); diff --git a/src/morse-pwd/index.ts b/src/morse-pwd/index.ts index b12a1088..8a8d4c55 100644 --- a/src/morse-pwd/index.ts +++ b/src/morse-pwd/index.ts @@ -1 +1,2 @@ export { MorsePwd } from './morse-pwd'; +export { simpleMorse } from './simple-morse'; diff --git a/src/morse-pwd/simple-morse.ts b/src/morse-pwd/simple-morse.ts new file mode 100644 index 00000000..bb81afad --- /dev/null +++ b/src/morse-pwd/simple-morse.ts @@ -0,0 +1,46 @@ +let clickCount = 0; +let simpleMorseTimer: ReturnType; + + +/** + * 简单的摩斯密码,只有点击 + * @param param {object} 参数 + * + * @example + * ```ts + * simpleMorse({ + * target: 5, // 目标值 + * callback: () => console.log('test'), + * timeout: 300, // 超时取消 + * debug: false, + * }) + * ``` + */ +export function simpleMorse({ + target = 5, + callback = () => { + console.log('[Simple Morse]'); + }, + timeout = 300, + debug = false, +}: { + callback?: Function; + target?: number; + timeout?: number; + debug?: boolean; +}) { + clickCount = clickCount + 1; + clearTimeout(simpleMorseTimer); + + if (debug) { + console.log('[simpleMorse: clickCount]', clickCount); + } + + if (clickCount >= target) { + callback?.(); + clickCount = 0; + } + simpleMorseTimer = setTimeout(() => { + clickCount = 0; + }, timeout); +} diff --git a/src/node-port/index.ts b/src/node-port/index.ts new file mode 100644 index 00000000..9c895aae --- /dev/null +++ b/src/node-port/index.ts @@ -0,0 +1 @@ +export { getValidPort } from './node-port'; diff --git a/src/node-port/node-port.ts b/src/node-port/node-port.ts new file mode 100644 index 00000000..3dac704c --- /dev/null +++ b/src/node-port/node-port.ts @@ -0,0 +1,25 @@ +export function getValidPort(port: number) { + // eslint-disable-next-line @typescript-eslint/no-require-imports + const net = require('net'); + const server = net.createServer().listen(port); + + + return new Promise((resolve, reject) => { + // 如果监听成功,表示端口没有被其他服务占用,端口可用,取消监听,返回端口给调用者。 + server.on('listening', () => { + server.close(); + resolve(port); + }); + + // 如果监听出错,端口+1,继续监听,直到监听成功。 + server.on('error', (err: any) => { + if (err.code === 'EADDRINUSE') { + resolve(getValidPort(port + 1)); + console.log(`this port ${port} is occupied try another.`); + } else { + reject(err); + } + }); + }); +} + diff --git a/src/open-location/index.ts b/src/open-location/index.ts new file mode 100644 index 00000000..0337df94 --- /dev/null +++ b/src/open-location/index.ts @@ -0,0 +1,2 @@ +export { openLocationInH5, openLocationInMp } from './option-location'; +export type { OpenLocation } from './types'; diff --git a/src/open-location/option-location.ts b/src/open-location/option-location.ts new file mode 100644 index 00000000..a9a05183 --- /dev/null +++ b/src/open-location/option-location.ts @@ -0,0 +1,81 @@ +import type { OpenLocation } from './types'; + +/** + * 打开地图,查看位置 + * @param param 参数 + * @returns 查看Promise + * @example + * ```ts + * openLocationInMp({ + * lat, + * lng, + * name, + * address, + * }); + */ +export function openLocationInMp({ + lat = '', + lng = '', + name = '', + address = '', + scale = 18, +}: OpenLocation) { + return new Promise((resolve, reject) => { + uni.openLocation({ + latitude: +lat, // 纬度 + longitude: +lng, // 经度 + name, // 地点名称 + address, // 地址的详细说明 + scale, // 缩放比例 + success(res: any) { + console.log('打开地图成功'); + resolve(res); + }, + fail(err: any) { + console.log('打开地图失败', err); + reject(err); + }, + }); + }); +} + +/** + * 打开地图,查看位置 + * @param param 参数 + * @returns 查看Promise + * @example + * ```ts + * openLocationInH5({ + * lat, + * lng, + * name, + * address, + * + * context: this, + * route: '/map' + * }); + * ``` + */ +export function openLocationInH5({ + lat = '', + lng = '', + name = '', + address = '', + + route, + context, +}: OpenLocation): Promise { + const href = `https://apis.map.qq.com/uri/v1/marker?marker=coord:${lat},${lng};title:${name};addr:${address}&referer=tip`; + if (route && context) { + context.$router.push({ + path: route, + query: { + url: decodeURIComponent(href), + }, + }); + return Promise.resolve(1); + } + window.location.href = href; + + return Promise.resolve(1); +} diff --git a/src/open-location/types.ts b/src/open-location/types.ts new file mode 100644 index 00000000..83721d75 --- /dev/null +++ b/src/open-location/types.ts @@ -0,0 +1,11 @@ +export interface OpenLocation { + lat?: string; + lng?: string; + name?: string; + address?: string; + scale?: number; + + context?: any; + route?: string; +} + diff --git a/src/rainbow/rainbow-user.ts b/src/rainbow/rainbow-user.ts index 61c563a5..3ac31426 100644 --- a/src/rainbow/rainbow-user.ts +++ b/src/rainbow/rainbow-user.ts @@ -50,6 +50,7 @@ export function fetchRainbowConfig(key: string, secretInfo: { items: Array<{ key_values: Array<{ key: any; + value: any; }> }> } diff --git a/src/router/helper.ts b/src/router/helper.ts new file mode 100644 index 00000000..ed99a03a --- /dev/null +++ b/src/router/helper.ts @@ -0,0 +1,22 @@ +/** + * 根据路由跳转时的参数,提取 path 和其他参数 + * @param route $router.push 或者 $router.replace 的参数 + * @returns 解析结果 + */ +export function getRouterFuncPath(route: any) { + let rawPath; + let rawOther: any = {}; + + if (typeof route === 'object' && route.path) { + rawPath = route.path; + const { path, ...other } = route; + rawOther = other; + } else if (typeof route === 'string') { + rawPath = route; + } + + return { + path: rawPath, + other: rawOther, + }; +} diff --git a/src/router/index.ts b/src/router/index.ts index 2661b074..a677e20d 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1 +1,4 @@ export { findRouteName } from './find-route-name'; +export { getRouterFuncPath } from './helper'; +export { matchParams, getH5CurrentUrl } from './match-params'; +export { default as pathToRegexp } from './path-to-regexp'; diff --git a/src/router/match-params.ts b/src/router/match-params.ts new file mode 100644 index 00000000..09b292cc --- /dev/null +++ b/src/router/match-params.ts @@ -0,0 +1,32 @@ +export function matchParams(rawPath = '', params: Record = {}) { + return rawPath.replace(/:(\w+)\???(?=$|\/)/g, (a, b) => { + if (params[b]) { + return params[b]; + } + return ''; + }); +} + +/** + * 小程序下,获取对应的 H5 路由信息 + * @param {Object} route 路由信息 + * @returns H5 Url + * @example + * ```ts + * getH5CurrentUrl(this.$route); + * ``` + */ +export function getH5CurrentUrl(route: { + name?: string; + meta?: { + rawPath?: Array; + }; + params: Record +}) { + const { name = '', meta, params } = route; + const { rawPath = [] } = meta || {}; + if (!Object.keys(params).length || !rawPath.length) { + return `/${name}`; + } + return matchParams(rawPath[0], params); +} diff --git a/src/router/path-to-regexp.js b/src/router/path-to-regexp.ts similarity index 89% rename from src/router/path-to-regexp.js rename to src/router/path-to-regexp.ts index 273f7879..cc48794e 100644 --- a/src/router/path-to-regexp.js +++ b/src/router/path-to-regexp.ts @@ -31,13 +31,13 @@ const PATH_REGEXP = new RegExp([ * @param {Object=} options * @return {!Array} */ -function parse(str, options) { +function parse(str: string, options?: any) { const tokens = []; let key = 0; let index = 0; let path = ''; - const defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER; - const delimiters = (options && options.delimiters) || DEFAULT_DELIMITERS; + const defaultDelimiter = (options?.delimiter) || DEFAULT_DELIMITER; + const delimiters = (options?.delimiters) || DEFAULT_DELIMITERS; let pathEscaped = false; let res; @@ -111,7 +111,7 @@ function parse(str, options) { * @param {Object=} options * @return {!function(Object=, Object=)} */ -function compile(str, options) { +function compile(str: string, options?: any) { return tokensToFunction(parse(str, options)); } @@ -119,7 +119,7 @@ function compile(str, options) { * Expose a method for transforming tokens into the path function. * @ignore */ -function tokensToFunction(tokens) { +function tokensToFunction(tokens: Array) { // Compile all the tokens into regexps. const matches = new Array(tokens.length); @@ -130,9 +130,9 @@ function tokensToFunction(tokens) { } } - return function (data, options) { + return function (data: any, options: any) { let path = ''; - const encode = (options && options.encode) || encodeURIComponent; + const encode = (options?.encode) || encodeURIComponent; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; @@ -200,7 +200,7 @@ function tokensToFunction(tokens) { * @param {string} str * @return {string} */ -function escapeString(str) { +function escapeString(str: string) { return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1'); } @@ -210,7 +210,7 @@ function escapeString(str) { * @param {string} group * @return {string} */ -function escapeGroup(group) { +function escapeGroup(group: string) { return group.replace(/([=!:$/()])/g, '\\$1'); } @@ -220,8 +220,8 @@ function escapeGroup(group) { * @param {Object} options * @return {string} */ -function flags(options) { - return options && options.sensitive ? '' : 'i'; +function flags(options: any) { + return options?.sensitive ? '' : 'i'; } /** @@ -231,7 +231,7 @@ function flags(options) { * @param {Array=} keys * @return {!RegExp} */ -function regexpToRegexp(path, keys) { +function regexpToRegexp(path: any, keys?: Array) { if (!keys) return path; // Use a negative lookahead to match only capturing groups. @@ -262,7 +262,7 @@ function regexpToRegexp(path, keys) { * @param {Object=} options * @return {!RegExp} */ -function arrayToRegexp(path, keys, options) { +function arrayToRegexp(path: any, keys?: Array, options?: any): any { const parts = []; for (let i = 0; i < path.length; i++) { @@ -280,7 +280,7 @@ function arrayToRegexp(path, keys, options) { * @param {Object=} options * @return {!RegExp} */ -function stringToRegexp(path, keys, options) { +function stringToRegexp(path: string, keys?: Array, options?: any) { return tokensToRegExp(parse(path, options), keys, options); } @@ -292,7 +292,7 @@ function stringToRegexp(path, keys, options) { * @param {Object=} options * @return {!RegExp} */ -function tokensToRegExp(tokens, keys, options) { +function tokensToRegExp(tokens: Array, keys?: Array, options?: any) { options = options || {}; const { strict } = options; @@ -356,7 +356,7 @@ function tokensToRegExp(tokens, keys, options) { * @param {Object=} options * @return {!RegExp} */ -function pathToRegexp(path, keys, options) { +function pathToRegexp(path: string | RegExp | Array, keys?: Array, options?: any) { if (path instanceof RegExp) { return regexpToRegexp(path, keys); } @@ -373,6 +373,11 @@ function pathToRegexp(path, keys, options) { * @ignore */ +pathToRegexp.parse = parse; +pathToRegexp.compile = compile; +pathToRegexp.tokensToFunction = tokensToFunction; +pathToRegexp.tokensToRegExp = tokensToRegExp; + export default pathToRegexp; export { parse, diff --git a/src/slash/index.ts b/src/slash/index.ts new file mode 100644 index 00000000..c2c8bf6a --- /dev/null +++ b/src/slash/index.ts @@ -0,0 +1 @@ +export { removeFirstAndLastSlash, removeFirstSlash } from './slash'; diff --git a/src/slash/slash.ts b/src/slash/slash.ts new file mode 100644 index 00000000..8b2cf4a0 --- /dev/null +++ b/src/slash/slash.ts @@ -0,0 +1,11 @@ +export function removeFirstSlash(key = '') { + if (key.startsWith('/')) { + return key.slice(1); + } + return key; +} + + +export function removeFirstAndLastSlash(str = '') { + return str.replace(/^\/|\/$/g, ''); +} diff --git a/src/tam/api/index.ts b/src/tam/api/index.ts index 07d485fe..f1623d22 100644 --- a/src/tam/api/index.ts +++ b/src/tam/api/index.ts @@ -1,4 +1,8 @@ export { getMultiCustomEventData } from './custom-event'; export { getRUMAllProject, getRUMScores } from './rum-score'; -export { getTAMSummaryScoreByGroupIdList, getTAMScoreInfoByProjectId } from './summary-score'; +export { + getTAMSummaryScoreByGroupIdList, + getTAMScoreInfoByProjectId, + getProjectByGroupId, +} from './summary-score'; diff --git a/src/tam/api/summary-score.ts b/src/tam/api/summary-score.ts index 195eb649..e221d2c3 100644 --- a/src/tam/api/summary-score.ts +++ b/src/tam/api/summary-score.ts @@ -68,6 +68,8 @@ export async function getTAMScoreInfoByProjectId({ headers: { ...credential, }, + }).catch((err) => { + console.log('[getTAMScoreInfoByProjectId.err]', err); }); return result?.data?.message || []; @@ -128,7 +130,7 @@ export async function getTAMScoreInfoByProjectId({ * ]; * */ -async function getProjectByGroupId({ +export async function getProjectByGroupId({ groupId, secretInfo, }: { @@ -143,6 +145,8 @@ async function getProjectByGroupId({ headers: { ...credential, }, + }).catch((err) => { + console.log('[getProjectByGroupId.err]', err); }); return result?.data?.result || []; } diff --git a/src/tam/index.ts b/src/tam/index.ts index 0cd512d8..9271fd55 100644 --- a/src/tam/index.ts +++ b/src/tam/index.ts @@ -9,4 +9,5 @@ export { getRUMScores, getTAMScoreInfoByProjectId, getTAMSummaryScoreByGroupIdList, + getProjectByGroupId, } from './api/index'; diff --git a/src/uni-app/index.ts b/src/uni-app/index.ts new file mode 100644 index 00000000..5b32ee51 --- /dev/null +++ b/src/uni-app/index.ts @@ -0,0 +1 @@ +export { getRouteLeaveCache } from './route-leave-cache'; diff --git a/src/uni-app/route-leave-cache.ts b/src/uni-app/route-leave-cache.ts new file mode 100644 index 00000000..7e15d578 --- /dev/null +++ b/src/uni-app/route-leave-cache.ts @@ -0,0 +1,52 @@ +/** + * 路由离开前记住缓存,返回后不刷新页面 + * + * 比如创建赛事页面,如果前往查看规则,返回后,希望保留之前的表单 + * + * 注意,用了这个 mixin,就不要用 onShow 了,而是用 mounted, + * 否则可能会重复触发刷新 + * + * @param {string} config.refresh 刷新方法 + * @returns 返回对象,包含 beforeRouteLeave 和 activated 方法 + */ +export function getRouteLeaveCache({ + refresh, + // cacheRoutes = [], +}: { + refresh?: string; + // cacheRoutes?: Array; +}) { + let randomKey = ''; + const RANDOM_KEY = 'RANDOM_KEY_CREATE'; + + return { + // beforeRouteLeave(to: { name: string }, from: any, next: Function) { + // if (cacheRoutes.includes(to.name)) { + // randomKey = `${Math.random() * 10000000}`; + // localStorage.setItem(RANDOM_KEY, randomKey); + // } else { + // localStorage.setItem(RANDOM_KEY, ''); + // } + // next(); + // }, + activated() { + const localRandomKey = localStorage.getItem(RANDOM_KEY); + localStorage.setItem(RANDOM_KEY, ''); + const useCache = (localRandomKey && localRandomKey == randomKey); + + if (!useCache && refresh) { + // @ts-ignore + this[refresh]?.(); + } + }, + mounted() { + localStorage.setItem(RANDOM_KEY, ''); + }, + methods: { + _jumpToCacheRoute() { + randomKey = `${Math.random() * 10000000}`; + localStorage.setItem(RANDOM_KEY, randomKey); + }, + }, + }; +} diff --git a/src/uploader/request.ts b/src/uploader/request.ts index 6373f3d0..43c11ecc 100644 --- a/src/uploader/request.ts +++ b/src/uploader/request.ts @@ -44,6 +44,13 @@ export function requestUploadFile({ }): Promise<{ url: string; }> { + if (['mp-weixin', 'mp-qq'].includes(process.env.UNI_PLATFORM || '')) { + return requestUploadFileInMp({ + file, + hashCode, + url, + }); + } return new Promise((resolve, reject) => { const formData = new FormData(); formData.append(uploadFileKey, file); @@ -69,3 +76,52 @@ export function requestUploadFile({ }); } + +function requestUploadFileInMp({ + hashCode, + file, + url: prefixUrl, +}: { + file: File; + hashCode: string; + url: string; +}): Promise<{ + url: string; + }> { + return new Promise((resolve, reject) => { + const widthHeight = ''; + const url = `${prefixUrl}${hashCode}&width_height=${widthHeight}`; + + uni.uploadFile({ + url, + // @ts-ignore + filePath: file.path, + name: 'upload_pic_input', + formData: { + _hash: hashCode, + }, + success(res: any) { + if (res.data) { + let data = { url: '', r: 0 }; + try { + data = JSON.parse(res.data); + } catch (err) {} + + if (data.r == 0) { + resolve({ + url: data.url, + }); + return; + } + + reject(res); + } else { + reject(res); + } + }, + fail(res: any) { + reject(res); + }, + }); + }); +} diff --git a/src/uploader/types.ts b/src/uploader/types.ts index 1a5b8e0e..2e944a23 100644 --- a/src/uploader/types.ts +++ b/src/uploader/types.ts @@ -1,5 +1,5 @@ export type IUploaderOptions = { - requestHashUrl?: string; + requestHashUrl?: string | Function; uploadFileKey?: string; uploadUrlPrefix?: string; }; diff --git a/src/uploader/uploader.ts b/src/uploader/uploader.ts index 848a4eb5..2ba2a324 100644 --- a/src/uploader/uploader.ts +++ b/src/uploader/uploader.ts @@ -44,9 +44,16 @@ export class UploadManager { return new Promise((resolve, reject) => { // 后台是两小时过期,这里稍微减去5分钟 this.isRequesting = true; - requestHashCode(this.options.requestHashUrl).then((response) => { + let promise: Promise; + if (typeof this.options.requestHashUrl === 'function') { + promise = this.options.requestHashUrl(); + } else { + promise = requestHashCode(this.options.requestHashUrl); + } + + promise.then((response) => { this.isRequesting = false; - this.hash = response.hash; + this.hash = response.hash || response._hash; this.timestamp = response.timestamp; resolve(this.hash); @@ -109,6 +116,13 @@ export class UploadManager { /** * 上传文件 + * + * 上传的本质: + * + * 1. 小程序上传文件是先用 chooseFile 获取一个文件,可以得到 + * 一个临时路径,然后用 uploadFile 上传该临时路径 + * + * 2. H5 是 input 获取文件,然后用 FormData 上传 File 对象 * @param {File} file 文件 * @returns {Promise<{url: string}>} 上传结果 * diff --git a/src/version-tip/gen-version-tip.ts b/src/version-tip/gen-version-tip.ts index c35f7e40..7507734f 100644 --- a/src/version-tip/gen-version-tip.ts +++ b/src/version-tip/gen-version-tip.ts @@ -18,11 +18,15 @@ export function parseChangeLog({ changelogStr: string, targetVersion: string, }) { + // 非大版本(1.0.0,2.0.0等),比如 1.1.1 + // 不是第一个版本 let currentVersion = changelogStr.match(new RegExp( `(?<=### \\[${targetVersion}\\].*\n).*?(?=\n##+ \\[?\\d+.\\d+.\\d+)`, 's', )); + // 大版本 + // 不是第一个版本 if (!currentVersion || !currentVersion[0]) { currentVersion = changelogStr.match(new RegExp( `(?<=## \\[${targetVersion}\\].*\n).*?(?=\n##+ \\[?\\d+.\\d+.\\d+)`, @@ -30,6 +34,33 @@ export function parseChangeLog({ )); } + // changeLog 的另一种形式,lerna 生成的 + if (!currentVersion || !currentVersion[0]) { + changelogStr = changelogStr.replace(/<\/?small>/g, ''); + currentVersion = changelogStr.match(new RegExp( + `(?<=## ${targetVersion}.*\n).*?(?=\n##+ ?\\d+.\\d+.\\d+)`, + 's', + )); + } + + // 非大版本 + // 第一个版本 + if (!currentVersion || !currentVersion[0]) { + currentVersion = changelogStr.match(new RegExp( + `(?<=### ${targetVersion}.*\n).*`, + 's', + )); + } + + // 大版本 + // 第一个版本 + if (!currentVersion || !currentVersion[0]) { + currentVersion = changelogStr.match(new RegExp( + `(?<=## ${targetVersion}.*\n).*`, + 's', + )); + } + if (!currentVersion || !currentVersion[0]) { console.log(`[GEN VERSION TIP] ERROR: NOT FOUND CHANGELOG INFO OF ${targetVersion} `); return ''; @@ -124,7 +155,11 @@ function generatePublishInfo({ * appInfo, * }); */ -export function genVersionTip({ readmeFilePath, appInfo, showNpmLink = false }: { +export function genVersionTip({ + readmeFilePath, + appInfo, + showNpmLink = false, +}: { showNpmLink?: boolean readmeFilePath: string appInfo: IAppInfo diff --git a/src/version-tip/gen-version.ts b/src/version-tip/gen-version.ts index 263afad5..3b2a57e6 100644 --- a/src/version-tip/gen-version.ts +++ b/src/version-tip/gen-version.ts @@ -4,6 +4,7 @@ import { getGitCommitsBeforeTag, getGitTagTime, } from '../git'; +import { timeStampFormat } from '../time/time'; import { execCommand } from '../node/node-command'; import { TAG_MAP } from './config'; @@ -76,7 +77,8 @@ export function shouldGenVersion(root?: string, forceGenVersion?: boolean): numb } const tagTimeStamp = getTimeStampFromDate(tagDate); - console.log(`[GEN VERSION] Tag TimeStamp: ${tagTimeStamp}`); + const dateStr = timeStampFormat(tagTimeStamp, 'yyyy-MM-dd hh:mm:ss'); + console.log(`[GEN VERSION] Tag TimeStamp: ${dateStr}`); if (Date.now() - tagTimeStamp < INTERVAL_TIME) { console.log(`[GEN VERSION] ERROR: 间隔小于${INTERVAL_TIME}`); diff --git a/src/version-tip/index.ts b/src/version-tip/index.ts index f5959bc5..ab39132e 100644 --- a/src/version-tip/index.ts +++ b/src/version-tip/index.ts @@ -1,3 +1,3 @@ -export { genVersionTip } from './gen-version-tip'; +export { genVersionTip, parseChangeLog } from './gen-version-tip'; export { genVersion, shouldGenVersion } from './gen-version'; export { genVersionAndSendChangeLog } from './gen-send-version'; diff --git a/test/router/match-params.spec.ts b/test/router/match-params.spec.ts new file mode 100644 index 00000000..59bb46e2 --- /dev/null +++ b/test/router/match-params.spec.ts @@ -0,0 +1,21 @@ +import { matchParams } from '../../src/router/match-params'; + +describe('matchParams', () => { + it('matchParams', () => { + const params = { + childid: '123', + inviteteamid: '222', + }; + expect(matchParams('/match/match-detail-index/:childid/:inviteteamid?', params)) + .toBe('/match/match-detail-index/123/222'); + + expect(matchParams('/match/match-detail-index/:inviteteamid?', params)) + .toBe('/match/match-detail-index/222'); + + expect(matchParams('/match/match-detail-index/:childid/:inviteteamid/', params)) + .toBe('/match/match-detail-index/123/222/'); + + expect(matchParams('/match/match-detail-index', params)) + .toBe('/match/match-detail-index'); + }); +});