Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49851d4a57 | ||
|
|
df4229bf2f | ||
|
|
43d87b40f7 | ||
|
|
660f6921de | ||
|
|
86101e01d1 | ||
|
|
1f2a2ad6bd | ||
|
|
b91a9271a7 | ||
|
|
ec635b9ae6 | ||
|
|
6f96a69900 | ||
|
|
58d8d74158 | ||
|
|
96b3414d22 | ||
|
|
529011b0dd | ||
|
|
4da257c2e2 | ||
|
|
f11eb63ee1 | ||
|
|
49c4f7f0d4 | ||
|
|
4158887d2e | ||
|
|
a8e16f5972 | ||
|
|
d9825d6d68 | ||
|
|
fab73f00ab | ||
|
|
edb26b3d8b | ||
|
|
443f82ea75 | ||
|
|
75adb97abb | ||
|
|
b36996e352 | ||
|
|
6bef08f12e | ||
|
|
1f24a59bd9 | ||
|
|
14d0c9c123 | ||
|
|
cd8ca7dcc4 | ||
|
|
7a5d43281b |
@@ -0,0 +1,95 @@
|
|||||||
|
import { API, IAnyData, GeneralCallbackResult } from "../core/Api";
|
||||||
|
import { EventType } from "../core/Emitter";
|
||||||
|
|
||||||
|
interface ILoginEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* session 过期
|
||||||
|
*/
|
||||||
|
expire: GeneralCallbackResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录失败
|
||||||
|
*/
|
||||||
|
unauthorized: GeneralCallbackResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未知的问题
|
||||||
|
*/
|
||||||
|
error: GeneralCallbackResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据损坏或丢失
|
||||||
|
*/
|
||||||
|
badData: GeneralCallbackResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 教务处基础 API
|
||||||
|
* @template I API 输入数据
|
||||||
|
* @template O API 输出数据
|
||||||
|
* @template E API 中的事件
|
||||||
|
* @template U 用户自定义的输出数据
|
||||||
|
*/
|
||||||
|
abstract class EduBase<
|
||||||
|
I extends IAnyData = IAnyData,
|
||||||
|
O extends IAnyData = IAnyData,
|
||||||
|
E extends Record<EventType, any> = {}
|
||||||
|
> extends API<I, O, {
|
||||||
|
[P in (keyof ILoginEvent | keyof E)]: P extends keyof ILoginEvent ? ILoginEvent[P] : E[P]
|
||||||
|
}> {
|
||||||
|
|
||||||
|
protected useEduCallback(
|
||||||
|
parseFunction: (data: any) => O
|
||||||
|
): void {
|
||||||
|
|
||||||
|
this.addFailedCallBack();
|
||||||
|
|
||||||
|
this.on("success", (data) => {
|
||||||
|
|
||||||
|
let isSuccess = true;
|
||||||
|
let errMsg = "";
|
||||||
|
let res: O | undefined;
|
||||||
|
const info: any = data.data;
|
||||||
|
|
||||||
|
// 数据缺失检测
|
||||||
|
if(!info) {
|
||||||
|
isSuccess = false;
|
||||||
|
errMsg = "Bad Data";
|
||||||
|
this.emit("badData", { errMsg });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSuccess) switch (info.code) {
|
||||||
|
case (1):
|
||||||
|
res = parseFunction(info.data);
|
||||||
|
errMsg = info.err_msg ?? "Success";
|
||||||
|
this.emit("ok", res!);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (2):
|
||||||
|
isSuccess = false;
|
||||||
|
errMsg = info.err_msg ?? "Session Expire";
|
||||||
|
this.emit("expire", { errMsg });
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (3):
|
||||||
|
isSuccess = false;
|
||||||
|
errMsg = info.err_msg ?? "Unauthorized";
|
||||||
|
this.emit("unauthorized", { errMsg });
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (4):
|
||||||
|
isSuccess = false;
|
||||||
|
errMsg = info.err_msg ?? "Error";
|
||||||
|
this.emit("error", { errMsg });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSuccess) this.emit("no", { errMsg });
|
||||||
|
this.emit("done", { errMsg, data: res });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { EduBase };
|
||||||
|
export default EduBase;
|
||||||
+10
-76
@@ -1,4 +1,5 @@
|
|||||||
import { API, HTTPMethod, IParamSetting, GeneralCallbackResult } from "../core/Api";
|
import { HTTPMethod, IParamSetting } from "../core/Api";
|
||||||
|
import { EduBase } from "./EduBase";
|
||||||
|
|
||||||
interface ILoginInput {
|
interface ILoginInput {
|
||||||
|
|
||||||
@@ -42,35 +43,12 @@ interface ILoginOutput {
|
|||||||
eduSession: string;
|
eduSession: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ILoginEvent {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* session 过期
|
|
||||||
*/
|
|
||||||
expire: GeneralCallbackResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录失败
|
|
||||||
*/
|
|
||||||
unauthorized: GeneralCallbackResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 未知的问题
|
|
||||||
*/
|
|
||||||
error: GeneralCallbackResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据损坏或丢失
|
|
||||||
*/
|
|
||||||
badData: GeneralCallbackResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login API
|
* Login API
|
||||||
* 此 API 用来向教务处发起登录请求
|
* 此 API 用来向教务处发起登录请求
|
||||||
* 请求成功后将获得教务处返回的 session
|
* 请求成功后将获得教务处返回的 session
|
||||||
*/
|
*/
|
||||||
class Login extends API<ILoginInput, ILoginOutput, ILoginEvent> {
|
class Login extends EduBase<ILoginInput, ILoginOutput> {
|
||||||
|
|
||||||
public override url: string = "/login";
|
public override url: string = "/login";
|
||||||
|
|
||||||
@@ -92,57 +70,13 @@ class Login extends API<ILoginInput, ILoginOutput, ILoginEvent> {
|
|||||||
super();
|
super();
|
||||||
this.initDebugLabel("Login");
|
this.initDebugLabel("Login");
|
||||||
|
|
||||||
this.addFailedCallBack();
|
this.useEduCallback((data) => ({
|
||||||
|
idCardLast6: data.idCard,
|
||||||
this.on("success", (data) => {
|
eduService: data.ip,
|
||||||
|
actualName: data.name,
|
||||||
let isSuccess = true;
|
isSubscribeWxAccount: data.official,
|
||||||
let errMsg = "";
|
eduSession: data.session
|
||||||
let res: ILoginOutput | undefined;
|
}));
|
||||||
const info: any = data.data;
|
|
||||||
|
|
||||||
// 数据缺失检测
|
|
||||||
if(!info) {
|
|
||||||
isSuccess = false;
|
|
||||||
errMsg = "Bad Data";
|
|
||||||
this.emit("badData", { errMsg });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSuccess) switch (info.code) {
|
|
||||||
case (1):
|
|
||||||
res = {
|
|
||||||
idCardLast6: info.data.idCard,
|
|
||||||
eduService: info.data.ip,
|
|
||||||
actualName: info.data.name,
|
|
||||||
isSubscribeWxAccount: info.data.official,
|
|
||||||
eduSession: info.data.session
|
|
||||||
};
|
|
||||||
errMsg = info.err_msg ?? "Success";
|
|
||||||
this.emit("ok", res);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (2):
|
|
||||||
isSuccess = false;
|
|
||||||
errMsg = info.err_msg ?? "Session Expire";
|
|
||||||
this.emit("expire", { errMsg });
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (3):
|
|
||||||
isSuccess = false;
|
|
||||||
errMsg = info.err_msg ?? "Unauthorized";
|
|
||||||
this.emit("unauthorized", { errMsg });
|
|
||||||
break;
|
|
||||||
|
|
||||||
case (4):
|
|
||||||
isSuccess = false;
|
|
||||||
errMsg = info.err_msg ?? "Error";
|
|
||||||
this.emit("error", { errMsg });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSuccess) this.emit("no", { errMsg });
|
|
||||||
this.emit("done", { errMsg, data: res });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import { HTTPMethod, IParamSetting } from "../core/Api";
|
||||||
|
import { EduBase } from "./EduBase";
|
||||||
|
|
||||||
|
interface IScheduleInput {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* session
|
||||||
|
*/
|
||||||
|
cookie: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学期
|
||||||
|
*/
|
||||||
|
semester: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IClassData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程名字
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上课地点
|
||||||
|
*/
|
||||||
|
room?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程老师
|
||||||
|
*/
|
||||||
|
teacher?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 周数
|
||||||
|
*/
|
||||||
|
week: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IScheduleOutput = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程列表
|
||||||
|
*/
|
||||||
|
classList: IClassData[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 稀疏矩阵编号
|
||||||
|
*/
|
||||||
|
index: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule API
|
||||||
|
* 需要session与semester
|
||||||
|
* 此 API 用来向教务处发起获取课程表的请求
|
||||||
|
* 请求成功后将获得教务处返回的课程表JSON文件
|
||||||
|
*/
|
||||||
|
class Schedlue extends EduBase<IScheduleInput, IScheduleOutput> {
|
||||||
|
|
||||||
|
public override url = "/course_timetable";
|
||||||
|
|
||||||
|
public override method: HTTPMethod = HTTPMethod.GET;
|
||||||
|
|
||||||
|
public override params: IParamSetting<IScheduleInput> = {
|
||||||
|
|
||||||
|
cookie: {
|
||||||
|
mapKey: "cookie",
|
||||||
|
isHeader: true
|
||||||
|
},
|
||||||
|
|
||||||
|
semester: {
|
||||||
|
mapKey: "semester",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
super();
|
||||||
|
this.initDebugLabel("Schedule");
|
||||||
|
|
||||||
|
this.useEduCallback((data) => {
|
||||||
|
const res: IScheduleOutput = [];
|
||||||
|
|
||||||
|
for( let i = 0; i < data.length; i++ ) {
|
||||||
|
const classList: IClassData[] = [];
|
||||||
|
const CTTDetails = data[i].CTTDetails ?? [];
|
||||||
|
|
||||||
|
for( let j = 0; j < CTTDetails.length; j++ ) {
|
||||||
|
|
||||||
|
classList.push({
|
||||||
|
name: CTTDetails[j].Name,
|
||||||
|
room: CTTDetails[j].Room,
|
||||||
|
teacher: CTTDetails[j].Teacher,
|
||||||
|
week: CTTDetails[j].Week,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res.push({
|
||||||
|
classList,
|
||||||
|
index: data[i].Id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Schedlue };
|
||||||
|
export default Schedlue;
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
import { IAppAPIParam } from "./core/Api";
|
import { IAppAPIParam, IAnyData } from "./core/Api";
|
||||||
import { IAppStorageParam, Storage, IStorageData } from "./core/Storage";
|
import { IAppStorageParam, Storage, IStorageData } from "./core/Storage";
|
||||||
import { Logger, LevelLogLabel, LifeCycleLogLabel } from "./core/Logger";
|
import { Logger, LevelLogLabel, LifeCycleLogLabel } from "./core/Logger";
|
||||||
|
|
||||||
|
|
||||||
App<IAppAPIParam & IAppStorageParam>({
|
App<IAppAPIParam & IAppStorageParam & IAnyData>({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 模块需要的全局数据
|
* API 模块需要的全局数据
|
||||||
|
|||||||
@@ -168,16 +168,17 @@ class API<
|
|||||||
> {
|
> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础 URL
|
* 默认调试标签
|
||||||
* TODO: 这里可能涉及负载均衡
|
|
||||||
*/
|
*/
|
||||||
public static get baseUrl():string {
|
|
||||||
return "https://jwc.nogg.cn";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static defaultLogLabel:LogLabel = new LogLabel(
|
public static defaultLogLabel:LogLabel = new LogLabel(
|
||||||
`API:API`, colorRadio(200, 120, 222)
|
`API:API`, colorRadio(200, 120, 222)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础 URL
|
||||||
|
* TODO: 这里可能涉及负载均衡
|
||||||
|
*/
|
||||||
|
public baseUrl: string = "https://jwc.nogg.cn";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger 使用的标签
|
* Logger 使用的标签
|
||||||
@@ -319,7 +320,7 @@ class API<
|
|||||||
|
|
||||||
// 重置请求数据
|
// 重置请求数据
|
||||||
const requestData:IWxRequestOption<O> = this.requestData = {
|
const requestData:IWxRequestOption<O> = this.requestData = {
|
||||||
url: API.baseUrl + this.url,
|
url: this.baseUrl + this.url,
|
||||||
data: {}, header: {},
|
data: {}, header: {},
|
||||||
timeout: this.timeout,
|
timeout: this.timeout,
|
||||||
method: this.method,
|
method: this.method,
|
||||||
@@ -697,4 +698,4 @@ enum HTTPMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default API;
|
export default API;
|
||||||
export { API, IParamSetting, IAppAPIParam, ICallBack, HTTPMethod, RequestPolicy, GeneralCallbackResult }
|
export { API, IParamSetting, IAppAPIParam, IAnyData, ICallBack, HTTPMethod, RequestPolicy, GeneralCallbackResult }
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* 数据层键值设置
|
||||||
|
*/
|
||||||
|
interface IDataParamSettingItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
type: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 键值是否可以获取
|
||||||
|
*/
|
||||||
|
isGet: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 键值是否可以设置
|
||||||
|
*/
|
||||||
|
isSet: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否仅为异步获取
|
||||||
|
*/
|
||||||
|
isGetAsync?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否仅为异步设置
|
||||||
|
*/
|
||||||
|
isSetAsync?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据层参数类型
|
||||||
|
*/
|
||||||
|
interface IDataParamSetting {
|
||||||
|
[x: string]: IDataParamSettingItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type IGet<T> = () => T;
|
||||||
|
type IGetAsync<T> = () => Promise<T>;
|
||||||
|
type ISet<T> = (data: T) => INone;
|
||||||
|
type ISetAsync<T> = (data: T) => Promise<INone>;
|
||||||
|
|
||||||
|
type INone = undefined | void | unknown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册表结构
|
||||||
|
*/
|
||||||
|
type IRegistryItem<S extends IDataParamSettingItem> = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取方法
|
||||||
|
*/
|
||||||
|
get: S["isGetAsync"] extends true ? INone : S["isGet"] extends true ? IGet<S["type"]> : INone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步获取方法
|
||||||
|
*/
|
||||||
|
getAsync: S["isGet"] extends true ? IGetAsync<S["type"]> : INone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置方法
|
||||||
|
*/
|
||||||
|
set: S["isSetAsync"] extends true ? INone : S["isSet"] extends true ? ISet<S["type"]> : INone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步设置方法
|
||||||
|
*/
|
||||||
|
setAsync: S["isSet"] extends true ? ISetAsync<S["type"]> : INone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册表参数类型
|
||||||
|
*/
|
||||||
|
type IRegistry<D extends IDataParamSetting> = {
|
||||||
|
[P in keyof D]: IRegistryItem<D[P]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IRegistryPartial<D extends IDataParamSetting> = {
|
||||||
|
[P in keyof D]?: Partial<IRegistryItem<D[P]>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type IAutoSelect<IF extends boolean, A, B> = IF extends true ? A : B;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core 数据层架构
|
||||||
|
*
|
||||||
|
* 使用示例:
|
||||||
|
* ```typescript
|
||||||
|
* class TestData extends Data<{
|
||||||
|
* test: {
|
||||||
|
* type: number,
|
||||||
|
* isGet: true,
|
||||||
|
* isSet: true,
|
||||||
|
* isGetAsync: true
|
||||||
|
* }
|
||||||
|
* }> {
|
||||||
|
* public onLoad() {
|
||||||
|
* let dataObject = {key: 1}
|
||||||
|
* this.getter("test", () => 1);
|
||||||
|
* this.registerKeyFromObject("test", "key", dataObject);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class Data<D extends IDataParamSetting> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getter setter 注册表
|
||||||
|
*/
|
||||||
|
private registryList: IRegistryPartial<D> = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载函数
|
||||||
|
*/
|
||||||
|
public onLoad(): any {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个 Setter 到键值上
|
||||||
|
* @param key 注册的键值
|
||||||
|
* @param setter 注册的 Setter
|
||||||
|
* @param isAsync 是否为异步函数
|
||||||
|
*/
|
||||||
|
protected setter<KEY extends keyof D> (key: KEY, setter: IRegistryItem<D[KEY]>["set"]): this
|
||||||
|
protected setter<KEY extends keyof D> (key: KEY, setter: IRegistryItem<D[KEY]>["setAsync"], isAsync: true): this
|
||||||
|
protected setter<
|
||||||
|
KEY extends keyof D,
|
||||||
|
ASYNC extends boolean
|
||||||
|
> (
|
||||||
|
key: KEY,
|
||||||
|
setter: IAutoSelect<ASYNC, IRegistryItem<D[KEY]>["setAsync"], IRegistryItem<D[KEY]>["set"]>,
|
||||||
|
isAsync?: ASYNC
|
||||||
|
): this {
|
||||||
|
|
||||||
|
// 如果此键值不存在,新建
|
||||||
|
if (!this.registryList[key]) this.registryList[key] = {};
|
||||||
|
|
||||||
|
// 设置异步 setter
|
||||||
|
if (isAsync) this.registryList[key]!.setAsync = setter as IRegistryItem<D[KEY]>["setAsync"];
|
||||||
|
|
||||||
|
// 设置同步 setter
|
||||||
|
else this.registryList[key]!.set = setter as IRegistryItem<D[KEY]>["set"];
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个 Getter 到键值上
|
||||||
|
* @param key 注册的键值
|
||||||
|
* @param getter 注册的 Getter
|
||||||
|
* @param isAsync 是否为异步函数
|
||||||
|
*/
|
||||||
|
protected getter<KEY extends keyof D> (key: KEY, getter: IRegistryItem<D[KEY]>["get"]): this
|
||||||
|
protected getter<KEY extends keyof D> (key: KEY, getter: IRegistryItem<D[KEY]>["getAsync"], isAsync: true): this
|
||||||
|
protected getter<
|
||||||
|
KEY extends keyof D,
|
||||||
|
ASYNC extends boolean
|
||||||
|
> (
|
||||||
|
key: KEY,
|
||||||
|
getter: IAutoSelect<ASYNC, IRegistryItem<D[KEY]>["getAsync"], IRegistryItem<D[KEY]>["get"]>,
|
||||||
|
isAsync?: ASYNC
|
||||||
|
): this {
|
||||||
|
|
||||||
|
// 如果此键值不存在,新建
|
||||||
|
if (!this.registryList[key]) this.registryList[key] = {};
|
||||||
|
|
||||||
|
// 设置异步 getter
|
||||||
|
if (isAsync) this.registryList[key]!.getAsync = getter as IRegistryItem<D[KEY]>["getAsync"];
|
||||||
|
|
||||||
|
// 设置同步 getter
|
||||||
|
else this.registryList[key]!.get = getter as IRegistryItem<D[KEY]>["get"];
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象的键值关联到 Data 层中
|
||||||
|
* @param key Data 层键值
|
||||||
|
* @param keyFromObject 对象源键值
|
||||||
|
* @param object 关联对象
|
||||||
|
*/
|
||||||
|
protected registerKeyFromObject<
|
||||||
|
KEY extends keyof D,
|
||||||
|
F extends keyof O,
|
||||||
|
O extends {[K in F]: D[KEY]["type"]}
|
||||||
|
> (key: KEY, keyFromObject: F, object: O) {
|
||||||
|
|
||||||
|
// 注册同步获取
|
||||||
|
this.getter(key, () => {
|
||||||
|
return object[keyFromObject]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 注册同步设置
|
||||||
|
this.setter(key, (data: any) => {
|
||||||
|
object[keyFromObject] = data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出数据对象
|
||||||
|
* @returns 数据对象
|
||||||
|
*/
|
||||||
|
public export(): IRegistry<D> {
|
||||||
|
this.autoFillFunction();
|
||||||
|
return this.registryList as IRegistry<D>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动填充缺失的异步函数
|
||||||
|
* 在注册表中搜索全部的同步函数
|
||||||
|
* 并自动填充对应的异步函数
|
||||||
|
* 此函数会在 export 前静默执行
|
||||||
|
*/
|
||||||
|
protected autoFillFunction(): void {
|
||||||
|
|
||||||
|
// 填充函数
|
||||||
|
const fillFunction = <KEY extends keyof D>(key: KEY): void => {
|
||||||
|
|
||||||
|
const item = this.registryList[key] as IRegistryItem<D[KEY]>;
|
||||||
|
if (!item) return;
|
||||||
|
|
||||||
|
// 检验 getter
|
||||||
|
if (item.get && !item.getAsync) {
|
||||||
|
item.getAsync = this.syncFn2AsyncFn(item.get as IGet<D[KEY]["type"]>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检验 setter
|
||||||
|
if (item.set && !item.setAsync) {
|
||||||
|
item.setAsync = this.syncFn2AsyncFn(item.set as ISet<D[KEY]["type"]>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在注册表中查找
|
||||||
|
for (const key in this.registryList) fillFunction(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将同步函数转换为异步函数
|
||||||
|
* @param fn 同步函数
|
||||||
|
*/
|
||||||
|
protected syncFn2AsyncFn<D, H extends (IGet<D> | ISet<D>)> (fn: H):
|
||||||
|
IAutoSelect<H extends IGet<D> ? true : false, IGetAsync<D>, ISetAsync<D>> {
|
||||||
|
const asyncFn = async (...param: [D]) => {
|
||||||
|
return fn(...param);
|
||||||
|
};
|
||||||
|
return asyncFn as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
@import "../../app.scss";
|
||||||
|
|
||||||
view.mask {
|
view.mask {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -5,4 +6,40 @@ view.mask {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: rgba($color: #000000, $alpha: .2);
|
background-color: rgba($color: #000000, $alpha: .2);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.mask.block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.mask.none {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.mask.show {
|
||||||
|
animation: show .1s cubic-bezier(0, 0, 1, 1) both;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.mask.hide {
|
||||||
|
animation: hide .1s cubic-bezier(0, 0, 1, 1) both;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes show{
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes hide{
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,40 @@
|
|||||||
import { Modular, Manager } from "../../core/Module";
|
import { Modular, Manager } from "../../core/Module";
|
||||||
|
|
||||||
class Mask<M extends Manager> extends Modular<M> {
|
/**
|
||||||
|
* 蒙版事件
|
||||||
|
*/
|
||||||
|
type IMaskEvent = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蒙版显示事件
|
||||||
|
*/
|
||||||
|
show: void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蒙版隐藏事件
|
||||||
|
*/
|
||||||
|
hide: void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蒙版状态改变事件
|
||||||
|
*/
|
||||||
|
change: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蒙版点击事件
|
||||||
|
*/
|
||||||
|
click: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蒙版 Modular
|
||||||
|
*/
|
||||||
|
class Mask<M extends Manager> extends Modular<M, {}, IMaskEvent> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动画运行时间
|
||||||
|
*/
|
||||||
|
public static readonly animateTime: number = 100;
|
||||||
|
|
||||||
public data? = {
|
public data? = {
|
||||||
|
|
||||||
@@ -9,35 +43,71 @@ class Mask<M extends Manager> extends Modular<M> {
|
|||||||
*/
|
*/
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 蒙版是否显示
|
||||||
|
*/
|
||||||
|
isDisplay: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 蒙版是否显示
|
* 蒙版是否显示
|
||||||
*/
|
*/
|
||||||
isShow: false
|
isShow: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当点击时是否自动关闭蒙版
|
||||||
|
*/
|
||||||
|
public autoCloseOnClick: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消失动画计时器
|
||||||
|
*/
|
||||||
private disappearTimer?: number;
|
private disappearTimer?: number;
|
||||||
|
|
||||||
|
public override onLoad() {
|
||||||
|
this.setFunc(this.handleClickMask, "handleClickMask");
|
||||||
|
this.on("show", this.showMask);
|
||||||
|
this.on("hide", this.hideMask);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示蒙版
|
* 显示蒙版
|
||||||
*/
|
*/
|
||||||
public showMask() {
|
private showMask = () => {
|
||||||
this.setData({ isShow: true });
|
|
||||||
|
this.disappearTimer && clearTimeout(this.disappearTimer);
|
||||||
|
|
||||||
|
this.setData({
|
||||||
|
isShow: true,
|
||||||
|
isDisplay: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this.emit("change", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 隐藏蒙版
|
* 隐藏蒙版
|
||||||
*/
|
*/
|
||||||
public hideMask() {
|
private hideMask = () => {
|
||||||
this.setData({ isShow: false });
|
this.setData({
|
||||||
}
|
isShow: false
|
||||||
|
});
|
||||||
public override onLoad() {
|
|
||||||
this.setFunc(this.handleClickMask, "handleClickMask");
|
|
||||||
// Do something
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.disappearTimer = setTimeout(() => {
|
||||||
|
this.setData({
|
||||||
|
isDisplay: false
|
||||||
|
});
|
||||||
|
}, Mask.animateTime);
|
||||||
|
|
||||||
|
this.emit("change", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理蒙版点击事件
|
||||||
|
*/
|
||||||
private handleClickMask() {
|
private handleClickMask() {
|
||||||
this.hideMask();
|
if (this.autoCloseOnClick) this.emit("hide", void 0);
|
||||||
|
this.emit("click", void 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
@import "../../app.scss";
|
||||||
|
|
||||||
|
view.popups {
|
||||||
|
position: fixed;
|
||||||
|
width: 75%;
|
||||||
|
height: 75%;
|
||||||
|
margin:auto;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
top:0;
|
||||||
|
bottom:0;
|
||||||
|
background-color: $theme-color-light-layout;
|
||||||
|
border-radius: 15px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
view.popups.block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
view.popups.none {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.popups.show {
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-name: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
view.popups.hide {
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-name: hide;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes show{
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes hide{
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { Modular, Manager } from "../../core/Module";
|
||||||
|
|
||||||
|
class Popups<M extends Manager> extends Modular<M> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动画运行时间
|
||||||
|
*/
|
||||||
|
public static readonly animateTime: number = 100;
|
||||||
|
|
||||||
|
public data? = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹出层是否显示
|
||||||
|
*/
|
||||||
|
display:false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弹出层动画
|
||||||
|
*/
|
||||||
|
isShow:false
|
||||||
|
};
|
||||||
|
|
||||||
|
disappearTimer: number | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示弹出层
|
||||||
|
*/
|
||||||
|
public showPopups() {
|
||||||
|
this.setData({
|
||||||
|
isShow:true,
|
||||||
|
display:true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隐藏弹出层
|
||||||
|
*/
|
||||||
|
public hidePopups() {
|
||||||
|
this.setData({
|
||||||
|
isShow:false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.disappearTimer = setTimeout(() => {
|
||||||
|
this.setData({
|
||||||
|
display: false
|
||||||
|
});
|
||||||
|
}, Popups.animateTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override onLoad() {
|
||||||
|
// Do something
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Popups };
|
||||||
|
export default Popups;
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
@import "./MainFunction.scss";
|
@import "./MainFunction.scss";
|
||||||
@import "./FunctionList.scss";
|
@import "./FunctionList.scss";
|
||||||
@import "../../modular/Mask/Mask.scss";
|
@import "../../modular/Mask/Mask.scss";
|
||||||
|
@import "../../modular/Popups/Popups.scss";
|
||||||
|
|
||||||
view.container{
|
view.container{
|
||||||
padding-top: 50rpx;
|
padding-top: 50rpx;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { UserCard } from "./UserCard";
|
|||||||
import { MainFunction } from "./MainFunction";
|
import { MainFunction } from "./MainFunction";
|
||||||
import { FunctionList } from "./FunctionList";
|
import { FunctionList } from "./FunctionList";
|
||||||
import { Mask } from "../../modular/Mask/Mask";
|
import { Mask } from "../../modular/Mask/Mask";
|
||||||
|
import {Popups} from "../../modular/Popups/Popups"
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
@@ -12,8 +13,10 @@ import { Mask } from "../../modular/Mask/Mask";
|
|||||||
// 添加蒙版 Modular
|
// 添加蒙版 Modular
|
||||||
const mask = manager.addModule(Mask, "mask");
|
const mask = manager.addModule(Mask, "mask");
|
||||||
|
|
||||||
|
const popups = manager.addModule(Popups,"popups")
|
||||||
|
|
||||||
// 添加 UserCard Modular
|
// 添加 UserCard Modular
|
||||||
manager.addModule(UserCard, "userCard", { mask });
|
manager.addModule(UserCard, "userCard", { mask, popups });
|
||||||
|
|
||||||
// 添加 MainFunction Modular
|
// 添加 MainFunction Modular
|
||||||
manager.addModule(MainFunction, "mainFunction");
|
manager.addModule(MainFunction, "mainFunction");
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<!-- 蒙版 -->
|
<!-- 蒙版 -->
|
||||||
<view class="mask" bindtap="mask$handleClickMask" style="display:{{mask$isShow ? 'block' : 'none'}}"></view>
|
<view class="mask {{ mask$isShow ? 'show' : 'hide' }} {{ mask$isDisplay ? 'block' : 'none' }}"
|
||||||
|
bindtap="mask$handleClickMask"></view>
|
||||||
|
|
||||||
|
<!-- 弹出层 -->
|
||||||
|
<view class="popups" style="display:{{popups$isShow ? 'block' : 'none'}}"></view>
|
||||||
|
|
||||||
<!-- 顶部的阴影 -->
|
<!-- 顶部的阴影 -->
|
||||||
<view class="top-shadow"></view>
|
<view class="top-shadow"></view>
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
|
import Popups from "modular/Popups/Popups";
|
||||||
import { Modular, Manager } from "../../core/Module";
|
import { Modular, Manager } from "../../core/Module";
|
||||||
import { Mask } from "../../modular/Mask/Mask";
|
import { Mask } from "../../modular/Mask/Mask";
|
||||||
|
|
||||||
type IUserCardDependent<M extends Manager> = {
|
type IUserCardDependent<M extends Manager> = {
|
||||||
mask: Mask<M>
|
mask: Mask<M>
|
||||||
|
popups: Popups<M>
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>> {
|
type IUserCardEvent = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主题更换按钮点击事件
|
||||||
|
*/
|
||||||
|
clickChangeTheme: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>, IUserCardEvent> {
|
||||||
|
|
||||||
public override onLoad() {
|
public override onLoad() {
|
||||||
this.setFunc(this.handleChangeTheme, "changeTheme")
|
this.setFunc(this.handleChangeTheme, "changeTheme")
|
||||||
@@ -15,7 +25,9 @@ class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>> {
|
|||||||
* 处理主题更换
|
* 处理主题更换
|
||||||
*/
|
*/
|
||||||
private handleChangeTheme() {
|
private handleChangeTheme() {
|
||||||
this.depends?.mask.showMask();
|
this.depends?.popups.showPopups();
|
||||||
|
this.depends?.mask.emit("show", void 0);
|
||||||
|
this.emit("clickChangeTheme", void 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Modular, Manager, ILifetime } from "../../core/Module";
|
import { Modular, Manager, ILifetime } from "../../core/Module";
|
||||||
import { Login } from "../../api/Login";
|
import { Login } from "../../api/Login";
|
||||||
|
import { Schedlue } from "../../api/Schedule"
|
||||||
import { Storage } from "../../core/Storage";
|
import { Storage } from "../../core/Storage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,12 +29,14 @@ implements Partial<ILifetime> {
|
|||||||
s.set("be", 12);
|
s.set("be", 12);
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
// new Login().param({studentId: "1806240113", password: ""})
|
// new Login().param({studentId: "2017060129", password: ""})
|
||||||
// .request().wait({
|
// .request().wait({
|
||||||
// ok: (w) => {console.log("ok", w)},
|
// ok: (w) => {console.log("ok", w)},
|
||||||
// no: (w) => {console.log("no", w)},
|
// no: (w) => {console.log("no", w)},
|
||||||
// done: (w) => {console.log("done", w)}
|
// done: (w) => {console.log("done", w)}
|
||||||
// });
|
// });
|
||||||
|
// new Schedlue().param({cookie:"C729D1AB1B17077485ACCD9279135C22",semester:"2020-2021-2"})
|
||||||
|
// .request()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"setting": {},
|
||||||
"condition": {
|
"condition": {
|
||||||
"plugin": {
|
"plugin": {
|
||||||
"list": []
|
"list": []
|
||||||
@@ -16,6 +17,12 @@
|
|||||||
"pathName": "pages/Account/Account",
|
"pathName": "pages/Account/Account",
|
||||||
"query": "",
|
"query": "",
|
||||||
"scene": null
|
"scene": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pages/Account/Account",
|
||||||
|
"pathName": "pages/Account/Account",
|
||||||
|
"query": "",
|
||||||
|
"scene": null
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user