Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(service): new request implementation #138

Merged
2 changes: 1 addition & 1 deletion project.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"appid": "wxd4b11753654a636f",
"setting": {
"urlCheck": false,
"es6": false,
"es6": true,
"enhance": false,
"postcss": false,
"preloadBackgroundData": false,
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import useTimeInstance from "./useTimeString";
import useRequest from "./useRequest";
import useRequest, { useRequestNext } from "./useRequest";
import useDarkMode from "./useDarkMode";

export {
useTimeInstance,
useRequest,
useRequestNext,
useDarkMode
};
74 changes: 73 additions & 1 deletion src/hooks/useRequest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import Taro from "@tarojs/taro";
import { onMounted, ref } from "vue";
import { onMounted, ref, shallowRef } from "vue";

interface RequestConfigType<TData extends TaroGeneral.IAnyObject, TParams> {
/** 是否手动发起请求 */
Expand Down Expand Up @@ -36,6 +36,7 @@
}

/**
* @deprecated
* 封装请求成 hook
*
* 为请求函数扩展
Expand All @@ -58,7 +59,7 @@
data.value = undefined;
error.value = undefined;
config?.onBefore?.();
// TODO: add delay

Check warning on line 62 in src/hooks/useRequest.ts

View workflow job for this annotation

GitHub Actions / cache-and-install

Unexpected 'todo' comment: 'TODO: add delay'
const timer = setTimeout(() => {
loading.value = true;
}, config?.loadingDelay || 0);
Expand Down Expand Up @@ -94,3 +95,74 @@
};

export default useRequest;

type UseRequestOptions<Data, Params> = {
/** Promise 还未 fulfilled 时,给 `data` 的初始值 */
initialData: Data;
/** 自动触发请求,以及调用 `run` 函数不传参数时,默认给请求函数传入的参数 */
defaultParams?: Params;
/** 是否手动触发请求, 默认为 false */
manual?: boolean;
/** 最短加载时间,默认为 0ms,在有加载动画效果时防止渲染闪屏 */
minLoadingTime?: number;
/** 在执行 Promise 前,将 `data` 重置为 `initialData`,默认为 false */
resetOnRun?: boolean;
onSuccess?: (data: Data) => void;
onError?: (error: unknown) => void;
};

const promiseTimeout = (ms: number) => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
};

export function useRequestNext<State, Params extends Record<string, any>>(
promise: (params?: Params) => Promise<State>,
options: UseRequestOptions<State, Params>
) {
const {
initialData,
defaultParams,
manual = false,
minLoadingTime = 0,
resetOnRun = false,
onSuccess,
onError
} = options ?? {};

const loading = ref(false);
const data = ref(initialData);
const error = shallowRef<unknown | undefined>(undefined);

async function run(params?: Params) {
loading.value = true;
error.value = undefined;
if (resetOnRun) data.value = initialData;

// 用 `allSettled` 而不用 try-catch 是为了 Delay 也作用到异常状态
const delayedPromise = Promise.allSettled([
promise(params ?? defaultParams),
promiseTimeout(minLoadingTime)
]);
const [promiseResult] = await delayedPromise;
if (promiseResult.status === "fulfilled") {
data.value = promiseResult.value;
onSuccess?.(promiseResult.value);
} else {
error.value = promiseResult.reason;
onError?.(promiseResult.reason);
}

loading.value = false;
};

if (!manual) run();

return {
loading,
data,
error,
run
};
}
12 changes: 0 additions & 12 deletions src/services/api/apiList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,4 @@ const api = {
}
};

const defDevHost = "http://0.0.0.0:8080";
function appendHost(api: any) {
for (const key in api)
if (Object.prototype.hasOwnProperty.call(api, key))
if (api[key] instanceof Object) appendHost(api[key]);
else
api[key] = process.env.HOST
? process.env.HOST + api[key]
: defDevHost + api[key];
}

