diff --git a/src/app/pages/criminal-records-admin/criminal-records-admin.component.html b/src/app/pages/criminal-records-admin/criminal-records-admin.component.html index d2360c2..fe67121 100644 --- a/src/app/pages/criminal-records-admin/criminal-records-admin.component.html +++ b/src/app/pages/criminal-records-admin/criminal-records-admin.component.html @@ -1,6 +1,7 @@
+
@@ -13,6 +14,7 @@
+ +
@@ -89,15 +114,17 @@ 近一个月预警统计
- - - - +
统计
+
+
排名
+
油站
+
事件
+
-
@@ -106,19 +133,23 @@
+
-
+
预警级别
预警类型
+ 预警事件 +
+
所属公司
@@ -127,35 +158,34 @@
-
+
加油站
-
+
预警区域
+
+ 摄像头名称 +
预警时间
状态
-
+
操作
- - - - + + + +
-
+
Ⅰ级 Ⅱ级 Ⅲ级 @@ -165,6 +195,9 @@ {{item.violation.violationType}}
+ {{item.violation.eventSystemName}} +
+
{{item.gasStation.companyName}}
@@ -173,12 +206,15 @@
-
+
{{item.gasStation.stationName}}
-
+
{{item.violateArea}}
+
+ {{item.cameraNo}} +
{{item.violateTime | date:"yyyy-MM-dd HH:mm:ss"}}
@@ -186,10 +222,10 @@ 已处置 未处置
-
+
查看 - 处置 - 处置 +
@@ -200,5 +236,6 @@ 16条/页,共100条
-->
+
\ No newline at end of file diff --git a/src/app/pages/criminal-records-admin/criminal-records-admin.component.scss b/src/app/pages/criminal-records-admin/criminal-records-admin.component.scss index 055b7f1..aec9a11 100644 --- a/src/app/pages/criminal-records-admin/criminal-records-admin.component.scss +++ b/src/app/pages/criminal-records-admin/criminal-records-admin.component.scss @@ -34,7 +34,9 @@ nz-select { color: rgba(145, 204, 255, 0.95); } - + nz-tree-select { + color: rgba(145, 204, 255, 0.95); + } nz-range-picker { background-color: rgba(0, 0, 0, 0); width: 100%; @@ -200,18 +202,22 @@ flex-direction: row; z-index: 999; - button { - border: 1px solid #91CCFF; + .btn { + width: 64px; + height: 30px; + text-align: center; + line-height: 30px; + // border: 1px solid #91CCFF; color: #91CCFF; border-radius: 0px; - box-shadow: 0 0 5px 0 #2399FF inset; + box-shadow: 0 0 5px 1px #2399FF inset; background: none; + cursor: pointer; } - - .rankingBtn { - margin-right: 16px; + .rankingBtnbox{ + display: flex; + flex-direction: column; } - .selectedbtn { background: linear-gradient(180deg, #000D21 0%, #001331 27%, #2399FF 100%); color: white; diff --git a/src/app/pages/criminal-records-admin/criminal-records-admin.component.ts b/src/app/pages/criminal-records-admin/criminal-records-admin.component.ts index 2bf04ba..308d4b9 100644 --- a/src/app/pages/criminal-records-admin/criminal-records-admin.component.ts +++ b/src/app/pages/criminal-records-admin/criminal-records-admin.component.ts @@ -13,6 +13,7 @@ import { GetOutOfLineDetailsComponent } from '../today-warning/get-out-of-line-d import { OilUnloadingProcessComponent } from '../oil-unloading-process/oil-unloading-process.component'; import { DispositionComponent } from '../disposition/disposition.component'; import { NzMessageService } from 'ng-zorro-antd/message'; +import { TreeService } from 'src/app/service/tree.service'; @Component({ selector: 'app-criminal-records-admin', templateUrl: './criminal-records-admin.component.html', @@ -21,7 +22,7 @@ import { NzMessageService } from 'ng-zorro-antd/message'; export class CriminalRecordsAdminComponent implements OnInit { validateForm!: FormGroup; - constructor(private element: ElementRef, private http: HttpClient, private fb: FormBuilder, private router: Router, private modal: NzModalService, private viewContainerRef: ViewContainerRef, private message: NzMessageService) { } + constructor(private element: ElementRef, private toTree: TreeService, private http: HttpClient, private fb: FormBuilder, private router: Router, private modal: NzModalService, private viewContainerRef: ViewContainerRef, private message: NzMessageService) { } //饼图 myChart option = { @@ -62,7 +63,8 @@ export class CriminalRecordsAdminComponent implements OnInit { textStyle: { color: '#fff', fontSize: 12 - } + }, + formatter: "{b} : {c} ({d}%)" } } ] @@ -304,8 +306,11 @@ export class CriminalRecordsAdminComponent implements OnInit { this.validateForm = this.fb.group({ level: [null], + organization: [null], type: [null], + event: [null], site: [null], + disposalState: [null], datePicker: [[this.startdate, this.enddate]] }); @@ -317,7 +322,33 @@ export class CriminalRecordsAdminComponent implements OnInit { this.mybarChart.setOption(this.baroption); this.warningType() - this.getViolateRecordList() + this.getAllOrganization() + } + + defaultOrId: string + //获取所有组织机构 + nodes: any = [] + getAllOrganization() { + let OrganizationUnitId = sessionStorage.getItem('isGasStation') == 'true' ? JSON.parse(sessionStorage.getItem('userdataOfgasstation')).organization.id : JSON.parse(sessionStorage.getItem('userdata')).organization.id + let params = { + OrganizationUnitId: OrganizationUnitId, + IsContainsChildren: "true" + } + this.http.get('/api/services/app/Organization/GetAll', { + params: params + }).subscribe((data: any) => { + data.result.items.forEach(element => { + if (element.id == OrganizationUnitId) { + element.parentId = null + } + element.key = element.id + element.title = element.displayName + }); + this.nodes = [...this.toTree.toTree(data.result.items)] + this.defaultOrId = JSON.parse(sessionStorage.getItem('userdata')).organization.id + this.validateForm.value.organization = this.defaultOrId + this.getViolateRecordList() + }) } //刷新饼图图表数据 num @@ -405,17 +436,29 @@ export class CriminalRecordsAdminComponent implements OnInit { totalCount: string getViolateRecordList() { let ViolationIds = [] - if (this.validateForm.value.type) { + if (this.validateForm.value.event) { + ViolationIds.push(this.validateForm.value.event) + } + if (this.validateForm.value.type && !this.validateForm.value.event) { this.warningTypesDetails.forEach(item => { item.id ? ViolationIds.push(item.id) : null }); } + let disposalState + if (this.validateForm.value.disposalState == '0') { + disposalState = true + } else if (this.validateForm.value.disposalState == '1') { + disposalState = false + } else { + disposalState = null + } let params = { Level: this.validateForm.value.level, ViolationIds: ViolationIds, ViolateArea: this.validateForm.value.site, OrganizationUnitId: JSON.parse(sessionStorage.getItem('userdata')).organization.id, IsContainsChildren: 'true', + IsHandled: disposalState, ViolateTime: this.validateForm.value.datePicker ? [moment(this.validateForm.value.datePicker[0]).format('yyyy-MM-DD'), moment(this.validateForm.value.datePicker[1]).format('yyyy-MM-DD')] : null, SkipCount: this.SkipCount, MaxResultCount: this.MaxResultCount @@ -433,7 +476,13 @@ export class CriminalRecordsAdminComponent implements OnInit { }) } - + isMouseEnter = false + mouseEnter() { + this.isMouseEnter = true + } + mouseleave() { + this.isMouseEnter = false + } ngAfterViewInit(): void { fromEvent(this.element.nativeElement.querySelector(`#tbody`) as HTMLCanvasElement, 'scroll').pipe(debounceTime(100)).subscribe((event: any) => { //监听 DOM 滚动事件 @@ -497,6 +546,7 @@ export class CriminalRecordsAdminComponent implements OnInit { this.validateForm.controls[key].updateValueAndValidity(); } this.validateForm.patchValue({ + organization: JSON.parse(sessionStorage.getItem('userdata')).organization.id, datePicker: [this.startdate, this.enddate] }); this.list = [] @@ -529,58 +579,61 @@ export class CriminalRecordsAdminComponent implements OnInit { look(item) { // GetOutOfLineDetailsComponent // OilUnloadingProcessComponent - if (!item.violateImage && !item.violateVideo) { - this.message.create('warning', '没有预警照片或视频!'); - } else { - if (item.violation.eventSystemName == '灭火器维护' || item.violation.eventSystemName == '证照预警') { - this.message.create('warning', item.desc); - } else { - const modal = this.modal.create({ - nzContent: GetOutOfLineDetailsComponent, - nzWrapClassName: "vertical-center-modal", - nzViewContainerRef: this.viewContainerRef, - nzWidth: (document.documentElement.clientHeight < 650 || document.documentElement.clientWidth < 1400) ? 1000 : 1200, - nzBodyStyle: { - 'border': '1px solid #6d9cc7', - 'border-radius': '0px', - 'padding': '0px', - 'box-shadow': '0 0 8px 0 #fff', - 'background': '#000D21', - }, - nzComponentParams: { - data: item - }, - nzFooter: null, - nzOnOk: async () => { + // if (!item.violateImage && !item.violateVideo) { + // this.message.create('warning', '没有预警照片或视频!'); + // } else { + + // } + const modal = this.modal.create({ + nzContent: GetOutOfLineDetailsComponent, + nzWrapClassName: "vertical-center-modal", + nzViewContainerRef: this.viewContainerRef, + nzWidth: (document.documentElement.clientHeight < 650 || document.documentElement.clientWidth < 1400) ? 1000 : 1200, + nzBodyStyle: { + 'border': '1px solid #6d9cc7', + 'border-radius': '0px', + 'padding': '0px', + 'box-shadow': '0 0 8px 0 #fff', + 'background': '#000D21', + }, + nzComponentParams: { + data: item + }, + nzFooter: null, + nzOnOk: async () => { - } - }); - const instance = modal.getContentComponent(); } - } + }); + const instance = modal.getContentComponent(); } selectedType = '分布' - selectedRankingType = '站点排名' + selectedRankingType = null echartClick(type) { this.selectedType = type this.mybarChart.dispose() this.mybarChart = echarts.init(document.getElementById('barchart')); - if (type == '排名') { - console.log(this.selectedRankingType) - if (this.selectedRankingType == '站点排名') { - this.refreshBarLineData(this.echartsData, 'siteTop') - } - if (this.selectedRankingType == '事件排名') { - this.refreshBarLineData(this.echartsData, 'eventTop') - } - } else { - this.refreshBarLineData(this.echartsData, 'month') - } + // if (type == '排名') { + + // console.log(this.selectedRankingType) + // if (this.selectedRankingType == '站点排名') { + // this.refreshBarLineData(this.echartsData, 'siteTop') + // } + // if (this.selectedRankingType == '事件排名') { + // this.refreshBarLineData(this.echartsData, 'eventTop') + // } + // } else { + + // } + this.selectedRankingType = null + this.refreshBarLineData(this.echartsData, 'month') } echartClick2(type) { + this.mybarChart.dispose() + this.mybarChart = echarts.init(document.getElementById('barchart')); + this.selectedType = null this.selectedRankingType = type if (this.selectedRankingType == '站点排名') { this.refreshBarLineData(this.echartsData, 'siteTop') diff --git a/src/app/pages/criminal-records/criminal-records.component.html b/src/app/pages/criminal-records/criminal-records.component.html index ff9c502..b0012f6 100644 --- a/src/app/pages/criminal-records/criminal-records.component.html +++ b/src/app/pages/criminal-records/criminal-records.component.html @@ -34,6 +34,14 @@ + + + + + + + + @@ -46,7 +54,14 @@ - + + + + + + + + @@ -111,19 +126,25 @@
-
+
预警级别
-
+
预警类型
-
- 预警信息 +
+ 预警事件
-
+
+ 管理区域 +
+
预警区域
-
+
+ 摄像头名称 +
+
预警时间
@@ -136,31 +157,33 @@
- - - - + + + +
-
+
Ⅰ级 Ⅱ级 Ⅲ级 Ⅳ级
-
+
{{item.violation.violationType}}
-
+
+ {{item.violation.eventSystemName}} +
+
{{item.violation.violationName}}
-
+
{{item.violateArea}}
-
+
+ {{item.cameraNo}} +
+
{{item.violateTime | date:"yyyy-MM-dd HH:mm:ss"}}
@@ -169,8 +192,8 @@
查看 - 处置 - 处置 +
diff --git a/src/app/pages/criminal-records/criminal-records.component.ts b/src/app/pages/criminal-records/criminal-records.component.ts index f148660..4a4e8b1 100644 --- a/src/app/pages/criminal-records/criminal-records.component.ts +++ b/src/app/pages/criminal-records/criminal-records.component.ts @@ -57,7 +57,8 @@ export class CriminalRecordsComponent implements OnInit { textStyle: { color: '#fff', fontSize: 12 - } + }, + formatter: "{b} : {c} ({d}%)" } } ] @@ -311,6 +312,8 @@ export class CriminalRecordsComponent implements OnInit { this.validateForm = this.fb.group({ level: [null], type: [null], + event: [null], + disposalState: [null], site: [null], datePicker: [[this.startdate, this.enddate]] }); @@ -413,11 +416,22 @@ export class CriminalRecordsComponent implements OnInit { totalCount: string getViolateRecordList() { let ViolationIds = [] - if (this.validateForm.value.type) { + if (this.validateForm.value.event) { + ViolationIds.push(this.validateForm.value.event) + } + if (this.validateForm.value.type && !this.validateForm.value.event) { this.warningTypesDetails.forEach(item => { item.id ? ViolationIds.push(item.id) : null }); } + let disposalState + if (this.validateForm.value.disposalState == '0') { + disposalState = true + } else if (this.validateForm.value.disposalState == '1') { + disposalState = false + } else { + disposalState = null + } let params = { Level: this.validateForm.value.level, ViolationIds: ViolationIds, @@ -425,6 +439,7 @@ export class CriminalRecordsComponent implements OnInit { OrganizationUnitId: JSON.parse(sessionStorage.getItem('userdataOfgasstation')).organization.id, IsContainsChildren: 'true', ViolateTime: this.validateForm.value.datePicker ? [moment(this.validateForm.value.datePicker[0]).format('yyyy-MM-DD'), moment(this.validateForm.value.datePicker[1]).format('yyyy-MM-DD')] : null, + IsHandled: disposalState, SkipCount: this.SkipCount, MaxResultCount: this.MaxResultCount } @@ -482,7 +497,7 @@ export class CriminalRecordsComponent implements OnInit { warningTypesDetails: any warningType() { this.http.get('/api/services/app/Violation/GetAllList').subscribe((data: any) => { - // this.warningTypesDetails = data.result + this.warningTypesDetails = data.result this.warningTypes = (data.result as any).groupBy((t) => { return t.violationType }); }) } @@ -492,6 +507,9 @@ export class CriminalRecordsComponent implements OnInit { this.warningTypesDetails = element } }); + this.validateForm.patchValue({ + event: null, + }); } selectedType = '分布' selectedRankingType = '站点排名' @@ -510,35 +528,32 @@ export class CriminalRecordsComponent implements OnInit { look(item) { - if (!item.violateImage && !item.violateVideo) { - this.message.create('warning', '没有预警照片或视频!'); - } else { - if (item.violation.eventSystemName == '灭火器维护' || item.violation.eventSystemName == '证照预警') { - this.message.create('warning', item.desc); - } else { - const modal = this.modal.create({ - nzContent: GetOutOfLineDetailsComponent, - nzWrapClassName: "vertical-center-modal", - nzViewContainerRef: this.viewContainerRef, - nzWidth: (document.documentElement.clientHeight < 650 || document.documentElement.clientWidth < 1400) ? 1000 : 1200, - nzBodyStyle: { - 'border': '1px solid #6d9cc7', - 'border-radius': '0px', - 'padding': '0px', - 'box-shadow': '0 0 8px 0 #fff', - 'background': '#000D21', - }, - nzComponentParams: { - data: item - }, - nzFooter: null, - nzOnOk: async () => { + // if (!item.violateImage && !item.violateVideo) { + // this.message.create('warning', '没有预警照片或视频!'); + // } else { + + // } + const modal = this.modal.create({ + nzContent: GetOutOfLineDetailsComponent, + nzWrapClassName: "vertical-center-modal", + nzViewContainerRef: this.viewContainerRef, + nzWidth: (document.documentElement.clientHeight < 650 || document.documentElement.clientWidth < 1400) ? 1000 : 1200, + nzBodyStyle: { + 'border': '1px solid #6d9cc7', + 'border-radius': '0px', + 'padding': '0px', + 'box-shadow': '0 0 8px 0 #fff', + 'background': '#000D21', + }, + nzComponentParams: { + data: item + }, + nzFooter: null, + nzOnOk: async () => { - } - }); - const instance = modal.getContentComponent(); } - } + }); + const instance = modal.getContentComponent(); } goOilList() { diff --git a/src/app/pages/home-page/home-page.component.html b/src/app/pages/home-page/home-page.component.html index 16b0802..1a947a0 100644 --- a/src/app/pages/home-page/home-page.component.html +++ b/src/app/pages/home-page/home-page.component.html @@ -37,7 +37,7 @@
-
+

{{HomeAggregatioData.recordCount}}

预警总数 @@ -45,10 +45,10 @@
-
- 区域排名 +
+ 公司排名
-
+
- {{item.key}} + {{item.name}} @@ -65,7 +65,7 @@
-
@@ -111,9 +111,34 @@
- 站点排名 -
-
+ 油站排名 +
+
+
+
+ + {{'0' + (key + 1)}} + + + {{key + 1}} + +
+ {{item.name}} {{item.companyName}} +
+
+
+
+
+
+
+
+ {{item.count}} +
+
+
@@ -202,19 +227,37 @@
-
-
+
+
近30天卸油作业总数走势 -
+
-
+
+ +
+
+
+ 卸油正常 + {{HomeAggregatioData.ouViolationType.ouCorrectCount}} +
+
+
+ 卸油违规 + {{HomeAggregatioData.ouViolationType.ouNotCorrectCount}} +
+
+
+ 卸油总数 + {{HomeAggregatioData.ouViolationType.ouTotalCount}} +
+
diff --git a/src/app/pages/home-page/home-page.component.scss b/src/app/pages/home-page/home-page.component.scss index 42813d6..fb13c41 100644 --- a/src/app/pages/home-page/home-page.component.scss +++ b/src/app/pages/home-page/home-page.component.scss @@ -321,6 +321,10 @@ } + .leftitemlimit { + max-width: 318px; + } + .leftitem:nth-child(1) { flex: .8; position: relative; @@ -565,6 +569,32 @@ width: 76%; // border: 1px solid red; } + .oilNum{ + position: absolute; + left: 1%; + bottom: 20px; + display: flex; + flex-wrap: wrap; + .oilNumItem{ + margin-right: 6px; + } + div{ + display: flex; + align-items: center; + color: white; + font-size: 12px; + + span{ + margin:0 4px; + } + .point{ + width: 6px; + height: 6px; + background-color: #91CCFF; + + } + } + } } } @@ -674,6 +704,7 @@ height: 32px; line-height: 32px; font-size: 12px; + .infoitem { img { width: 28px; @@ -989,10 +1020,12 @@ img { width: 36px; } + .num { - font-size:23px; + font-size: 23px; margin: 0 5px; } + .today { font-size: 13px; margin-bottom: 10px; @@ -1004,6 +1037,7 @@ .inform { height: 30px; + .infologo { img { width: 20px; @@ -1024,6 +1058,7 @@ height: 22px; line-height: 22px; font-size: 10px; + .infoitem { img { width: 20px; @@ -1056,11 +1091,14 @@ .leftboxcontent { padding: 8px; padding-right: 4px; + .leftitem { margin: 0 4px; padding: 6px 8px; + .progress { height: 2px; + .colorbar { height: 2px; } @@ -1082,8 +1120,10 @@ .eventboxitem { font-size: 10px; + .eventname { width: 30%; + .block { width: 14px; height: 14px; @@ -1098,6 +1138,7 @@ .stationbox { .stationboxitem { font-size: 10px; + .stationname { .block { width: 14px; @@ -1114,12 +1155,14 @@ .leftitem:nth-child(1) { flex: .8; + .warningnum { width: 70px; position: absolute; left: 50%; transform: translateX(-50%); top: 19%; + h1 { font-size: 32px; } @@ -1203,7 +1246,7 @@ .bottombox { .title { - height:30px; + height: 30px; } .bottomitem { diff --git a/src/app/pages/home-page/home-page.component.ts b/src/app/pages/home-page/home-page.component.ts index daa742f..bd29be3 100644 --- a/src/app/pages/home-page/home-page.component.ts +++ b/src/app/pages/home-page/home-page.component.ts @@ -58,7 +58,8 @@ export class HomePageComponent implements OnInit { textStyle: { color: '#fff', fontSize: 12 - } + }, + formatter: "{b} : {c} ({d}%)" }, label: { normal: { @@ -213,173 +214,20 @@ export class HomePageComponent implements OnInit { top: '30px' } }; - - - oilchartpie//卸油饼图 - oilchartbar//卸油折线图 - - ngOnInit(): void { - // 饼图 - // this.equipmentechart = echarts.init(document.getElementById('equipmentechart')); - // 预警饼图 - this.warningechartpie = echarts.init(document.getElementById('eventechartpie')); - // 预警线图 - this.warningechartbar = echarts.init(document.getElementById('eventechartline')); - - - // 卸油饼图 - this.oilchartpie = echarts.init(document.getElementById('oilechartpie')); - // 卸油线图 - this.oilchartbar = echarts.init(document.getElementById('oilechartline')); - - - - window.onresize = () => { - setTimeout(() => { - this.warningechartpie.resize(); - this.warningechartbar.resize(); - this.oilchartpie.resize(); - this.oilchartbar.resize(); - }, 200); - - }; - - this.rollStart() - this.getHomeAggregation() - this.getUnreadNotification() - - this.getAggregations() - - // if (Number(sessionStorage.getItem('zoom')) != 1) { - // console.log('走这里了吗') - // let dom1 = document.getElementById('eventechartpie') - // let dom2 = document.getElementById('eventechartline') - // let dom3 = document.getElementById('oilechartpie') - // let dom4 = document.getElementById('oilechartline') - // let zoom = 1 / Number(sessionStorage.getItem('zoom')) - // let domList = [dom1, dom2, dom3, dom4] - // domList.forEach((item: any) => { - // item.style.zoom = zoom - // item.style.transform = "scale(" + Number(sessionStorage.getItem('zoom')) + ")" - // item.style.transformOrigin = "0%0%" - // item.style.width = 50 + "%" - // }) - // } - - } - - //获得所有未读消息 - unreadMessageList: any - getUnreadNotification() { - this.http.get('/api/services/app/Notification/GetUnreadNotification').subscribe((data: any) => { - console.log('获得所有未读消息', data) - this.unreadMessageList = data.result - }) - } - - - - //获得统计信息 - - HomeAggregatioData: any = { - areaAgg: [], - violationType: { - violationTypeAgg: [] - }, - dev: { - stationCount: '', - violationCount: '', - cameraCount: '' - } - } - totalCount - getHomeAggregation() { - - let organizationUnitId - if (this.router.url.indexOf('petrolStation') != -1) { - organizationUnitId = JSON.parse(sessionStorage.getItem('userdataOfgasstation')).organization.id - } else { - organizationUnitId = JSON.parse(sessionStorage.getItem('userdata')).organization.id - } - let body = { - organizationUnitId: organizationUnitId, - isContainsChildren: true - } - this.http.post('/api/services/app/Home/HomeAggregation', body).subscribe((data: any) => { - this.HomeAggregatioData = data.result - this.totalCount = data.result.todayRecordCount - this.equipmentechartdata = [ - { name: '接入油站数量', value: data.result.dev.stationCount }, - { name: '摄像头数量', value: data.result.dev.cameraCount }, - { name: '预警模型数量', value: data.result.dev.violationCount } - ] - console.log('图表信息', data.result) - - this.eventEcharts(data.result) - }) - - - // let starttime = moment(new Date()).format('YYYY-MM-DD') + '\xa0' + '00:00' - // let endtime = moment(new Date()).format('YYYY-MM-DD') + '\xa0' + '23:59' - // let params = { - // organizationUnitId: organizationUnitId, - // ViolateTime: [starttime, endtime], - // IsContainsChildren: 'true', - // SkipCount: '0', - // MaxResultCount: '1' - // } - // this.http.get('/api/services/app/ViolateRecord/GetAll', { - // params: params - // }).subscribe((data: any) => { - // this.totalCount = data.result.totalCount - // }) - } - //预警图表 - equipmentechartdata - eventEcharts(data) { - data.violationType.violationTypeAgg.forEach(element => { - // num += element.count - element.name = element.key - element.value = element.count - }); - this.warningechartpieOption.series[0].data = data.violationType.violationTypeAgg; - this.warningechartpieOption.series[0].label.normal.formatter = '{total|' + data.recordCount + '}' + '\n\r' + '{active|总数}' - this.warningechartpie.setOption(this.warningechartpieOption); - - - let monthArr = [] - let valuedata = [] - data.violationType.days30ViolationCount.forEach(element => { - monthArr.push(moment(element.key).format('MM.DD')) - valuedata.push(element.count) - }); - this.warningechartbarOption.xAxis.data = monthArr - this.warningechartbarOption.series[0].data = valuedata - this.warningechartbarOption.series[1].data = valuedata - this.warningechartbar.setOption(this.warningechartbarOption); - } //一级饼图 oilchartpieOption = { - color: ['#FF4B65', '#36A2FF'], + color: ['#91CCFF', '#46DFFF', '#36A2FF', '#FF6181', '#B4C3FF', '#FF9963', '#5A9CFF', '#4BFFD4', '#46DFFF', '#91CCFF'], tooltip: { trigger: 'item'//触发类型 }, legend: { - bottom: '12%', - left: 'center', - itemGap: 10, - itemWidth: 8, - itemHeight: 8, - orient: 'vertical', + top: '5%', + left: '20%', + itemGap: 8, + itemWidth: 6, + itemHeight: 6, formatter: (name) => { - let data = this.oilchartpieOptionPieData1 - let value - for (var i = 0, l = data.length; i < l; i++) { - if (data[i].name == name) { - value = data[i].value; - } - } - return '{a|' + name + '}' + '{b|' + value + '}'; + return '{a|' + name + '}'; }, textStyle: { color: '#fff', @@ -394,7 +242,8 @@ export class HomePageComponent implements OnInit { { type: 'pie', radius: ['50%', '60%'], - bottom: '20%', + bottom: '-5%', + right: '77%', avoidLabelOverlap: false,//防止标签重叠策略 label: { normal: { @@ -428,7 +277,8 @@ export class HomePageComponent implements OnInit { textStyle: { color: '#fff', fontSize: 12 - } + }, + formatter: "{b} : {c} ({d}%)" } } ] @@ -534,24 +384,162 @@ export class HomePageComponent implements OnInit { top: '66px' } }; + + oilchartpie//卸油饼图 + oilchartbar//卸油折线图 + userdata + ngOnInit(): void { + + this.userdata = JSON.parse(sessionStorage.getItem('userdata')) + + // 饼图 + // this.equipmentechart = echarts.init(document.getElementById('equipmentechart')); + // 预警饼图 + this.warningechartpie = echarts.init(document.getElementById('eventechartpie')); + // 预警线图 + this.warningechartbar = echarts.init(document.getElementById('eventechartline')); + + + // 卸油饼图 + this.oilchartpie = echarts.init(document.getElementById('oilechartpie')); + // 卸油线图 + this.oilchartbar = echarts.init(document.getElementById('oilechartline')); + + + + window.onresize = () => { + setTimeout(() => { + this.warningechartpie.resize(); + this.warningechartbar.resize(); + this.oilchartpie.resize(); + this.oilchartbar.resize(); + }, 200); + + }; + + this.rollStart() + this.getHomeAggregation() + this.getUnreadNotification() + + // this.getAggregations() + + + } + + //获得所有未读消息 + unreadMessageList: any + getUnreadNotification() { + this.http.get('/api/services/app/Notification/GetUnreadNotification').subscribe((data: any) => { + console.log('获得所有未读消息', data) + this.unreadMessageList = data.result + }) + } + + + + //获得统计信息 + + HomeAggregatioData: any = { + areaAgg: [], + violationType: { + violationTypeAgg: [] + }, + dev: { + stationCount: '', + violationCount: '', + cameraCount: '' + } + } + totalCount + getHomeAggregation() { + + let organizationUnitId + if (this.router.url.indexOf('petrolStation') != -1) { + organizationUnitId = JSON.parse(sessionStorage.getItem('userdataOfgasstation')).organization.id + } else { + organizationUnitId = JSON.parse(sessionStorage.getItem('userdata')).organization.id + } + let body = { + organizationUnitId: organizationUnitId, + isContainsChildren: true + } + this.http.post('/api/services/app/Home/HomeAggregation', body).subscribe((data: any) => { + this.HomeAggregatioData = data.result + this.totalCount = data.result.todayRecordCount + this.equipmentechartdata = [ + { name: '接入油站数量', value: data.result.dev.stationCount }, + { name: '摄像头数量', value: data.result.dev.cameraCount }, + { name: '预警模型数量', value: data.result.dev.violationCount } + ] + console.log('图表信息', data.result) + + this.eventEcharts(data.result) + }) + + + // let starttime = moment(new Date()).format('YYYY-MM-DD') + '\xa0' + '00:00' + // let endtime = moment(new Date()).format('YYYY-MM-DD') + '\xa0' + '23:59' + // let params = { + // organizationUnitId: organizationUnitId, + // ViolateTime: [starttime, endtime], + // IsContainsChildren: 'true', + // SkipCount: '0', + // MaxResultCount: '1' + // } + // this.http.get('/api/services/app/ViolateRecord/GetAll', { + // params: params + // }).subscribe((data: any) => { + // this.totalCount = data.result.totalCount + // }) + } + //预警图表 + equipmentechartdata + eventEcharts(data) { + data.violationType.violationTypeAgg.forEach(element => { + // num += element.count + element.name = element.key + element.value = element.count + }); + this.warningechartpieOption.series[0].data = data.violationType.violationTypeAgg; + this.warningechartpieOption.series[0].label.normal.formatter = '{total|' + data.recordCount + '}' + '\n\r' + '{active|总数}' + this.warningechartpie.setOption(this.warningechartpieOption); + + + let monthArr = [] + let valuedata = [] + data.violationType.days30ViolationCount.forEach(element => { + monthArr.push(moment(element.key).format('MM.DD')) + valuedata.push(element.count) + }); + this.warningechartbarOption.xAxis.data = monthArr + this.warningechartbarOption.series[0].data = valuedata + this.warningechartbarOption.series[1].data = valuedata + this.warningechartbar.setOption(this.warningechartbarOption); + + + //卸油两个图 + this.refreshEchartsData1(data) + } + oilDischargeNum: any refreshEchartsData1(data) { this.oilDischargeNum = data.totalCount //饼图 - this.oilchartpieOptionPieData1 = [ - { name: '预警事件', value: data.notCorrectCount }, - { name: '正常操作', value: data.correctCount }, - ] - this.oilchartpieOption.series[0].label.normal.formatter = '{total|' + data.totalCount + '}' + '\n\r' + '{active|总数}' + data.ouViolationType.ouViolationTypeAgg.forEach(element => { + element.name = element.key + element.value = element.count + }); + this.oilchartpieOptionPieData1 = data.ouViolationType.ouViolationTypeAgg + this.oilchartpieOption.series[0].label.normal.formatter = '{total|' + data.ouRecordCount + '}' + '\n\r' + '{active|总数}' this.oilchartpieOption.series[0].data = this.oilchartpieOptionPieData1 this.oilchartpie.setOption(this.oilchartpieOption); //柱状图 let monthArr = [] let valuedata = [] - data.list.forEach(element => { + data.ouViolationType.ouDays30ViolationCount.forEach(element => { monthArr.push(moment(element.key).format('MM.DD')) - valuedata.push(element.totalCount) + valuedata.push(element.count) }); this.oilchartbarOption.xAxis.data = monthArr this.oilchartbarOption.series[0].data = valuedata diff --git a/src/app/pages/oil-station-info/oil-station-info.component.html b/src/app/pages/oil-station-info/oil-station-info.component.html index 06e8773..e5882cc 100644 --- a/src/app/pages/oil-station-info/oil-station-info.component.html +++ b/src/app/pages/oil-station-info/oil-station-info.component.html @@ -78,12 +78,12 @@ - 所属公司 + 所属公司* - + diff --git a/src/app/pages/oil-unloading-process-list/oil-unloading-process-list.component.html b/src/app/pages/oil-unloading-process-list/oil-unloading-process-list.component.html index 88549ea..40c7c30 100644 --- a/src/app/pages/oil-unloading-process-list/oil-unloading-process-list.component.html +++ b/src/app/pages/oil-unloading-process-list/oil-unloading-process-list.component.html @@ -51,15 +51,23 @@ - + + + + + + +
diff --git a/src/app/pages/today-warning-admin/today-warning-admin.component.scss b/src/app/pages/today-warning-admin/today-warning-admin.component.scss index d4a330d..50e2df7 100644 --- a/src/app/pages/today-warning-admin/today-warning-admin.component.scss +++ b/src/app/pages/today-warning-admin/today-warning-admin.component.scss @@ -63,6 +63,7 @@ .searchParams { flex: 3; + // max-width: 100px; } .btn { diff --git a/src/app/pages/today-warning-admin/today-warning-admin.component.ts b/src/app/pages/today-warning-admin/today-warning-admin.component.ts index 30a152c..e4d9c77 100644 --- a/src/app/pages/today-warning-admin/today-warning-admin.component.ts +++ b/src/app/pages/today-warning-admin/today-warning-admin.component.ts @@ -33,6 +33,7 @@ export class TodayWarningAdminComponent implements OnInit { event: [null], organization: [null], area: [null], + disposalState: [null], datePickerStart: [new Date(`${moment(new Date()).format('YYYY-MM-DD')} 00:00`)], datePickerEnd: [new Date(`${moment(new Date()).format('YYYY-MM-DD')} 23:59`)] }); @@ -46,6 +47,7 @@ export class TodayWarningAdminComponent implements OnInit { warningType() { this.http.get('/api/services/app/Violation/GetAllList').subscribe((data: any) => { this.warningTypesDetails = data.result + console.log(this.warningTypesDetails) this.warningTypes = (data.result as any).groupBy((t) => { return t.violationType }); }) } @@ -101,7 +103,14 @@ export class TodayWarningAdminComponent implements OnInit { item.id ? ViolationIds.push(item.id) : null }); } - + let disposalState + if (this.validateForm.value.disposalState == '0') { + disposalState = true + } else if (this.validateForm.value.disposalState == '1') { + disposalState = false + } else { + disposalState = null + } console.log(this.validateForm.value) let params = { Level: this.validateForm.value.level, @@ -110,6 +119,7 @@ export class TodayWarningAdminComponent implements OnInit { organizationUnitId: this.validateForm.value.organization, ViolateTime: (this.validateForm.value.datePickerEnd && this.validateForm.value.datePickerStart) ? [moment(this.validateForm.value.datePickerStart).format('yyyy-MM-DD HH:mm:ss'), moment(this.validateForm.value.datePickerEnd).format('yyyy-MM-DD HH:mm:ss')] : null, // ViolateTime: ['2021-10-27', '2021-11-26'], + IsHandled: disposalState, IsContainsChildren: 'true', SkipCount: '0', MaxResultCount: '9999' @@ -159,33 +169,29 @@ export class TodayWarningAdminComponent implements OnInit { } - isVisible=false + isVisible = false look(item) { - if (item.violation.eventSystemName == '灭火器维护' || item.violation.eventSystemName == '证照预警') { - this.message.create('warning', item.desc); - } else { - const modal = this.modal.create({ - nzContent: GetOutOfLineDetailsComponent, - nzWrapClassName: "vertical-center-modal", - nzViewContainerRef: this.viewContainerRef, - nzWidth: (document.documentElement.clientHeight<650 || document.documentElement.clientWidth<1400) ? 1000 : 1200, - nzBodyStyle: { - 'border': '1px solid #6d9cc7', - 'border-radius': '0px', - 'padding': '0px', - 'box-shadow': '0 0 8px 0 #fff', - 'background': '#000D21', - }, - nzComponentParams: { - data: item - }, - nzFooter: null, - nzOnOk: async () => { + const modal = this.modal.create({ + nzContent: GetOutOfLineDetailsComponent, + nzWrapClassName: "vertical-center-modal", + nzViewContainerRef: this.viewContainerRef, + nzWidth: (document.documentElement.clientHeight < 650 || document.documentElement.clientWidth < 1400) ? 1000 : 1200, + nzBodyStyle: { + 'border': '1px solid #6d9cc7', + 'border-radius': '0px', + 'padding': '0px', + 'box-shadow': '0 0 8px 0 #fff', + 'background': '#000D21', + }, + nzComponentParams: { + data: item + }, + nzFooter: null, + nzOnOk: async () => { - } - }); - const instance = modal.getContentComponent(); - } + } + }); + const instance = modal.getContentComponent(); } diff --git a/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.html b/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.html index fc689e2..878aa06 100644 --- a/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.html +++ b/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.html @@ -5,21 +5,34 @@ 预警截图
-
+
预警视频
+
+ {{details}} +
-
+
+
+
+ 处置内容 + 提交 + 已处置 +
+
+ +
+
\ No newline at end of file diff --git a/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.scss b/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.scss index 8659464..8d6c8ee 100644 --- a/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.scss +++ b/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.scss @@ -1,6 +1,7 @@ .box { width: 100%; - height: 700px; + height: 715px; + overflow-y: auto; color: #fff; display: flex; flex-direction: column; @@ -60,14 +61,44 @@ .content { flex: 1; box-sizing: border-box; - padding: 18px; + padding: 12px; overflow: hidden; + display: flex; + flex-direction: column; + overflow-y: auto; + .details { + margin-bottom: 12px; + } + + .disposebox { + display: flex; + flex-direction: column; + height: 72px; + margin-bottom: 25px; + .title { + display: flex; + justify-content: space-between; + margin-bottom: 12px; + + } + + .textarea { + height: 60px; + + textarea { + color: #C4E2FC; + border: 1px solid #91CCFF; + background-color: #172c45; + } + + } + } .imgbox { + flex: 1; display: flex; width: 100%; - height: 100%; - + .imglist { display: flex; flex-direction: column; @@ -104,12 +135,22 @@ padding-left: 13px; display: flex; justify-content: center; + max-height: 500px; + img { max-width: 100%; max-height: 100%; } } } + + .vediobox { + flex: 1; + width: 100%; + video{ + max-height: 500px; + } + } } @@ -176,3 +217,21 @@ } } } + +::-webkit-input-placeholder { + /* WebKit browsers */ + color: #345d85; +} + +//滚动条样式 +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-thumb { + background-image: linear-gradient(#2495f8, #1c73c2, #0a3d6a, #061d3c); +} + +::-webkit-scrollbar-track { + background-color: #061d3c; +} \ No newline at end of file diff --git a/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.ts b/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.ts index b3173ed..fb97bce 100644 --- a/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.ts +++ b/src/app/pages/today-warning/get-out-of-line-details/get-out-of-line-details.component.ts @@ -1,21 +1,28 @@ +import { HttpClient } from '@angular/common/http'; import { Component, OnInit, Input } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ selector: 'app-get-out-of-line-details', templateUrl: './get-out-of-line-details.component.html', styleUrls: ['./get-out-of-line-details.component.scss'] }) export class GetOutOfLineDetailsComponent implements OnInit { - @Input() data: any - constructor() { } + constructor(private fb: FormBuilder, private http: HttpClient, private message: NzMessageService) { } imgUrl: string vedioUrl: string + content + details ngOnInit(): void { + console.log(this.data) + this.details = this.data.desc this.imgUrl = this.data.violateImage this.vedioUrl = this.data.violateVideo + this.content = this.data.handleRecord } @@ -23,4 +30,14 @@ export class GetOutOfLineDetailsComponent implements OnInit { contentType(type) { this.selectedType = type } + submit() { + let body = { + id: this.data.id, + handleRecord: this.content + } + this.http.post('/api/services/app/ViolateRecord/HandleViolateRecord', body).subscribe(data => { + this.message.create('success', '处置成功!'); + this.data.handleTime = new Date() + }) + } } diff --git a/src/app/pages/today-warning/today-warning.component.html b/src/app/pages/today-warning/today-warning.component.html index c46c181..befdc06 100644 --- a/src/app/pages/today-warning/today-warning.component.html +++ b/src/app/pages/today-warning/today-warning.component.html @@ -40,7 +40,14 @@ - + + + + + + + + @@ -98,19 +105,30 @@ Ⅳ级
-
+
预警类型: {{item.violation.violationType}}
-
+
预警信息: {{item.violation.violationName}}
-
+
区域: {{item.violateArea}}
-
+
+ 摄像头: {{item.cameraNo}} +
+
{{item.violateTime | date:"yyyy-MM-dd HH:mm:ss"}}
+ + 未处置 + + + 已处置 + +
+
已处置 diff --git a/src/app/pages/today-warning/today-warning.component.scss b/src/app/pages/today-warning/today-warning.component.scss index 254ebcb..ad0c680 100644 --- a/src/app/pages/today-warning/today-warning.component.scss +++ b/src/app/pages/today-warning/today-warning.component.scss @@ -62,7 +62,7 @@ } .searchParams { - flex: 3; + flex: 2.9; } .btn { diff --git a/src/app/pages/today-warning/today-warning.component.ts b/src/app/pages/today-warning/today-warning.component.ts index 3a068c1..7e68090 100644 --- a/src/app/pages/today-warning/today-warning.component.ts +++ b/src/app/pages/today-warning/today-warning.component.ts @@ -24,6 +24,7 @@ export class TodayWarningComponent implements OnInit { level: [null], type: [null], area: [null], + disposalState: [null], datePickerStart: [new Date(`${moment(new Date()).format('YYYY-MM-DD')} 00:00`)], datePickerEnd: [new Date(`${moment(new Date()).format('YYYY-MM-DD')} 23:59`)] }); @@ -60,12 +61,21 @@ export class TodayWarningComponent implements OnInit { item.id ? ViolationIds.push(item.id) : null }); } + let disposalState + if (this.validateForm.value.disposalState == '0') { + disposalState = true + } else if (this.validateForm.value.disposalState == '1') { + disposalState = false + } else { + disposalState = null + } let params = { Level: this.validateForm.value.level, ViolationIds: ViolationIds, ViolateArea: this.validateForm.value.area, organizationUnitId: JSON.parse(sessionStorage.getItem('userdataOfgasstation')).organization.id, ViolateTime: (this.validateForm.value.datePickerEnd && this.validateForm.value.datePickerStart) ? [moment(this.validateForm.value.datePickerStart).format('yyyy-MM-DD HH:mm:ss'), moment(this.validateForm.value.datePickerEnd).format('yyyy-MM-DD HH:mm:ss')] : null, + IsHandled: disposalState, // ViolateTime: ['2021-10-27', '2021-11-26'], IsContainsChildren: 'true', SkipCount: '0', @@ -113,32 +123,27 @@ export class TodayWarningComponent implements OnInit { look(item) { - console.log(item) - if (item.violation.eventSystemName == '灭火器维护' || item.violation.eventSystemName == '证照预警') { - this.message.create('warning', item.desc); - } else { - const modal = this.modal.create({ - nzContent: GetOutOfLineDetailsComponent, - nzWrapClassName: "vertical-center-modal", - nzViewContainerRef: this.viewContainerRef, - nzWidth: (document.documentElement.clientHeight < 650 || document.documentElement.clientWidth < 1400) ? 1000 : 1200, - nzBodyStyle: { - 'border': '1px solid #6d9cc7', - 'border-radius': '0px', - 'padding': '0px', - 'box-shadow': '0 0 8px 0 #fff', - 'background': '#000D21', - }, - nzComponentParams: { - data: item - }, - nzFooter: null, - nzOnOk: async () => { + const modal = this.modal.create({ + nzContent: GetOutOfLineDetailsComponent, + nzWrapClassName: "vertical-center-modal", + nzViewContainerRef: this.viewContainerRef, + nzWidth: (document.documentElement.clientHeight < 650 || document.documentElement.clientWidth < 1400) ? 1000 : 1200, + nzBodyStyle: { + 'border': '1px solid #6d9cc7', + 'border-radius': '0px', + 'padding': '0px', + 'box-shadow': '0 0 8px 0 #fff', + 'background': '#000D21', + }, + nzComponentParams: { + data: item + }, + nzFooter: null, + nzOnOk: async () => { - } - }); - const instance = modal.getContentComponent(); - } + } + }); + const instance = modal.getContentComponent(); } dispose(item) { diff --git a/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.html b/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.html index b1d07c8..46c34cc 100644 --- a/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.html +++ b/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.html @@ -7,6 +7,13 @@ + + + + + + + diff --git a/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.ts b/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.ts index a8b97d8..9a76b2d 100644 --- a/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.ts +++ b/src/app/system-management/analysis-of-the-host/addcamera/addcamera.component.ts @@ -15,6 +15,7 @@ export class AddcameraComponent implements OnInit { ngOnInit(): void { this.validateForm = this.fb.group({ name: [null, [Validators.required]], + ip: [null, [Validators.required]], code: [null, [Validators.required]] }); } diff --git a/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts b/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts index e70c1e4..9f2ba23 100644 --- a/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts +++ b/src/app/system-management/analysis-of-the-host/analysis-of-the-host.component.ts @@ -197,6 +197,7 @@ export class AnalysisOfTheHostComponent implements OnInit { console.log('表单信息', instance.validateForm) let body = { organizationUnitId: this.selectedOilStation.id, + ipAdress: instance.validateForm.value.ip, code: instance.validateForm.value.code, name: instance.validateForm.value.name, // description: "", @@ -235,6 +236,7 @@ export class AnalysisOfTheHostComponent implements OnInit { console.log('表单信息', instance.validateForm) data.name = instance.validateForm.value.name data.code = instance.validateForm.value.code + data.ipAdress = instance.validateForm.value.ip this.http.put('/api/services/app/Camera/Update', data).subscribe(data => { resolve(data) this.message.create('success', '编辑成功!'); diff --git a/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.html b/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.html index b1d07c8..46c34cc 100644 --- a/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.html +++ b/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.html @@ -7,6 +7,13 @@ + + + + + + + diff --git a/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.ts b/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.ts index 6d3b601..62d2d0c 100644 --- a/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.ts +++ b/src/app/system-management/analysis-of-the-host/editcamera/editcamera.component.ts @@ -17,6 +17,7 @@ export class EditcameraComponent implements OnInit { let datacopy = JSON.parse(JSON.stringify(this.data)) this.validateForm = this.fb.group({ name: [datacopy.name, [Validators.required]], + ip: [datacopy.ipAdress, [Validators.required]], code: [datacopy.code, [Validators.required]] }); } diff --git a/src/app/system-management/push/push.component.html b/src/app/system-management/push/push.component.html index 5ecc8f2..1fda6ab 100644 --- a/src/app/system-management/push/push.component.html +++ b/src/app/system-management/push/push.component.html @@ -28,7 +28,7 @@ {{item.violationType}} - {{item.violationName}} + {{item.eventSystemName}} {{i}}