diff --git a/miniprogram/app.ts b/miniprogram/app.ts index 41a361e..b7d0c2c 100644 --- a/miniprogram/app.ts +++ b/miniprogram/app.ts @@ -1,4 +1,7 @@ -// app.ts +import {Logger} from "./utils/Logger"; +import * as label from "./utils/LogLabel"; + + App({ /** @@ -10,5 +13,15 @@ App({ * 小程序加载时 */ onLaunch() { - }, + + Logger.log("hh", + label.FatalLabel,label.ErrorLabel,label.WarnLabel, + label.InfoLabel,label.DebugLabel,label.TraceLabel + ); + + Logger.logM( + [label.FatalLabel,label.ErrorLabel,label.WarnLabel, + label.InfoLabel,label.DebugLabel,label.TraceLabel], "hh" + ); + } }) \ No newline at end of file diff --git a/miniprogram/pages/Timetable/Timetable.wxss b/miniprogram/pages/Timetable/Timetable.scss similarity index 100% rename from miniprogram/pages/Timetable/Timetable.wxss rename to miniprogram/pages/Timetable/Timetable.scss diff --git a/miniprogram/utils/Config.ts b/miniprogram/utils/Config.ts new file mode 100644 index 0000000..823c874 --- /dev/null +++ b/miniprogram/utils/Config.ts @@ -0,0 +1,31 @@ +// APP 全局配置文件 + +/** + * 是否在控制台输出调试信息 + * 生产模式下一定要关闭此选项 + * + * 注意: + * 1、Release 时必须置为 false + * 2、调试模式将造成性能损失 + */ +export const LOGGER_CONSOLE:boolean = true; + +/** + * 调试过滤器 + * 按照 LogLabel 进行过滤 + * + * 注意: + * 1、行与行是之间是 || 关系 + * 2、每行的元素之间是 && 关系 + * 3、支持正则表达式 + * 4、字符串使用 === 严格匹配 + * 5、尽量将范围大的 Filter 写在前面以提高性能 + */ +export const LOGGER_FILTER:Array[] = [ + + // 调试输出全部内容 + [/.*/], + + // 输出警告和错误 + // ["WARN", "ERROR", "FATAL"], +]; diff --git a/miniprogram/utils/LogLabel.ts b/miniprogram/utils/LogLabel.ts new file mode 100644 index 0000000..d4d8b51 --- /dev/null +++ b/miniprogram/utils/LogLabel.ts @@ -0,0 +1,43 @@ +import {LogLabel, LogStyle} from "./Logger"; + +// 成功 +export const SuccessLabel = new LogLabel( + "SUCCESS", new LogStyle().setColor("#FFFFFF", "#EE113D").setBorder("5px") +); + +// 失败 +export const FailedLabel = new LogLabel( + "SUCCESS", new LogStyle().setColor("#FFFFFF", "#33ff66").setBorder("3px") +); + + + +// 致命 +export const FatalLabel = new LogLabel( + "FATAL", new LogStyle().setColor("#FFFFFF", "#FF00CC").setBorder("3px") +); + +// 错误 +export const ErrorLabel = new LogLabel( + "ERROR", new LogStyle().setColor("#FFFFFF", "#FF0000").setBorder("3px") +); + +// 警告 +export const WarnLabel = new LogLabel( + "WARN", new LogStyle().setColor("#FFFFFF", "#FF9900").setBorder("3px") +); + +// 消息 +export const InfoLabel = new LogLabel( + "INFO", new LogStyle().setColor("#FFFFFF", "#99FF00").setBorder("3px") +); + +// 调试 +export const DebugLabel = new LogLabel( + "DEBUG", new LogStyle().setColor("#FFFFFF", "#00FF99").setBorder("3px") +); + +// 追踪 +export const TraceLabel = new LogLabel( + "TRACE", new LogStyle().setColor("#FFFFFF", "#00CCFF").setBorder("3px") +); \ No newline at end of file diff --git a/miniprogram/utils/Logger.ts b/miniprogram/utils/Logger.ts new file mode 100644 index 0000000..ded1b76 --- /dev/null +++ b/miniprogram/utils/Logger.ts @@ -0,0 +1,391 @@ +import {LOGGER_CONSOLE, LOGGER_FILTER} from "./Config"; + +/** + * 调试输出样式 + */ +class LogStyle { + + /** + * 日志文字颜色 + */ + private color:string | undefined; + + /** + * 日志背景颜色 + */ + private backgroundColor:string | undefined; + + /** + * 日志文字粗细 + */ + private weight:string | undefined; + + /** + * 日志文字大小 + */ + private size:string | undefined; + + /** + * 日志文字字体 + */ + private family:string | undefined; + + /** + * 日志文字圆角 + */ + private borderRadius:string | undefined; + + /** + * 日志文字边框 + */ + private border:string | undefined; + + /** + * 设置颜色 + * @param color 日志文字颜色 + * @param backgroundColor 日志背景颜色 + */ + public setColor(color:string, backgroundColor?:string):LogStyle { + this.color = color; + this.backgroundColor = backgroundColor; + return this; + } + + /** + * 设置边框 + * @param borderRadius 日志文字圆角 + * @param border 日志文字边框 + */ + public setBorder(borderRadius:string, border?:string):LogStyle { + this.borderRadius = borderRadius; + this.border = border; + return this; + } + + /** + * 设置文字 + * @param weight 日志文字粗细 + * @param family 日志文字字体 + */ + public setFont(weight:string, family:string):LogStyle { + this.weight = weight; + this.family = family; + return this; + } + + /** + * 设置文字大小 + * @param size 日志文字大小 + */ + public setSize(size:string):LogStyle { + this.size = size; + return this; + } + + /** + * 字符化转义样式 + */ + public stringify():string { + let stringArr:string[] = []; + + this.color && stringArr.push(`color:${ this.color }`); + this.backgroundColor && stringArr.push(`background-color:${ this.backgroundColor }`); + this.weight && stringArr.push(`font-weight:${ this.weight }`); + this.family && stringArr.push(`font-family:${ this.family }`); + this.borderRadius && stringArr.push(`border-radius:${ this.borderRadius }`); + this.border && stringArr.push(`border:${ this.border }`); + this.size && stringArr.push(`font-size:${ this.size }`); + + stringArr.push(`margin-bottom:5px`); + + return stringArr.join(";"); + } +} + +/** + * 日志标签 + */ +class LogLabel { + + /** + * 关键字 + * 用于标识这个类别 + */ + public key:string; + + /** + * 文字样式 + */ + public style:LogStyle; + + /** + * @param key 关键字 + * @param style 文字样式 + */ + constructor(key:string, style:LogStyle) { + this.key = key; + this.style = style; + } + + /** + * 获得 Logger 输出使用的内容 + */ + public getLoggerOutput():string { + return `%c ${ this.key } `; + } + + /** + * 获得 Text 输出内容 + */ + public getTextOutput():string { + return `[${ this.key }]`; + } + + /** + * 获得 style 格式化 + */ + public getStyleOutput():string { + return this.style.stringify(); + } +} + +/** + * 栈信息 + */ +class StackInfo { + + /** + * 函数名 + */ + public functionName:string | undefined; + + /** + * 文件名 + */ + public fileName:string | undefined; + + /** + * 文件路径 + */ + public url:string | undefined; + + public setInfo(functionName:string, fileName:string, url:string):StackInfo { + this.functionName = functionName; + this.fileName = fileName; + this.url = url; + return this; + } + + /** + * 获取函数调用栈列表 + */ + static getCallStack():StackInfo[] { + + // 获取堆栈信息 + let stack:string | undefined = new Error().stack; + + if (stack === void 0) return []; + + // 去除 Error + stack = stack.replace(/^(Error)\s/, ""); + + // 获取堆栈信息 + let stackList:string[] = stack.split(/\n/); + + let callStack:StackInfo[] = []; + + for(let i = 0; i < stackList.length; i++) { + + let matcher = stackList[i].match(/^\s+at\s+(.+)\s(\(.+\))/); + if (matcher === null || matcher.length < 3) continue; + + let fileName = matcher[2].match(/.+\/(.+\..+:\d+:\d+)\)/); + if (fileName === null || matcher.length < 2) continue; + + callStack.push(new StackInfo().setInfo( + matcher[1], fileName[1], matcher[2] + )) + } + + return callStack; + } + + /** + * 排除的 + */ + static readonly excludeFile:RegExp = /^Logger\.js:\d+:\d+/; + + /** + * 获取第一个调用栈 + */ + static getFirstStack():StackInfo | undefined { + + let callStack = this.getCallStack(); + + for(let i = 0; i < callStack.length; i++) { + + if(!callStack[i].fileName) continue; + + if(!StackInfo.excludeFile.test(callStack[i].fileName ?? "")) { + return callStack[i]; + } + } + + return; + } +} + +/** + * 多重内容捆绑 + * 用于 log 输出 + */ +class MultipleLogContent { + + /** + * 输出内容 + */ + private content:any[]; + + /** + * @param content 输出内容 + */ + public constructor(...content:any[]) { + this.content = content; + } + + /** + * 获取内容 + */ + public getContent():any[] { + return this.content; + } +} + +/** + * 格式化日志输出 + */ +class Logger { + + /** + * 堆栈路径样式 + */ + static readonly pathStyle:LogStyle = new LogStyle().setColor("#CCCCCC"); + + /** + * 标签过滤 + */ + static filterLog(filter:Array, labels:LogLabel[]):boolean { + + let passNum:number = 0; + + for(let i = 0; i < filter.length; i++) { + + let pass:boolean = false; + for(let j = 0; j < labels.length; j++) { + + if(filter[i] instanceof RegExp) { + pass = (filter[i] as RegExp).test(labels[j].key) + } else { + pass = (filter[i] as String) === labels[j].key; + } + + if(pass) break; + } + + if(pass) passNum ++; + } + + return passNum === filter.length; + } + + /** + * 检测是否应该输出 + * @param labels 使用标签 + */ + static testLog(...labels:LogLabel[]):boolean { + + if(!LOGGER_CONSOLE) return false; + + let isLogging = false; + for(let i = 0; i < LOGGER_FILTER.length; i++) { + + // 判断是否进行输出 + isLogging = Logger.filterLog(LOGGER_FILTER[i], labels); + + if(isLogging) break; + } + + return isLogging; + } + + /** + * + * @param styledLabel calcStyle的处理结果 + */ + static addFileNameLabel():LogLabel { + + // 获得调用堆栈 + let stack = StackInfo.getFirstStack(); + + return new LogLabel(stack?.fileName ?? "", Logger.pathStyle); + } + + /** + * 收集计算样式 + * @param labels 使用标签 + */ + static calcStyle(...labels:LogLabel[]):[string[], string[]] { + + let consoleLabels:string[] = []; + let consoleStyles:string[] = []; + + // 放置标签 + for(let i = 0; i < labels.length; i++) { + consoleLabels.push(labels[i].getLoggerOutput()); + + if (i !== ( labels.length - 1)) + consoleLabels.push("%c "); + + consoleStyles.push(labels[i].getStyleOutput()); + + if (i !== ( labels.length - 1)) + consoleStyles.push(""); + } + + return [consoleLabels, consoleStyles]; + } + + /** + * 调试输出 + * @param content 输出内容 + * @param label 使用标签 + */ + static log(content:T, ...labels:LogLabel[]):T { + + let fileNameLabel = Logger.addFileNameLabel(); + + if(!Logger.testLog(...labels, fileNameLabel)) return content; + + let styledLabel = Logger.calcStyle(...labels); + + console.log( + styledLabel[0].join("") + fileNameLabel.getLoggerOutput(), + ...[...styledLabel[1], fileNameLabel.getStyleOutput()], + content + ); + + return content; + } + + /** + * 多重调试输出 + * @param labels 输出内容 + * @param content 使用标签 + */ + static logM(labels:LogLabel[], ...content:T[]):T[] { + return Logger.log(content, ...labels); + } +} + +export default Logger; +export {Logger, LogStyle, LogLabel} \ No newline at end of file diff --git a/project.config.json b/project.config.json index ad2e2d8..b4b9816 100644 --- a/project.config.json +++ b/project.config.json @@ -17,7 +17,7 @@ "newFeature": false, "coverView": true, "nodeModules": false, - "autoAudits": true, + "autoAudits": false, "showShadowRootInWxmlPanel": true, "scopeDataCheck": false, "uglifyFileName": true,