Angular BaseView抽离页面公用属性

前言

如果有一系列的页面布局很类似,为了节省时间,我们可以把这些类似的页面所通用的属性和方法抽离成一个BaseView,让其它页面继承该基础页面,同时将一些经常改变的属性和差异的属性写到配置文件里。例如树容器初始时是否展开、某些图表是否显示等都可以写到配置文件里面。本文将带你实现该功能,抽离出BaseView页面组件,鉴于json文件无法写注释的情况,配置文件采取yml的格式

页面设计

在这里插入图片描述

组件抽离

BaseViewComponent

import { Injectable, OnDestroy, OnInit } from "@angular/core";import { ConfigService } from "@app/core/config/config.service";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { deepMergeKey } from "../utils";
import { HandlebarCalendarModelType } from "./baseView.type";
import { TimeRange } from "topdsm-lib/core/util"import dayjs from 'dayjs';
var customParseFormat = require('dayjs/plugin/advancedFormat')@Injectable()
export class BaseViewComponent implements OnInit, OnDestroy {/** 页面通用属性 */pageNum = 1pageSize = 10tableData = []tableTotal = 0public unsubscribe$ = new Subject<void>();/** 原始config */public originalConfig: Record<string, any> = null/** 页面config */public config: Record<string, any> = {leftPanelExpand: true,handlebarCalendarModel: [],query: {}}constructor(public viewKey: string, // 页面唯一keypublic configService: ConfigService // 用来读取json配置文件) {console.log("BaseViewComponent constructor");}ngOnInit(): void {console.log();this.configService.change.pipe(takeUntil(this.unsubscribe$)).subscribe(async (config) => {console.log(config);if (config) {this.originalConfig = configif (this['configServiceReaderBefore']) {await this['configServiceReaderBefore'](config)}this.handleConfig()if (this['configServiceReaderAfter']) {await this['configServiceReaderAfter'](config)}}});}ngOnDestroy(): void {const { unsubscribe$ } = this;unsubscribe$.next();unsubscribe$.complete();}handleConfig() {deepMergeKey(this.config, true, this.originalConfig.global, this.originalConfig?.modules?.[this.viewKey])this.handleCalendarTime()this.handleBarBtn()console.log(this.config);}/*** handlebar 日历组件初始值处理,* 获取开始时间和结束时间,该逻辑可以根据自己的业务场景自定义*/handleCalendarTime() {let tg = {start: "",end: ""}switch (this.config.handlebarCalendarModelType) {case HandlebarCalendarModelType.CUSTOM:if (this.config.handlebarCalendarModel.length === 1) {tg.start = this.config.handlebarCalendarModel[0]tg.end = dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss").substring(0, 10) + " 23:59:59"} else if (this.config.handlebarCalendarModel.length === 2) {tg.start = this.config.handlebarCalendarModel[0]tg.end = this.config.handlebarCalendarModel[1]}break;case HandlebarCalendarModelType.LASTYEAY: // 上一年tg = TimeRange.getLastYearRange()break;case HandlebarCalendarModelType.LASTQUATER: // 上一季度tg = TimeRange.getLastQuarterRange()break;case HandlebarCalendarModelType.LASTMONTH: // 上一月tg = TimeRange.getLastMonthRange()break;case HandlebarCalendarModelType.LAST7DAY: // 近7天tg = {start: TimeRange.getLast7dayRange().start,end: dayjs(new Date()).format("YYYY-MM-DD HH:mm:ss").substring(0, 10) + " 23:59:59"}break;case HandlebarCalendarModelType.MONTH: // 本月tg = TimeRange.getMonthRange()break;case HandlebarCalendarModelType.QUATER: // 本年度tg = TimeRange.getQuarterRange()break;case HandlebarCalendarModelType.YEAR: // 本年度tg = TimeRange.getYearRange()break;default:break;}if (tg.start !== "" && tg.end !== "") {tg.start = tg.start.substring(0, 10) + " 00:00:00"tg.end = tg.end.substring(0, 10) + " 23:59:59"}this.config.query.startTimeStr = tg.startthis.config.query.endTimeStr = tg.endif (tg.start !== "" && tg.end !== "") {this.config.handlebarCalendarModel = [dayjs(this.config.query.startTimeStr, "YYYY-MM-DD HH:mm:ss").toDate(),dayjs(this.config.query.endTimeStr, "YYYY-MM-DD HH:mm:ss").toDate(),]} else {this.config.handlebarCalendarModel = []}}handleBarBtn() {let btnSelected = {}this.config.handlebarRightBtn = this.config.handlebarRightBtn.filter(item => item.show)this.config.handlebarRightBtn.forEach(item => {btnSelected[item.key] = item.selected})this.config.handlebarRightBtnSelected = btnSelected}
}

时间段枚举

export enum HandlebarCalendarModelType {/** 自定义 */CUSTOM = "0",/** 上一年 */LASTYEAY = "1",/** 上一季度 */LASTQUATER = "2",/** 上一月 */LASTMONTH = "3",/** 上一周 */LASTWEEK = "4",/** 本周 */WEEK = "5",/** 本月 */MONTH = "6",/** 本季度 */QUATER = "7",/** 本年度 */YEAR = "8",/** 近7天 */LAST7DAY = "9"
}

属性合并的函数


/*** Deep merge object.** 深度合并对象** @param original 原始对象* @param arrayProcessMethod 数组处理方式*  - `true` 表示替换新值,不管新值为哪种类型*  - `false` 表示会合并整个数组(将旧数据与新数据合并成新数组)* @param objects 要合并的对象*/export function deepMergeKey(original: unknown, arrayProcessMethod: boolean, ...objects: NzSafeAny[]): NzSafeAny {if (Array.isArray(original) || typeof original !== 'object') return original;const isObject = (v: unknown): boolean => typeof v === 'object';const merge = (target: NzSafeAny, obj: NzSafeAny): NzSafeAny => {Object.keys(obj).filter(key => key !== '__proto__' && Object.prototype.hasOwnProperty.call(obj, key)).forEach(key => {const fromValue = obj[key];const toValue = target[key];if (Array.isArray(toValue)) {target[key] = arrayProcessMethod ? fromValue : [...toValue, ...fromValue];} else if (typeof fromValue === 'function') {target[key] = fromValue;} else if (fromValue != null && isObject(fromValue) && toValue != null && isObject(toValue)) {target[key] = merge(toValue, fromValue);} else {target[key] = deepCopy(fromValue);}});return target;};objects.filter(v => v != null && isObject(v)).forEach(v => merge(original, v));return original;
}

ConfigService

读取yml配置文件

import { Injectable } from "@angular/core";
import { environment } from "@env/environment";
import { BehaviorSubject, Observable } from "rxjs";
import yaml from "js-yaml"
import axios from "axios"
@Injectable({providedIn: 'root'
})
export class ConfigService {private change$ = new BehaviorSubject(null);constructor() {this.getGlobalConfig()}get change(): Observable<any> {return this.change$.asObservable();}getGlobalConfig() {return new Promise((resolve, reject) => {let url = "/assets/config.yml"if(environment.production){url = environment.assetBaseUrl + "/assets/config.yml"}axios.get(url).then(res => {const config = yaml.load(res.data)this.change$.next(config);             }).catch(err => {reject(err)})})}
}

config.yml

global: handlebarCalendarModelType: "0"handlebarCalendarModel: - "2023-01-01 00:00:00"leftPanelWidth: "200px" # 左侧树容器宽度leftPanelExpand: true   # 左侧容器初始是否展开 true: 展开  false: 收起handlebarRight: true # 是否展示 handlebar右侧的操作按钮handlebarRightBtn: # hanlebar右侧操作按钮 控制图标统计区域的显示与否- selected: true      # 是否选中show: true          # 是否显示label: "总量统计"icon: "icon-proxy"key: "cardNumStatis" # 每个按钮都应该有唯一的key- selected: trueshow: truelabel: "对比统计"icon: "icon-pie1"key: "pieAndBar"- selected: trueshow: falselabel: "趋势统计"icon: "icon-pie1"key: "lineTrend"barStyleConfig:grid: bottom: 30xAxis:axisLabel: width: 80modules: demoPage: leftPanelExpand: truebarStyleConfig:grid: bottom: 45xAxis:axisLabel:overflow: "truncate" # 截断rotate: 330  # 旋转度数

demo

demo-component.ts

import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
import { ActivatedRoute, NavigationEnd, Router, RouterEvent } from "@angular/router";
import { BaseViewComponent } from "@app/core/config/base-view.component";
import { ConfigService } from "@app/core/config/config.service";
import { DEMOPAGE } from "@app/core/config/view-key";
import { removeNullProperty } from "@app/core/utils";
import { AccountAssetService } from "@app/services/data-asset-management/account-asset/account-asset.service";
import { format } from "date-fns";@Component({selector: 'app-demo',templateUrl: './demo.component.html',styleUrls: ['./demo.component.less']
})
export class DemoComponent extends BaseViewComponent {q = {}constructor(private router: Router,public activatedRoute: ActivatedRoute,public configService: ConfigService,private apiService: AccountAssetService,) {super(DEMOPAGE, configService)console.log("DemoComponent constructor");}ngOnInit(): void {console.log("DemoComponent ngOnInit");super.ngOnInit()}ngOnDestroy(): void {console.log("DemoComponent ngOnDestroy");super.ngOnDestroy()}configServiceReaderAfter(config) {console.log("configServiceReaderAfter...");return new Promise(async (resolve, reject) => {this.refsh()resolve(null)})}async refsh() {//await this.getAccountTypeTreeL1()if (this.config.handlebarRight) {this.getPieChart1Data()this.getPieChart2Data()this.getBarChartData()this.getAccountCard()}this.getData()}getAccountCard() {}getPieChart1Data() {}getPieChart2Data() {}getBarChartData() {}getData() {let params: { [key: string]: any } = {...this.q,pageNum: this.pageNum,pageSize: this.pageSize,}if (this.config.handlebarRight) {params.startTimeStr = this.config.query.startTimeStrparams.endTimeStr = this.config.query.endTimeStr}this.apiService.getAccountListByPageApi(removeNullProperty(params)).then((res: resType) => {if (res.resultStat == "0") {this.tableData = res.data.listthis.tableTotal = res.data.total}})}/** handlebar 操作栏 */handleChange(e: any) {console.log(e);if(e.type === "button"){this.config.handlebarRightBtnSelected[e.data.key] = e.data.selected}else if(e.type === "calendar"){if(e.data.length === 2){this.config.query = {startTimeStr: format(e.data[0], 'yyyy-MM-dd HH:mm:ss').substring(0,10)+ " 00:00:00",endTimeStr: format(e.data[1], 'yyyy-MM-dd HH:mm:ss').substring(0,10)+ " 23:59:59",}}else{this.config.query = {startTimeStr: "",endTimeStr: ""}}this.refsh()}}}

合并后的配置对象config

{"leftPanelExpand": true,"handlebarCalendarModel": ["2022-12-31T16:00:00.000Z","2024-02-04T15:59:59.000Z"],"query": {"startTimeStr": "2023-01-01 00:00:00","endTimeStr": "2024-02-04 23:59:59"},"handlebarCalendarModelType": "0","leftPanelWidth": "200px","handlebarRight": true,"handlebarRightBtn": [{"selected": true,"show": true,"label": "总量统计","icon": "icon-proxy","key": "cardNumStatis"},{"selected": true,"show": true,"label": "对比统计","icon": "icon-pie1","key": "pieAndBar"}],"barStyleConfig": {"grid": {"bottom": 45},"xAxis": {"axisLabel": {"width": 80,"overflow": "truncate","rotate": 330}}},"handlebarRightBtnSelected": {"cardNumStatis": true,"pieAndBar": true}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/452983.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

问题:下列哪些属于历史文化资源的特征( ). #学习方法#学习方法

问题&#xff1a;下列哪些属于历史文化资源的特征( ). A、稀缺性 B、脆弱性 C、可再生性 D、多样性 参考答案如图所示

C语言KR圣经笔记 7.1标准输入和输出 7.2格式化输出-printf

第七章 输入和输出 输入和输出功能并不是 C 语言本身的一部分&#xff0c;故到目前为止&#xff0c;本书都没有对其着重说明。然而&#xff0c;程序与其环境之间交互的方式&#xff0c;比书中之前所展示的更为复杂。本章我们会详描述标准库&#xff0c;即一系列为 C 程序提供输…

Stable Diffusion 模型下载:国风3 GuoFeng3

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十推荐提示词下载地址模型介绍 欢迎使用GuoFeng3模型 - 这是一个中国华丽古风风格模型,也可以说是一个古风游戏角色模型,具有2.5D的质感。 条目内

数字人客服技术预研

技术洞察 引言 在当今数字化时代&#xff0c;不断进步和创新的人工智能&#xff08;AI&#xff09;技术已经渗透到各行各业中。随着AI技术、大模型技术逐步发展&#xff0c;使得数字人的广泛应用成为可能&#xff0c;本文将跟大家一起探讨AI数字人客服的概念、优势、应用场景…

【Java八股文面试系列】JVM-内存区域

目录 Java内存区域 运行时数据区域 线程独享区域 程序计数器 Java 虚拟机栈 StackFlowError&OOM 本地方法栈 线程共享区域 堆 GCR-分代回收算法 字符串常量池 方法区 运行时常量池 HotSpot 虚拟机对象探秘 对象的创建 对象的内存布局 句柄 Java内存区域 运…

使用WPS制作三线表

点击边框和底纹点击1、2、3、4并且应用于表格点击确定 再次选中表格点击右键表格属性选择边框和底纹 选中表格第一行右键点击表格属性选择边框和底纹 如果表格中存在虚线

左旋字符串的三种方法,并判断一个字符串是否为另外一个字符串旋转之后的字符串。(strcpy,strncat,strcmp,strstr函数的介绍)

一. 实现一个函数&#xff0c;可以左旋字符串中的k个字符。 例如&#xff1a; ABCD左旋一个字符得到BCDA ABCD左旋两个字符得到CDAB 通过分析&#xff0c;可以知道实际的旋转次数&#xff0c;其实是k%&#xff08;字符串长度&#xff09;。假设一个字…

Unity_修改天空球

Unity_修改天空球 Unity循序渐进的深入会发现可以改变的其实很多&#xff0c;剖开代码逻辑&#xff0c;可视化的表现对于吸引客户的眼球是很重要的。尤其对于知之甚少的客户&#xff0c;代码一般很难说服客户&#xff0c;然表现确很容易。 非代码色彩通才&#xff0c;持续学习…

PyTorch 2.2 中文官方教程(十七)

&#xff08;Beta&#xff09;使用缩放点积注意力&#xff08;SDPA&#xff09;实现高性能 Transformer 原文&#xff1a;pytorch.org/tutorials/intermediate/scaled_dot_product_attention_tutorial.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 注意 点击这…

《动手学深度学习(PyTorch版)》笔记7.2

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…

前端面试题——Vue的双向绑定

前言 双向绑定机制是Vue中最重要的机制之一&#xff0c;甚至可以说是Vue框架的根基&#xff0c;它将数据与视图模板相分离&#xff0c;使得数据处理和页面渲染更为高效&#xff0c;同时它也是前端面试题中的常客&#xff0c;接下来让我们来了解什么是双向绑定以及其实现原理。…

笔记本电脑的WIFI模块,突然不显示了,网络也连接不上

问题复现&#xff1a; 早上&#xff0c;在更新完笔记本电脑的系统之后&#xff0c;连网之后&#xff0c;网络突然直接断开&#xff0c;一查看&#xff0c;WiFi模块居然不见了&#xff0c;开机重启也是如此&#xff0c;这种情况常常出现在更新系统之后&#xff0c;WiFi模块驱动就…