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.mzph.cn/news/668435.shtml

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

相关文章

什么是前端工程化,请举例说明

前端工程化 前端工程化的定义为什么需要前端工程化前端工程化的核心概念 模块化开发&#xff1a;组件化开发&#xff1a;规范化开发&#xff1a;自动化开发&#xff1a;持续集成 前端工程化的主要工具前端工程化的应用总结&#xff1a; 前端工程化 前端工程化的定义 前端工程…

从资深用户角度谈三款出色数据可视化工具

作为一名数据可视化领域的老用户&#xff0c;我接触过众多数据可视化产品&#xff0c;其中不乏佼佼者。今天&#xff0c;我想为大家介绍三款在我心目中颇具特色的数据可视化产品&#xff0c;它们分别是山海鲸可视化、Tableau和Power BI。 首先&#xff0c;让我们来谈谈山海鲸可…

STM32单片机的基本原理与应用(六)

串口测试实验 基本原理 在串口实验中&#xff0c;是通过mini_USB线搭建终端与电脑端&#xff08;也可称终端&#xff0c;为做区分称电脑端&#xff09;的“桥梁”&#xff0c;电脑端的串口调试助手通过mini_USB线向终端发送信息&#xff0c;由CH340芯片将USB接口进行转换&…

机器学习中常用的性能度量—— ROC 和 AUC

什么是泛化能力&#xff1f; 通常我们用泛化能力来评判一个模型的好坏&#xff0c;通俗的说&#xff0c;泛化能力是指一个机器学期算法对新样本&#xff08;即模型没有见过的样本&#xff09;的举一反三的能力&#xff0c;也就是学以致用的能力。 举个例子&#xff0c;高三的…

vulhub中Apache APISIX Dashboard API权限绕过导致RCE(CVE-2021-45232)

Apache APISIX是一个动态、实时、高性能API网关&#xff0c;而Apache APISIX Dashboard是一个配套的前端面板。 Apache APISIX Dashboard 2.10.1版本前存在两个API/apisix/admin/migrate/export和/apisix/admin/migrate/import&#xff0c;他们没有经过droplet框架的权限验证&…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 2月5日,星期一

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年2月5日 星期一 农历腊月廿六 1、 证监会&#xff1a;依法严厉打击操纵市场、恶意做空、内幕交易等重大违法行为。 2、 夜间高铁开行&#xff01;多地火车站候车室开启通宵服务。 3、 气象台&#xff1a;5日晚至7日湘中以…

Prometheus部署监控报警

在容器环境中配置安装Prometheus部署企业微信容器报警Grafana展示 下载Prometheus &#xff08;监控Server端&#xff09; [rootPrometheus-Grafana prometheus]# mkdir /prometheus [rootPrometheus-Grafana prometheus]# docker run -d --name test -P prom/prometheus [ro…

数据与广告系列三十七:广告,商业化的高雅,中间商赚差价的无奈

作者黄崇远 『数据巢』 全文8872字 题图ssyer.com “ 商业化广告&#xff0c;看着其技术复杂又富有挑战性&#xff0c;业务覆盖行业的方方面面又似乎不可或缺&#xff0c;但究其本质&#xff0c;依然是中间商赚差价的生意而已&#xff0c;但细究其背后的深层原因&#xff0c;却…

深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之行存(一)

在当今的大数据时代&#xff0c;高效的数据检索和分析能力已成为许多应用程序的核心需求。Elasticsearch&#xff0c;作为一款强大的分布式搜索和分析引擎&#xff0c;正是为了满足这些需求而诞生的。它之所以能够在海量数据中实现毫秒级的搜索响应&#xff0c;以及灵活的数据分…

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

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

RK3399平台开发系列讲解(内存篇)进程内存详解

🚀返回专栏总目录 文章目录 一、虚拟地址映射的物理内存1.1、物理内存1.2、虚拟内存1.2.1、用户态:低特权运行程序1.2.2、内核态:运行的程序需要访问操作系统内核数据二、PageCache三、指标查询命令沉淀、分享、成长,让自己和他人都能有所收获!😄 📢进程消耗的内存包…

docker proxy 【docker 代理】

第一种 创建代理配置文件 mkdir -p /etc/systemd/system/docker.service.d/ cat <<EOF > /etc/systemd/system/docker.service.d/http-proxy.conf Environment"HTTP_PROXYhttp://192.168.21.101:7890" Environment"HTTPS_PROXYhttp://192.168.21.1…

同城外卖跑腿app开发:重新定义城市生活

随着科技的发展和人们生活节奏的加快&#xff0c;同城外卖跑腿app应运而生&#xff0c;成为现代城市生活中的重要组成部分。本文将探讨同城外卖跑腿app开发的意义、市场需求、功能特点以及未来的发展趋势。 一、同城外卖跑腿app开发的意义 同城外卖跑腿app作为一种便捷的生活…

sqli.labs靶场(41-53关)

41、第四十一关 -1 union select 1,2,3-- -1 union select 1,database(),(select group_concat(table_name) from information_schema.tables where table_schemadatabase()) -- -1 union select 1,2,(select group_concat(column_name) from information_schema.columns wher…

0基础学习VR全景平台篇第141篇:如何制作卫星航拍全景

大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 很多人都看过或者拍摄过航拍全景&#xff0c;其效果相比于普通的地拍的确有着更加震撼的拍摄效果&#xff0c;但是受限于无人机高度&#xff0c;以及禁飞区等等限制&#xff0c;导致很多大场景无法展示完全&a…

Linux防火墙与iptables五表五链规则介绍

目录 一、防火墙基本认识 1. 安全技术 2. 防火墙分类 3. 防火墙工具介绍 二、iptables 1. 概述 2. 五表五链 3. 语法 3.1 基本语法 3.2 语法总结 4. 管理选项 5. 通用匹配 6. 控制类型 7. iptables应用 7.1 新增防火墙规则 7.2 查看规则表 7.3 黑白名单 7.4 …

C++ 调用lua 脚本

需求&#xff1a; 使用Qt/C 调用 lua 脚本 扩展原有功能。 步骤&#xff1a; 1&#xff0c;工程中引入 头文件&#xff0c;库文件。lua二进制下载地址&#xff08;Lua Binaries&#xff09; 2&#xff0c; 调用脚本内函数。 这里调用lua 脚本中的process函数&#xff0c;并…

canvas图片上设置镂空文字效果

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

C语言-3

定义指针 /*指针的概念:1.为了方便访问内存中的内容&#xff0c;给每一个内存单元&#xff0c;进行编号&#xff0c;那么我们称这个编号为地址&#xff0c;也就是指针。2.指针也是一种数据类型&#xff0c;指针变量有自己的内存&#xff0c;里面存储的是地址&#xff0c;也就是…

【HarmonyOS应用开发】APP应用的通知(十五)

相关介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用&#xff0c;通知主要有以下使用场景&#xff1a; 显示接收…