@@ -7,7 +7,7 @@
Search
-
@@ -36,12 +36,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/users/users.component.ts b/frontend/src/app/component/page/users/users.component.ts
index 3c665fc..47795a9 100644
--- a/frontend/src/app/component/page/users/users.component.ts
+++ b/frontend/src/app/component/page/users/users.component.ts
@@ -15,6 +15,8 @@ import { NzUploadFile, NzUploadModule } from 'ng-zorro-antd/upload'
import { imgToBase64, uploadImgToBase64 } from '../../../../tool/imageUpload'
import { Observable, Observer } from 'rxjs'
import { NzSelectModule } from 'ng-zorro-antd/select'
+import { findMenuItem } from '../../tool-function'
+import { UserStoreService } from '../../../../state/user.service'
@Component({
// selector: 'app-footer',
@@ -37,8 +39,29 @@ import { NzSelectModule } from 'ng-zorro-antd/select'
export class UsersComponent {
constructor(
private message: NzMessageService,
- private modalService: NzModalService
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
+
searchForm: any = {
page: 1,
From 3ac34a0c65cf615dd071b6b6f7a6d40441905d21 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 19:01:43 -0400
Subject: [PATCH 004/127] update for dept & menu page user access control
---
.../page/department/department.component.html | 6 +++--
.../page/department/department.component.ts | 27 +++++++++++++++++--
.../component/page/menu/menu.component.html | 5 ++--
.../app/component/page/menu/menu.component.ts | 27 +++++++++++++++++--
frontend/src/app/component/sub-router.ts | 2 +-
5 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/frontend/src/app/component/page/department/department.component.html b/frontend/src/app/component/page/department/department.component.html
index 8386297..306ae17 100644
--- a/frontend/src/app/component/page/department/department.component.html
+++ b/frontend/src/app/component/page/department/department.component.html
@@ -1,5 +1,5 @@
-
+
@@ -7,7 +7,7 @@
Search
-
@@ -34,11 +34,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/department/department.component.ts b/frontend/src/app/component/page/department/department.component.ts
index e066d3b..83400dd 100644
--- a/frontend/src/app/component/page/department/department.component.ts
+++ b/frontend/src/app/component/page/department/department.component.ts
@@ -12,6 +12,8 @@ import moment from 'moment'
import { DepartmentForm } from './interface'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzPaginationModule } from 'ng-zorro-antd/pagination'
+import { UserStoreService } from '../../../../state/user.service'
+import { findMenuItem } from '../../tool-function'
@Component({
// selector: 'app-footer',
@@ -22,8 +24,29 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
})
export class DepartmentComponent {
constructor(
- private message: NzMessageService
- ) {}
+ private message: NzMessageService,
+ private userStoreService: UserStoreService
+ ) {
+
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
page: 1,
diff --git a/frontend/src/app/component/page/menu/menu.component.html b/frontend/src/app/component/page/menu/menu.component.html
index 1d56427..6c0d341 100644
--- a/frontend/src/app/component/page/menu/menu.component.html
+++ b/frontend/src/app/component/page/menu/menu.component.html
@@ -1,5 +1,5 @@
-
+
@@ -7,7 +7,7 @@
Search
-
@@ -33,6 +33,7 @@
Edit
diff --git a/frontend/src/app/component/page/menu/menu.component.ts b/frontend/src/app/component/page/menu/menu.component.ts
index 53c5d27..90a543f 100644
--- a/frontend/src/app/component/page/menu/menu.component.ts
+++ b/frontend/src/app/component/page/menu/menu.component.ts
@@ -13,6 +13,8 @@ import { NzSelectModule } from 'ng-zorro-antd/select'
import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
import { NzRadioModule } from 'ng-zorro-antd/radio'
import { NzMessageService } from 'ng-zorro-antd/message'
+import { findMenuItem } from '../../tool-function'
+import { UserStoreService } from '../../../../state/user.service'
@Component({
standalone: true,
@@ -34,14 +36,35 @@ import { NzMessageService } from 'ng-zorro-antd/message'
})
export class MenuListComponent implements OnInit {
constructor(
- private message: NzMessageService
- ) {}
+ private message: NzMessageService,
+ private userStoreService: UserStoreService
+ ) {
+
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+ }
ngOnInit(): void {
this.loadSysMenuLists()
this.loadMainItemLists()
}
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
+
listOfData = [
{
id: '1',
diff --git a/frontend/src/app/component/sub-router.ts b/frontend/src/app/component/sub-router.ts
index 048b977..6043580 100644
--- a/frontend/src/app/component/sub-router.ts
+++ b/frontend/src/app/component/sub-router.ts
@@ -80,7 +80,7 @@ export const pagesRoutes: Routes = [
canActivate: [AuthGuard]
},
{
- path: 'department',
+ path: 'departments',
component: DepartmentComponent,
canActivate: [AuthGuard]
},
From 9209f510402ddc2cc32b7d0be51672f754e723f4 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 19:33:19 -0400
Subject: [PATCH 005/127] bugs fix
---
backend/src/module/sys-role/role.schame.ts | 2 +-
backend/src/module/sys-role/role.service.ts | 32 +++++++++++--------
.../src/app/component/page/role/interface.ts | 4 +--
.../app/component/page/role/role.component.ts | 2 ++
4 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/backend/src/module/sys-role/role.schame.ts b/backend/src/module/sys-role/role.schame.ts
index 24483a7..9e10637 100644
--- a/backend/src/module/sys-role/role.schame.ts
+++ b/backend/src/module/sys-role/role.schame.ts
@@ -15,7 +15,7 @@ export class SysRole extends BaseSchema {
remark?: string
@Prop({ type: SchemaTypes.Mixed })
- menuIds?: any
+ menuIds: any
@Prop({ type: SchemaTypes.Boolean })
read: boolean
diff --git a/backend/src/module/sys-role/role.service.ts b/backend/src/module/sys-role/role.service.ts
index b35b2ce..026ac90 100644
--- a/backend/src/module/sys-role/role.service.ts
+++ b/backend/src/module/sys-role/role.service.ts
@@ -239,7 +239,7 @@ export class SysRoleService {
return await this.sysRoleModel.findOne({ name, code, status: 1})
}
- async loadRoleWithMenu(roleIds: string[]) {
+ async loadRoleWithMenu(roleIds: any) {
const objectIds = roleIds.map(id => {
if (id && Types.ObjectId.isValid(id)) {
return new Types.ObjectId(id);
@@ -283,19 +283,25 @@ export class SysRoleService {
{
$addFields: {
"menuLists": {
- $map: {
- input: "$menuLists",
- as: "menu",
- in: {
- $mergeObjects: [
- "$$menu",
- {
- read: "$read",
- write: "$write",
- delete: "$delete",
- update: "$update"
+ $cond: {
+ if: { $eq: ["$menuLists", []] },
+ then: [],
+ else: {
+ $map: {
+ input: "$menuLists",
+ as: "menu",
+ in: {
+ $mergeObjects: [
+ "$$menu",
+ {
+ read: "$read",
+ write: "$write",
+ delete: "$delete",
+ update: "$update"
+ }
+ ]
}
- ]
+ }
}
}
}
diff --git a/frontend/src/app/component/page/role/interface.ts b/frontend/src/app/component/page/role/interface.ts
index 1813df7..6649b18 100644
--- a/frontend/src/app/component/page/role/interface.ts
+++ b/frontend/src/app/component/page/role/interface.ts
@@ -2,8 +2,8 @@ export interface RoleForm {
_id?: string,
name: string
code: string
- remark?: string
- meunIds?: number[]
+ remark: string
+ menuIds: string[]
read: boolean
write: boolean
delete: boolean
diff --git a/frontend/src/app/component/page/role/role.component.ts b/frontend/src/app/component/page/role/role.component.ts
index 05ba70b..218ed47 100644
--- a/frontend/src/app/component/page/role/role.component.ts
+++ b/frontend/src/app/component/page/role/role.component.ts
@@ -75,6 +75,7 @@ export class RoleComponent implements OnInit{
code: '',
name: '',
remark: '',
+ menuIds: [],
read: false,
write: false,
delete: false,
@@ -112,6 +113,7 @@ export class RoleComponent implements OnInit{
code: '',
name: '',
remark: '',
+ menuIds: [],
read: false,
write: false,
delete: false,
From 582cf9cb0f8dad8cc611b9a9d75a3b45d3b6b3bb Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 21:46:45 -0400
Subject: [PATCH 006/127] add user access control
---
.../action-record.component.html | 2 +-
.../action-record/action-record.component.ts | 24 ++++++++++++-----
.../inventory-record.component.html | 2 +-
.../inventory-record.component.ts | 20 +++++++++++---
.../stock-take-form.component.html | 2 +-
.../stock-take-form.component.ts | 26 +++++++++++++++++--
.../stock-take-list.component.html | 9 ++++---
.../stock-take-list.component.ts | 26 +++++++++++++++++--
8 files changed, 90 insertions(+), 21 deletions(-)
diff --git a/frontend/src/app/component/page/action-record/action-record.component.html b/frontend/src/app/component/page/action-record/action-record.component.html
index 8c839d6..2a02ed2 100644
--- a/frontend/src/app/component/page/action-record/action-record.component.html
+++ b/frontend/src/app/component/page/action-record/action-record.component.html
@@ -1,5 +1,5 @@
-
+
{
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false
+ }
searchForm: any = {
page: 1,
diff --git a/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.html b/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.html
index e2620c6..7618b74 100644
--- a/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.html
+++ b/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.html
@@ -1,5 +1,5 @@
-
+
diff --git a/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts b/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts
index b015d24..75d8164 100644
--- a/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts
+++ b/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts
@@ -13,6 +13,8 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
import { Router } from '@angular/router'
import { NzSelectModule } from 'ng-zorro-antd/select'
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
+import { UserStoreService } from '../../../../../state/user.service'
+import { findMenuItem } from '../../../tool-function'
@Component({
// selector: 'app-footer',
@@ -34,10 +36,20 @@ import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
})
export class InventoryRecordListComponent {
constructor(
- private message: NzMessageService,
- private modalService: NzModalService,
- private routeTo: Router
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false
+ }
searchForm: any = {
page: 1,
diff --git a/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.html b/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.html
index 561092b..731fbe6 100644
--- a/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.html
+++ b/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.html
@@ -1,5 +1,5 @@
-
+
diff --git a/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts b/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts
index 5d3e29e..b760eb1 100644
--- a/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts
+++ b/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts
@@ -18,6 +18,8 @@ import { getApiWithAuth, postApiWithAuth } from '../../../../../tool/httpRequest
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
import { MatButtonModule } from '@angular/material/button'
import { MatIconModule } from '@angular/material/icon'
+import { UserStoreService } from '../../../../../state/user.service'
+import { findMenuItem } from '../../../tool-function'
@Component({
standalone: true,
@@ -44,8 +46,28 @@ export class StockTakeFormComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private routeTo: Router,
- private message: NzMessageService
- ) {}
+ private message: NzMessageService,
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
theId: any = ''
diff --git a/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.html b/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.html
index 39a62b7..f118107 100644
--- a/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.html
+++ b/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.html
@@ -1,5 +1,5 @@
-
+
@@ -20,7 +20,7 @@
Search
-
@@ -61,18 +61,19 @@
Detail
Cancel
Finished
diff --git a/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts b/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts
index 4a206a2..c4b9923 100644
--- a/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts
+++ b/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts
@@ -15,6 +15,8 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'
import { NzSelectModule } from 'ng-zorro-antd/select'
import { StockTakeForm } from './interface'
+import { findMenuItem } from '../../../tool-function'
+import { UserStoreService } from '../../../../../state/user.service'
@Component({
standalone: true,
@@ -37,14 +39,34 @@ import { StockTakeForm } from './interface'
export class StockTakeListComponent implements OnInit{
constructor(
private message: NzMessageService,
- private routeTo: Router
- ) {}
+ private routeTo: Router,
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+ }
ngOnInit(): void {
this.loadLocationList()
this.loadStockTakeLists()
}
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
+
dataLists: any[] = []
totals: number = 0
handleId: string = ''
From 83df37a2c877c6c7bb4f515111b1eb09d5795008 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 21:49:45 -0400
Subject: [PATCH 007/127] update user access control
---
.../asset-list-all.component.html | 2 +-
.../asset-list-all.component.ts | 19 ++++++++++++++++---
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.html b/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.html
index f344e84..adccbe3 100644
--- a/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.html
+++ b/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.html
@@ -1,5 +1,5 @@
-
+
Asset List Report
diff --git a/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts b/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts
index e0b6a9c..346b4fa 100644
--- a/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts
+++ b/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts
@@ -12,6 +12,8 @@ import { NzMessageService } from 'ng-zorro-antd/message'
import { NzPaginationModule } from 'ng-zorro-antd/pagination'
import { Router } from '@angular/router'
import { NzSelectModule } from 'ng-zorro-antd/select'
+import { UserStoreService } from '../../../../../state/user.service'
+import { findMenuItem } from '../../../tool-function'
@Component({
// selector: 'app-footer',
@@ -32,10 +34,21 @@ import { NzSelectModule } from 'ng-zorro-antd/select'
})
export class AssetListAllComponent {
constructor(
- private message: NzMessageService,
- private modalService: NzModalService,
+ private userStoreService: UserStoreService,
private routeTo: Router
- ) {}
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false
+ }
searchForm: any = {
page: 1,
From 1ce61650e772700127a7ef447d8e9963eb83356b Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 22:03:33 -0400
Subject: [PATCH 008/127] update user access control
---
.../action-record/action-record.component.ts | 2 +-
.../asset-list-all.component.ts | 2 +-
.../asset-type/asset-type.component.html | 6 +++--
.../asset/asset-type/asset-type.component.ts | 27 +++++++++++++++++--
.../inventory-record.component.ts | 2 +-
.../page/dashboard/dashboard.component.ts | 18 +++++++++++++
.../page/department/department.component.ts | 2 +-
.../component/page/menu/menu.component.html | 1 +
.../app/component/page/menu/menu.component.ts | 2 +-
.../stock-take-form.component.ts | 2 +-
.../stock-take-list.component.ts | 2 +-
.../page/vendor/vendor.component.html | 6 +++--
.../component/page/vendor/vendor.component.ts | 25 +++++++++++++++--
13 files changed, 82 insertions(+), 15 deletions(-)
diff --git a/frontend/src/app/component/page/action-record/action-record.component.ts b/frontend/src/app/component/page/action-record/action-record.component.ts
index ed5e1d2..5f78298 100644
--- a/frontend/src/app/component/page/action-record/action-record.component.ts
+++ b/frontend/src/app/component/page/action-record/action-record.component.ts
@@ -25,7 +25,7 @@ export class ActionRecordComponent {
private userStoreService: UserStoreService
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Action Log', 'action-record')
this.userRightInside = {
read: answer.read
diff --git a/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts b/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts
index 346b4fa..2ade908 100644
--- a/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts
+++ b/frontend/src/app/component/page/asset/asset-list-all/asset-list-all.component.ts
@@ -38,7 +38,7 @@ export class AssetListAllComponent {
private routeTo: Router
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Asset List Report', 'asset-list-all')
this.userRightInside = {
read: answer.read
diff --git a/frontend/src/app/component/page/asset/asset-type/asset-type.component.html b/frontend/src/app/component/page/asset/asset-type/asset-type.component.html
index 1e69293..b50afc0 100644
--- a/frontend/src/app/component/page/asset/asset-type/asset-type.component.html
+++ b/frontend/src/app/component/page/asset/asset-type/asset-type.component.html
@@ -1,5 +1,5 @@
-
+
@@ -7,7 +7,7 @@
Search
-
@@ -36,11 +36,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts b/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
index 47a6657..a8cedc0 100644
--- a/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
+++ b/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
@@ -12,6 +12,8 @@ import { AssetTypeForm } from './interface'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzPaginationModule } from 'ng-zorro-antd/pagination'
import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
+import { UserStoreService } from '../../../../../state/user.service'
+import { findMenuItem } from '../../../tool-function'
@Component({
// selector: 'app-footer',
@@ -33,8 +35,29 @@ import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
export class AssetTypeComponent {
constructor(
private message: NzMessageService,
- private modalService: NzModalService
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'User', 'users')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
page: 1,
diff --git a/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts b/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts
index 75d8164..9816ebd 100644
--- a/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts
+++ b/frontend/src/app/component/page/asset/inventory-record/inventory-record.component.ts
@@ -39,7 +39,7 @@ export class InventoryRecordListComponent {
private userStoreService: UserStoreService
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Inventory Record', 'inventory-record')
this.userRightInside = {
read: answer.read
diff --git a/frontend/src/app/component/page/dashboard/dashboard.component.ts b/frontend/src/app/component/page/dashboard/dashboard.component.ts
index 1b9ea72..a406abf 100644
--- a/frontend/src/app/component/page/dashboard/dashboard.component.ts
+++ b/frontend/src/app/component/page/dashboard/dashboard.component.ts
@@ -15,6 +15,8 @@ import { CanvasChartComponent } from '../../components/chart/chart.component'
import { transformData, transformDataNoDate } from './function'
import { NzSelectModule } from 'ng-zorro-antd/select'
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
+import { UserStoreService } from '../../../../state/user.service'
+import { findMenuItem } from '../../tool-function'
@Component({
standalone: true,
@@ -35,6 +37,22 @@ import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
styleUrl: './dashboard.component.css',
})
export class DashboardComponent implements OnInit {
+ constructor(
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Dashboard', 'dashboard')
+
+ this.userRightInside = {
+ read: answer.read
+ }
+ })
+ }
+
+ userRightInside = {
+ read: false
+ }
+
ngOnInit(): void {
this.getByDeptAndDateOfCosts()
this.getByDeptAndDateOfCount()
diff --git a/frontend/src/app/component/page/department/department.component.ts b/frontend/src/app/component/page/department/department.component.ts
index 83400dd..afa8fee 100644
--- a/frontend/src/app/component/page/department/department.component.ts
+++ b/frontend/src/app/component/page/department/department.component.ts
@@ -29,7 +29,7 @@ export class DepartmentComponent {
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Department', 'departments')
this.userRightInside = {
read: answer.read,
diff --git a/frontend/src/app/component/page/menu/menu.component.html b/frontend/src/app/component/page/menu/menu.component.html
index 6c0d341..0566f8c 100644
--- a/frontend/src/app/component/page/menu/menu.component.html
+++ b/frontend/src/app/component/page/menu/menu.component.html
@@ -53,6 +53,7 @@
Edit
diff --git a/frontend/src/app/component/page/menu/menu.component.ts b/frontend/src/app/component/page/menu/menu.component.ts
index 90a543f..c0bd815 100644
--- a/frontend/src/app/component/page/menu/menu.component.ts
+++ b/frontend/src/app/component/page/menu/menu.component.ts
@@ -41,7 +41,7 @@ export class MenuListComponent implements OnInit {
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Menu', 'menu')
this.userRightInside = {
read: answer.read,
diff --git a/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts b/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts
index b760eb1..b838380 100644
--- a/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts
+++ b/frontend/src/app/component/page/stock-take/stock-take-form/stock-take-form.component.ts
@@ -50,7 +50,7 @@ export class StockTakeFormComponent implements OnInit {
private userStoreService: UserStoreService
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Stock Take', 'stock-takes')
this.userRightInside = {
read: answer.read,
diff --git a/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts b/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts
index c4b9923..771f839 100644
--- a/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts
+++ b/frontend/src/app/component/page/stock-take/stock-take-list/stock-take-list.component.ts
@@ -43,7 +43,7 @@ export class StockTakeListComponent implements OnInit{
private userStoreService: UserStoreService
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Stock Take', 'stock-takes')
this.userRightInside = {
read: answer.read,
diff --git a/frontend/src/app/component/page/vendor/vendor.component.html b/frontend/src/app/component/page/vendor/vendor.component.html
index e4bb26d..963d317 100644
--- a/frontend/src/app/component/page/vendor/vendor.component.html
+++ b/frontend/src/app/component/page/vendor/vendor.component.html
@@ -1,5 +1,5 @@
-
+
@@ -17,7 +17,7 @@
Search
-
@@ -48,11 +48,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/vendor/vendor.component.ts b/frontend/src/app/component/page/vendor/vendor.component.ts
index fae0fc8..ea867fe 100644
--- a/frontend/src/app/component/page/vendor/vendor.component.ts
+++ b/frontend/src/app/component/page/vendor/vendor.component.ts
@@ -11,6 +11,8 @@ import moment from 'moment'
import { VendorForm } from './interface'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzPaginationModule } from 'ng-zorro-antd/pagination'
+import { findMenuItem } from '../../tool-function'
+import { UserStoreService } from '../../../../state/user.service'
@Component({
// selector: 'app-footer',
@@ -22,8 +24,27 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
export class VendorComponent {
constructor(
private message: NzMessageService,
- private modalService: NzModalService
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Vendor', 'vendor')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
page: 1,
From 7749b78be29f69d025b0f3177170b7e7e1d415d2 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 22:11:56 -0400
Subject: [PATCH 009/127] add user access function control
---
.../page/budget/budget.component.html | 7 +++---
.../component/page/budget/budget.component.ts | 25 +++++++++++++++++--
.../page/code-type/code-type.component.html | 6 +++--
.../page/code-type/code-type.component.ts | 25 +++++++++++++++++--
.../page/department/department.component.html | 2 +-
.../page/location/location.component.html | 6 +++--
.../page/location/location.component.ts | 25 +++++++++++++++++--
7 files changed, 82 insertions(+), 14 deletions(-)
diff --git a/frontend/src/app/component/page/budget/budget.component.html b/frontend/src/app/component/page/budget/budget.component.html
index 5782cf8..a9f8e88 100644
--- a/frontend/src/app/component/page/budget/budget.component.html
+++ b/frontend/src/app/component/page/budget/budget.component.html
@@ -1,5 +1,5 @@
-
+
@@ -47,7 +47,7 @@
Search
-
@@ -82,12 +82,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/budget/budget.component.ts b/frontend/src/app/component/page/budget/budget.component.ts
index a25d9c7..13bf73c 100644
--- a/frontend/src/app/component/page/budget/budget.component.ts
+++ b/frontend/src/app/component/page/budget/budget.component.ts
@@ -14,6 +14,8 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
import { NzSelectModule } from 'ng-zorro-antd/select'
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
+import { findMenuItem } from '../../tool-function'
+import { UserStoreService } from '../../../../state/user.service'
@Component({
// selector: 'app-footer',
@@ -37,8 +39,27 @@ import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
export class BudgetComponent {
constructor(
private message: NzMessageService,
- private modalService: NzModalService
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Budget', 'budget')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
date: [],
diff --git a/frontend/src/app/component/page/code-type/code-type.component.html b/frontend/src/app/component/page/code-type/code-type.component.html
index 1e351e7..a2d9805 100644
--- a/frontend/src/app/component/page/code-type/code-type.component.html
+++ b/frontend/src/app/component/page/code-type/code-type.component.html
@@ -1,5 +1,5 @@
-
+
@@ -7,7 +7,7 @@
Search
-
@@ -36,11 +36,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/code-type/code-type.component.ts b/frontend/src/app/component/page/code-type/code-type.component.ts
index 629bace..af66ce3 100644
--- a/frontend/src/app/component/page/code-type/code-type.component.ts
+++ b/frontend/src/app/component/page/code-type/code-type.component.ts
@@ -11,6 +11,8 @@ import moment from 'moment'
import { CodeTypeForm } from './interface'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzPaginationModule } from 'ng-zorro-antd/pagination'
+import { findMenuItem } from '../../tool-function'
+import { UserStoreService } from '../../../../state/user.service'
@Component({
// selector: 'app-footer',
@@ -22,8 +24,27 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
export class CodeTypeComponent {
constructor(
private message: NzMessageService,
- private modalService: NzModalService
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Code Type', 'code-type')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
page: 1,
diff --git a/frontend/src/app/component/page/department/department.component.html b/frontend/src/app/component/page/department/department.component.html
index 306ae17..f316eb0 100644
--- a/frontend/src/app/component/page/department/department.component.html
+++ b/frontend/src/app/component/page/department/department.component.html
@@ -34,7 +34,7 @@
Edit
diff --git a/frontend/src/app/component/page/location/location.component.html b/frontend/src/app/component/page/location/location.component.html
index dd223f0..f48e14f 100644
--- a/frontend/src/app/component/page/location/location.component.html
+++ b/frontend/src/app/component/page/location/location.component.html
@@ -1,5 +1,5 @@
-
+
@@ -7,7 +7,7 @@
Search
-
@@ -34,11 +34,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/location/location.component.ts b/frontend/src/app/component/page/location/location.component.ts
index 15e6448..6df903b 100644
--- a/frontend/src/app/component/page/location/location.component.ts
+++ b/frontend/src/app/component/page/location/location.component.ts
@@ -12,6 +12,8 @@ import moment from 'moment'
import { LocationForm } from './interface'
import { NzMessageService } from 'ng-zorro-antd/message'
import { NzPaginationModule } from 'ng-zorro-antd/pagination'
+import { UserStoreService } from '../../../../state/user.service'
+import { findMenuItem } from '../../tool-function'
@Component({
// selector: 'app-footer',
@@ -22,8 +24,27 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
})
export class LocationComponent {
constructor(
- private message: NzMessageService
- ) {}
+ private message: NzMessageService,
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Location', 'location')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
page: 1,
From 34ddc2afd2f2a90f185f85320ae409030c0f17aa Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 22:14:19 -0400
Subject: [PATCH 010/127] add user access function control
---
.../tax-information.component.html | 7 +++---
.../tax-information.component.ts | 24 +++++++++++++++++--
2 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/frontend/src/app/component/page/tax-information/tax-information.component.html b/frontend/src/app/component/page/tax-information/tax-information.component.html
index 1cddc46..fd48945 100644
--- a/frontend/src/app/component/page/tax-information/tax-information.component.html
+++ b/frontend/src/app/component/page/tax-information/tax-information.component.html
@@ -1,5 +1,5 @@
-
+
@@ -10,7 +10,7 @@
Search
-
@@ -45,12 +45,13 @@
Edit
Delete
diff --git a/frontend/src/app/component/page/tax-information/tax-information.component.ts b/frontend/src/app/component/page/tax-information/tax-information.component.ts
index c50843b..176a1ae 100644
--- a/frontend/src/app/component/page/tax-information/tax-information.component.ts
+++ b/frontend/src/app/component/page/tax-information/tax-information.component.ts
@@ -14,6 +14,8 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'
import { NzSelectModule } from 'ng-zorro-antd/select'
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
+import { findMenuItem } from '../../tool-function'
+import { UserStoreService } from '../../../../state/user.service'
@Component({
// selector: 'app-footer',
@@ -37,8 +39,26 @@ import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
export class TaxInformationComponent {
constructor(
private message: NzMessageService,
- private modalService: NzModalService
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Tax Information', 'tax-information')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
date: [],
From ea00799538008df2977512ee82dbe21452636c42 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 22:15:01 -0400
Subject: [PATCH 011/127] fix
---
.../app/component/page/asset/asset-type/asset-type.component.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts b/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
index a8cedc0..744f5c4 100644
--- a/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
+++ b/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
@@ -39,7 +39,7 @@ export class AssetTypeComponent {
) {
this.userStoreService.menuRole$.subscribe((data: any) => {
- const answer = findMenuItem(data, 'User', 'users')
+ const answer = findMenuItem(data, 'Asset Type', 'asset-type')
this.userRightInside = {
read: answer.read,
From 4f52f7044eb8821bb97021348edda0bfad530231 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 22:34:44 -0400
Subject: [PATCH 012/127] ADD user access control
---
.../asset-form/asset-form.component.html | 2 +-
.../asset/asset-form/asset-form.component.ts | 18 ++++++++++--
.../asset-list/asset-list.component.html | 7 +++--
.../asset/asset-list/asset-list.component.ts | 28 +++++++++++++++----
.../asset/asset-type/asset-type.component.ts | 1 -
.../repair-record-create.component.ts | 4 +--
.../repair-record-list.component.html | 6 ++--
.../repair-record-list.component.ts | 25 +++++++++++++++--
.../write-off-form.component.html | 2 +-
.../write-off-form.component.ts | 24 ++++++++++++++--
.../write-off-list.component.html | 2 +-
.../write-off-list.component.ts | 27 +++++++++++++++---
12 files changed, 119 insertions(+), 27 deletions(-)
diff --git a/frontend/src/app/component/page/asset/asset-form/asset-form.component.html b/frontend/src/app/component/page/asset/asset-form/asset-form.component.html
index a36cdbf..8a71e5c 100644
--- a/frontend/src/app/component/page/asset/asset-form/asset-form.component.html
+++ b/frontend/src/app/component/page/asset/asset-form/asset-form.component.html
@@ -1,5 +1,5 @@
-
+
diff --git a/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts b/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts
index bba58a2..c25698a 100644
--- a/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts
+++ b/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts
@@ -23,6 +23,8 @@ import { NzUploadChangeParam, NzUploadFile, NzUploadModule } from 'ng-zorro-antd
import { NzIconModule } from 'ng-zorro-antd/icon'
import { uploadImgToBase64 } from '../../../../../tool/imageUpload'
import { FileViewComponent } from '../../../components/file-view-dialog/file-view-dialog.component'
+import { findMenuItem } from '../../../tool-function'
+import { UserStoreService } from '../../../../../state/user.service'
// import { UploadComponentComponent } from '../../../components/upload-component/upload-component.component'
@Component({
@@ -57,14 +59,26 @@ export class AssetFormComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private routeTo: Router,
- private message: NzMessageService
+ private message: NzMessageService,
+ private userStoreService: UserStoreService
) {
this.changeEvent$.pipe(debounceTime(300)).subscribe(event => {
this.preAction(event.file.originFileObj);
})
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Asset List', 'asset-lists')
+
+ this.userRightInside = {
+ write: answer.write,
+ update: answer.update
+ }
+ })
}
-
+ userRightInside: any = {
+ write: false,
+ update: false
+ }
private changeEvent$ = new Subject ()
diff --git a/frontend/src/app/component/page/asset/asset-list/asset-list.component.html b/frontend/src/app/component/page/asset/asset-list/asset-list.component.html
index 69872a0..9d8eaa6 100644
--- a/frontend/src/app/component/page/asset/asset-list/asset-list.component.html
+++ b/frontend/src/app/component/page/asset/asset-list/asset-list.component.html
@@ -1,5 +1,5 @@
-
+
Search
-
@@ -95,6 +95,7 @@
Repiar
@@ -105,11 +106,13 @@
QR Tag
Edit
Write Off
diff --git a/frontend/src/app/component/page/asset/asset-list/asset-list.component.ts b/frontend/src/app/component/page/asset/asset-list/asset-list.component.ts
index b4afd92..9248dc1 100644
--- a/frontend/src/app/component/page/asset/asset-list/asset-list.component.ts
+++ b/frontend/src/app/component/page/asset/asset-list/asset-list.component.ts
@@ -8,13 +8,14 @@ import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal'
import { NzInputModule } from 'ng-zorro-antd/input'
import { NzFormModule } from 'ng-zorro-antd/form'
import moment from 'moment'
-import { NzMessageService } from 'ng-zorro-antd/message'
import { NzPaginationModule } from 'ng-zorro-antd/pagination'
import { Router } from '@angular/router'
import { NzSelectModule } from 'ng-zorro-antd/select'
import { QRcodeComponent } from '../../../components/qr-code/qr-code.component'
import { RepairRecordCreateComponent } from '../repair-record-create/repair-record-create.component'
import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
+import { UserStoreService } from '../../../../../state/user.service'
+import { findMenuItem } from '../../../tool-function'
@Component({
// selector: 'app-footer',
@@ -38,16 +39,33 @@ import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'
})
export class AssetListComponent {
constructor(
- private message: NzMessageService,
- private modalService: NzModalService,
- private routeTo: Router
- ) {}
+ private routeTo: Router,
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Asset List', 'asset-lists')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
searchForm: any = {
page: 1,
limit: 10
}
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
+
dataLists: any[] = []
totals: number = 0
diff --git a/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts b/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
index 744f5c4..3708db3 100644
--- a/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
+++ b/frontend/src/app/component/page/asset/asset-type/asset-type.component.ts
@@ -47,7 +47,6 @@ export class AssetTypeComponent {
update: answer.update,
delete: answer.delete
}
- console.log(this.userRightInside, 'answer')
})
}
diff --git a/frontend/src/app/component/page/asset/repair-record-create/repair-record-create.component.ts b/frontend/src/app/component/page/asset/repair-record-create/repair-record-create.component.ts
index 30dd23a..9ad2cc3 100644
--- a/frontend/src/app/component/page/asset/repair-record-create/repair-record-create.component.ts
+++ b/frontend/src/app/component/page/asset/repair-record-create/repair-record-create.component.ts
@@ -47,9 +47,7 @@ export class RepairRecordCreateComponent implements OnInit {
private route: ActivatedRoute,
private routeTo: Router,
private message: NzMessageService
- ) {
-
- }
+ ) {}
editForm: AssetFormDto = {
_id: '',
diff --git a/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.html b/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.html
index 3cd90ca..ea11811 100644
--- a/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.html
+++ b/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.html
@@ -1,5 +1,5 @@
-
+
Edit
Void
@@ -79,7 +81,7 @@
(nzOnOk)="goToWriteOff()"
>
- Are you sure to confirm write off this asset?
+ Are you sure to confirm remove this record?
diff --git a/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.ts b/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.ts
index 170a019..82f8e30 100644
--- a/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.ts
+++ b/frontend/src/app/component/page/asset/repair-record-list/repair-record-list.component.ts
@@ -17,6 +17,8 @@ import { UpdateRepairRecordDto } from './interface'
import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'
import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
import { timer } from 'rxjs'
+import { UserStoreService } from '../../../../../state/user.service'
+import { findMenuItem } from '../../../tool-function'
@Component({
// selector: 'app-footer',
@@ -41,9 +43,26 @@ import { timer } from 'rxjs'
export class RepairRecordListComponent {
constructor(
private message: NzMessageService,
- private modalService: NzModalService,
- private routeTo: Router
- ) {}
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Repair Record', 'repair-records')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
page: 1,
diff --git a/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.html b/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.html
index 0174719..e86821d 100644
--- a/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.html
+++ b/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.html
@@ -1,5 +1,5 @@
-
+
diff --git a/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.ts b/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.ts
index de1725f..c523ed9 100644
--- a/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.ts
+++ b/frontend/src/app/component/page/asset/write-off-form/write-off-form.component.ts
@@ -19,6 +19,8 @@ import { ActivatedRoute, Router } from '@angular/router'
import { timer } from 'rxjs'
import { MatButtonModule } from '@angular/material/button'
import { MatIconModule } from '@angular/material/icon'
+import { UserStoreService } from '../../../../../state/user.service'
+import { findMenuItem } from '../../../tool-function'
@Component({
// selector: 'app-footer',
@@ -47,8 +49,26 @@ export class WriteOffFormComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private routeTo: Router,
- private message: NzMessageService
- ) {}
+ private message: NzMessageService,
+ private userStoreService: UserStoreService
+ ) {
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Asset List', 'asset-lists')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
editForm: AssetFormDto = {
_id: '',
diff --git a/frontend/src/app/component/page/asset/write-off-list/write-off-list.component.html b/frontend/src/app/component/page/asset/write-off-list/write-off-list.component.html
index 1045bb9..f77c1be 100644
--- a/frontend/src/app/component/page/asset/write-off-list/write-off-list.component.html
+++ b/frontend/src/app/component/page/asset/write-off-list/write-off-list.component.html
@@ -1,5 +1,5 @@
-
+
{
+ const answer = findMenuItem(data, 'Write Off Record', 'write-off-list')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
searchForm: any = {
page: 1,
From a66abb547aec903a848e6a77f6ae290e49efa4e9 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 22:59:50 -0400
Subject: [PATCH 013/127] remove useless files
---
frontend/src/app/state/CartsStoreService.ts | 37 ---------
.../src/app/state/PromotionStoreService.ts | 37 ---------
frontend/src/app/state/interfaceType.ts | 82 -------------------
3 files changed, 156 deletions(-)
delete mode 100644 frontend/src/app/state/CartsStoreService.ts
delete mode 100644 frontend/src/app/state/PromotionStoreService.ts
delete mode 100644 frontend/src/app/state/interfaceType.ts
diff --git a/frontend/src/app/state/CartsStoreService.ts b/frontend/src/app/state/CartsStoreService.ts
deleted file mode 100644
index 3e91f1a..0000000
--- a/frontend/src/app/state/CartsStoreService.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Injectable } from '@angular/core'
-import { BehaviorSubject } from 'rxjs'
-import { CartStateFace, Promotion, CartFace } from './interfaceType'
-
-@Injectable({
- providedIn: 'root'
-})
-export class CartsStoreService {
- private initialState: CartStateFace = { list: [] }
- private cartSubject = new BehaviorSubject< CartStateFace>(this.initialState)
- carts$ = this.cartSubject.asObservable()
-
- get carts(): CartFace[] {
- return this.cartSubject.value.list
- }
-
- setPromotions(carts: CartFace[]): void {
- this.cartSubject.next({ list: carts })
- }
-
- addPromotion(promotion: CartFace): void {
- const updatedList = [...this.carts, promotion]
- this.cartSubject.next({ list: updatedList })
- }
-
- updatePromotion(productId: number, cartSubject: Partial): void {
- const updatedList = this.carts.map(promo =>
- promo.productId === productId ? { ...promo, ...cartSubject } : promo
- )
- this.cartSubject.next({ list: updatedList })
- }
-
- deletePromotion(productId: number): void {
- const updatedList = this.carts.filter(promo => promo.productId !== productId);
- this.cartSubject.next({ list: updatedList })
- }
-}
\ No newline at end of file
diff --git a/frontend/src/app/state/PromotionStoreService.ts b/frontend/src/app/state/PromotionStoreService.ts
deleted file mode 100644
index b9f619c..0000000
--- a/frontend/src/app/state/PromotionStoreService.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Injectable } from '@angular/core'
-import { BehaviorSubject } from 'rxjs'
-import { Promotion, PromotionStateFace } from './interfaceType'
-import { getApi } from '../tool/http/httpRequest';
-
-@Injectable({
- providedIn: 'root'
-})
-export class PromotionStoreService {
- private initialState: PromotionStateFace = { list: [] }
-
- private promotionsSubject = new BehaviorSubject(this.initialState);
- promotions$ = this.promotionsSubject.asObservable()
-
- get promotions(): Promotion[] {
- return this.promotionsSubject.value.list
- }
-
- setPromotions(promotions: Promotion[]): void {
- this.promotionsSubject.next({ list: promotions })
- }
-
- addPromotion(promotion: Promotion): void {
- const updatedList = [...this.promotions, promotion]
- this.promotionsSubject.next({ list: updatedList })
- }
-
- deletePromotion(id: number): void {
- const updatedList = this.promotions.filter(promo => promo.id !== id);
- this.promotionsSubject.next({ list: updatedList })
- }
-
- async loadPromotionData(): Promise {
- const res = await getApi('/base/promotion/store/list')
- this.setPromotions(res.data)
- }
-}
\ No newline at end of file
diff --git a/frontend/src/app/state/interfaceType.ts b/frontend/src/app/state/interfaceType.ts
deleted file mode 100644
index bbbd409..0000000
--- a/frontend/src/app/state/interfaceType.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-export interface PromotionDepartmentItems {
- id: number
- promotionId: number
- deptId: number
- deptIdCode: string
- deptIdName: string
- promotionName: string
- promotionCode: string
- discountAmount: number
- discountType: string
-}
-
-export interface PromotionTypeItems {
- id: number
- promotionId: number
- typeId: number
- typeCode: string
- typeName: string
- promotionName: string
- promotionCode: string
- discountAmount: number
- discountType: string
-}
-
-export interface Promotion {
- id: number
- promotionName: string
- promotionCode: string
- promotionType: string
- description: string
- periodStart: string
- periodEnd: string
- online: number
- inStore: number
- member: number
- afterBeforeTax: number
- discount: number
- discountType: string
- allOneDiscount: number
- couponRequest: number
- couponMainCode: string
- remark: string
- promotionDepartmentItems: PromotionDepartmentItems[]
- promotionTypeItems: PromotionTypeItems[]
-}
-
-export interface PromotionStateFace {
- list: Promotion[]
-}
-
-export const promotionState: PromotionStateFace = {
- list: []
-}
-
-
-// Carts
-
-export interface CartFace {
- productId: number
- productName: string
- productCode: string
- qty: number
- price: string
- taxRate: number
- taxAmount: number
- finalPrice: number
- typeId: number
- typeName: string
- deptId: number
- deptName: string
- unit: string
- itemCode: string
- brandName: string
-}
-
-export interface CartStateFace {
- list: CartFace[]
-}
-
-export const cartState: CartStateFace = {
- list: []
-}
From 62c6d1a620776de593b90afb71765579940ed4b2 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Fri, 21 Mar 2025 23:28:59 -0400
Subject: [PATCH 014/127] update and remove useless code
---
frontend/src/state/globalData.service.ts | 23 +++++++++++++++++++++++
frontend/src/state/user.service.ts | 7 +++----
2 files changed, 26 insertions(+), 4 deletions(-)
create mode 100644 frontend/src/state/globalData.service.ts
diff --git a/frontend/src/state/globalData.service.ts b/frontend/src/state/globalData.service.ts
new file mode 100644
index 0000000..232cb62
--- /dev/null
+++ b/frontend/src/state/globalData.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core'
+import { BehaviorSubject } from 'rxjs'
+import { getApiWithAuth } from '../tool/httpRequest-auth'
+
+@Injectable({ providedIn: 'root' })
+export class GlobalDataService {
+ private placeListData: any[] = []
+ private placeListDataSubject = new BehaviorSubject(this.placeListData)
+ placeListData$ = this.placeListDataSubject.asObservable()
+
+ setPlaceListData(data: any[]) {
+ this.placeListDataSubject.next(data)
+ }
+
+ async loadPlaceListData() {
+ const dada = await getApiWithAuth('/base/location/getAll')
+ this.setPlaceListData(dada)
+ }
+
+ async loadAllGlobalData() {
+ await this.loadPlaceListData()
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/state/user.service.ts b/frontend/src/state/user.service.ts
index a24e344..6015038 100644
--- a/frontend/src/state/user.service.ts
+++ b/frontend/src/state/user.service.ts
@@ -3,17 +3,14 @@ import { BehaviorSubject } from 'rxjs'
import { UserInfo } from './interface'
import { Router } from '@angular/router'
import { LocalStorageService } from './LocalStorageService'
-import { HttpService } from '../tool/HttpService'
import { getApiWithAuth, postApiWithAuth } from '../tool/httpRequest-auth'
-// import { CartStateFace, Promotion, CartFace } from './interfaceType'
@Injectable({
providedIn: 'root'
})
export class UserStoreService {
constructor(
- private localStorageService: LocalStorageService,
- private httpService: HttpService
+ private localStorageService: LocalStorageService
) {}
router = inject(Router)
@@ -94,6 +91,8 @@ export class UserStoreService {
loginRecords: []
})
+ this.menuSubject.next([])
+ this.menuRoleSubject.next([])
localStorage.clear()
this.tokenSubject.next('')
this.toLoginPage()
From a70906eab874ff26c0d13281d19d079f37fba9f0 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 00:56:21 -0400
Subject: [PATCH 015/127] add xlxs function
---
frontend/package.json | 4 +
frontend/src/tool/excel-helper.ts | 143 +++++++++++++++++++++++++++++
frontend/yarn.lock | 148 +++++++++++++++++++++++++++++-
3 files changed, 294 insertions(+), 1 deletion(-)
create mode 100644 frontend/src/tool/excel-helper.ts
diff --git a/frontend/package.json b/frontend/package.json
index 7b70b08..b787abb 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -37,6 +37,7 @@
"@primeng/themes": "^19.0.9",
"@tailwindcss/postcss": "^4.0.12",
"@techiediaries/ngx-qrcode": "^9.1.0",
+ "@types/file-saver": "^2.0.7",
"@types/plotly.js-dist-min": "^2.3.4",
"angular-plotly.js": "^6.0.0",
"angularx-qrcode": "^19.0.0",
@@ -44,6 +45,7 @@
"echarts": "^5.6.0",
"eva-icons": "^1.1.3",
"express": "^4.21.2",
+ "file-saver": "^2.0.5",
"moment": "^2.30.1",
"ng-lightning": "^9.0.0",
"ng-zorro-antd": "19.1.0",
@@ -55,6 +57,8 @@
"rxjs": "~7.8.2",
"tailwindcss": "^4.0.12",
"tslib": "^2.8.1",
+ "xlsx": "^0.18.5",
+ "xlsx-style": "^0.8.13",
"zone.js": "~0.15.0"
},
"devDependencies": {
diff --git a/frontend/src/tool/excel-helper.ts b/frontend/src/tool/excel-helper.ts
new file mode 100644
index 0000000..52ee367
--- /dev/null
+++ b/frontend/src/tool/excel-helper.ts
@@ -0,0 +1,143 @@
+const XLSX = require('xlsx')
+const XLSXS = require('xlsx-style')
+import { saveAs } from 'file-saver'
+import { NzUploadFile } from 'ng-zorro-antd/upload'
+
+export function readExcelFile(file: NzUploadFile) {
+ return new Promise((resolve: any, reject :any) => {
+ const types = file.name.split('.')[1]
+ const fileType = [
+ 'xlsx',
+ 'xls',
+ 'csv'
+ ].some((item) => item == types )
+
+ if (!fileType) {
+ return reject({ message: 'Format not is Excel!!'})
+ }
+
+ const reader = new FileReader()
+ const result: any = []
+ reader.onload = function (e) {
+ const data = e.target?.result
+ const wb = XLSX.read(data, {
+ type: 'binary'
+ })
+ wb.SheetNames.forEach((sheetName: string) =>{
+ result.push({
+ sheetName,
+ sheet: XLSX.utils.sheet_to_json(wb.Sheets[sheetName])
+ })
+ resolve(result.length > 1 ? result[0]: result[0].sheet)
+ })
+ }
+ reader.onerror = function(error : any) {
+ return reject(error)
+ }
+ reader.readAsArrayBuffer(file.response.Blob)
+ })
+}
+
+export function formatJson (header: any, filterVal: any, jsonData: any) {
+ const updatedArray = jsonData.map((obj: any) => {
+ const newObj: any = {}
+
+ header.forEach((oldKey: string, index: number) => {
+
+ const newKey = filterVal[index]
+ console.log(obj[oldKey])
+ if (obj[oldKey] !== undefined) {
+ newObj[newKey] = obj[oldKey]
+ }
+ })
+ return newObj
+ })
+
+ return updatedArray
+
+ /* return jsonData.map((v: any)=> {
+ const obj: any = {}
+ header.forEach((h, i) => {
+ const anyD: any = [filterVal[i]]
+
+ const newData: any = v[h]
+ console.log(newData, 'data')
+ obj[anyD] = newData
+
+ })
+ return obj
+ }) */
+}
+
+export function formatJsonToSheet(filterVal: any, jsonData: any) {
+ return jsonData.map(v => filterVal.map( j => {
+ return v[j]
+ }))
+}
+
+
+export function downloadTempExcelFile(
+ excelHeader: any,
+ fileName: string,
+ excelStyle?: any,
+ headerColSeetting? : any
+ ) {
+ const ws = XLSX.utils.aoa_to_sheet([excelHeader])
+ if (excelStyle) {
+ if (excelStyle) {
+ for (const [key] of Object.entries(ws)) {
+ if (key !== '!cols' && key !== '!ref') {
+ ws[key].s = excelStyle
+ }
+ }
+ }
+ if(headerColSeetting) {
+ ws['!cols'] = headerColSeetting['!cols']
+ }
+ }
+ XLSX.utils.sheet_add_aoa(ws, [], { origin: 'A2' })
+ let wb = XLSX.utils.book_new()
+ XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
+ const wopts = { bookType: 'xlsx', bookSST: false , type: 'binary' }
+ const fileEx = XLSXS.write(wb, wopts)
+ saveAs(new Blob([s2ab(fileEx)],{type:""}), fileName)
+ }
+ export function saveJsonToExcel(
+ headers: any,
+ data: any,
+ excelHeader: any,
+ fileName: string,
+ excelStyle?: any,
+ headerColSeetting? : any
+ ) {
+ let dataSet = formatJsonToSheet(headers, data)
+ const ws = XLSX.utils.aoa_to_sheet([excelHeader])
+
+ if (excelStyle) {
+ if (excelStyle) {
+ for (const [key] of Object.entries(ws)) {
+ if (key !== '!cols' && key !== '!ref') {
+ ws[key].s = excelStyle
+ }
+ }
+ }
+ if(headerColSeetting) {
+ ws['!cols'] = headerColSeetting['!cols']
+ }
+ }
+ console.log(ws)
+ XLSX.utils.sheet_add_aoa(ws, dataSet, { origin: 'A2' })
+ let wb = XLSX.utils.book_new()
+ XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
+ const wopts = { bookType: 'xlsx', bookSST: false , type: 'binary' }
+ const fileEx = XLSXS.write(wb, wopts)
+ // const fileEx = XLSX.writeFile(wb, fileName)
+ saveAs(new Blob([s2ab(fileEx)],{type:""}), fileName)
+}
+
+function s2ab(s: any) {
+ var buf = new ArrayBuffer(s.length)
+ var view = new Uint8Array(buf)
+ for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
+ return buf
+}
\ No newline at end of file
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index ca80f18..5a44c4a 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -2306,6 +2306,11 @@
"@types/qs" "*"
"@types/serve-static" "*"
+"@types/file-saver@^2.0.7":
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.7.tgz#8dbb2f24bdc7486c54aa854eb414940bbd056f7d"
+ integrity sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==
+
"@types/http-errors@*":
version "2.0.4"
resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz"
@@ -2591,6 +2596,11 @@ adjust-sourcemap-loader@^4.0.0:
loader-utils "^2.0.0"
regex-parser "^2.2.11"
+adler-32@, adler-32@~1.3.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2"
+ integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==
+
agent-base@6:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
@@ -2960,6 +2970,14 @@ caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001688:
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001701.tgz"
integrity sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw==
+cfb@>=0.10.0, cfb@~1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
+ integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
+ dependencies:
+ adler-32 "~1.3.0"
+ crc-32 "~1.2.0"
+
chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
@@ -3090,6 +3108,20 @@ clone@^1.0.2:
resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz"
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
+codepage@~1.15.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab"
+ integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==
+
+codepage@~1.3.6:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/codepage/-/codepage-1.3.8.tgz#4f2e5d7c0975de28f88498058dcb5afcab6a5f71"
+ integrity sha512-cjAoQW5L/TCKWRbzt/xGBvhwJKQFhcIVO0jWQtpKQx4gr9qvXNkpRfq6gSmjjA8dB2Is/DPOb7gNwqQXP7UgTQ==
+ dependencies:
+ commander ""
+ concat-stream ""
+ voc ""
+
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
@@ -3107,6 +3139,11 @@ colorette@^2.0.10, colorette@^2.0.20:
resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz"
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
+colors@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc"
+ integrity sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==
+
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@@ -3114,6 +3151,11 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
+commander@:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46"
+ integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==
+
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
@@ -3149,6 +3191,16 @@ concat-map@0.0.1:
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+concat-stream@:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
+ integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
+ dependencies:
+ buffer-from "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^3.0.2"
+ typedarray "^0.0.6"
+
connect-history-api-fallback@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz"
@@ -3250,6 +3302,11 @@ cosmiconfig@^9.0.0:
js-yaml "^4.1.0"
parse-json "^5.2.0"
+crc-32@, crc-32@~1.2.0, crc-32@~1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
+ integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
+
critters@0.0.20:
version "0.0.20"
resolved "https://registry.yarnpkg.com/critters/-/critters-0.0.20.tgz#08ddb961550ab7b3a59370537e4f01df208f7646"
@@ -3860,6 +3917,11 @@ faye-websocket@^0.11.3:
dependencies:
websocket-driver ">=0.5.1"
+file-saver@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
+ integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
+
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz"
@@ -3955,6 +4017,16 @@ forwarded@0.2.0:
resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+frac@0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/frac/-/frac-0.3.1.tgz#577677b7fdcbe6faf7c461f1801d34137cda4354"
+ integrity sha512-1Lzf2jOjhIkRaa013KlxNOn2D9FemmQNeYUDpEIyPeFXmpLvbZXJOlaayMBT6JKXx+afQFgQ1QJ4kaF7Z07QFQ==
+
+frac@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
+ integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
+
fraction.js@^4.3.7:
version "4.3.7"
resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz"
@@ -4729,6 +4801,13 @@ jsonparse@^1.3.1:
resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz"
integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
+jszip@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/jszip/-/jszip-2.4.0.tgz#487a93b76c3bffa6cb085cd61eb934eabe2d294f"
+ integrity sha512-m+yvNmYfRCaf1gr5YFT5e3fnSqLnE9McbNyRd0fNycsT0HltS19NKc18fh3Lvl/AIW/ovL6/MQ1JnfFg4G3o4A==
+ dependencies:
+ pako "~0.2.5"
+
karma-chrome-launcher@~3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz"
@@ -5695,6 +5774,11 @@ pacote@20.0.0:
ssri "^12.0.0"
tar "^6.1.11"
+pako@~0.2.5:
+ version "0.2.9"
+ resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+ integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==
+
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
@@ -6033,7 +6117,7 @@ readable-stream@^2.0.1:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
-readable-stream@^3.0.6, readable-stream@^3.4.0:
+readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.4.0:
version "3.6.2"
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz"
integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
@@ -6674,6 +6758,22 @@ sprintf-js@^1.1.3:
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz"
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
+ssf@~0.11.2:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c"
+ integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==
+ dependencies:
+ frac "~1.1.2"
+
+ssf@~0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/ssf/-/ssf-0.8.2.tgz#b9d4dc6a1c1bcf76f8abfa96d7d7656fb2abecd6"
+ integrity sha512-+ZkFDAG+ImJ48DcZvabx6YTrZ67DKkM0kbyOOtH73mbUEvNhQWWgRZrHC8+k7GuGKWQnACYLi7bj0eCt1jmosQ==
+ dependencies:
+ colors "0.6.2"
+ frac "0.3.1"
+ voc ""
+
ssri@^12.0.0:
version "12.0.0"
resolved "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz"
@@ -6958,6 +7058,11 @@ typed-assert@^1.0.8:
resolved "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz"
integrity sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+ integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
+
typescript@~5.8.2:
version "5.8.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4"
@@ -7095,6 +7200,11 @@ vite@6.2.0:
optionalDependencies:
fsevents "~2.3.3"
+voc@:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/voc/-/voc-1.2.0.tgz#c459024531d71067c09e2c0c2bda6c2b13af32d8"
+ integrity sha512-BOuDjFFYvJdZO6e/N65AlaDItXo2TgyLjeyRYcqgAPkXpp5yTJcvkL2n+syO1r9Qc5g96tfBD2tuiMhYDmaGcA==
+
void-elements@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz"
@@ -7299,6 +7409,16 @@ wildcard@^2.0.1:
resolved "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz"
integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==
+wmf@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da"
+ integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==
+
+word@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961"
+ integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
@@ -7364,6 +7484,32 @@ xhr2@^0.2.0:
resolved "https://registry.npmjs.org/xhr2/-/xhr2-0.2.1.tgz"
integrity sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==
+xlsx-style@^0.8.13:
+ version "0.8.13"
+ resolved "https://registry.yarnpkg.com/xlsx-style/-/xlsx-style-0.8.13.tgz#ed238d6b8c0562f9447c2906abbded2d339e0486"
+ integrity sha512-Cj3pGUvzrP2q9oowpLP8GyujovTaBGjBRRUlCKPitNvHWj9JDD5+FDPZIM5QQggGb995ZhkuBSsMZOSd5TzIWg==
+ dependencies:
+ adler-32 ""
+ cfb ">=0.10.0"
+ codepage "~1.3.6"
+ commander ""
+ crc-32 ""
+ jszip "2.4.0"
+ ssf "~0.8.1"
+
+xlsx@^0.18.5:
+ version "0.18.5"
+ resolved "https://registry.yarnpkg.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0"
+ integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==
+ dependencies:
+ adler-32 "~1.3.0"
+ cfb "~1.2.1"
+ codepage "~1.15.0"
+ crc-32 "~1.2.1"
+ ssf "~0.11.2"
+ wmf "~1.0.1"
+ word "~0.3.0"
+
xml-name-validator@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
From 87ade64975ae1110984893a2778e620de9720ee6 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 01:08:59 -0400
Subject: [PATCH 016/127] ui update
---
frontend/src/app/component/page/menu/menu.component.html | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/frontend/src/app/component/page/menu/menu.component.html b/frontend/src/app/component/page/menu/menu.component.html
index 0566f8c..bb47387 100644
--- a/frontend/src/app/component/page/menu/menu.component.html
+++ b/frontend/src/app/component/page/menu/menu.component.html
@@ -25,7 +25,8 @@
@for (data of dataLists; track data) {
- |
+ |
+ 0" [(nzExpand)]="data.expand"> |
{{ data.name }} |
{{ data.icon }} |
{{ data.path }} |
From 187dc0bee2669b2c94b9cf1819b6da29a6a5d28c Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 01:33:35 -0400
Subject: [PATCH 017/127] access logic change
---
.../page/asset/asset-form/asset-form.component.html | 6 +++---
.../component/page/asset/asset-form/asset-form.component.ts | 2 ++
.../page/asset/asset-list/asset-list.component.html | 3 +--
3 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/frontend/src/app/component/page/asset/asset-form/asset-form.component.html b/frontend/src/app/component/page/asset/asset-form/asset-form.component.html
index 8a71e5c..097946b 100644
--- a/frontend/src/app/component/page/asset/asset-form/asset-form.component.html
+++ b/frontend/src/app/component/page/asset/asset-form/asset-form.component.html
@@ -1,5 +1,5 @@
-
+
@@ -276,10 +276,10 @@
-
+
Reset
-
+
{{ editForm._id ? 'Update' : 'Create' }}
diff --git a/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts b/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts
index c25698a..6b16fee 100644
--- a/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts
+++ b/frontend/src/app/component/page/asset/asset-form/asset-form.component.ts
@@ -69,6 +69,7 @@ export class AssetFormComponent implements OnInit {
const answer = findMenuItem(data, 'Asset List', 'asset-lists')
this.userRightInside = {
+ read: answer.read,
write: answer.write,
update: answer.update
}
@@ -76,6 +77,7 @@ export class AssetFormComponent implements OnInit {
}
userRightInside: any = {
+ read: false,
write: false,
update: false
}
diff --git a/frontend/src/app/component/page/asset/asset-list/asset-list.component.html b/frontend/src/app/component/page/asset/asset-list/asset-list.component.html
index 9d8eaa6..7885ebe 100644
--- a/frontend/src/app/component/page/asset/asset-list/asset-list.component.html
+++ b/frontend/src/app/component/page/asset/asset-list/asset-list.component.html
@@ -106,10 +106,9 @@
QR Tag
- Edit
+ Detail
Date: Sat, 22 Mar 2025 09:40:49 -0400
Subject: [PATCH 018/127] add excel db field match module
---
backend/src/app.module.ts | 2 +
.../excelFieldMatch/excelFieldMatch.dto.ts | 16 ++++++++
.../excelFieldMatch/excelFieldMatch.module.ts | 19 ++++++++++
.../excelFieldMatch/excelFieldMatch.schema.ts | 27 +++++++++++++
.../excelFieldMatch.service.ts | 38 +++++++++++++++++++
5 files changed, 102 insertions(+)
create mode 100644 backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts
create mode 100644 backend/src/module/excelFieldMatch/excelFieldMatch.module.ts
create mode 100644 backend/src/module/excelFieldMatch/excelFieldMatch.schema.ts
create mode 100644 backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts
index 26ed04a..35ed7f0 100644
--- a/backend/src/app.module.ts
+++ b/backend/src/app.module.ts
@@ -24,6 +24,7 @@ import { WriteOffModule } from './module/write-off/write-off.module'
import { SysMenuMoudule } from './module/sys-menu/sys-menu.module'
import { RepairRecordMoudule } from './module/repair-record/repair-record.module'
import { StockTakeMoudule } from './module/stock-take/stcok-take.module'
+import { ExcelFieldMatchModule } from './module/excelFieldMatch/excelFieldMatch.module'
@Module({
imports: [
@@ -44,6 +45,7 @@ import { StockTakeMoudule } from './module/stock-take/stcok-take.module'
SysRoleMoudule,
SysUserMoudule,
SysMenuMoudule,
+ ExcelFieldMatchModule,
MongooseModule.forRoot('mongodb://localhost/fixedasset'),
MongooseModule.forFeature([
{ name: 'SysRoles', schema: SysRoleSchema },
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts
new file mode 100644
index 0000000..1e3165b
--- /dev/null
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts
@@ -0,0 +1,16 @@
+export interface ExcelFieldList {
+ dbFieldName: string
+ excelFieldName: string
+ sort: number
+}
+
+export interface ExcelFieldMatchCreate {
+ functionCode: string
+ functionName: string
+ functionType: string
+ fieldLists?: ExcelFieldList[]
+}
+
+export interface ExcelFieldMatchUpdate extends ExcelFieldMatchCreate {
+ _id: string
+}
\ No newline at end of file
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.module.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.module.ts
new file mode 100644
index 0000000..597618e
--- /dev/null
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.module.ts
@@ -0,0 +1,19 @@
+import { Module } from '@nestjs/common'
+import { MongooseModule } from '@nestjs/mongoose'
+import { ActionRecordService } from '../action-record/actionRecord.service'
+import { ActionRecord, ActionRecordSchema } from '../action-record/actionRecord.schame'
+import { ExcelFieldMatch, ExcelFieldMatchSchema } from './excelFieldMatch.schema'
+import { ExcelFieldMatchService } from './excelFieldMatch.service'
+
+@Module({
+ imports: [
+ MongooseModule.forFeature([
+ { name: ActionRecord.name, schema: ActionRecordSchema },
+ { name: ExcelFieldMatch.name, schema: ExcelFieldMatchSchema }
+ ])
+ ],
+ providers: [ActionRecordService, ExcelFieldMatchService],
+ exports: [],
+ controllers: []
+})
+export class ExcelFieldMatchModule {}
\ No newline at end of file
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.schema.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.schema.ts
new file mode 100644
index 0000000..182cfc9
--- /dev/null
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.schema.ts
@@ -0,0 +1,27 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
+import { HydratedDocument, SchemaTypes, Types } from 'mongoose'
+import { BaseSchema } from '../base/baseSchema'
+
+interface ExcelFieldList {
+ dbFieldName: string
+ excelFieldName: string
+ sort: number
+}
+
+export type ExcelFieldMatchDocument = HydratedDocument
+@Schema()
+export class ExcelFieldMatch extends BaseSchema {
+ @Prop({ type: SchemaTypes.String, required: true })
+ functionCode: string
+
+ @Prop({ type: SchemaTypes.String, required: true })
+ functionName: string
+
+ @Prop({ type: SchemaTypes.String, required: true })
+ functionType: string
+
+ @Prop({ type: SchemaTypes.Array, schema: { type: ExcelFieldMatch } })
+ fieldLists: any[]
+}
+
+export const ExcelFieldMatchSchema = SchemaFactory.createForClass(ExcelFieldMatch)
\ No newline at end of file
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
new file mode 100644
index 0000000..d8d9fd6
--- /dev/null
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
@@ -0,0 +1,38 @@
+import { InjectModel } from '@nestjs/mongoose'
+import { ActionRecordService } from '../action-record/actionRecord.service'
+import { Injectable } from '@nestjs/common'
+import { ExcelFieldMatch } from './excelFieldMatch.schema'
+import { Model } from 'mongoose'
+
+
+@Injectable()
+export class ExcelFieldMatchService {
+ constructor(
+ @InjectModel(ExcelFieldMatch.name) private excelFieldMatchModel: Model,
+ private actionRecordService: ActionRecordService
+ ) {}
+
+ async getOneById(_id: string) {
+ const data = await this.excelFieldMatchModel.findOne({ _id, status: 1 })
+
+ if (data) {
+ return data
+ } else {
+ return {
+ msg: 'This setting may be invalidated! Please contact admin!'
+ }
+ }
+ }
+
+ async getOneByCode(functionCode: string) {
+ const data = await this.excelFieldMatchModel.findOne({ functionCode })
+
+ if (data?.status === 1) {
+ return data
+ } else {
+ return {
+ msg: 'This setting may be invalidated! Please contact admin!'
+ }
+ }
+ }
+}
\ No newline at end of file
From 15e5c22f69fc1f5203df3fe1caf0ee5a1294c04c Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 09:44:15 -0400
Subject: [PATCH 019/127] add method
---
.../excelFieldMatch.service.ts | 44 +++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
index d8d9fd6..a3081ae 100644
--- a/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
@@ -35,4 +35,48 @@ export class ExcelFieldMatchService {
}
}
}
+
+ async invalidate(_id: string) {
+ const checkData = await this.excelFieldMatchModel.findOne({ _id })
+
+ if (checkData?.status === 0) {
+ await this.actionRecordService.saveRecord({
+ actionName: 'Void Excel Field Match',
+ actionMethod: 'GET',
+ actionFrom: 'Excel Field Match',
+ actionData: {
+ _id
+ },
+ actionSuccess: 'FAILURE',
+ createdAt: new Date()
+ })
+
+ return {
+ msg: 'This RECORD has been invalidated! Please contact admin!'
+ }
+ } else {
+ await this.excelFieldMatchModel.updateOne({ _id}, {
+ status: 0,
+ updateAt: new Date()
+ })
+
+ await this.actionRecordService.saveRecord({
+ actionName: 'Void Excel Field Match',
+ actionMethod: 'GET',
+ actionFrom: 'Excel Field Match',
+ actionData: {
+ _id,
+ status: 0,
+ updateAt: new Date()
+ },
+ actionSuccess: 'Success',
+ createdAt: new Date()
+ })
+
+ return {
+ msg: 'Invalidate successfully!'
+ }
+
+ }
+ }
}
\ No newline at end of file
From c0a0c40ebcda1ce5b7d06963a7500dae62406f4e Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 11:28:12 -0400
Subject: [PATCH 020/127] update excel field match service
---
.../excelFieldMatch/excelFieldMatch.dto.ts | 7 ++
.../excelFieldMatch.service.ts | 115 ++++++++++++++++++
2 files changed, 122 insertions(+)
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts
index 1e3165b..829e604 100644
--- a/backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.dto.ts
@@ -13,4 +13,11 @@ export interface ExcelFieldMatchCreate {
export interface ExcelFieldMatchUpdate extends ExcelFieldMatchCreate {
_id: string
+}
+
+export interface ExcelFieldMatchListRequestDto {
+ page: number
+ limit: number
+ name?: string
+ type?: string
}
\ No newline at end of file
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
index a3081ae..d5cb066 100644
--- a/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.service.ts
@@ -3,6 +3,7 @@ import { ActionRecordService } from '../action-record/actionRecord.service'
import { Injectable } from '@nestjs/common'
import { ExcelFieldMatch } from './excelFieldMatch.schema'
import { Model } from 'mongoose'
+import { ExcelFieldMatchListRequestDto, ExcelFieldMatchUpdate } from './excelFieldMatch.dto'
@Injectable()
@@ -79,4 +80,118 @@ export class ExcelFieldMatchService {
}
}
+
+ async create(createData: ExcelFieldMatchUpdate) {
+ const { _id, functionCode, functionName, ..._data } = createData
+
+ const checkData = await this.excelFieldMatchModel.findOne({ functionCode, functionName })
+
+ if (checkData?.status === 1) {
+ await this.actionRecordService.saveRecord({
+ actionName: 'Create Excel Field Match',
+ actionMethod: 'POST',
+ actionFrom: 'Excel Field Match',
+ actionData: createData,
+ actionSuccess: 'FAILURE',
+ createdAt: new Date()
+ })
+
+ return {
+ msg: 'This record already exist!'
+ }
+ } else {
+
+ const finalData = {
+ functionCode,
+ functionName,
+ ..._data,
+ status: 1,
+ createdAt: new Date()
+ }
+
+ await this.actionRecordService.saveRecord({
+ actionName: 'Create Excel Field Match',
+ actionMethod: 'POST',
+ actionFrom: 'Excel Field Match',
+ actionData: finalData,
+ actionSuccess: 'Sussess',
+ createdAt: new Date()
+ })
+
+ const create = new this.excelFieldMatchModel(finalData)
+ return await create.save()
+
+ }
+ }
+
+ async update(updateData: ExcelFieldMatchUpdate) {
+
+ const { _id, ..._data } = updateData
+
+ const checkData = await this.excelFieldMatchModel.findOne({ _id })
+
+ if (checkData?.status === 1) {
+
+ const finalData = {
+ ..._data,
+ updatedAt: new Date()
+ }
+
+ await this.actionRecordService.saveRecord({
+ actionName: 'Update Excel Field Match',
+ actionMethod: 'POST',
+ actionFrom: 'Excel Field Match',
+ actionData: finalData,
+ actionSuccess: 'Sussess',
+ createdAt: new Date()
+ })
+
+ return await this.excelFieldMatchModel.updateOne({ _id}, finalData)
+
+ } else {
+
+ await this.actionRecordService.saveRecord({
+ actionName: 'Update Excel Field Match',
+ actionMethod: 'POST',
+ actionFrom: 'Excel Field Match',
+ actionData: updateData,
+ actionSuccess: 'FAILURE',
+ createdAt: new Date()
+ })
+
+ return {
+ msg: 'This record has been invalidated! Please contact admin!'
+ }
+ }
+
+ }
+
+ async listAndPage(req: ExcelFieldMatchListRequestDto) {
+ const { page, limit, name, type } = req
+
+ const skip = (page - 1) * limit
+
+ const filters = {
+ ... name ? { $or: [
+ { funcationCode: { $regex: name, $options: 'i'} },
+ { funcationName: { $regex: name, $options: 'i'} }
+ ] } : {},
+ ...type ? { funcationType: type } : {},
+ status: 1
+ }
+
+ const lists = await this.excelFieldMatchModel.find(filters).skip(skip)
+ .limit(limit)
+ .exec()
+ const total = await this.excelFieldMatchModel.countDocuments()
+
+ return {
+ total,
+ page,
+ limit,
+ totalPages: Math.ceil(total / limit),
+ lists
+ }
+
+ }
}
\ No newline at end of file
From 683938e848e26caac2d50f27d53308d4622570b8 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 11:50:29 -0400
Subject: [PATCH 021/127] add excel field match controller in backend
---
.../excelFieldMatch.controller.ts | 45 +++++++++++++++++++
.../excelFieldMatch/excelFieldMatch.module.ts | 3 +-
2 files changed, 47 insertions(+), 1 deletion(-)
create mode 100644 backend/src/module/excelFieldMatch/excelFieldMatch.controller.ts
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.controller.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.controller.ts
new file mode 100644
index 0000000..2e092bb
--- /dev/null
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.controller.ts
@@ -0,0 +1,45 @@
+import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common'
+import { ExcelFieldMatchService } from './excelFieldMatch.service'
+import { ExcelFieldMatchListRequestDto, ExcelFieldMatchUpdate } from './excelFieldMatch.dto'
+import { AuthGuard } from '../auth/AuthGuard'
+
+@Controller('sys/excel-field-match')
+export class ExcelFieldMatchController {
+ constructor(private excelFieldMatchService: ExcelFieldMatchService) {}
+
+ @Post('create')
+ @UseGuards(AuthGuard)
+ async create(@Body() createData: ExcelFieldMatchUpdate) {
+ return await this.excelFieldMatchService.create(createData)
+ }
+
+ @Post('update')
+ @UseGuards(AuthGuard)
+ async update(@Body() updateDto: ExcelFieldMatchUpdate) {
+ return await this.excelFieldMatchService.update(updateDto)
+ }
+
+ @Get('one/:id')
+ @UseGuards(AuthGuard)
+ async getOneById(@Param('id') id: string) {
+ return await this.excelFieldMatchService.getOneById(id)
+ }
+
+ @Get('code/:code')
+ @UseGuards(AuthGuard)
+ async getOneByCode(@Param('code') code: string) {
+ return await this.excelFieldMatchService.getOneByCode(code)
+ }
+
+ @Get('remove/:id')
+ @UseGuards(AuthGuard)
+ async removeById(@Param('id') id: string) {
+ return await this.excelFieldMatchService.invalidate(id)
+ }
+
+ @Post('list')
+ @UseGuards(AuthGuard)
+ async listAndPage(@Body() req: ExcelFieldMatchListRequestDto) {
+ return this.excelFieldMatchService.listAndPage(req)
+ }
+}
\ No newline at end of file
diff --git a/backend/src/module/excelFieldMatch/excelFieldMatch.module.ts b/backend/src/module/excelFieldMatch/excelFieldMatch.module.ts
index 597618e..83e8989 100644
--- a/backend/src/module/excelFieldMatch/excelFieldMatch.module.ts
+++ b/backend/src/module/excelFieldMatch/excelFieldMatch.module.ts
@@ -4,6 +4,7 @@ import { ActionRecordService } from '../action-record/actionRecord.service'
import { ActionRecord, ActionRecordSchema } from '../action-record/actionRecord.schame'
import { ExcelFieldMatch, ExcelFieldMatchSchema } from './excelFieldMatch.schema'
import { ExcelFieldMatchService } from './excelFieldMatch.service'
+import { ExcelFieldMatchController } from './excelFieldMatch.controller'
@Module({
imports: [
@@ -14,6 +15,6 @@ import { ExcelFieldMatchService } from './excelFieldMatch.service'
],
providers: [ActionRecordService, ExcelFieldMatchService],
exports: [],
- controllers: []
+ controllers: [ExcelFieldMatchController]
})
export class ExcelFieldMatchModule {}
\ No newline at end of file
From a087376599cfdabebd1426e3f5e09f05b4d049ad Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 15:29:13 -0400
Subject: [PATCH 022/127] add excel field setting frontend
---
.../excel-field-match.component.css | 13 ++
.../excel-field-match.component.html | 158 ++++++++++++++++
.../excel-field-match.component.spec.ts | 0
.../excel-field-match.component.ts | 176 ++++++++++++++++++
.../page/excel-field-match/interface.ts | 13 ++
frontend/src/app/component/sub-router.ts | 6 +
6 files changed, 366 insertions(+)
create mode 100644 frontend/src/app/component/page/excel-field-match/excel-field-match.component.css
create mode 100644 frontend/src/app/component/page/excel-field-match/excel-field-match.component.html
create mode 100644 frontend/src/app/component/page/excel-field-match/excel-field-match.component.spec.ts
create mode 100644 frontend/src/app/component/page/excel-field-match/excel-field-match.component.ts
create mode 100644 frontend/src/app/component/page/excel-field-match/interface.ts
diff --git a/frontend/src/app/component/page/excel-field-match/excel-field-match.component.css b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.css
new file mode 100644
index 0000000..b6b81d2
--- /dev/null
+++ b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.css
@@ -0,0 +1,13 @@
+.mat-mdc-row .mat-mdc-cell {
+ border-bottom: 1px solid transparent;
+ border-top: 1px solid transparent;
+ cursor: pointer;
+ }
+
+ .mat-mdc-row:hover .mat-mdc-cell {
+ border-color: currentColor;
+ }
+
+ .demo-row-is-clicked {
+ font-weight: bold;
+ }
\ No newline at end of file
diff --git a/frontend/src/app/component/page/excel-field-match/excel-field-match.component.html b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.html
new file mode 100644
index 0000000..0e2146d
--- /dev/null
+++ b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.html
@@ -0,0 +1,158 @@
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+ Create
+
+
+
+
+
+ | Code |
+ Name |
+ Type |
+ Created At |
+ Updated At |
+ Action |
+
+
+
+
+ | {{data.functionCode}} |
+ {{data.functionName}} |
+ {{data.functionType}} |
+ {{ dateFormat(data.createdAt) }} |
+ {{ dateFormat(data.updatedAt) }} |
+
+
+
+ Edit
+
+
+ Delete
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Are you sure to confirm delete this record?
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/app/component/page/excel-field-match/excel-field-match.component.spec.ts b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.spec.ts
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/src/app/component/page/excel-field-match/excel-field-match.component.ts b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.ts
new file mode 100644
index 0000000..f11a493
--- /dev/null
+++ b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.ts
@@ -0,0 +1,176 @@
+import { Component } from '@angular/core'
+import { CommonModule } from '@angular/common'
+import { RouterLink, RouterLinkActive, RouterOutlet, Router } from '@angular/router'
+import { FormsModule } from '@angular/forms'
+import { deleteApiWithAuth, getApiWithAuth, postApiWithAuth } from '../../../../tool/httpRequest-auth'
+import { NzTableModule } from 'ng-zorro-antd/table'
+import { NzButtonModule } from 'ng-zorro-antd/button'
+import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal'
+import { NzInputModule } from 'ng-zorro-antd/input'
+import { NzFormModule } from 'ng-zorro-antd/form'
+import moment from 'moment'
+import { ExcelFieldListForm } from './interface'
+import { NzMessageService } from 'ng-zorro-antd/message'
+import { NzPaginationModule } from 'ng-zorro-antd/pagination'
+import { UserStoreService } from '../../../../state/user.service'
+import { findMenuItem } from '../../tool-function'
+import { NzSelectModule } from 'ng-zorro-antd/select'
+import { NzInputNumberModule } from 'ng-zorro-antd/input-number'
+
+@Component({
+ // selector: 'app-footer',
+ standalone: true,
+ imports: [
+ CommonModule,
+ NzFormModule,
+ NzButtonModule,
+ FormsModule,
+ NzModalModule,
+ NzTableModule,
+ NzInputModule,
+ NzPaginationModule,
+ NzSelectModule,
+ NzInputNumberModule,
+ ],
+ templateUrl: './excel-field-match.component.html',
+ styleUrl: './excel-field-match.component.css',
+})
+export class ExcelFieldMatchComponent {
+ constructor(
+ private message: NzMessageService,
+ private userStoreService: UserStoreService
+ ) {
+
+ this.userStoreService.menuRole$.subscribe((data: any) => {
+ const answer = findMenuItem(data, 'Excel Field Match', 'excel-field-matchs')
+
+ this.userRightInside = {
+ read: answer.read,
+ write: answer.write,
+ update: answer.update,
+ delete: answer.delete
+ }
+ console.log(this.userRightInside, 'answer')
+ })
+ }
+
+ userRightInside: any = {
+ read: false,
+ write: false,
+ update: false,
+ delete: false
+ }
+
+ searchForm: any = {
+ page: 1,
+ limit: 10
+ }
+
+ editForm: ExcelFieldListForm = {
+ _id: '',
+ functionCode: '',
+ functionName: '',
+ functionType: '',
+ fieldLists: []
+ }
+
+ okText: string = 'Create'
+
+ dataLists: any[] = []
+ totals: number = 0
+ editFormDialog: boolean = false
+ removeDialog: boolean = false
+ handleRemoveId: string = ''
+
+ ngOnInit() {
+ this.loadRecordLists()
+ this.loadCodeType()
+ }
+
+ async submitForm() {
+ const url = this.editForm._id === '' ? '/sys/excel-field-match/create' : `/sys/excel-field-match/update`
+
+ const res = await postApiWithAuth(url, {
+
+ ...this.editForm,
+ ...this.editForm._id ? { _id: this.editForm._id} : {},
+ })
+
+ if (res.msg) {
+ this.message.error(res.msg)
+ } else if (res.matchedCount === 1 || !res.msg) {
+ this.message.success('Save successful!')
+ this.closeDialog()
+ this.loadRecordLists()
+
+ this.editForm = {
+ _id: '',
+ functionCode: '',
+ functionName: '',
+ functionType: '',
+ fieldLists: []
+ }
+ }
+ }
+
+ async loadRecordLists() {
+ const res = await postApiWithAuth('/sys/excel-field-match/list', this.searchForm)
+ this.dataLists = res.lists
+ this.totals = res.total
+ }
+
+ showDialog() {
+ this.editFormDialog = true
+ }
+
+ closeDialog() {
+ this.editFormDialog = false
+ }
+
+ handleRomeve(id: string) {
+ this.handleRemoveId = id
+ this.removeDialog = true
+ }
+
+ closeRemoveDialog() {
+ this.removeDialog = false
+ }
+
+ async handleRemove() {
+ const url = `/sys/excel-field-match/remove/${this.handleRemoveId}`
+
+ const res: any = await getApiWithAuth(url)
+
+ this.message.info(res.msg)
+
+ this.closeRemoveDialog()
+ this.loadRecordLists()
+ }
+
+
+ dateFormat(data: string) {
+ return data ? moment(new Date(data)).format('DD-MM-YYYY HH:MM') : null
+ }
+
+ async getOneData(id:string) {
+ const res = await getApiWithAuth(`/sys/excel-field-match/one/${id}`)
+ this.editForm = res
+ this.okText = 'Update'
+ this.showDialog()
+ }
+
+ codeTypeLists: any[] = []
+ async loadCodeType() {
+ this.codeTypeLists = await getApiWithAuth('/base/code-type/get-type/ExcelFieldMatch')
+ }
+
+ fieldAddRow(): void {
+ this.editForm.fieldLists = [...this.editForm.fieldLists, { dbFieldName: '', excelFieldName: '', sort: 0 }]
+ }
+
+ deleteRow(index: number): void {
+ this.editForm.fieldLists.splice(index, 1)
+ this.editForm.fieldLists = [...this.editForm.fieldLists]
+ }
+
+}
\ No newline at end of file
diff --git a/frontend/src/app/component/page/excel-field-match/interface.ts b/frontend/src/app/component/page/excel-field-match/interface.ts
new file mode 100644
index 0000000..8162d8b
--- /dev/null
+++ b/frontend/src/app/component/page/excel-field-match/interface.ts
@@ -0,0 +1,13 @@
+export interface ExcelFieldListForm {
+ _id?: string,
+ functionCode: string
+ functionName: string
+ functionType: string
+ fieldLists: ExcelFieldList[]
+}
+
+export interface ExcelFieldList {
+ dbFieldName: string
+ excelFieldName: string
+ sort: number
+}
\ No newline at end of file
diff --git a/frontend/src/app/component/sub-router.ts b/frontend/src/app/component/sub-router.ts
index 6043580..23fed24 100644
--- a/frontend/src/app/component/sub-router.ts
+++ b/frontend/src/app/component/sub-router.ts
@@ -22,6 +22,7 @@ import { StockTakeListComponent } from './page/stock-take/stock-take-list/stock-
import { StockTakeFormComponent } from './page/stock-take/stock-take-form/stock-take-form.component'
import { DashboardComponent } from './page/dashboard/dashboard.component'
import { MenuListComponent } from './page/menu/menu.component'
+import { ExcelFieldMatchComponent } from './page/excel-field-match/excel-field-match.component'
export const pagesRoutes: Routes = [
{
@@ -54,6 +55,11 @@ export const pagesRoutes: Routes = [
component: DashboardComponent,
canActivate: [AuthGuard]
},
+ {
+ path: 'excel-field-matchs',
+ component: ExcelFieldMatchComponent,
+ canActivate: [AuthGuard]
+ },
{
path: 'write-off',
component: WriteOffFormComponent,
From 6309e301794afb3d40bda57c711fef9a9901391c Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sat, 22 Mar 2025 15:31:26 -0400
Subject: [PATCH 023/127] style update
---
.../excel-field-match.component.html | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/frontend/src/app/component/page/excel-field-match/excel-field-match.component.html b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.html
index 0e2146d..1d67f99 100644
--- a/frontend/src/app/component/page/excel-field-match/excel-field-match.component.html
+++ b/frontend/src/app/component/page/excel-field-match/excel-field-match.component.html
@@ -65,7 +65,7 @@
>
+
+
\ No newline at end of file
diff --git a/frontend/src/app/component/page/dashboard/dashboard.component.ts b/frontend/src/app/component/page/dashboard/dashboard.component.ts
index 8bbde63..5c2b126 100644
--- a/frontend/src/app/component/page/dashboard/dashboard.component.ts
+++ b/frontend/src/app/component/page/dashboard/dashboard.component.ts
@@ -62,6 +62,7 @@ export class DashboardComponent implements OnInit {
this.getByPlaceAndDateOfCosts()
this.getByPlaceCosts()
this.getByTypeCosts()
+ this.getByDeptCosts()
// this.getByTotalCost()
// this.getByTotalCount()
this.loadTypeList()
@@ -95,6 +96,7 @@ export class DashboardComponent implements OnInit {
await this.getByTypeAndDateOfCosts()
await this.getByPlaceCosts()
await this.getByTypeCosts()
+ await this.getByDeptCosts()
// await this.getByTotalCost()
// await this.getByTotalCount()
}
@@ -350,6 +352,35 @@ export class DashboardComponent implements OnInit {
}
+ deptInCostsLoading: boolean = false
+ deptInCosts: any = {}
+ async getByDeptCosts() {
+ this.deptInCostsLoading = false
+ const dataQuery: DashboardReqDto = {
+ dateType: false,
+ dateTypeValue: 'none',
+ dataType: true,
+ dataTypeValue: 'dept',
+ valueField: 'costs'
+ }
+ const res = await this.runQueryData(dataQuery)
+ const data = transformDataPointsOnly(res, 'deptName', 'costs')
+ this.deptInCosts = {
+ animationEnabled: true,
+ data: [
+ {
+ type: "pie",
+ startAngle: 240,
+ yValueFormatString: '$##0.00\"\"',
+ indexLabel: "{label} {y}",
+ dataPoints: data
+ }
+ ]
+ }
+ this.deptInCostsLoading = true
+
+ }
+
async runQueryData(dataQuery: DashboardReqDto) {
const finalQuery = {
...dataQuery,
From 4675177a78982affa426ea8e9329ebc17bf8bec3 Mon Sep 17 00:00:00 2001
From: Felix <53119101+felix9611@users.noreply.github.com>
Date: Sun, 23 Mar 2025 13:11:25 -0400
Subject: [PATCH 032/127] style update
---
.../app/layout/header/header.component.html | 7 +-
.../src/app/layout/menu/menu.component.html | 73 +++++++++++--------
.../src/app/layout/menu/menu.component.ts | 2 +
3 files changed, 45 insertions(+), 37 deletions(-)
diff --git a/frontend/src/app/layout/header/header.component.html b/frontend/src/app/layout/header/header.component.html
index 10caa31..1c1f819 100644
--- a/frontend/src/app/layout/header/header.component.html
+++ b/frontend/src/app/layout/header/header.component.html
@@ -1,8 +1,5 @@
- | | | | | | | | | | | | |