appendHost(api);
export { api };
3 changes: 3 additions & 0 deletions src/services/api/codes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* @deprecated
*/
export const ServerCode = {
OK: 1,

Expand Down
5 changes: 4 additions & 1 deletion src/services/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ const globalConfig: Partial<Taro.request.Option> = {
timeout: 12 * 1000
};

/**
* @deprecated
*/
const request = <TData extends TaroGeneral.IAnyObject | any> (
url: string,
config: Omit<Taro.request.Option, "url">
) => {
return Taro.request<IResponse<TData>>({
...globalConfig,
url,
url: process.env.HOST + url,
...config
});

Expand Down
1 change: 1 addition & 0 deletions src/services/services/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import errCodeHandler from "../utils/errHandler";
import { ServerCode } from "../api/codes";

/**
* @deprecated
* 与微信建立链接,获取 session
* 场景: 发送带 session 的请求 postWithSession,打开小程序页面
*/
Expand Down
6 changes: 5 additions & 1 deletion src/services/utils/errHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { ServerCode } from "../api/codes";
import Taro from "@tarojs/taro";
import store, { serviceStore } from "@/store";

// comment: 微信相关登录异常处理
/**
* @deprecated
* 微信相关登录异常处理
* TODO: 迁移处理逻辑至具体的业务模块
*/
export default async function errCodeHandler(code: number, showModal = true) {
console.error("Error code", code);
if (showModal)
Expand Down
3 changes: 3 additions & 0 deletions src/services/utils/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { LoginByTaro } from "../services/authService";
import { ServerCode } from "../api/codes";

/**
* @deprecated
* 调用 fetch 带上 session 发送请求
*
* 一般通过 `updateDateStateWithSession` 调用
Expand Down Expand Up @@ -42,6 +43,7 @@ async function postWithSession(
}

/**
* @deprecated
* 检查有无 session
* @returns 状态
*/
Expand All @@ -50,6 +52,7 @@ function checkSession(): boolean {
}

/**
* @deprecated
* 检查 session 对应的微信用户有没有激活记录
* @returns 状态
*/
Expand Down
2 changes: 2 additions & 0 deletions src/services/utils/updateDateState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ServerCode } from "../api/codes";
import errCodeHandler from "./errHandler";

/**
* @deprecated
* 无 session 请求更新全局状态,系统请求专用
* @param api
* @param data
Expand Down Expand Up @@ -34,6 +35,7 @@ async function updateDateState(
}

/**
* @deprecated
* 带 session 发送请求,并更新状态
* @param api
* @param data
Expand Down
10 changes: 8 additions & 2 deletions src/utils/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ interface FetchResult extends Taro.request.SuccessCallbackResult<any> {
cookies?: string[];
}

/**
* @deprecated
*/
function get(url: string, cookies?: ICookie[]): Promise<FetchResult> {
const header = cookies
? {
Expand All @@ -17,7 +20,7 @@ function get(url: string, cookies?: ICookie[]): Promise<FetchResult> {
};
return new Promise((resolve, reject) => {
Taro.request({
url: url,
url: process.env.HOST + url,
header: header,
mode: "cors",
success: (res) => {
Expand All @@ -31,6 +34,9 @@ function get(url: string, cookies?: ICookie[]): Promise<FetchResult> {
});
}

/**
* @deprecated
*/
function postJson(
url: string,
data: any,
Expand All @@ -47,7 +53,7 @@ function postJson(
};

Taro.request({
url: url,
url: process.env.HOST + url,
data: data ? data : undefined,
header: header,
method: "POST",
Expand Down
10 changes: 9 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import timeUtils from "./time";
import type { ICookie } from "./cookie";
import type { FetchResult } from "./fetch";
import { debounce } from "./debounce";
import request from "./request/requestImpl";
import RequestError, { ServiceErrorCode, MPErrorCode } from "./request/requestError";
import CookieUtils from "./request/cookie";

export {
ICookie,
Expand All @@ -20,5 +23,10 @@ export {
checkBind,
checkNotification,
timeUtils,
debounce
debounce,
request,
ServiceErrorCode,
MPErrorCode,
RequestError,
CookieUtils
};
66 changes: 66 additions & 0 deletions src/utils/request/cookie.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import Taro from "@tarojs/taro";
import { persistedStateStorage } from "../storage";
import RequestError, { MPErrorCode, ServiceErrorCode } from "./requestError";
import { api } from "@/services";

export default class CookieUtils {
private static keyInStorage = "__cookie__";
private static cookie: string = "";

/**
* 从内存、持久化储存中获取 Cookie
*
* 若两处都没有 Cookie,则触发登录流程获取新的 Cookie
*/
public static async get(): Promise<string> {
if (!this.cookie) {
const cookieInStore = persistedStateStorage.getItem(this.keyInStorage);
this.cookie = cookieInStore || await this.refresh();
}

return this.cookie;
}

/**
* 登录以获取服务端 Cookie
*
* @throws {RequestError}
* @returns 新 Cookie
*/
public static async refresh(): Promise<string> {
try {
const { code, errMsg } = await Taro.login({ timeout: 3000 });
if (!code) {
console.error(new Error(errMsg));
return Promise.reject(
new RequestError({ message: errMsg, code: MPErrorCode.MP_LOGIN_ERROR_MISSING_WX_CODE })
);
}

const taroWrapped = await Taro.request<{ data: { user: any }, code: number }>({
url: process.env.HOST + api.user.login.wechat,
data: { code },
method: "POST"
});
const { data: realResponse, cookies } = taroWrapped;
if (realResponse && realResponse.code === ServiceErrorCode.OK) {
if (cookies && cookies.length > 0) {
const cookie = cookies[0]; // 现业务全局仅有一个 Cookie,所以取第一个
persistedStateStorage.setItem(this.keyInStorage, cookie);
return cookie;
}
return Promise.reject(
new RequestError({ message: "小程序登录失败", code: MPErrorCode.MP_LOGIN_ERROR_MISSING_COOKIE })
);
}
throw new Error(JSON.stringify(taroWrapped));
} catch (e) {
console.error(e);
throw new RequestError({ message: "小程序登录失败", code: MPErrorCode.MP_LOGIN_ERROR_UNKNOWN });
}
}

public static clear() {
persistedStateStorage.removeItem(this.keyInStorage);
}
}
37 changes: 37 additions & 0 deletions src/utils/request/requestError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export const MPErrorCode = {
MP_NETWORK_ERROR: Symbol("MP_NETWORK_ERROR"),
MP_LOGIN_ERROR_MISSING_WX_CODE: Symbol("MP_LOGIN_ERROR_MISSING_WX_CODE"),
MP_LOGIN_ERROR_MISSING_COOKIE: Symbol("MP_LOGIN_ERROR_MISSING_COOKIE"),
MP_LOGIN_ERROR_UNKNOWN: Symbol("MP_LOGIN_ERROR_UNKNOWN")
};

export enum ServiceErrorCode {
OK = 1,
NOT_ADMIN = 100403,

USER_ALREADY_EXISTED = 200508,
USER_USERNAME_PASSWORD_UNMATCHED = 200504,
USER_NOT_LOGIN = 200503,

SYSTEM_ERROR_1 = 200500,
SYSTEM_ERROR_2 = 200506,

ACTIVATION_SCHOOL_ID_OR_ID_NOT_EXIST_NOT_MATCH = 200510,
ACTIVATION_PASSWORD_LENGTH_ERROR = 200511,
ACTIVATION_PASSPORT_EXISTED = 200512,
ACTIVATION_SCHOOL_ID_ERROR = 200513
}

export default class RequestError extends Error {
public message: string;
public code: ServiceErrorCode | number | symbol;

constructor(props: {
message: string;
code: ServiceErrorCode | number | symbol;
}) {
super();
this.message = props.message;
this.code = props.code;
}
}
Loading
Loading