diff --git a/.vs/ExpenseRecord/DesignTimeBuild/.dtbcache.v2 b/.vs/ExpenseRecord/DesignTimeBuild/.dtbcache.v2
new file mode 100644
index 0000000..e2373d2
Binary files /dev/null and b/.vs/ExpenseRecord/DesignTimeBuild/.dtbcache.v2 differ
diff --git a/.vs/ExpenseRecord/FileContentIndex/339eda24-9029-409b-9eee-bc26f12495fe.vsidx b/.vs/ExpenseRecord/FileContentIndex/339eda24-9029-409b-9eee-bc26f12495fe.vsidx
new file mode 100644
index 0000000..fcf2e94
Binary files /dev/null and b/.vs/ExpenseRecord/FileContentIndex/339eda24-9029-409b-9eee-bc26f12495fe.vsidx differ
diff --git a/.vs/ExpenseRecord/FileContentIndex/3e34afab-1d40-44d0-a90c-c24c8cd73546.vsidx b/.vs/ExpenseRecord/FileContentIndex/3e34afab-1d40-44d0-a90c-c24c8cd73546.vsidx
new file mode 100644
index 0000000..a6920b1
Binary files /dev/null and b/.vs/ExpenseRecord/FileContentIndex/3e34afab-1d40-44d0-a90c-c24c8cd73546.vsidx differ
diff --git a/.vs/ExpenseRecord/FileContentIndex/5f049127-5cd8-4f62-81ce-14eff33f8f80.vsidx b/.vs/ExpenseRecord/FileContentIndex/5f049127-5cd8-4f62-81ce-14eff33f8f80.vsidx
new file mode 100644
index 0000000..a6e7829
Binary files /dev/null and b/.vs/ExpenseRecord/FileContentIndex/5f049127-5cd8-4f62-81ce-14eff33f8f80.vsidx differ
diff --git a/.vs/ExpenseRecord/FileContentIndex/b74583b2-94c0-4531-b3d2-17ac1046c661.vsidx b/.vs/ExpenseRecord/FileContentIndex/b74583b2-94c0-4531-b3d2-17ac1046c661.vsidx
new file mode 100644
index 0000000..c6023f1
Binary files /dev/null and b/.vs/ExpenseRecord/FileContentIndex/b74583b2-94c0-4531-b3d2-17ac1046c661.vsidx differ
diff --git a/.vs/ExpenseRecord/FileContentIndex/bf66d6a7-17e7-405c-aa44-ae7ff7a5da67.vsidx b/.vs/ExpenseRecord/FileContentIndex/bf66d6a7-17e7-405c-aa44-ae7ff7a5da67.vsidx
new file mode 100644
index 0000000..a9b30d2
Binary files /dev/null and b/.vs/ExpenseRecord/FileContentIndex/bf66d6a7-17e7-405c-aa44-ae7ff7a5da67.vsidx differ
diff --git a/.vs/ExpenseRecord/config/applicationhost.config b/.vs/ExpenseRecord/config/applicationhost.config
new file mode 100644
index 0000000..8c14e9a
--- /dev/null
+++ b/.vs/ExpenseRecord/config/applicationhost.config
@@ -0,0 +1,964 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.vs/ExpenseRecord/v17/.futdcache.v2 b/.vs/ExpenseRecord/v17/.futdcache.v2
new file mode 100644
index 0000000..fb67118
Binary files /dev/null and b/.vs/ExpenseRecord/v17/.futdcache.v2 differ
diff --git a/.vs/ExpenseRecord/v17/.suo b/.vs/ExpenseRecord/v17/.suo
new file mode 100644
index 0000000..36de27e
Binary files /dev/null and b/.vs/ExpenseRecord/v17/.suo differ
diff --git a/.vs/ExpenseRecord/v17/fileList.bin b/.vs/ExpenseRecord/v17/fileList.bin
new file mode 100644
index 0000000..23e5a71
Binary files /dev/null and b/.vs/ExpenseRecord/v17/fileList.bin differ
diff --git a/.vs/ProjectEvaluation/expenserecord.metadata.v7.bin b/.vs/ProjectEvaluation/expenserecord.metadata.v7.bin
new file mode 100644
index 0000000..1c187d6
Binary files /dev/null and b/.vs/ProjectEvaluation/expenserecord.metadata.v7.bin differ
diff --git a/.vs/ProjectEvaluation/expenserecord.projects.v7.bin b/.vs/ProjectEvaluation/expenserecord.projects.v7.bin
new file mode 100644
index 0000000..c50c6aa
Binary files /dev/null and b/.vs/ProjectEvaluation/expenserecord.projects.v7.bin differ
diff --git a/ExpenseRecord/ClientApp/src/app/app-routing.module.ts b/ExpenseRecord/ClientApp/src/app/app-routing.module.ts
new file mode 100644
index 0000000..f88ba14
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/app-routing.module.ts
@@ -0,0 +1,17 @@
+import { RouterModule, Routes } from "@angular/router";
+import { NgModel } from "@angular/forms";
+import { NgModule } from "@angular/core";
+
+import { ExpenseComponent } from "./expense/expense.component";
+import { ChildComponent } from "./expense/child/child.component";
+
+
+const route: Routes=[
+ {path:'',component:ExpenseComponent},
+ {path:'new',component:ChildComponent},
+];
+@NgModule({
+ imports: [RouterModule.forRoot(route)],
+ exports: [RouterModule]
+})
+export class AppRoutingModule{}
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/app/app.component.html b/ExpenseRecord/ClientApp/src/app/app.component.html
index fa05fe7..c60267b 100644
--- a/ExpenseRecord/ClientApp/src/app/app.component.html
+++ b/ExpenseRecord/ClientApp/src/app/app.component.html
@@ -1 +1,11 @@
-
+
+
+
+ Expense
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/app/app.module.ts b/ExpenseRecord/ClientApp/src/app/app.module.ts
index 73c9837..5f68935 100644
--- a/ExpenseRecord/ClientApp/src/app/app.module.ts
+++ b/ExpenseRecord/ClientApp/src/app/app.module.ts
@@ -7,19 +7,30 @@ import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { CounterComponent } from './counter/counter.component';
import {GreetingComponent} from "./greeting/greeting.component";
+import { ExpenseComponent } from './expense/expense.component';
+import { ExpenseService } from './expense/expense.service';
+import "@angular/compiler";
+import { ChildComponent } from './expense/child/child.component';
+import { ExpenseModule } from './expense/expense.module';
+import { AppRoutingModule } from './app-routing.module';
@NgModule({
declarations: [
AppComponent,
CounterComponent,
- GreetingComponent
+ GreetingComponent,
+ ExpenseComponent,
+
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
HttpClientModule,
FormsModule,
+ RouterModule,
+ ExpenseModule,
+ AppRoutingModule
],
- providers: [],
+ providers: [ExpenseService],
bootstrap: [AppComponent]
})
export class AppModule { }
diff --git a/ExpenseRecord/ClientApp/src/app/app.server.module.ts b/ExpenseRecord/ClientApp/src/app/app.server.module.ts
deleted file mode 100644
index cfb0e02..0000000
--- a/ExpenseRecord/ClientApp/src/app/app.server.module.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { NgModule } from '@angular/core';
-import { ServerModule } from '@angular/platform-server';
-import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
-import { AppComponent } from './app.component';
-import { AppModule } from './app.module';
-
-@NgModule({
- imports: [AppModule, ServerModule, ModuleMapLoaderModule],
- bootstrap: [AppComponent]
-})
-export class AppServerModule { }
diff --git a/ExpenseRecord/ClientApp/src/app/expense/child/child.component.css b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.css
new file mode 100644
index 0000000..8946723
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.css
@@ -0,0 +1,70 @@
+.centered-box {
+ position: fixed;
+ top: 50%; /* 将框顶部垂直居中 */
+ left: 50%; /* 将框左侧水平居中 */
+ transform: translate(-50%, -50%); /* 使用transform属性来微调位置 */
+ background-color: #fff;
+ width: 80%; /* 调整框的宽度和高度 */
+ height: 85%;
+ border: 2px solid rgba(3, 41, 81, 0.5);
+ border-radius: 5px;
+ padding: 20px;
+}
+.input{
+ border: 2px, solid rgba(3, 41, 81, 0.5);
+ font-size: large;
+ text-align: center;
+ width: 100%;
+}
+.goback{
+ height: 50px;
+ width: 100%;
+ align-content: left;
+ align-self: flex-start;
+ background-color: rgba(17, 64, 108, 0.5);
+ font-size: large;
+ color: #fff;
+ margin-top: 5px;
+ font-family: 'Montserrat', sans-serif;
+}
+.title{
+ color: rgba(3, 41, 81, 0.8);
+ width: 100%;
+ text-align: center;
+ font-size: 30px;;
+ /* font-family: 'Montserrat', serif; */
+ height:10%;
+ margin-bottom: 0%;
+}
+.table{
+ width: 100%;
+ height: 18%;
+ text-align: center;
+ color:rgba(3, 41, 81, 1);
+}
+.label{
+ border: 2px, solid rgba(3, 41, 81, 0.5);
+ font-size: large;
+ text-align: center;
+}
+
+
+.container{
+ height: 80%;
+ line-height: 3;
+ overflow-y: auto;
+ font-size: large;
+ font-family: 'Montserrat', sans-serif;
+}
+.save{
+ height: 50px;
+ width: 100%;
+ align-content: center;
+ align-self: flex-start;
+ background-color: rgba(17, 64, 108, 0.5);
+ font-size: large;
+ color: #fff;
+ margin-top: 5px;
+ font-family: 'Montserrat', sans-serif;
+
+}
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/app/expense/child/child.component.html b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.html
new file mode 100644
index 0000000..4125080
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ |
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/app/expense/child/child.component.spec.ts b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.spec.ts
new file mode 100644
index 0000000..357a919
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ChildComponent } from './child.component';
+
+describe('ChildComponent', () => {
+ let component: ChildComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ChildComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ChildComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/ExpenseRecord/ClientApp/src/app/expense/child/child.component.ts b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.ts
new file mode 100644
index 0000000..7042837
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/child/child.component.ts
@@ -0,0 +1,38 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { INewExpenseItem } from '../newexpense';
+import { ExpenseService } from '../expense.service';
+
+@Component({
+ selector: 'app-child',
+ templateUrl: './child.component.html',
+ styleUrls: ['./child.component.css']
+})
+export class ChildComponent implements OnInit {
+ selectedExpenseType: string ='';
+
+
+ constructor(private route: ActivatedRoute,
+ private router: Router,
+ private expenseService:ExpenseService) { }
+ public Description:string='';
+
+ public Amount :number =0;
+ ngOnInit(): void {
+ }
+ onBack(): void {
+ this.router.navigateByUrl('/');
+ //navigate(['items']);
+ }
+ save() {
+ // if (!this.content) {
+ const newItem: INewExpenseItem = {
+ description: this.Description,
+ type: this.selectedExpenseType,
+ amount:this.Amount
+
+ }
+ console.log(newItem)
+ this.expenseService.addItems(newItem).subscribe()
+ }
+}
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expense-service.service.spec.ts b/ExpenseRecord/ClientApp/src/app/expense/expense-service.service.spec.ts
new file mode 100644
index 0000000..d5bc651
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expense-service.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+import { ExpenseService } from './expense.service';
+
+
+describe('ExpenseServiceService', () => {
+ let service: ExpenseService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(ExpenseService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expense.component.css b/ExpenseRecord/ClientApp/src/app/expense/expense.component.css
new file mode 100644
index 0000000..a227e77
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expense.component.css
@@ -0,0 +1,59 @@
+.centered-box {
+ position: fixed;
+ top: 50%; /* 将框顶部垂直居中 */
+ left: 50%; /* 将框左侧水平居中 */
+ transform: translate(-50%, -50%); /* 使用transform属性来微调位置 */
+ background-color: #fff;
+ width: 80%; /* 调整框的宽度和高度 */
+ height: 85%;
+ border: 2px solid rgba(3, 41, 81, 0.5);
+ border-radius: 5px;
+ padding: 20px;
+}
+.title{
+ color: rgba(3, 41, 81, 0.8);
+ width: 100%;
+ text-align: center;
+ font-size: 30px;;
+ /* font-family: 'Montserrat', serif; */
+ height:10%;
+ margin-bottom: 0%;
+}
+.table{
+ width: 100%;
+ height: 18%;
+ text-align: center;
+ color:rgba(3, 41, 81, 1);
+}
+.container{
+ height: 80%;
+ line-height: 3;
+ overflow-y: auto;
+ font-size: large;
+ font-family: 'Montserrat', sans-serif;
+}
+.Created{
+ height: 50px;
+ width: 100%;
+ align-content: center;
+ align-self: flex-end;
+ background-color: rgba(17, 64, 108, 0.5);
+ font-size: large;
+ color: #fff;
+ margin-top: 5px;
+ font-family: 'Montserrat', sans-serif;
+
+}
+.deletebutton{
+ background-color: #fff;
+ border-color: #fff;
+ border-radius: 10%;
+ align-content: center;
+ font-size: large;
+ color: rgba(17, 64, 108, 1);
+ margin-top: 5px;
+ font-family: 'Montserrat', sans-serif;
+
+
+
+}
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expense.component.html b/ExpenseRecord/ClientApp/src/app/expense/expense.component.html
new file mode 100644
index 0000000..699f4c2
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expense.component.html
@@ -0,0 +1,27 @@
+
+
{{title}}
+
+
+
+
+ | Description |
+ Type |
+ Amount |
+ CreateTime |
+ Delete? |
+
+
+
+
+ | {{item.description}} |
+ {{item.type}} |
+ {{item.amount}} |
+ {{item.createTime}} |
+ |
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expense.component.spec.ts b/ExpenseRecord/ClientApp/src/app/expense/expense.component.spec.ts
new file mode 100644
index 0000000..fcca3d8
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expense.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ExpenseComponent } from './expense.component';
+
+describe('ExpenseComponent', () => {
+ let component: ExpenseComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ ExpenseComponent ]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(ExpenseComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expense.component.ts b/ExpenseRecord/ClientApp/src/app/expense/expense.component.ts
new file mode 100644
index 0000000..10d8ff8
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expense.component.ts
@@ -0,0 +1,73 @@
+import { Component, Inject, OnInit } from '@angular/core';
+import { IExpenseItem } from './expenseItem';
+import { HttpClient } from '@angular/common/http';
+import { ExpenseService } from './expense.service';
+import { ActivatedRoute } from '@angular/router';
+
+
+@Component({
+ selector: 'app-expense',
+ templateUrl: './expense.component.html',
+ styleUrls: ['./expense.component.css'],
+ providers: [ExpenseService] // 声明服务提供者
+})
+
+export class ExpenseComponent implements OnInit {
+
+ constructor(private itemservice:ExpenseService,
+ private route: ActivatedRoute){
+
+ }
+
+ title = "Expense Record"
+ existingRecords : IExpenseItem[] = [];
+ ngOnInit(): void {
+ this.getAll();
+
+ }
+
+
+ // getAll(): void {
+ // this.itemservice.getItems().subscribe({
+ // next: (data) => {
+ // // 统一日期格式为 ISO 8601 格式
+ // data.forEach((item) => {
+ // item.createTime = this.formatDateToISO(item.createTime);
+ // });
+
+ // // 对数据按日期倒序排序
+ // this.existingRecords = data.sort((a, b) => new Date(b.createTime) - new Date(a.createTime));
+ // }
+
+ // });
+ // }
+
+ getAll(): void {
+ this.itemservice.getItems().subscribe({
+ next: (data) => {
+ this.existingRecords = data.reverse();
+ }
+ });
+ }
+
+ formatDateToISO(dateString: string): string {
+ if (/^\d{8}$/.test(dateString)) {
+ const year = dateString.substring(0, 4);
+ const month = dateString.substring(4, 6);
+ const day = dateString.substring(6, 8);
+ return `${year}-${month}-${day}`;
+ } else if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
+ return dateString;
+ } else {
+ return '';
+ }
+ }
+
+ deleteItems(id: string){
+ this.itemservice.deleteExpense(id).subscribe(()=>{
+ this.getAll()
+ })
+ }
+}
+
+
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expense.module.ts b/ExpenseRecord/ClientApp/src/app/expense/expense.module.ts
new file mode 100644
index 0000000..d49af97
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expense.module.ts
@@ -0,0 +1,23 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { HttpClientModule } from '@angular/common/http';
+import { FormsModule } from '@angular/forms';
+import { RouterModule } from '@angular/router';
+import { ChildComponent } from './child/child.component';
+import { ExpenseComponent } from './expense.component';
+
+@NgModule({
+ declarations: [
+ ChildComponent
+ ],
+ imports: [
+ CommonModule,
+ FormsModule,
+ HttpClientModule,
+ RouterModule.forChild([
+ { path:'',component:ExpenseComponent},
+ { path:'new',component: ChildComponent}]
+ )
+ ]
+})
+export class ExpenseModule { }
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expense.service.ts b/ExpenseRecord/ClientApp/src/app/expense/expense.service.ts
new file mode 100644
index 0000000..5896f74
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expense.service.ts
@@ -0,0 +1,33 @@
+import { HttpClient } from '@angular/common/http';
+import { Inject, Injectable } from '@angular/core';
+import { Observable, tap } from 'rxjs';
+import { IExpenseItem } from './expenseItem';
+import { INewExpenseItem } from './newexpense';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ExpenseService {
+
+ private baseUrl = "https://localhost:7081/api/v1/Expense";
+ //private baseUrl = "./assets/api/expense.json";
+ constructor(private http: HttpClient,) {
+
+ }
+
+ getItems(): Observable {
+ return this.http.get(this.baseUrl)
+ .pipe(
+ tap(data => console.log('All: ', JSON.stringify(data)))
+ )};
+
+ addItems(newItem:INewExpenseItem):Observable{
+ return this.http.post<[IExpenseItem]>(this.baseUrl,newItem)
+ }
+
+ deleteExpense(id:string):Observable{
+ const deleteUrl = `${this.baseUrl}/${id}`;
+ console.log(deleteUrl);
+ return this.http.delete(deleteUrl);
+ }
+}
diff --git a/ExpenseRecord/ClientApp/src/app/expense/expenseItem.ts b/ExpenseRecord/ClientApp/src/app/expense/expenseItem.ts
new file mode 100644
index 0000000..e71c8fa
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/expenseItem.ts
@@ -0,0 +1,8 @@
+export interface IExpenseItem
+{
+ id:string
+ description: string;
+ type:string;
+ amount:number;
+ createTime: string;
+}
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/app/expense/newexpense.ts b/ExpenseRecord/ClientApp/src/app/expense/newexpense.ts
new file mode 100644
index 0000000..7a8eaa5
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/app/expense/newexpense.ts
@@ -0,0 +1,7 @@
+export interface INewExpenseItem
+{
+ description: string;
+ type:string;
+ amount:number;
+
+}
\ No newline at end of file
diff --git a/ExpenseRecord/ClientApp/src/assets/api/expense.json b/ExpenseRecord/ClientApp/src/assets/api/expense.json
new file mode 100644
index 0000000..272e839
--- /dev/null
+++ b/ExpenseRecord/ClientApp/src/assets/api/expense.json
@@ -0,0 +1,26 @@
+[
+ {
+ "Amount": 1,
+ "Description": "AAAitem1",
+ "Type": "meals",
+ "CreateTime": "20230709"
+ },
+ {
+ "Amount": 22,
+ "Description": "BBBitem1",
+ "Type": "meals",
+ "CreateTime": "20230909"
+ },
+ {
+ "Amount": 233,
+ "Description": "CCCitem1",
+ "Type": "meals",
+ "CreateTime": "20030909"
+ },
+ {
+ "Amount": 22,
+ "Description": "DDitem1",
+ "Type": "meals",
+ "CreateTime": "2019-07-31"
+ }
+ ]
\ No newline at end of file
diff --git a/ExpenseRecord/Controllers/ExpenseController.cs b/ExpenseRecord/Controllers/ExpenseController.cs
new file mode 100644
index 0000000..a4d8a86
--- /dev/null
+++ b/ExpenseRecord/Controllers/ExpenseController.cs
@@ -0,0 +1,55 @@
+using ExpenseRecord.DataModel;
+using ExpenseRecord.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace ExpenseRecord.Controllers
+{
+ [ApiController]
+ [Produces("application/json")]
+ [Route("api/v1/[controller]")]
+ [AllowAnonymous]
+ public class ExpenseController : ControllerBase
+ {
+ private readonly IExpenseService _expenseServices;
+ public ExpenseController(IExpenseService expenseService)
+ {
+ _expenseServices = expenseService;
+ }
+
+ [HttpGet]
+ public async Task> GetALL()
+ {
+ var result = await _expenseServices.GetAsync();
+ if (result == null)
+ {
+ return new List();
+ }
+ return result;
+ }
+
+ [HttpPost]
+ public async Task> PostAsync([FromBody] ExpenseItemCreateRequest toDoItemCreateRequest)
+ {
+ DateTime currentTime = DateTime.Now;
+ var toDoItemDto = new ExpenseItem
+ {
+ Id = Guid.NewGuid().ToString(),
+ Description = toDoItemCreateRequest.Description,
+ Type = toDoItemCreateRequest.Type,
+ Amount = toDoItemCreateRequest.Amount,
+ CreateTime = currentTime.ToString("yyyyMMdd"),
+
+ };
+ await _expenseServices.CreateAsync(toDoItemDto);
+ return Created("", toDoItemDto);
+ }
+ [HttpDelete("{id}")]
+ public async Task DeleteAsync(string id)
+ {
+ await _expenseServices.DeleteAsync(id);
+
+ }
+
+ }
+}
diff --git a/ExpenseRecord/DataModel/ExpenseItem.cs b/ExpenseRecord/DataModel/ExpenseItem.cs
new file mode 100644
index 0000000..955f697
--- /dev/null
+++ b/ExpenseRecord/DataModel/ExpenseItem.cs
@@ -0,0 +1,15 @@
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace ExpenseRecord.DataModel
+{
+ public class ExpenseItem
+ {
+ [BsonId]
+ public string Id { get; set; }
+ public string Description { get; set; }
+ public string Type { get; set; }
+ public double Amount { get; set; }
+ public string CreateTime { get; set; } // 修正拼写
+ }
+
+}
diff --git a/ExpenseRecord/DataModel/ExpenseItemCreateRequest.cs b/ExpenseRecord/DataModel/ExpenseItemCreateRequest.cs
new file mode 100644
index 0000000..8f2ded0
--- /dev/null
+++ b/ExpenseRecord/DataModel/ExpenseItemCreateRequest.cs
@@ -0,0 +1,14 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace ExpenseRecord.DataModel
+{
+ public class ExpenseItemCreateRequest
+ {
+ [Required]
+ [StringLength(50)]
+ public string Description { get; set; }
+ public string Type { get; set; }
+ public double Amount { get; set; }
+
+ }
+}
diff --git a/ExpenseRecord/ExpenseRecord.csproj b/ExpenseRecord/ExpenseRecord.csproj
index 0fd2d82..1a36bf1 100644
--- a/ExpenseRecord/ExpenseRecord.csproj
+++ b/ExpenseRecord/ExpenseRecord.csproj
@@ -12,6 +12,7 @@
+
diff --git a/ExpenseRecord/Program.cs b/ExpenseRecord/Program.cs
index 2a69b14..7cd2447 100644
--- a/ExpenseRecord/Program.cs
+++ b/ExpenseRecord/Program.cs
@@ -1,10 +1,33 @@
+using ExpenseRecord.Services;
+
+
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
+builder.Services.AddCors(policy =>
+
+{
+
+ policy.AddPolicy("CorsPolicy", opt => opt
+
+ .AllowAnyOrigin()
+
+ .AllowAnyHeader()
+
+ .AllowAnyMethod()
+
+ .WithExposedHeaders("X-Pagination"));
+
+});
+
+builder.Services.AddSingleton();
+builder.Services.Configure(builder.Configuration.GetSection("ExpenseDatabases"));
+
var app = builder.Build();
+app.UseCors("CorsPolicy");
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
diff --git a/ExpenseRecord/Services/DataBaseSetting.cs b/ExpenseRecord/Services/DataBaseSetting.cs
new file mode 100644
index 0000000..014b54e
--- /dev/null
+++ b/ExpenseRecord/Services/DataBaseSetting.cs
@@ -0,0 +1,9 @@
+namespace ExpenseRecord.Services
+{
+ public class DataBaseSetting
+ {
+ public string ConnectionString { get; set; } = null!;
+ public string DatabaseName { get; set; } = null!;
+ public string CollectionName { get; set; } = null!;
+ }
+}
diff --git a/ExpenseRecord/Services/ExpenseService.cs b/ExpenseRecord/Services/ExpenseService.cs
new file mode 100644
index 0000000..f56a292
--- /dev/null
+++ b/ExpenseRecord/Services/ExpenseService.cs
@@ -0,0 +1,52 @@
+using ExpenseRecord.DataModel;
+using Microsoft.Extensions.Options;
+using MongoDB.Driver;
+
+namespace ExpenseRecord.Services
+{
+ public class ExpenseService : IExpenseService
+ {
+ //依赖注入MongoDB数据库
+ private readonly IMongoCollection _expenseItemCollection;
+ public ExpenseService(IOptions DataBaseSetting)
+ {
+ var mongoClient = new MongoClient(DataBaseSetting.Value.ConnectionString);
+ var mongoDatabase = mongoClient.GetDatabase(DataBaseSetting.Value.DatabaseName);
+ _expenseItemCollection = mongoDatabase.GetCollection(DataBaseSetting.Value.CollectionName);
+ }
+ //create
+ public async Task CreateAsync(ExpenseItem newToDoItem)
+ {
+ await _expenseItemCollection.InsertOneAsync(newToDoItem);
+ }
+
+ //Getall
+ public async Task> GetAsync()
+ {
+ var expenseItemDtos = new List();
+ var expenseItems = await _expenseItemCollection.Find(_ => true).ToListAsync();
+ if (expenseItems is null)
+ {
+ return expenseItemDtos;
+ }
+ for (var i = 0; i< expenseItems.Count; i++)
+ {
+ expenseItemDtos.Add(new ExpenseItem
+ {
+ Id = expenseItems[i].Id,
+ Description = expenseItems[i].Description,
+ Type = expenseItems[i].Type,
+ Amount = expenseItems[i].Amount,
+ CreateTime = expenseItems[i].CreateTime,
+
+ });
+ }
+ return expenseItemDtos;
+ }
+ public async Task DeleteAsync(string id)
+ {
+ await _expenseItemCollection.DeleteOneAsync(x => x.Id == id);
+
+ }
+ }
+}
diff --git a/ExpenseRecord/Services/IExpenseService.cs b/ExpenseRecord/Services/IExpenseService.cs
new file mode 100644
index 0000000..9c19170
--- /dev/null
+++ b/ExpenseRecord/Services/IExpenseService.cs
@@ -0,0 +1,11 @@
+using ExpenseRecord.DataModel;
+
+namespace ExpenseRecord.Services
+{
+ public interface IExpenseService
+ {
+ Task> GetAsync();
+ Task CreateAsync(ExpenseItem newItem);
+ Task DeleteAsync(string id);
+ }
+}
diff --git a/ExpenseRecord/WeatherForecast.cs b/ExpenseRecord/WeatherForecast.cs
deleted file mode 100644
index fa9c69d..0000000
--- a/ExpenseRecord/WeatherForecast.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace ExpenseRecord;
-
-public class WeatherForecast
-{
- public DateTime Date { get; set; }
-
- public int TemperatureC { get; set; }
-
- public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
-
- public string? Summary { get; set; }
-}
\ No newline at end of file
diff --git a/ExpenseRecord/appsettings.json b/ExpenseRecord/appsettings.json
index ad75fee..92781dd 100644
--- a/ExpenseRecord/appsettings.json
+++ b/ExpenseRecord/appsettings.json
@@ -1,10 +1,15 @@
{
"Logging": {
- "LogLevel": {
+ "LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
- }
- },
-"AllowedHosts": "*"
+ }
+ },
+ "AllowedHosts": "*",
+ "ExpenseDatabases": {
+ "ConnectionString": "mongodb://localhost:27017/",
+ "DatabaseName": "Expense",
+ "CollectionName": "ExpenseItem"
+ }
}