diff --git a/README.md b/README.md index 0e91ec7..e92f1a1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ __*!!!警告!!!*__ -请在主仓库提交代码,而非镜像仓库!在镜像仓库提交的代码将会在同步时被覆盖! +*请在主仓库提交代码,而非镜像仓库!在镜像仓库提交的代码将会在同步时被覆盖!* 主仓库: http://git.mrkbear.com/MrKBear/mini-dlpu-v3 @@ -15,8 +15,9 @@ __*!!!警告!!!*__ - [社区介绍](#小程序社区) - [项目设计](#第三代小程序) - [贡献规范](#社区贡献规范) +- [社区福利](#贡献者分配制度) - [API文档](https://docs.apipost.cn/preview/e737de418d4ef150/419d45d8c97d6a9f) -- [入门文档(等待撰写)](#第三代掌上教务处小程序) +- [入门文档(等待撰写)](#快速入门) - [设计架构(等待撰写)](#第三代掌上教务处小程序) ## 小程序社区 @@ -98,6 +99,65 @@ __*!!!警告!!!*__ 5. 一个文件不要超过 1000 行代码,尽量保证代码可读性 +## 贡献者分配制度 + +作为公益的开源项目: + +第三代开发时,将计划加入一个赞助功能,每个月赞助累计到达一定数额,将在下个月去除开屏广告。 + +第三代上线后,我们将在每个月公示小程序的账目流水,去除服务器成本和其他费用(微信认证,微信支付,域名,...)后,若有剩余数额将按照开发时大家的贡献分配。 + +小程序的广告位将计划外包给其他组织管理,我们也会得到一定收入,此收入也将按上面的规则处理。 + +小程序开屏广告收入也同样按上面的规则处理。 + +以上内容请大家仔细阅读,另外有意向负责项目财务的同学,处理财务账目也算做贡献。 + +## 快速入门 + +下面对大家的小问题进行解答: + +> 我在参与贡献之前,我需要先会哪些知识?他们好学吗? + +下面列出此项目使用的全部技术,从上到下是推荐学习顺序和学习重点,也是难度顺序: +- HTML + - 标签结构和语法 +- CSS + - 基础样式 + - 选择器 + - 盒模型 + - 布局和定位 + - 行内元素和块级元素 +- JS + - 数据类型 + - 基础运算符 + - 流程控制语句 + - 函数与闭包 (瓶颈) + - 原型和对象 (突破) +- Vue (不用深入了解) + - 组件化设计思想 +- 小程序 API + - 了解小程序如何编写页面 + - 了解小程序大概的 API + - 不用深入了解,随时查阅 +- TypeScript (只要JS数据结构玩的6,TS五分钟学会) + - 类型约束 + - 接口 + - 泛型 + - 类型运算 +- Sass (拓展了CSS语法,实际上没有任何新知识) + - 语法 + +> 小程序和主流前端技术差别在哪?对我以后职业发展帮助大嘛? + +如果你已经掌握了前端主流技术,例如 Vue,React,那么上手小程序只是 __1__ 天的事情 + +换句话来说小程序开发用到技术和主流前端技术,有大概 __90%__ 是重叠的。 + +小程序学了可以成为加分项,参与贡献拥有 __20000__ 人的项目,丰富项目经历,稳赚不亏。 + +掌上教务处前端项目采用了很多创新的架构设计,虽然不一定优秀,但是一定是值得学习的。 + ## 贡献者 @MrKBear (熊鲜森) \ No newline at end of file diff --git a/miniprogram/api/Login.ts b/miniprogram/api/Login.ts new file mode 100644 index 0000000..47b3caf --- /dev/null +++ b/miniprogram/api/Login.ts @@ -0,0 +1,149 @@ +import { API, HTTPMethod, IParamSetting, GeneralCallbackResult } from "../core/Api"; + +interface ILoginInput { + + /** + * 学号 + */ + studentId: string; + + /** + * 教务处密码 + */ + password: string; +} + +interface ILoginOutput { + + /** + * 身份证后六位 + * 用于尝试水卡登录 + */ + idCardLast6: string; + + /** + * 使用的教务处链接 + */ + eduService: string; + + /** + * 用户的真实姓名 + */ + actualName: string; + + /** + * 用户是否关注了公共号 + */ + isSubscribeWxAccount: boolean; + + /** + * 教务处的 session + */ + eduSession: string; +} + +interface ILoginEvent { + + /** + * session 过期 + */ + expire: GeneralCallbackResult; + + /** + * 登录失败 + */ + unauthorized: GeneralCallbackResult; + + /** + * 未知的问题 + */ + error: GeneralCallbackResult; + + /** + * 数据损坏或丢失 + */ + badData: GeneralCallbackResult; +} + +/** + * Login API + * 此 API 用来向教务处发起登录请求 + * 请求成功后将获得教务处返回的 session + */ +class Login extends API { + + public override url: string = "/login"; + + public override method: HTTPMethod = HTTPMethod.POST; + + public override params: IParamSetting = { + + studentId: { + mapKey: "id", + tester: /^\d{8,12}$/, + }, + + password: { + mapKey: "pwd" + } + }; + + public constructor() { + super(); + this.initDebugLabel("Login"); + + this.addFailedCallBack(); + + this.on("success", (data) => { + + let isSuccess = true; + let errMsg = ""; + 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 }); + }); + } +} + +export { Login, ILoginInput, ILoginOutput }; \ No newline at end of file diff --git a/miniprogram/core/Api.ts b/miniprogram/core/Api.ts index 05bab2f..21dda78 100644 --- a/miniprogram/core/Api.ts +++ b/miniprogram/core/Api.ts @@ -32,6 +32,11 @@ type DeepReadonly = { */ type IParamSetting = { [P in keyof T]: { + + /** + * 键值映射 + */ + mapKey?: string, /** * 默认值 @@ -130,13 +135,13 @@ type IAPIResultEvent = { * 无论因为什么 * 总之数据获取到 */ - no: { message: string } & U, + no: GeneralCallbackResult & U, /** * 完成了 * 无论失败与否 */ - done: { message: string, data: O } & U + done: { data?: O } & GeneralCallbackResult & U } /** @@ -343,14 +348,15 @@ class API< for (let key in this.params) { let data = this.data[key]; - let { isHeader, isTemplate } = this.params[key]; + let { isHeader, isTemplate, mapKey } = this.params[key]; + let useKey = mapKey ?? key; // 加载数据 if (!isTemplate) { if (isHeader) { - requestData.header![key] = data; + requestData.header![useKey] = data; } else { - (requestData.data as IAnyData)[key] = data; + (requestData.data as IAnyData)[useKey] = data; } } } @@ -593,6 +599,17 @@ class API< return this; } + /** + * 自动挂载失败回调 + */ + public addFailedCallBack(): this { + this.on("fail", (e) => { + this.emit("no", e as any); + this.emit("done", e as any); + }); + return this; + } + /** * 请求失败后的提示语句 */ @@ -680,4 +697,4 @@ enum HTTPMethod { } export default API; -export { API, IParamSetting, IAppAPIParam, ICallBack, HTTPMethod, RequestPolicy } \ No newline at end of file +export { API, IParamSetting, IAppAPIParam, ICallBack, HTTPMethod, RequestPolicy, GeneralCallbackResult } \ No newline at end of file diff --git a/miniprogram/pages/Timetable/TestCore.ts b/miniprogram/pages/Timetable/TestCore.ts index 70259d0..6a81997 100644 --- a/miniprogram/pages/Timetable/TestCore.ts +++ b/miniprogram/pages/Timetable/TestCore.ts @@ -1,5 +1,5 @@ import { Modular, Manager, ILifetime } from "../../core/Module"; -import { API, IParamSetting } from "../../core/Api"; +import { Login } from "../../api/Login"; import { Storage } from "../../core/Storage"; /** @@ -27,44 +27,13 @@ implements Partial { setTimeout(() => { s.set("be", 12); }, 1000) - - interface ITestApiInput { - name: string, - id: number, - info: { - data: string - } - } - class TestApi extends API { - - public override params: IParamSetting = { - name: { - tester: "123", - isHeader: true - }, - id: { - parse: (i) => ++i, - }, - info: {} - } - - public constructor() { - super(); - this.initDebugLabel("TestApi"); - } - } - - let api = new TestApi(); - api.param({ - name: "123", - id: 456, - info: { - data: "abc" - } - }).request().waitRequest({ - success: (d) => console.log(d) - }) + new Login().param({studentId: "1806240113", password: "qazxsw123"}) + .request().wait({ + ok: (w) => {console.log("ok", w)}, + no: (w) => {console.log("no", w)}, + done: (w) => {console.log("done", w)} + }); } }