22 Commits
Author SHA1 Message Date
MrKBear 4c66a8974f Add login UI style 2022-06-10 12:33:38 +08:00
MrKBear 349930d438 Add login layer 2022-06-10 00:09:20 +08:00
MrKBear f9c73b25fe Optimize account page ui style 2022-06-09 20:08:27 +08:00
MrKBear d733c75371 Update project config 2022-06-09 17:23:09 +08:00
MrKBear 2fd3f5a0db (#22) Add Data Modular. 2022-01-28 08:41:22 +08:00
MrKBear f2f68c1f4a Merge branch 'master' into dev-mrkbear 2022-01-26 14:51:03 +08:00
MrKBear 1917828eab Merge pull request '(#22)(#56) Add student info data ware.' (#67) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/67
2022-01-25 17:13:12 +08:00
MrKBear afae6b7903 (#22)(#56) Add student info data ware. 2022-01-25 17:11:29 +08:00
MrKBear b2854908a4 Merge pull request '(#56) Data prototype use custrmers function.' (#65) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/65
2022-01-25 13:05:55 +08:00
MrKBear 7f86ae9fd2 Merge branch 'master' into dev-mrkbear 2022-01-25 13:05:42 +08:00
MrKBear 22188907c2 (#56) Data prototype use custrmers function. 2022-01-25 13:04:41 +08:00
MrKBear 33e49cb8be Merge pull request '(#36) Optimization popup layer modular.' (#64) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/64
2022-01-24 16:57:00 +08:00
MrKBear 1dcc09980c (#36) Optimization popup layer modular. 2022-01-24 16:55:58 +08:00
MrKBear 6a4cae757d Merge pull request '(#36) Merge mask modular & popup modular in popup layer modular.' (#63) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/63
2022-01-24 14:59:33 +08:00
MrKBear 18381aa0c4 (#36) Merge mask modular & popup modular in popup layer modular. 2022-01-24 14:58:33 +08:00
MrKBear 943798f53c (#36) Add popuplayer. 2022-01-23 20:34:52 +08:00
MrKBear a5dc26cd17 Merge pull request '(#60) Remove mixin generic paradigm.' (#62) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/62
2022-01-23 12:10:05 +08:00
MrKBear 464a9d3e59 (#60) Remove mixin generic paradigm. 2022-01-23 12:08:38 +08:00
MrKBear 292a4c26c5 (#60) Core emitter generic optimization 2022-01-22 17:50:25 +08:00
MrKBear e97514a67f (#60) Core emitter generic optimization 2022-01-22 17:49:03 +08:00
MrKBear 27ac19141f Merge pull request '(#60) Core emitter generic optimization' (#61) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/61
2022-01-22 16:13:40 +08:00
MrKBear c385965655 (#60) Core emitter generic optimization 2022-01-22 16:10:24 +08:00
29 changed files with 1640 additions and 266 deletions
+9 -9
View File
@@ -1,7 +1,7 @@
import { API, IAnyData, GeneralCallbackResult } from "../core/Api"; import { API, IAnyData, GeneralCallbackResult } from "../core/Api";
import { EventType } from "../core/Emitter"; import { EventType, Emitter } from "../core/Emitter";
interface ILoginEvent { type ILoginEvent = {
/** /**
* session 过期 * session 过期
@@ -56,37 +56,37 @@ abstract class EduBase<
if(!info) { if(!info) {
isSuccess = false; isSuccess = false;
errMsg = "Bad Data"; errMsg = "Bad Data";
this.emit("badData", { errMsg }); (this as Emitter<IAnyData>).emit("badData", { errMsg });
} }
if (isSuccess) switch (info.code) { if (isSuccess) switch (info.code) {
case (1): case (1):
res = parseFunction(info.data); res = parseFunction(info.data);
errMsg = info.err_msg ?? "Success"; errMsg = info.err_msg ?? "Success";
this.emit("ok", res!); (this as Emitter<IAnyData>).emit("ok", res!);
break; break;
case (2): case (2):
isSuccess = false; isSuccess = false;
errMsg = info.err_msg ?? "Session Expire"; errMsg = info.err_msg ?? "Session Expire";
this.emit("expire", { errMsg }); (this as Emitter<IAnyData>).emit("expire", { errMsg });
break; break;
case (3): case (3):
isSuccess = false; isSuccess = false;
errMsg = info.err_msg ?? "Unauthorized"; errMsg = info.err_msg ?? "Unauthorized";
this.emit("unauthorized", { errMsg }); (this as Emitter<IAnyData>).emit("unauthorized", { errMsg });
break; break;
case (4): case (4):
isSuccess = false; isSuccess = false;
errMsg = info.err_msg ?? "Error"; errMsg = info.err_msg ?? "Error";
this.emit("error", { errMsg }); (this as Emitter<IAnyData>).emit("error", { errMsg });
break; break;
} }
if (!isSuccess) this.emit("no", { errMsg }); if (!isSuccess) (this as Emitter<IAnyData>).emit("no", { errMsg });
this.emit("done", { errMsg, data: res }); (this as Emitter<IAnyData>).emit("done", { errMsg, data: res });
}); });
} }
} }
-5
View File
@@ -32,11 +32,6 @@ interface ILoginOutput {
*/ */
actualName: string; actualName: string;
/**
* 用户是否关注了公共号
*/
isSubscribeWxAccount: boolean;
/** /**
* 教务处的 session * 教务处的 session
*/ */
+17 -2
View File
@@ -6,20 +6,27 @@ $theme-color-light-layout: #F8F8F8;
$theme-color-light-background: #f4f0f1; $theme-color-light-background: #f4f0f1;
$theme-color-light-title: rgba(0, 0, 0, .65); $theme-color-light-title: rgba(0, 0, 0, .65);
$theme-color-light-text: rgba(0, 0, 0, .5); $theme-color-light-text: rgba(0, 0, 0, .5);
$theme-color-light-line: rgba(0, 0, 0, .25);
$theme-color-dark-layout: #1f1f1f; $theme-color-dark-layout: #1f1f1f;
$theme-color-dark-background: #181615; $theme-color-dark-background: #181615;
$theme-color-dark-title: rgba(255, 255, 255, .65); $theme-color-dark-title: rgba(255, 255, 255, .65);
$theme-color-dark-text: rgba(255, 255, 255, .5); $theme-color-dark-text: rgba(255, 255, 255, .5);
$theme-color-dark-line: rgba(255, 255, 255, .25);
$black-filter: brightness(0) opacity(.65); $black-filter: brightness(0) opacity(.65);
$white-filter: brightness(100) opacity(.65); $white-filter: brightness(100) opacity(.65);
$blue-filter: opacity(1); $blue-filter: opacity(1);
$green-filter: hue-rotate(-110deg) opacity(1);
@mixin container {
width: 88%;
padding: 0 6%;
}
// 页面容器外边距 // 页面容器外边距
view.container { view.container {
width: 88%; @include container;
padding: 0 6%;
} }
// 带阴影的 card // 带阴影的 card
@@ -79,6 +86,14 @@ view.h3 {
font-size: 1em; font-size: 1em;
letter-spacing: .1em; letter-spacing: .1em;
} }
view.button {
color: white;
background-color: $theme-color-blue;
text-align: center;
padding: 10px;
border-radius: 10px;
}
@media (prefers-color-scheme: dark){ @media (prefers-color-scheme: dark){
page { page {
+14 -23
View File
@@ -1,4 +1,4 @@
import { Emitter, EventType } from "./Emitter"; import { Emitter, EventType, EventMixin } from "./Emitter";
import { API_FAILED_SHOW_MESSAGE } from "./Config"; import { API_FAILED_SHOW_MESSAGE } from "./Config";
import { Logger, LogLabel, LevelLogLabel, colorRadio, StatusLabel } from "./Logger"; import { Logger, LogLabel, LevelLogLabel, colorRadio, StatusLabel } from "./Logger";
interface IAppAPIParam { interface IAppAPIParam {
@@ -156,16 +156,7 @@ class API<
O extends IAnyData = IAnyData, O extends IAnyData = IAnyData,
E extends Record<EventType, any> = Record<EventType, any>, E extends Record<EventType, any> = Record<EventType, any>,
U extends IAnyData = IAnyData U extends IAnyData = IAnyData
> extends Emitter < > extends Emitter<EventMixin<IAPIEvent<I, O> & IAPIResultEvent<O, U>, E>> {
{
// 这个复杂的泛型是为了 MixIn 用户自定义事件类型
// 懂得如何使用就可以了
// 不要试图去理解下面这三行代码,真正的恶魔在等着你
[P in (keyof (IAPIEvent<I, O> & IAPIResultEvent<O, U>) | keyof E)] :
P extends keyof IAPIEvent<I, O> ? IAPIEvent<I, O>[P] :
P extends keyof IAPIResultEvent<O, U> ? IAPIResultEvent<O, U>[P] : E[P]
}
> {
/** /**
* 默认调试标签 * 默认调试标签
@@ -316,7 +307,7 @@ class API<
} }
// 触发数据初始化事件 // 触发数据初始化事件
this.emit("initData", this.data); (this as Emitter<IAnyData>).emit("initData", this.data);
// 重置请求数据 // 重置请求数据
const requestData:IWxRequestOption<O> = this.requestData = { const requestData:IWxRequestOption<O> = this.requestData = {
@@ -343,7 +334,7 @@ class API<
} }
// 触发数据解析 // 触发数据解析
this.emit("parseRequestData", this.data); (this as Emitter<IAnyData>).emit("parseRequestData", this.data);
// 数据收集 // 数据收集
for (let key in this.params) { for (let key in this.params) {
@@ -461,18 +452,18 @@ class API<
let request = () => { let request = () => {
// 触发请求发送事件 // 触发请求发送事件
this.emit("request", this.requestData!) (this as Emitter<IAnyData>).emit("request", this.requestData!)
wx.request<O>({ wx.request<O>({
...this.requestData!, ...this.requestData!,
success: (e) => { success: (e) => {
this.emit("success", e); (this as Emitter<IAnyData>).emit("success", e);
}, },
fail: (e) => { fail: (e) => {
this.emit("fail", e); (this as Emitter<IAnyData>).emit("fail", e);
}, },
complete: (e) => { complete: (e) => {
this.emit("complete", e); (this as Emitter<IAnyData>).emit("complete", e);
} }
}); });
} }
@@ -490,12 +481,12 @@ class API<
// 使用上次请求结果 // 使用上次请求结果
if (this.policy === RequestPolicy.useLastRequest) { if (this.policy === RequestPolicy.useLastRequest) {
lastAPI.on("success", (e) => { lastAPI.on("success", (e) => {
this.emit("success", e as SuccessCallbackResult<O>); (this as Emitter<IAnyData>).emit("success", e as SuccessCallbackResult<O>);
this.emit("complete", {errMsg: e.errMsg}); (this as Emitter<IAnyData>).emit("complete", {errMsg: e.errMsg});
}); });
lastAPI.on("fail", (e) => { lastAPI.on("fail", (e) => {
this.emit("fail", e); (this as Emitter<IAnyData>).emit("fail", e);
this.emit("complete", {errMsg: e.errMsg}); (this as Emitter<IAnyData>).emit("complete", {errMsg: e.errMsg});
}); });
} }
@@ -605,8 +596,8 @@ class API<
*/ */
public addFailedCallBack(): this { public addFailedCallBack(): this {
this.on("fail", (e) => { this.on("fail", (e) => {
this.emit("no", e as any); (this as Emitter<IAnyData>).emit("no", e as any);
this.emit("done", e as any); (this as Emitter<IAnyData>).emit("done", e as any);
}); });
return this; return this;
} }
+55 -28
View File
@@ -1,3 +1,4 @@
import { Storage } from "./Storage";
/** /**
* 数据层键值设置 * 数据层键值设置
@@ -12,22 +13,22 @@ interface IDataParamSettingItem {
/** /**
* 键值是否可以获取 * 键值是否可以获取
*/ */
isGet: boolean; get?: ((...P: any) => this["type"]) | INone;
/** /**
* 键值是否可以设置 * 键值是否可以设置
*/ */
isSet: boolean; set?: ((...P: [this["type"], ...any]) => any) | INone;
/** /**
* 是否仅为异步获取 * 是否仅为异步获取
*/ */
isGetAsync?: boolean; getAsync?: ((...P: any) => Promise<this["type"]>) | INone;
/** /**
* 是否仅为异步设置 * 是否仅为异步设置
*/ */
isSetAsync?: boolean; setAsync?: ((...P: [this["type"], ...any]) => Promise<any>) | INone;
} }
/** /**
@@ -37,12 +38,7 @@ interface IDataParamSetting {
[x: string]: IDataParamSettingItem [x: string]: IDataParamSettingItem
} }
type IGet<T> = () => T; type INone = undefined | void;
type IGetAsync<T> = () => Promise<T>;
type ISet<T> = (data: T) => INone;
type ISetAsync<T> = (data: T) => Promise<INone>;
type INone = undefined | void | unknown;
/** /**
* 注册表结构 * 注册表结构
@@ -52,22 +48,24 @@ type IRegistryItem<S extends IDataParamSettingItem> = {
/** /**
* 获取方法 * 获取方法
*/ */
get: S["isGetAsync"] extends true ? INone : S["isGet"] extends true ? IGet<S["type"]> : INone; get: S["get"];
/** /**
* 异步获取方法 * 异步获取方法
*/ */
getAsync: S["isGet"] extends true ? IGetAsync<S["type"]> : INone; getAsync: S["getAsync"] extends Function ? S["getAsync"] :
S["get"] extends ((...P: any) => S["type"]) ? (...param: Parameters<S["get"]>) => Promise<S["type"]> : INone;
/** /**
* 设置方法 * 设置方法
*/ */
set: S["isSetAsync"] extends true ? INone : S["isSet"] extends true ? ISet<S["type"]> : INone; set: S["set"];
/** /**
* 异步设置方法 * 异步设置方法
*/ */
setAsync: S["isSet"] extends true ? ISetAsync<S["type"]> : INone; setAsync: S["setAsync"] extends Function ? S["setAsync"] :
S["set"] extends ((...P: [S["type"], ...any]) => any) ? (...param: Parameters<S["set"]>) => Promise<ReturnType<S["set"]>> : INone;
} }
/** /**
@@ -91,16 +89,16 @@ type IAutoSelect<IF extends boolean, A, B> = IF extends true ? A : B;
* ```typescript * ```typescript
* class TestData extends Data<{ * class TestData extends Data<{
* test: { * test: {
* type: number, * type: number
* isGet: true, * get: () => number,
* isSet: true, * set: (val: number) => void,
* isGetAsync: true * getAsync: () => Promise<number>
* } * }
* }> { * }> {
* public onLoad() { * public onLoad() {
* let dataObject = {key: 1} * let dataObject = {key: 1}
* this.getter("test", () => 1); * this.getter("test", () => 1);
* this.registerKeyFromObject("test", "key", dataObject); * this.registerKeyFromObject(dataObject, "test", "key");
* } * }
* } * }
* ``` * ```
@@ -183,9 +181,9 @@ class Data<D extends IDataParamSetting> {
*/ */
protected registerKeyFromObject< protected registerKeyFromObject<
KEY extends keyof D, KEY extends keyof D,
F extends keyof O, F extends string,
O extends {[K in F]: D[KEY]["type"]} O extends {[K in F]: D[KEY]["type"]}
> (key: KEY, keyFromObject: F, object: O) { > (object: O, key: KEY, keyFromObject: F = key as any) {
// 注册同步获取 // 注册同步获取
this.getter(key, () => { this.getter(key, () => {
@@ -198,6 +196,33 @@ class Data<D extends IDataParamSetting> {
}) })
} }
/**
* 关联 Storage 中的 key
* @param key Data 层键值
* @param keyFromStorage StorageKey
*/
protected registerKeyFromStorage<
KEY extends keyof D,
F extends string,
S extends Storage<{[K in F]: D[KEY]["type"]}>
> (storage: S, key: KEY, keyFromStorage: F = key as any) {
// 同步获取
this.getter(key, () => {
return storage.get(keyFromStorage);
});
// 同步设置
this.setter(key, (data: any) => {
storage.set(keyFromStorage, data);
});
// 异步设置
this.setter(key, (async (data: any) => {
await storage.set(keyFromStorage, data);
}) as any, true);
}
/** /**
* 导出数据对象 * 导出数据对象
* @returns 数据对象 * @returns 数据对象
@@ -223,12 +248,12 @@ class Data<D extends IDataParamSetting> {
// 检验 getter // 检验 getter
if (item.get && !item.getAsync) { if (item.get && !item.getAsync) {
item.getAsync = this.syncFn2AsyncFn(item.get as IGet<D[KEY]["type"]>); item.getAsync = this.syncFn2AsyncFn(item.get) as any;
} }
// 检验 setter // 检验 setter
if (item.set && !item.setAsync) { if (item.set && !item.setAsync) {
item.setAsync = this.syncFn2AsyncFn(item.set as ISet<D[KEY]["type"]>); item.setAsync = this.syncFn2AsyncFn(item.set) as any;
} }
} }
@@ -240,11 +265,13 @@ class Data<D extends IDataParamSetting> {
* 将同步函数转换为异步函数 * 将同步函数转换为异步函数
* @param fn 同步函数 * @param fn 同步函数
*/ */
protected syncFn2AsyncFn<D, H extends (IGet<D> | ISet<D>)> (fn: H): protected syncFn2AsyncFn<F extends (...p: any) => any> (fn: F): (...param: Parameters<F>) => ReturnType<F> {
IAutoSelect<H extends IGet<D> ? true : false, IGetAsync<D>, ISetAsync<D>> {
const asyncFn = async (...param: [D]) => { const asyncFn = async (...param: [D]) => {
return fn(...param); return fn(...param);
}; };
return asyncFn as any; return asyncFn as any;
} }
} }
export { Data };
export default Data;
+18 -1
View File
@@ -13,6 +13,21 @@ export type EventHandlerMap<Events extends Record<EventType, any>> = Map<
EventHandlerList<Events[keyof Events]> EventHandlerList<Events[keyof Events]>
>; >;
// Emitter function type
type IEmitParamType<E extends Record<EventType, any>, K extends keyof E> =
E[K] extends ( undefined | void ) ? [type: K] : [type: K, evt: E[K]];
// Mixin to event object
export type EventMixin<A extends Record<EventType, any>, B extends Record<EventType, any>> = {
[P in (keyof A | keyof B)] :
P extends (keyof A & keyof B) ?
A[P] :
P extends keyof A ?
A[P] :
P extends keyof B ? B[P] :
never;
}
export class Emitter<Events extends Record<EventType, any>> { export class Emitter<Events extends Record<EventType, any>> {
/** /**
@@ -74,7 +89,8 @@ export class Emitter<Events extends Record<EventType, any>> {
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
* @memberOf mitt * @memberOf mitt
*/ */
emit<Key extends keyof Events>(type: Key, evt: Events[Key]) { public emit<Key extends keyof Events>(...param: IEmitParamType<Events, Key>): this {
const [ type, evt ] = param;
let handlers = this.all!.get(type); let handlers = this.all!.get(type);
if (handlers) { if (handlers) {
(handlers as EventHandlerList<Events[keyof Events]>) (handlers as EventHandlerList<Events[keyof Events]>)
@@ -83,5 +99,6 @@ export class Emitter<Events extends Record<EventType, any>> {
handler(evt!); handler(evt!);
}); });
} }
return this;
} }
} }
+154
View File
@@ -0,0 +1,154 @@
import { Data } from "../core/Data";
import { Storage } from "../core/Storage";
import { Login, ILoginOutput } from "../api/Login";
/**
* 登录状态
*/
enum LoginStatus {
/**
* 已认证
*/
verified = 1,
/**
* 失效的认证
* 通常为用户名密码错误
*/
invalid = 2,
/**
* 没有登录信息
*/
none = 3
}
/**
* API 返回数据
*/
type ILoginApiData = {
[P in keyof ILoginOutput]: {
type: ILoginOutput[P];
getAsync: () => Promise<ILoginOutput[P]>;
}
}
/**
* Storage 缓存数据类型
*/
type IStudentInfoStorageData = ILoginOutput & {
[P in keyof IStudentInfoData]: IStudentInfoData[P]["type"];
};
/**
* 学生信息数据结构
*/
type IStudentInfoData = {
/**
* 学号
*/
studentId: {
type: string,
};
/**
* 教务处密码
*/
password: {
type: string
};
/**
* 登录状态
*/
loginStatus: {
type: LoginStatus
}
/**
* 上次登录时间
* 时间戳
*/
lastLoginTime: {
type: number
}
/**
* 距离上次登录后
* 学号和密码是否发生过改变
*/
isUserInfoChange: {
type: boolean
}
}
/**
* 学生信息
*/
class StudentInfo extends Data<IStudentInfoData & ILoginApiData> {
/**
* 学生信息缓存
*/
private eduStorage = new Storage<IStudentInfoStorageData>("StudentInfo", {
idCardLast6: "",
eduService: "",
actualName: "",
eduSession: "",
studentId: "",
password: "",
loginStatus: LoginStatus.none,
lastLoginTime: 0,
isUserInfoChange: false
});
public override onLoad() {
}
/**
* 用户登录
*/
private async login(): Promise<boolean> {
// 获取账号密码
const stuId = this.eduStorage.get("studentId");
const pwd = this.eduStorage.get("password");
if (!stuId || !pwd) return false;
// 发送请求
const data = await new Login().param({
studentId: stuId,
password: pwd
}).request().wait();
// 请求成功
let res = data.data;
if (res) {
// 保存数据
this.eduStorage.set("actualName", res.actualName);
this.eduStorage.set("eduService", res.eduService);
this.eduStorage.set("eduSession", res.eduSession);
this.eduStorage.set("idCardLast6", res.idCardLast6);
// 记录时间
this.eduStorage.set("lastLoginTime", new Date().getTime());
return true;
} else {
return false;
}
}
/**
* 获取状态
*/
private async getStatus() {}
}
export { StudentInfo };
export default StudentInfo;
@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4F0F1;}
.st1{fill:#FFFFFF;}
.st2{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;}
.st3{fill:#1A1A1A;}
.st4{fill:none;stroke:#1A1A1A;stroke-width:3;stroke-miterlimit:10;}
.st5{fill:none;stroke:#1A1A1A;stroke-miterlimit:10;}
.st6{fill:#3EA3D8;}
.st7{display:none;}
.st8{display:inline;}
.st9{fill:#808080;}
.st10{display:inline;fill:#808080;}
.st11{fill:none;stroke:#808080;stroke-miterlimit:10;}
.st12{fill:#7AC943;}
.st13{fill:none;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st14{fill:#FFFFFF;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st15{fill:none;stroke:#3EA3D8;stroke-miterlimit:10;}
.st16{fill:#CCCCCC;}
.st17{fill:none;stroke:#CCCCCC;stroke-linecap:square;stroke-miterlimit:10;}
.st18{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;stroke-dasharray:1.9084,1.9084;}
.st19{fill:none;stroke:#E6E6E6;stroke-miterlimit:10;}
.st20{fill:#666666;}
.st21{fill:none;stroke:#B3B3B3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st22{fill:#B3B3B3;}
.st23{opacity:0.05;}
.st24{clip-path:url(#SVGID_00000047771584930258237770000008464236368807665038_);}
.st25{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st26{opacity:0.4;fill:#3EA3D8;}
.st27{fill:none;stroke:#3EA3D8;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="A3">
<g id="HEADER_x5F_BAR_00000036974300579741410940000000488572858971942531_">
</g>
</g>
<g id="A2">
<g id="HEADER_x5F_BAR_00000019648451390881128220000012673596900810320021_">
</g>
<g id="BUTTON_00000117651906535404305420000016044620869483747487_">
</g>
<g id="USER_x5F_FORM">
</g>
<g id="INTRO">
</g>
<g id="DLPU_x5F_LOGO">
</g>
</g>
<g id="A1">
<g id="NAV_x5F_BAR_00000129914889952932149030000011711506177042644156_">
</g>
<g id="HEADER_x5F_BAR_00000015351907221170818370000001589878730520391302_">
</g>
<g id="FUNC_x5F_LIST">
</g>
<g id="MAIN_x5F_FUNC">
</g>
<g id="USER_x5F_CARD">
<g id="BG" class="st23">
</g>
</g>
</g>
<g id="ICON">
<g>
<path class="st6" d="M50,0c8.69,0,17.06,2.22,24.48,6.39c2.24,1.26,3.03,4.1,1.78,6.34c-1.26,2.24-4.1,3.03-6.34,1.78
C63.84,11.08,56.98,9.29,50,9.3C27.53,9.3,9.3,27.52,9.3,50S27.53,90.7,50,90.7c22.48,0,40.7-18.22,40.7-40.7
c0-7.9-2.25-15.46-6.42-21.96c-1.39-2.16-0.76-5.04,1.4-6.43c2.16-1.39,5.04-0.76,6.43,1.4c5.17,8.05,7.91,17.42,7.9,26.99
c0,27.61-22.38,50-50,50C22.39,100,0,77.61,0,50C0,22.39,22.39,0,50,0L50,0z M50,0"/>
<path class="st6" d="M83.48,20.51c1.7-1.82,4.53-1.97,6.42-0.36c1.89,1.61,2.18,4.43,0.65,6.39l-0.33,0.38L51.09,67.99
c-1.67,1.75-4.4,1.93-6.29,0.41l-0.39-0.35L26.66,50.11c-1.75-1.75-1.82-4.58-0.16-6.41c1.67-1.84,4.48-2.04,6.4-0.47l0.37,0.34
L47.65,58.1L83.48,20.51z M83.48,20.51"/>
</g>
</g>
<g id="DEFAULT_x5F_AVATOR">
</g>
<g id="COLOR">
</g>
<g id="NAV_x5F_BAR">
<g id="ICON_x5F_SETTING">
</g>
<g id="ICON_x5F_INFO">
</g>
<g id="ICON_x5F_KCB">
</g>
</g>
<g id="HEADER_x5F_BAR">
<g id="BUTTON">
</g>
<g id="TOP">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4F0F1;}
.st1{fill:#FFFFFF;}
.st2{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;}
.st3{fill:#1A1A1A;}
.st4{fill:none;stroke:#1A1A1A;stroke-width:3;stroke-miterlimit:10;}
.st5{fill:none;stroke:#1A1A1A;stroke-miterlimit:10;}
.st6{fill:#3EA3D8;}
.st7{display:none;}
.st8{display:inline;}
.st9{fill:#808080;}
.st10{display:inline;fill:#808080;}
.st11{fill:none;stroke:#808080;stroke-miterlimit:10;}
.st12{fill:#7AC943;}
.st13{fill:none;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st14{fill:#FFFFFF;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st15{fill:none;stroke:#3EA3D8;stroke-miterlimit:10;}
.st16{fill:#CCCCCC;}
.st17{fill:none;stroke:#CCCCCC;stroke-linecap:square;stroke-miterlimit:10;}
.st18{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;stroke-dasharray:1.9084,1.9084;}
.st19{fill:none;stroke:#E6E6E6;stroke-miterlimit:10;}
.st20{fill:#666666;}
.st21{fill:none;stroke:#B3B3B3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st22{fill:#B3B3B3;}
.st23{opacity:0.05;}
.st24{clip-path:url(#SVGID_00000177474060957557094400000000012443665588057228_);}
.st25{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st26{opacity:0.4;fill:#3EA3D8;}
.st27{fill:none;stroke:#3EA3D8;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="A3">
<g id="HEADER_x5F_BAR_00000036974300579741410940000000488572858971942531_">
</g>
</g>
<g id="A2">
<g id="HEADER_x5F_BAR_00000019648451390881128220000012673596900810320021_">
</g>
<g id="BUTTON_00000117651906535404305420000016044620869483747487_">
</g>
<g id="USER_x5F_FORM">
</g>
<g id="INTRO">
</g>
<g id="DLPU_x5F_LOGO">
</g>
</g>
<g id="A1">
<g id="NAV_x5F_BAR_00000129914889952932149030000011711506177042644156_">
</g>
<g id="HEADER_x5F_BAR_00000015351907221170818370000001589878730520391302_">
</g>
<g id="FUNC_x5F_LIST">
</g>
<g id="MAIN_x5F_FUNC">
</g>
<g id="USER_x5F_CARD">
<g id="BG" class="st23">
</g>
</g>
</g>
<g id="ICON">
<g>
<path class="st6" d="M50,0C22.39,0,0,22.39,0,50c0,27.61,22.39,50,50,50c27.61,0,50-22.39,50-50C100,22.39,77.61,0,50,0L50,0z
M50,8.77c22.77,0,41.23,18.46,41.23,41.23S72.77,91.23,50,91.23S8.77,72.77,8.77,50S27.23,8.77,50,8.77L50,8.77z M50,8.77"/>
<path class="st6" d="M50,43.19c3.04,0,4.56,1.52,4.56,4.56v23.72c0,3.04-1.52,4.56-4.56,4.56c-3.04,0-4.56-1.52-4.56-4.56V47.75
C45.44,44.71,46.96,43.19,50,43.19L50,43.19z M50,43.19"/>
<path class="st6" d="M43.33,30.64c0,2.38,1.27,4.58,3.33,5.77c2.06,1.19,4.6,1.19,6.67,0c2.06-1.19,3.33-3.39,3.33-5.77
c0-2.38-1.27-4.58-3.33-5.77c-2.06-1.19-4.6-1.19-6.67,0C44.6,26.05,43.33,28.25,43.33,30.64L43.33,30.64z M43.33,30.64"/>
</g>
</g>
<g id="DEFAULT_x5F_AVATOR">
</g>
<g id="COLOR">
</g>
<g id="NAV_x5F_BAR">
<g id="ICON_x5F_SETTING">
</g>
<g id="ICON_x5F_INFO">
</g>
<g id="ICON_x5F_KCB">
</g>
</g>
<g id="HEADER_x5F_BAR">
<g id="BUTTON">
</g>
<g id="TOP">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4F0F1;}
.st1{fill:#FFFFFF;}
.st2{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;}
.st3{fill:#1A1A1A;}
.st4{fill:none;stroke:#1A1A1A;stroke-width:3;stroke-miterlimit:10;}
.st5{fill:none;stroke:#1A1A1A;stroke-miterlimit:10;}
.st6{fill:#3EA3D8;}
.st7{display:none;}
.st8{display:inline;}
.st9{fill:#808080;}
.st10{display:inline;fill:#808080;}
.st11{fill:none;stroke:#808080;stroke-miterlimit:10;}
.st12{fill:#7AC943;}
.st13{fill:none;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st14{fill:#FFFFFF;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st15{fill:none;stroke:#3EA3D8;stroke-miterlimit:10;}
.st16{fill:#CCCCCC;}
.st17{fill:none;stroke:#CCCCCC;stroke-linecap:square;stroke-miterlimit:10;}
.st18{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;stroke-dasharray:1.9084,1.9084;}
.st19{fill:none;stroke:#E6E6E6;stroke-miterlimit:10;}
.st20{fill:#666666;}
.st21{fill:none;stroke:#B3B3B3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st22{fill:#B3B3B3;}
.st23{opacity:0.05;}
.st24{clip-path:url(#SVGID_00000096743565441905941170000016958695224966735273_);}
.st25{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st26{opacity:0.4;fill:#3EA3D8;}
.st27{fill:none;stroke:#3EA3D8;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="A3">
<g id="HEADER_x5F_BAR_00000036974300579741410940000000488572858971942531_">
</g>
</g>
<g id="A2">
<g id="HEADER_x5F_BAR_00000019648451390881128220000012673596900810320021_">
</g>
<g id="BUTTON_00000117651906535404305420000016044620869483747487_">
</g>
<g id="USER_x5F_FORM">
</g>
<g id="INTRO">
</g>
<g id="DLPU_x5F_LOGO">
</g>
</g>
<g id="A1">
<g id="NAV_x5F_BAR_00000129914889952932149030000011711506177042644156_">
</g>
<g id="HEADER_x5F_BAR_00000015351907221170818370000001589878730520391302_">
</g>
<g id="FUNC_x5F_LIST">
</g>
<g id="MAIN_x5F_FUNC">
</g>
<g id="USER_x5F_CARD">
<g id="BG" class="st23">
</g>
</g>
</g>
<g id="ICON">
<path class="st6" d="M99.46,50.54c-0.71-1.43-18.11-35.5-49.55-35.5c-2.62,0-5.24,0.24-7.86,0.71c-1.91,0.48-3.34,2.14-2.86,4.05
c0.48,1.91,2.14,3.34,4.05,2.86c2.14-0.48,4.29-0.48,6.43-0.48c23.35,0,38.59,23.35,42.41,29.78c-1.19,2.14-3.57,5.96-7.15,10.24
c-1.19,1.43-0.95,3.81,0.48,5c0.71,0.48,1.43,0.71,2.38,0.71c0.95,0,2.14-0.48,2.86-1.19c5.72-6.91,8.81-12.86,8.81-13.1
C100.18,52.68,100.18,51.49,99.46,50.54z M16.8,9.56c-1.43-1.43-3.57-1.43-5,0s-1.43,3.57,0,5l10.24,10.24
C8.22,35.05,0.83,49.58,0.36,50.3c-0.48,0.95-0.48,2.14,0,3.34c0.71,1.43,18.11,35.26,49.55,35.26c9.29,0,18.34-3.1,26.92-9.05
l10.72,10.72c0.71,0.71,1.67,0.95,2.62,0.95c0.95,0,1.91-0.24,2.62-0.95c1.43-1.43,1.43-3.57,0-5L16.8,9.56z M43.95,46.96
l11.67,11.67c-1.43,1.43-3.57,2.38-5.72,2.38c-4.53,0-8.34-3.81-8.34-8.34C41.57,50.54,42.53,48.39,43.95,46.96z M49.91,81.75
c-23.35,0-38.59-23.35-42.41-29.78c2.38-4.05,9.05-14.53,19.54-21.92l11.67,11.67c-2.86,2.86-4.29,6.67-4.29,10.72
c0,8.58,6.91,15.49,15.49,15.49c4.05,0,7.86-1.67,10.72-4.29L71.59,74.6C64.68,79.36,57.3,81.75,49.91,81.75z"/>
</g>
<g id="DEFAULT_x5F_AVATOR">
</g>
<g id="COLOR">
</g>
<g id="NAV_x5F_BAR">
<g id="ICON_x5F_SETTING">
</g>
<g id="ICON_x5F_INFO">
</g>
<g id="ICON_x5F_KCB">
</g>
</g>
<g id="HEADER_x5F_BAR">
<g id="BUTTON">
</g>
<g id="TOP">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4F0F1;}
.st1{fill:#FFFFFF;}
.st2{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;}
.st3{fill:#1A1A1A;}
.st4{fill:none;stroke:#1A1A1A;stroke-width:3;stroke-miterlimit:10;}
.st5{fill:none;stroke:#1A1A1A;stroke-miterlimit:10;}
.st6{fill:#3EA3D8;}
.st7{display:none;}
.st8{display:inline;}
.st9{fill:#808080;}
.st10{display:inline;fill:#808080;}
.st11{fill:none;stroke:#808080;stroke-miterlimit:10;}
.st12{fill:#7AC943;}
.st13{fill:none;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st14{fill:#FFFFFF;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st15{fill:none;stroke:#3EA3D8;stroke-miterlimit:10;}
.st16{fill:#CCCCCC;}
.st17{fill:none;stroke:#CCCCCC;stroke-linecap:square;stroke-miterlimit:10;}
.st18{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;stroke-dasharray:1.9084,1.9084;}
.st19{fill:none;stroke:#E6E6E6;stroke-miterlimit:10;}
.st20{fill:#666666;}
.st21{fill:none;stroke:#B3B3B3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st22{fill:#B3B3B3;}
.st23{opacity:0.05;}
.st24{clip-path:url(#SVGID_00000124849447952852579110000006476751934385998486_);}
.st25{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st26{opacity:0.4;fill:#3EA3D8;}
.st27{fill:none;stroke:#3EA3D8;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="A3">
<g id="HEADER_x5F_BAR_00000036974300579741410940000000488572858971942531_">
</g>
</g>
<g id="A2">
<g id="HEADER_x5F_BAR_00000019648451390881128220000012673596900810320021_">
</g>
<g id="BUTTON_00000117651906535404305420000016044620869483747487_">
</g>
<g id="USER_x5F_FORM">
</g>
<g id="INTRO">
</g>
<g id="DLPU_x5F_LOGO">
</g>
</g>
<g id="A1">
<g id="NAV_x5F_BAR_00000129914889952932149030000011711506177042644156_">
</g>
<g id="HEADER_x5F_BAR_00000015351907221170818370000001589878730520391302_">
</g>
<g id="FUNC_x5F_LIST">
</g>
<g id="MAIN_x5F_FUNC">
</g>
<g id="USER_x5F_CARD">
<g id="BG" class="st23">
</g>
</g>
</g>
<g id="ICON">
<g>
<path class="st6" d="M50,66.23c-8.59,0-15.51-6.92-15.51-15.51S41.4,35.2,50,35.2s15.51,6.92,15.51,15.51S58.59,66.23,50,66.23z
M50,42.36c-4.53,0-8.35,3.82-8.35,8.35s3.82,8.35,8.35,8.35s8.35-3.82,8.35-8.35S54.53,42.36,50,42.36z"/>
<path class="st6" d="M50,86.99c-31.5,0-48.93-33.89-49.64-35.32c-0.48-0.95-0.48-2.15,0-3.34C1.07,46.9,18.73,13.01,50,13.01
c31.5,0,48.93,34.13,49.64,35.56c0.48,0.95,0.48,2.15,0,3.34C98.92,53.1,81.5,86.99,50,86.99z M7.51,50
C11.33,56.44,26.61,79.83,50,79.83S88.66,56.44,92.48,50C88.66,43.56,73.39,20.17,50,20.17S11.33,43.56,7.51,50z"/>
</g>
</g>
<g id="DEFAULT_x5F_AVATOR">
</g>
<g id="COLOR">
</g>
<g id="NAV_x5F_BAR">
<g id="ICON_x5F_SETTING">
</g>
<g id="ICON_x5F_INFO">
</g>
<g id="ICON_x5F_KCB">
</g>
</g>
<g id="HEADER_x5F_BAR">
<g id="BUTTON">
</g>
<g id="TOP">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4F0F1;}
.st1{fill:#FFFFFF;}
.st2{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;}
.st3{fill:#1A1A1A;}
.st4{fill:none;stroke:#1A1A1A;stroke-width:3;stroke-miterlimit:10;}
.st5{fill:none;stroke:#1A1A1A;stroke-miterlimit:10;}
.st6{fill:#3EA3D8;}
.st7{display:none;}
.st8{display:inline;}
.st9{fill:#808080;}
.st10{display:inline;fill:#808080;}
.st11{fill:none;stroke:#808080;stroke-miterlimit:10;}
.st12{fill:#7AC943;}
.st13{fill:none;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st14{fill:#FFFFFF;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st15{fill:none;stroke:#3EA3D8;stroke-miterlimit:10;}
.st16{fill:#CCCCCC;}
.st17{fill:none;stroke:#CCCCCC;stroke-linecap:square;stroke-miterlimit:10;}
.st18{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;stroke-dasharray:1.9084,1.9084;}
.st19{fill:none;stroke:#E6E6E6;stroke-miterlimit:10;}
.st20{fill:#666666;}
.st21{fill:none;stroke:#B3B3B3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st22{fill:#B3B3B3;}
.st23{opacity:0.05;}
.st24{clip-path:url(#SVGID_00000091016287826886391250000017486262032961877648_);}
.st25{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st26{opacity:0.4;fill:#3EA3D8;}
.st27{fill:none;stroke:#3EA3D8;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="A3">
<g id="HEADER_x5F_BAR_00000036974300579741410940000000488572858971942531_">
</g>
</g>
<g id="A2">
<g id="HEADER_x5F_BAR_00000019648451390881128220000012673596900810320021_">
</g>
<g id="BUTTON_00000117651906535404305420000016044620869483747487_">
</g>
<g id="USER_x5F_FORM">
</g>
<g id="INTRO">
</g>
<g id="DLPU_x5F_LOGO">
</g>
</g>
<g id="A1">
<g id="NAV_x5F_BAR_00000129914889952932149030000011711506177042644156_">
</g>
<g id="HEADER_x5F_BAR_00000015351907221170818370000001589878730520391302_">
</g>
<g id="FUNC_x5F_LIST">
</g>
<g id="MAIN_x5F_FUNC">
</g>
<g id="USER_x5F_CARD">
<g id="BG" class="st23">
</g>
</g>
</g>
<g id="ICON">
<g>
<path class="st6" d="M50,0C22.39,0,0,22.39,0,50c0,27.61,22.39,50,50,50c27.61,0,50-22.39,50-50C100,22.39,77.61,0,50,0L50,0z
M50,8.77c22.77,0,41.23,18.46,41.23,41.23S72.77,91.23,50,91.23S8.77,72.77,8.77,50S27.23,8.77,50,8.77L50,8.77z M50,8.77"/>
<path class="st6" d="M53.59,61.54v-0.98c0-1.69,0.35-3.17,1.05-4.58c0.64-1.27,1.55-2.46,2.82-3.52c3.38-2.95,5.42-4.86,6.05-5.56
c1.68-2.25,2.6-5.14,2.6-8.66c0-4.3-1.41-7.67-4.22-10.13c-2.81-2.53-6.54-3.73-11.12-3.73c-5.21,0-9.29,1.48-12.32,4.43
c-3.09,2.96-4.58,7.04-4.58,12.25h8.02c0-2.95,0.56-5.28,1.76-6.89c1.34-1.97,3.52-2.89,6.61-2.89c2.39,0,4.3,0.63,5.63,1.97
c1.26,1.34,1.97,3.16,1.97,5.49c0,1.76-0.63,3.45-1.9,5l-0.85,0.98c-4.58,4.08-7.32,7.04-8.23,8.94c-0.99,1.9-1.41,4.22-1.41,6.9
v0.99H53.59z M49.51,75.61c1.54,0,2.81-0.49,3.87-1.48c1.05-0.98,1.61-2.32,1.61-3.87c0-1.55-0.56-2.81-1.54-3.8
c-1.06-0.98-2.39-1.48-3.94-1.48c-1.55,0-2.82,0.49-3.87,1.47c-1.06,0.99-1.55,2.26-1.55,3.8c0,1.55,0.49,2.81,1.55,3.8
C46.69,75.05,47.96,75.61,49.51,75.61L49.51,75.61z M49.51,75.61"/>
</g>
</g>
<g id="DEFAULT_x5F_AVATOR">
</g>
<g id="COLOR">
</g>
<g id="NAV_x5F_BAR">
<g id="ICON_x5F_SETTING">
</g>
<g id="ICON_x5F_INFO">
</g>
<g id="ICON_x5F_KCB">
</g>
</g>
<g id="HEADER_x5F_BAR">
<g id="BUTTON">
</g>
<g id="TOP">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4F0F1;}
.st1{fill:#FFFFFF;}
.st2{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;}
.st3{fill:#1A1A1A;}
.st4{fill:none;stroke:#1A1A1A;stroke-width:3;stroke-miterlimit:10;}
.st5{fill:none;stroke:#1A1A1A;stroke-miterlimit:10;}
.st6{fill:#3EA3D8;}
.st7{display:none;}
.st8{display:inline;}
.st9{fill:#808080;}
.st10{display:inline;fill:#808080;}
.st11{fill:none;stroke:#808080;stroke-miterlimit:10;}
.st12{fill:#7AC943;}
.st13{fill:none;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st14{fill:#FFFFFF;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st15{fill:none;stroke:#3EA3D8;stroke-miterlimit:10;}
.st16{fill:#CCCCCC;}
.st17{fill:none;stroke:#CCCCCC;stroke-linecap:square;stroke-miterlimit:10;}
.st18{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;stroke-dasharray:1.9084,1.9084;}
.st19{fill:none;stroke:#E6E6E6;stroke-miterlimit:10;}
.st20{fill:#666666;}
.st21{fill:none;stroke:#B3B3B3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st22{fill:#B3B3B3;}
.st23{opacity:0.05;}
.st24{clip-path:url(#SVGID_00000145045565268559361070000017782594028069641132_);}
.st25{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st26{opacity:0.4;fill:#3EA3D8;}
.st27{fill:none;stroke:#3EA3D8;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="A3">
<g id="HEADER_x5F_BAR_00000036974300579741410940000000488572858971942531_">
</g>
</g>
<g id="A2">
<g id="HEADER_x5F_BAR_00000019648451390881128220000012673596900810320021_">
</g>
<g id="BUTTON_00000117651906535404305420000016044620869483747487_">
</g>
<g id="USER_x5F_FORM">
</g>
<g id="INTRO">
</g>
<g id="DLPU_x5F_LOGO">
</g>
</g>
<g id="A1">
<g id="NAV_x5F_BAR_00000129914889952932149030000011711506177042644156_">
</g>
<g id="HEADER_x5F_BAR_00000015351907221170818370000001589878730520391302_">
</g>
<g id="FUNC_x5F_LIST">
</g>
<g id="MAIN_x5F_FUNC">
</g>
<g id="USER_x5F_CARD">
<g id="BG" class="st23">
</g>
</g>
</g>
<g id="ICON">
<g>
<path class="st6" d="M80.89,59.07c7.16-4.63,11.49-13.25,9.73-22.74c-1.52-8.17-7.87-14.98-15.9-17.09
c-5.26-1.38-10.26-0.79-14.57,1.09c0.9,1.91,1.62,3.92,2.02,6.05c2.06-0.99,4.34-1.6,6.79-1.6c10,0,17.85,9.35,15.27,19.76
c-0.99,4.01-3.81,7.32-7.28,9.55l1.19-0.77c-0.86,0.56-1.6,1.32-2.12,2.28c-0.52,0.96-0.77,2-0.77,3.01v0.75
c0,1.15,0.31,2.32,0.97,3.36c0.66,1.05,1.57,1.83,2.61,2.32l-0.67-0.32c8.3,3.97,14.1,12.67,15.6,23.09H68.95
c0.26,2.06,0.42,4.16,0.42,6.31h24.27c3.79,0,6.85-3.35,6.28-7.1C97.98,74.34,90.85,63.82,80.89,59.07L80.89,59.07z M80.89,59.07"
/>
<path class="st6" d="M6.35,94.15h68.9c0-19.11-10.42-35.32-24.98-41.47c9.04-5.4,14.5-16.17,11.56-28.01
c-2.2-8.87-9.45-16.03-18.36-18.1c-16.57-3.86-31.29,8.6-31.29,24.52c0,9.21,4.99,17.19,12.37,21.59
C11.83,58.05,2.27,71.13,0.06,87.11C-0.46,90.84,2.58,94.15,6.35,94.15L6.35,94.15z M27.01,58.49l0.25-0.1
c1.11-0.47,2.09-1.25,2.8-2.32c0.71-1.07,1.05-2.29,1.05-3.48v0.26c0-1.06-0.27-2.13-0.83-3.11c-0.56-0.98-1.34-1.76-2.25-2.3
l-0.25-0.14c-5.82-3.47-9.29-9.52-9.29-16.17c0-10.44,8.48-18.92,18.92-18.92s18.92,8.48,18.92,18.92c0,6.65-3.47,12.7-9.29,16.17
l-0.25,0.14c-0.9,0.55-1.7,1.32-2.25,2.3c-0.56,0.98-0.83,2.05-0.83,3.11v-0.27c0,1.19,0.33,2.41,1.05,3.48
c0.71,1.07,1.7,1.85,2.8,2.32l0.25,0.1C58.76,63.1,66.6,74.47,68.49,87.83H6.33C8.23,74.48,16.06,63.11,27.01,58.49L27.01,58.49z
M27.01,58.49"/>
</g>
</g>
<g id="DEFAULT_x5F_AVATOR">
</g>
<g id="COLOR">
</g>
<g id="NAV_x5F_BAR">
<g id="ICON_x5F_SETTING">
</g>
<g id="ICON_x5F_INFO">
</g>
<g id="ICON_x5F_KCB">
</g>
</g>
<g id="HEADER_x5F_BAR">
<g id="BUTTON">
</g>
<g id="TOP">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4F0F1;}
.st1{fill:#FFFFFF;}
.st2{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;}
.st3{fill:#1A1A1A;}
.st4{fill:none;stroke:#1A1A1A;stroke-width:3;stroke-miterlimit:10;}
.st5{fill:none;stroke:#1A1A1A;stroke-miterlimit:10;}
.st6{fill:#3EA3D8;}
.st7{display:none;}
.st8{display:inline;}
.st9{fill:#808080;}
.st10{display:inline;fill:#808080;}
.st11{fill:none;stroke:#808080;stroke-miterlimit:10;}
.st12{fill:#7AC943;}
.st13{fill:none;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st14{fill:#FFFFFF;stroke:#E6E6E6;stroke-width:3;stroke-miterlimit:10;}
.st15{fill:none;stroke:#3EA3D8;stroke-miterlimit:10;}
.st16{fill:#CCCCCC;}
.st17{fill:none;stroke:#CCCCCC;stroke-linecap:square;stroke-miterlimit:10;}
.st18{fill:none;stroke:#CCCCCC;stroke-miterlimit:10;stroke-dasharray:1.9084,1.9084;}
.st19{fill:none;stroke:#E6E6E6;stroke-miterlimit:10;}
.st20{fill:#666666;}
.st21{fill:none;stroke:#B3B3B3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
.st22{fill:#B3B3B3;}
.st23{opacity:0.05;}
.st24{clip-path:url(#SVGID_00000067940495327550631130000006202591132779276672_);}
.st25{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
.st26{opacity:0.4;fill:#3EA3D8;}
.st27{fill:none;stroke:#3EA3D8;stroke-width:11;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="A3">
<g id="HEADER_x5F_BAR_00000036974300579741410940000000488572858971942531_">
</g>
</g>
<g id="A2">
<g id="HEADER_x5F_BAR_00000019648451390881128220000012673596900810320021_">
</g>
<g id="BUTTON_00000117651906535404305420000016044620869483747487_">
</g>
<g id="USER_x5F_FORM">
</g>
<g id="INTRO">
</g>
<g id="DLPU_x5F_LOGO">
</g>
</g>
<g id="A1">
<g id="NAV_x5F_BAR_00000129914889952932149030000011711506177042644156_">
</g>
<g id="HEADER_x5F_BAR_00000015351907221170818370000001589878730520391302_">
</g>
<g id="FUNC_x5F_LIST">
</g>
<g id="MAIN_x5F_FUNC">
</g>
<g id="USER_x5F_CARD">
<g id="BG" class="st23">
</g>
</g>
</g>
<g id="ICON">
<g>
<path class="st6" d="M49.92,0C22.35,0,0,22.35,0,49.92c0,27.57,22.35,49.92,49.92,49.92c27.57,0,49.92-22.35,49.92-49.92
C99.85,22.35,77.49,0,49.92,0L49.92,0z M49.92,8.76c22.74,0,41.16,18.43,41.16,41.16S72.66,91.09,49.92,91.09
S8.76,72.66,8.76,49.92S27.19,8.76,49.92,8.76L49.92,8.76z M49.92,8.76"/>
</g>
</g>
<g id="DEFAULT_x5F_AVATOR">
</g>
<g id="COLOR">
</g>
<g id="NAV_x5F_BAR">
<g id="ICON_x5F_SETTING">
</g>
<g id="ICON_x5F_INFO">
</g>
<g id="ICON_x5F_KCB">
</g>
</g>
<g id="HEADER_x5F_BAR">
<g id="BUTTON">
</g>
<g id="TOP">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

-45
View File
@@ -1,45 +0,0 @@
@import "../../app.scss";
view.mask {
position: fixed;
width: 100%;
height: 100%;
background-color: rgba($color: #000000, $alpha: .2);
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;
}
}
-115
View File
@@ -1,115 +0,0 @@
import { Modular, Manager } from "../../core/Module";
/**
* 蒙版事件
*/
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? = {
/**
* 蒙版的层级
*/
zIndex: 1,
/**
* 蒙版是否显示
*/
isDisplay: false,
/**
* 蒙版是否显示
*/
isShow: false
};
/**
* 当点击时是否自动关闭蒙版
*/
public autoCloseOnClick: boolean = true;
/**
* 消失动画计时器
*/
private disappearTimer?: number;
public override onLoad() {
this.setFunc(this.handleClickMask, "handleClickMask");
this.on("show", this.showMask);
this.on("hide", this.hideMask);
}
/**
* 显示蒙版
*/
private showMask = () => {
this.disappearTimer && clearTimeout(this.disappearTimer);
this.setData({
isShow: true,
isDisplay: true
});
this.emit("change", true);
}
/**
* 隐藏蒙版
*/
private hideMask = () => {
this.setData({
isShow: false
});
this.disappearTimer = setTimeout(() => {
this.setData({
isDisplay: false
});
}, Mask.animateTime);
this.emit("change", false);
}
/**
* 处理蒙版点击事件
*/
private handleClickMask() {
if (this.autoCloseOnClick) this.emit("hide", void 0);
this.emit("click", void 0);
}
}
export { Mask };
export default Mask;
+99
View File
@@ -0,0 +1,99 @@
@import "../app.scss";
view.mask {
position: fixed;
width: 100%;
height: 100%;
background-color: rgba($color: #000000, $alpha: .2);
z-index: 1;
}
view.layer {
position: fixed;
@include container;
height: 100%;
z-index: 2;
justify-content: center;
align-items: center;
}
view.occlude {
position: fixed;
width: 100%;
height: 100%;
z-index: 3;
}
view.mask.block, view.layer.block, view.occlude.block {
display: flex;
}
view.mask.none, view.layer.none, view.occlude.none {
display: none;
}
view.mask.show-fade, view.layer.show-fade, view.occlude.show-fade {
animation: show-fade .1s cubic-bezier(0, 0, 1, 1) both;
opacity: 1;
}
view.mask.hide-fade, view.layer.hide-fade, view.occlude.hide-fade {
animation: hide-fade .1s cubic-bezier(0, 0, 1, 1) both;
opacity: 0;
}
view.mask.show-scale, view.layer.show-scale, view.occlude.show-scale {
animation: show-scale .3s cubic-bezier(.1, .9, .2, 1) both,
show-fade .1s cubic-bezier(0, 0, 1, 1) both;
transform: scale3d(1, 1, 1);
opacity: 1;
}
view.mask.hide-scale, view.layer.hide-scale, view.occlude.hide-scale {
animation: hide-scale .3s cubic-bezier(.1, .9, .2, 1) both,
hide-fade .1s cubic-bezier(0, 0, 1, 1) both;
transform: scale3d(.9, .9, 1);
opacity: 0;
}
@media (prefers-color-scheme: dark) {
view.mask {
background-color: rgba($color: #000000, $alpha: .5);
}
}
@keyframes show-fade{
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes hide-fade{
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes show-scale{
from {
transform: scale3d(1.15, 1.15, 1);
}
to {
transform: scale3d(1, 1, 1);
}
}
@keyframes hide-scale{
from {
transform: scale3d(1, 1, 1);
}
to {
transform: scale3d(.9, .9, 1);
}
}
+309
View File
@@ -0,0 +1,309 @@
import { IAnyData } from "../core/Api";
import { Emitter } from "../core/Emitter";
import { Modular, Manager } from "../core/Module";
/**
* 动画类型
*/
enum AnimateType {
fade = 1,
scale = 2,
none = 3,
}
/**
* 显示层
*/
class DisplayLayer {
/**
* 类名
*/
public get className(): string {
let res = this.isDisplay ? "block" : "none";
switch (this.animateType) {
case AnimateType.fade:
res += " mask";
break;
case AnimateType.scale:
res += " layer";
break;
case AnimateType.none:
res += " occlude";
break;
}
switch (this.animateType) {
case AnimateType.fade:
res += this.isShow ? " show-fade" : " hide-fade";
break;
case AnimateType.scale:
res += this.isShow ? " show-scale" : " hide-scale";
break;
case AnimateType.none:
break;
}
return res;
}
/**
* Layer 使用的 key
*/
public key: string = "";
/**
* 使用的动画类型
*/
public animateType: AnimateType = AnimateType.scale;
/**
* 动画时间
*/
public get animateTime(): number {
switch (this.animateType) {
case AnimateType.fade:
return 100;
case AnimateType.scale:
return 300;
case AnimateType.none:
return -1;
}
};
/**
* 是否显示
*/
public isDisplay: boolean = false;
/**
* 是否显示
*/
public isShow: boolean = false;
/**
* 消失动画计时器
*/
public disappearTimer?: number;
}
/**
* 弹出层事件
*/
type IPopupLayerEvent<L extends string> = {
/**
* 点击蒙版时
*/
clickMask: void
/**
* 显示层
*/
show: L;
/**
* 隐藏层
*/
hide: L;
/**
* 层状态改变
*/
change: Readonly<DisplayLayer>;
}
type commonLayerType = "mask" | "occlude";
/**
* 弹出层
*/
class PopupLayer<
L extends string,
M extends Manager = Manager
> extends Modular<M, {}, IPopupLayerEvent<L | commonLayerType>> {
/**
* 当点击时是否自动关闭蒙版
*/
public autoCloseOnClick: boolean = true;
/**
* 关闭动画执行时是否屏蔽用户点击
*/
public showOccludeWhenHide: boolean = true;
/**
* 显示 Layer 时自动关闭其他层
*/
public hideOtherWhenShow: boolean = true;
/**
* 层列表
*/
private layers: Map<L | commonLayerType, DisplayLayer> = new Map();
/**
* 初始化层
* @param key 初始化关键字
*/
public initLayers(key: L[]) {
for (let i = 0; i < key.length; i++) {
this.render(this.getDisplayLayer(key[i]));
}
}
public onLoad(): void {
this.on("show", this.handleShowLayer);
this.on("hide", this.handleHideLayer);
this.setFunc(this.handleClickMask, "clickMask");
// 添加蒙版层
const maskLayer = this.getDisplayLayer("mask");
maskLayer.animateType = AnimateType.fade;
this.render(maskLayer);
// 添加遮蔽层
const occludeLayer = this.getDisplayLayer("occlude");
occludeLayer.animateType = AnimateType.none;
this.render(occludeLayer);
}
/**
* 渲染 Layers
*/
private render(layer: DisplayLayer) {
this.setData({ [`${ layer.key }$className`]: layer.className });
}
/**
* 获取显示层
*/
private getDisplayLayer<K extends L | commonLayerType>(e: K): DisplayLayer {
let displayLayer = this.layers.get(e);
if (!displayLayer) {
displayLayer = new DisplayLayer();
displayLayer.key = e;
this.layers.set(e, displayLayer);
}
return displayLayer;
}
/**
* 响应蒙版点击事件
*/
private handleClickMask = () => {
if (!this.autoCloseOnClick) return;
// 关闭全部开启的层
this.layers.forEach((layer) => {
if (layer.isShow) (this as Emitter<IAnyData>).emit("hide", layer.key);
});
// 关闭蒙版
(this as Emitter<IAnyData>).emit("hide", "mask");
}
/**
* 响应显示层事件
*/
private handleShowLayer = <K extends L | commonLayerType>(e: K) => {
let displayLayer = this.getDisplayLayer(e);
// 阻止未发生的变化
if (displayLayer.isShow) return;
// 关闭其他层
if (e !== "mask" && e !== "occlude" && this.hideOtherWhenShow) {
this.layers.forEach((layer) => {
if (layer.key === "mask" || layer.key === "occlude") return;
if (layer.isShow) {
(this as Emitter<IAnyData>).emit("hide", layer.key);
}
});
}
// 显示蒙版
if (e !== "mask" && e !== "occlude")
(this as Emitter<IAnyData>).emit("show", "mask");
// 取消消失定时
displayLayer.disappearTimer &&
clearTimeout(displayLayer.disappearTimer);
displayLayer.isShow = true;
displayLayer.isDisplay = true;
this.render(displayLayer);
this.emit("change", displayLayer);
};
/**
* 响应隐藏层事件
*/
private handleHideLayer = <K extends L | commonLayerType>(e: K) => {
let displayLayer = this.getDisplayLayer(e);
// 阻止未发生的变化
if (!displayLayer.isShow) return;
if (displayLayer.animateTime <= 0) {
displayLayer.isShow = false;
displayLayer.isDisplay = false;
this.render(displayLayer);
} else {
displayLayer.isShow = false;
this.render(displayLayer);
// 开启遮蔽
if (this.showOccludeWhenHide) {
(this as Emitter<IAnyData>).emit("show", "occlude");
}
displayLayer.disappearTimer = setTimeout(() => {
displayLayer.isDisplay = false;
this.render(displayLayer);
// 取消 timer
displayLayer.disappearTimer = undefined;
// 检测是否关闭遮蔽
let needOcclude = true;
this.layers.forEach((layer) => {
if (layer === displayLayer) return;
if (layer.disappearTimer) needOcclude = false;
});
// 关闭遮蔽
if (needOcclude && this.showOccludeWhenHide) {
(this as Emitter<IAnyData>).emit("hide", "occlude");
}
}, displayLayer.animateTime);
}
// 关闭蒙版
if (e !== "mask" && e !== "occlude") {
let needMask = true;
this.layers.forEach((layer) => {
if (layer === displayLayer) return;
if (layer.isShow) needMask = false;
});
if (needMask) (this as Emitter<IAnyData>).emit("hide", "mask");
}
this.emit("change", displayLayer);
}
}
export { PopupLayer };
export default PopupLayer;
+4 -2
View File
@@ -1,10 +1,12 @@
@import "./UserCard.scss"; @import "./UserCard.scss";
@import "./MainFunction.scss"; @import "./MainFunction.scss";
@import "./FunctionList.scss"; @import "./FunctionList.scss";
@import "../../modular/Mask/Mask.scss"; @import "./Login.scss";
@import "../../modular/PopupLayer.scss";
view.container{ view.container{
padding-top: 50rpx; padding-top: 20px;
padding-bottom: 20px;
} }
+15 -4
View File
@@ -2,18 +2,29 @@ import { Manager } from "../../core/Module";
import { UserCard } from "./UserCard"; 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 { Login } from "./Login";
import { PopupLayer } from "../../modular/PopupLayer";
(async () => { (async () => {
// 初始化页面 // 初始化页面
const { manager, query } = await Manager.PageAsync(); const { manager, query } = await Manager.PageAsync();
// 添加蒙版 Modular // 添加弹出层 Modular
const mask = manager.addModule(Mask, "mask"); const popupLayer: PopupLayer<"loginLayer"> = manager.addModule(PopupLayer, "mask") as any;
// 初始化弹出层
popupLayer.initLayers(["loginLayer"]);
// 添加 UserCard Modular // 添加 UserCard Modular
manager.addModule(UserCard, "userCard", { mask }); const userCard = manager.addModule(UserCard, "userCard");
// 添加登录模块
const loginLayer = manager.addModule(Login, "loginLayer");
userCard.on("clickChangeTheme", () => {
popupLayer.emit("show", "loginLayer");
});
// 添加 MainFunction Modular // 添加 MainFunction Modular
manager.addModule(MainFunction, "mainFunction"); manager.addModule(MainFunction, "mainFunction");
+79 -3
View File
@@ -1,6 +1,82 @@
<!-- 层遮蔽层 -->
<view class="{{ mask$occlude$className }}" bindtap="mask$clickMask"></view>
<!-- 蒙版 --> <!-- 蒙版 -->
<view class="mask {{ mask$isShow ? 'show' : 'hide' }} {{ mask$isDisplay ? 'block' : 'none' }}" <view class="{{ mask$mask$className }}" bindtap="mask$clickMask"></view>
bindtap="mask$handleClickMask"></view>
<!-- 登录层 -->
<view class="{{ mask$loginLayer$className }}" bindtap="mask$clickMask">
<view class="card login-layer" catchtap>
<!-- 学校logo -->
<view class="school-logo">
<view>
<image src="../../image/account/School_DLPU.png"></image>
</view>
</view>
<view class="line-bg">
<view wx:for="{{ [0, 1, 2, 3, 4] }}" wx:key="item"></view>
</view>
<!-- 学生姓名 -->
<view class="student-name h2">秦浩轩</view>
<!-- 学号 -->
<view class="student-id">1806240113</view>
<!-- 状态 -->
<view class="login-state">
<view class="certified">
<view class="certifi-info">已认证</view>
<image class="text-icon" src="../../image/account/Account_OK.svg"></image>
</view>
</view>
<!-- 学号输入框 -->
<view class="student-info-input">
<view class="input-icon">
<image class="icon" src="../../image/account/Account_UserName.svg"></image>
</view>
<view class="input-view">
<input placeholder="请输入学号"/>
</view>
</view>
<!-- 密码输入框 -->
<view class="student-info-input">
<view class="input-icon">
<image class="icon" src="../../image/account/Account_PasswordHidden.svg"></image>
</view>
<view class="input-view">
<input placeholder="请输入密码"/>
</view>
</view>
<view style="height: 30px"/>
<!-- 提示语 -->
<view class="tip-info last-active">
<image src="../../image/account/Account_Info.svg"></image>
<view>账号最后活动时间: 2022.1.25-8.20</view>
</view>
<view class="tip-info agree-lic">
<image src="../../image/account/Account_Complete.svg"></image>
<view>同意<text>《用户协议》</text>和<text>《隐私政策》</text></view>
</view>
<view class="tip-info helper-link">
<image src="../../image/account/Account_Question.svg"></image>
<view>遇到问题了戳这里-><text>常见问题</text></view>
</view>
<!-- 登录按钮 -->
<view class="button save-button">
保存并验证
</view>
</view>
</view>
<!-- 顶部的阴影 --> <!-- 顶部的阴影 -->
<view class="top-shadow"></view> <view class="top-shadow"></view>
@@ -49,7 +125,7 @@
<!--每个功能的容器--> <!--每个功能的容器-->
<view class="branch-funtion" wx:for="{{ mainFunction$mainFunctionList }}" wx:key="index"> <view class="branch-funtion" wx:for="{{ mainFunction$mainFunctionList }}" wx:key="index">
<view style="{{ index == (mainFunction$mainFunctionList - 1) ? 'border-bottom: 0px' : '' }}"> <view style="{{ index == (mainFunction$mainFunctionList.length - 1) ? 'border-right: 0px' : '' }}">
<!--每个功能的图片--> <!--每个功能的图片-->
<image class="icon" src="../../image/account/Account_{{ item.iconUrl }}.svg"></image> <image class="icon" src="../../image/account/Account_{{ item.iconUrl }}.svg"></image>
<!--每个功能的文字--> <!--每个功能的文字-->
+1 -2
View File
@@ -1,8 +1,7 @@
@import "../../app.scss"; @import "../../app.scss";
view.function-list { view.function-list {
margin-top: 50rpx; margin-top: 20px;
margin-bottom: 50rpx;
padding: 0 0 !important; padding: 0 0 !important;
width: 100% !important; width: 100% !important;
+170
View File
@@ -0,0 +1,170 @@
@import "../../app.scss";
$logo-height: 100px;
view.login-layer {
view.school-logo {
height: 0;
padding-top: 25px;
width: 100%;
text-align: center;
view {
z-index: 2;
display: inline-block;
position: relative;
border-radius: 1000px;
background-color: $theme-color-light-layout;
width: $logo-height;
height: $logo-height;
image {
width: 100%;
height: 100%;
}
}
}
view.line-bg {
display: flex;
box-sizing: border-box;
padding: 35px 0;
height: $logo-height;
width: calc( 100% + 40px );
position: relative;
left: -20px;
flex-direction: column;
justify-content: space-around;
view {
height: 0;
width: 100%;
opacity: .5;
border-top: 2px solid $theme-color-light-line;
}
}
view.student-name {
margin: 10px 0 1px 0;
text-align: center;
}
view.student-id {
margin-bottom: 1px;
text-align: center;
}
view.login-state {
width: 100%;
margin-bottom: 20px;
text-align: center;
view.certified {
color: $theme-color-blue;
border: 1px solid $theme-color-blue;
border-radius: 4px;
margin-left: .3em;
font-size: .85em;
height: 1.2em;
padding: 0 2px;
display: inline-flex;
justify-content: center;
align-items: center;
image.text-icon {
margin-left: .25em;
width: 10px;
height: 10px;
}
}
}
view.student-info-input {
display: flex;
justify-content: center;
padding: 8px 0;
view.input-icon {
box-sizing: border-box;
padding: 3px 12px 3px 0;
flex-shrink: 0;
width: 38px;
height: 32px;
image {
width: 100%;
height: 100%;
}
}
view.input-view {
position: relative;
bottom: 3px;
box-sizing: border-box;
border-bottom: 1.5px solid $theme-color-light-line;
flex-grow: 1;
width: 100%;
height: 32px;
input {
width: 100%;
height: 100%;
}
}
}
view.tip-info {
width: 100%;
vertical-align: middle;
padding: 1px 0;
font-size: .9em;
image {
vertical-align: middle;
width: 16px;
height: 16px;
margin-right: 5px;
}
view {
vertical-align: middle;
display: inline;
text {
color: $theme-color-blue;
text-decoration: underline;
}
}
}
view.agree-lic image {
filter: $green-filter;
}
view.save-button {
margin: 15px 0 25px 0;
}
}
@media (prefers-color-scheme: dark) {
view.login-layer {
view.school-logo view {
background-color: $theme-color-dark-layout;
image {
filter: $white-filter;
}
}
view.line-bg view {
border-top: 2px solid $theme-color-dark-line;
}
view.student-info-input view.input-view {
border-bottom: 1.5px solid $theme-color-dark-line;
}
}
}
+15
View File
@@ -0,0 +1,15 @@
import { Modular, Manager } from "../../core/Module";
type ILoginEvent = {
}
class Login<M extends Manager> extends Modular<M, {}> {
public override onLoad() {
}
}
export { Login };
export default Login;
+1 -1
View File
@@ -3,7 +3,7 @@
//主要功能 //主要功能
view.main-function { view.main-function {
display: flex; display: flex;
margin-top: 50rpx; margin-top: 20px;
padding: 0 !important; padding: 0 !important;
width: 100% !important; width: 100% !important;
+3 -9
View File
@@ -1,9 +1,4 @@
import { Modular, Manager } from "../../core/Module"; import { Modular, Manager } from "../../core/Module";
import { Mask } from "../../modular/Mask/Mask";
type IUserCardDependent<M extends Manager> = {
mask: Mask<M>
}
type IUserCardEvent = { type IUserCardEvent = {
@@ -13,18 +8,17 @@ type IUserCardEvent = {
clickChangeTheme: void; clickChangeTheme: void;
} }
class UserCard<M extends Manager> extends Modular<M, IUserCardDependent<M>, IUserCardEvent> { class UserCard<M extends Manager> extends Modular<M, {}, IUserCardEvent> {
public override onLoad() { public override onLoad() {
this.setFunc(this.handleChangeTheme, "changeTheme") this.setFunc(this.handleChangeTheme, "changeTheme");
} }
/** /**
* 处理主题更换 * 处理主题更换
*/ */
private handleChangeTheme() { private handleChangeTheme() {
this.depends?.mask.emit("show", void 0); this.emit("clickChangeTheme");
this.emit("clickChangeTheme", void 0);
} }
} }
+11 -7
View File
@@ -1,7 +1,8 @@
{ {
"description": "项目配置文件", "description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"packOptions": { "packOptions": {
"ignore": [] "ignore": [],
"include": []
}, },
"miniprogramRoot": "miniprogram/", "miniprogramRoot": "miniprogram/",
"compileType": "miniprogram", "compileType": "miniprogram",
@@ -46,13 +47,16 @@
"useCompilerPlugins": [ "useCompilerPlugins": [
"typescript", "typescript",
"sass" "sass"
] ],
"useStaticServer": true
}, },
"simulatorType": "wechat", "simulatorType": "wechat",
"simulatorPluginLibVersion": {}, "simulatorPluginLibVersion": {},
"appid": "wx7d809f5e8955843d", "appid": "wx7d809f5e8955843d",
"scripts": { "condition": {},
"beforeCompile": "" "srcMiniprogramRoot": "miniprogram/",
}, "editorSetting": {
"condition": {} "tabIndent": "insertSpaces",
"tabSize": 2
}
} }
+6 -10
View File
@@ -1,14 +1,5 @@
{ {
"condition": { "condition": {
"plugin": {
"list": []
},
"game": {
"list": []
},
"gamePlugin": {
"list": []
},
"miniprogram": { "miniprogram": {
"list": [ "list": [
{ {
@@ -19,5 +10,10 @@
} }
] ]
} }
} },
"projectname": "mini-dlpu-v3",
"setting": {
"compileHotReLoad": true
},
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html"
} }