diff --git a/back/Contracts/DTOs/ChangeRecordDto.cs b/back/Contracts/DTOs/ChangeRecordDto.cs index 21d140c..30f8dbd 100644 --- a/back/Contracts/DTOs/ChangeRecordDto.cs +++ b/back/Contracts/DTOs/ChangeRecordDto.cs @@ -5,6 +5,7 @@ public class ChangeRecordDto public Guid Id { get; set; } public Guid UserId { get; set; } public Guid? SpendingGroupId { get; set; } + public string? SpendingGroupName { get; set; } public decimal Sum { get; set; } public DateTime ChangedAt { get; set; } } \ No newline at end of file diff --git a/back/Contracts/DTOs/UserLoginDTO.cs b/back/Contracts/DTOs/UserLoginDTO.cs index 73210e9..31acccc 100644 --- a/back/Contracts/DTOs/UserLoginDTO.cs +++ b/back/Contracts/DTOs/UserLoginDTO.cs @@ -1,6 +1,6 @@ namespace Contracts.DTO; -public class UserLoginDTO +public class UserLoginDto { public string Name { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; diff --git a/back/Contracts/Mappers/ChangeRecordMapper.cs b/back/Contracts/Mappers/ChangeRecordMapper.cs index 606344d..3f251ed 100644 --- a/back/Contracts/Mappers/ChangeRecordMapper.cs +++ b/back/Contracts/Mappers/ChangeRecordMapper.cs @@ -10,6 +10,7 @@ public static class ChangeRecordMapper { Id = dto.Id, Sum = dto.Sum, - ChangedAt = dto.ChangedAt + ChangedAt = dto.ChangedAt, + SpendingGroupName = dto.SpendingGroupName ?? string.Empty }; } \ No newline at end of file diff --git a/back/Contracts/SearchModels/ChangeRecordSearch.cs b/back/Contracts/SearchModels/ChangeRecordSearch.cs index 65a5094..cfad78f 100644 --- a/back/Contracts/SearchModels/ChangeRecordSearch.cs +++ b/back/Contracts/SearchModels/ChangeRecordSearch.cs @@ -6,4 +6,5 @@ public class ChangeRecordSearch public Guid? SpendingGroupId { get; set; } public DateTime? From { get; set; } public DateTime? To { get; set; } + public Guid? UserId { get; set; } } \ No newline at end of file diff --git a/back/Contracts/SearchModels/SpendingGroupSearch.cs b/back/Contracts/SearchModels/SpendingGroupSearch.cs index 927a206..8ae4ba6 100644 --- a/back/Contracts/SearchModels/SpendingGroupSearch.cs +++ b/back/Contracts/SearchModels/SpendingGroupSearch.cs @@ -4,4 +4,5 @@ public class SpendingGroupSearch { public Guid? Id { get; set; } public string? Name { get; set; } + public Guid? UserId { get; set; } } \ No newline at end of file diff --git a/back/Contracts/Services/IAuthService.cs b/back/Contracts/Services/IAuthService.cs index 03548f7..5829bce 100644 --- a/back/Contracts/Services/IAuthService.cs +++ b/back/Contracts/Services/IAuthService.cs @@ -6,6 +6,6 @@ namespace Contracts.Services; public interface IAuthService { - public Task Login(UserLoginDTO loginData); + public Task Login(UserLoginDto loginData); public Task Register(UserDto user); } \ No newline at end of file diff --git a/back/Contracts/ViewModels/ChangeRecordViewModel.cs b/back/Contracts/ViewModels/ChangeRecordViewModel.cs index 3a75eb3..99e6d82 100644 --- a/back/Contracts/ViewModels/ChangeRecordViewModel.cs +++ b/back/Contracts/ViewModels/ChangeRecordViewModel.cs @@ -5,4 +5,5 @@ public class ChangeRecordViewModel public Guid Id { get; set; } public decimal Sum { get; set; } public DateTime ChangedAt { get; set; } + public string SpendingGroupName { get; set; } = string.Empty; } \ No newline at end of file diff --git a/back/Controllers/Controllers/AuthController.cs b/back/Controllers/Controllers/AuthController.cs index 15eb928..3a5c5d1 100644 --- a/back/Controllers/Controllers/AuthController.cs +++ b/back/Controllers/Controllers/AuthController.cs @@ -18,7 +18,7 @@ public class AuthController : ControllerBase } [HttpPost] - public async Task> Login([FromBody] UserLoginDTO loginData) + public async Task> Login([FromBody] UserLoginDto loginData) { try { diff --git a/back/Infrastructure/Repositories/ChangeRecordRepo.cs b/back/Infrastructure/Repositories/ChangeRecordRepo.cs index 6da1839..289d89e 100644 --- a/back/Infrastructure/Repositories/ChangeRecordRepo.cs +++ b/back/Infrastructure/Repositories/ChangeRecordRepo.cs @@ -70,8 +70,12 @@ public class ChangeRecordRepo : IChangeRecordRepo { query = query.Where(x => x.ChangedAt >= search.From && x.ChangedAt <= search.To); } + if (search.UserId.HasValue) + { + query = query.Where(x => x.UserId == search.UserId); + } } - return await query.Select(x => x.ToDto()).ToListAsync(); + return await query.Include(x => x.SpendingGroup).Select(x => x.ToDto()).ToListAsync(); } public async Task Update(ChangeRecordDto changeRecord) diff --git a/back/Infrastructure/Repositories/SpendingGroupRepo.cs b/back/Infrastructure/Repositories/SpendingGroupRepo.cs index 6c8382a..e35215f 100644 --- a/back/Infrastructure/Repositories/SpendingGroupRepo.cs +++ b/back/Infrastructure/Repositories/SpendingGroupRepo.cs @@ -49,7 +49,9 @@ public class SpendingGroupRepo : ISpendingGroupRepo .Include(x => x.ChangeRecords) .Include(x => x.SpendingPlans) .FirstOrDefaultAsync(x => x.Id == search.Id - || x.Name == search.Name); + || (!string.IsNullOrWhiteSpace(search.Name) + && x.Name == search.Name + && x.UserId == search.UserId)); return group?.ToDto(); } @@ -67,9 +69,10 @@ public class SpendingGroupRepo : ISpendingGroupRepo query = query.Where(x => x.Id == search.Id); } - if (!string.IsNullOrWhiteSpace(search.Name)) + if (!string.IsNullOrWhiteSpace(search.Name) && search.UserId.HasValue) { - query = query.Where(x => x.Name.Contains(search.Name, StringComparison.OrdinalIgnoreCase)); + query = query.Where(x => x.Name.Contains(search.Name, StringComparison.OrdinalIgnoreCase) + && x.UserId == search.UserId); } } diff --git a/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs index cd5d76e..6f62cd6 100644 --- a/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs +++ b/back/Infrastructure/Support/Mappers/ChangeRecordMapper.cs @@ -12,7 +12,8 @@ public static class ChangeRecordMapper Sum = changeRecord.Sum, ChangedAt = changeRecord.ChangedAt, SpendingGroupId = changeRecord.SpendingGroupId, - UserId = changeRecord.UserId + UserId = changeRecord.UserId, + SpendingGroupName = changeRecord.SpendingGroup?.Name }; public static ChangeRecord ToModel(this ChangeRecordDto changeRecord) diff --git a/back/Services/Domain/AuthService.cs b/back/Services/Domain/AuthService.cs index 4d59a79..c00a47a 100644 --- a/back/Services/Domain/AuthService.cs +++ b/back/Services/Domain/AuthService.cs @@ -17,7 +17,7 @@ public class AuthService : IAuthService _userRepo = userRepo; } - public async Task Login(UserLoginDTO loginData) + public async Task Login(UserLoginDto loginData) { if (loginData == null || string.IsNullOrWhiteSpace(loginData.Name) || string.IsNullOrWhiteSpace(loginData.Password)) diff --git a/front/components.d.ts b/front/components.d.ts index f648f6c..917c6e7 100644 --- a/front/components.d.ts +++ b/front/components.d.ts @@ -9,6 +9,8 @@ declare module 'vue' { export interface GlobalComponents { AButton: typeof import('ant-design-vue/es')['Button'] ACol: typeof import('ant-design-vue/es')['Col'] + ADatePicker: typeof import('ant-design-vue/es')['DatePicker'] + AFlex: typeof import('ant-design-vue/es')['Flex'] AForm: typeof import('ant-design-vue/es')['Form'] AFormItem: typeof import('ant-design-vue/es')['FormItem'] AInput: typeof import('ant-design-vue/es')['Input'] @@ -20,12 +22,24 @@ declare module 'vue' { AMenu: typeof import('ant-design-vue/es')['Menu'] AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] ARow: typeof import('ant-design-vue/es')['Row'] + ASelect: typeof import('ant-design-vue/es')['Select'] + ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] + ASpace: typeof import('ant-design-vue/es')['Space'] + ASpin: typeof import('ant-design-vue/es')['Spin'] + ATable: typeof import('ant-design-vue/es')['Table'] ATypographyText: typeof import('ant-design-vue/es')['TypographyText'] + ChangeRecordManager: typeof import('./src/components/support/ChangeRecordManager.vue')['default'] + ChangeRecordMenu: typeof import('./src/components/support/ChangeRecordMenu.vue')['default'] + Groups: typeof import('./src/components/pages/Groups.vue')['default'] Header: typeof import('./src/components/main/Header.vue')['default'] Home: typeof import('./src/components/pages/Home.vue')['default'] Login: typeof import('./src/components/pages/Login.vue')['default'] + Manager: typeof import('./src/components/support/Manager.vue')['default'] + PlanManager: typeof import('./src/components/support/PlanManager.vue')['default'] + Plans: typeof import('./src/components/pages/Plans.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] SignUp: typeof import('./src/components/pages/SignUp.vue')['default'] + SpendingGroupManager: typeof import('./src/components/support/SpendingGroupManager.vue')['default'] } } diff --git a/front/package-lock.json b/front/package-lock.json index 7f99dfb..c1ae6fb 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -8,7 +8,9 @@ "name": "dombudg", "version": "0.0.0", "dependencies": { + "@vueuse/core": "^12.0.0", "ant-design-vue": "^4.2.6", + "dayjs": "^1.11.13", "pinia": "^2.2.8", "vue": "^3.5.12", "vue-router": "^4.5.0" @@ -895,6 +897,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.0.tgz", @@ -1080,6 +1088,42 @@ "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", "license": "MIT" }, + "node_modules/@vueuse/core": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.0.0.tgz", + "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "12.0.0", + "@vueuse/shared": "12.0.0", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.0.0.tgz", + "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.0.0.tgz", + "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==", + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", diff --git a/front/package.json b/front/package.json index daa2045..9dae701 100644 --- a/front/package.json +++ b/front/package.json @@ -10,7 +10,9 @@ "gen-api": "swagger-typescript-api -r -o ./src/core/api/ --modular -p " }, "dependencies": { + "@vueuse/core": "^12.0.0", "ant-design-vue": "^4.2.6", + "dayjs": "^1.11.13", "pinia": "^2.2.8", "vue": "^3.5.12", "vue-router": "^4.5.0" diff --git a/front/src/App.vue b/front/src/App.vue index bf3d117..5e62ec2 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -6,16 +6,16 @@ import Header from './components/main/Header.vue';
- + + + \ No newline at end of file diff --git a/front/src/components/main/Header.vue b/front/src/components/main/Header.vue index e614b8b..d2d0563 100644 --- a/front/src/components/main/Header.vue +++ b/front/src/components/main/Header.vue @@ -5,7 +5,7 @@ import { AuthService } from '../../core/services/auth-service'; import router from '../../router'; const store = useUserStore(); -const authService = inject(typeof(AuthService)) as AuthService; +const authService = inject(AuthService.name) as AuthService; function logout() { authService.logout(); @@ -20,13 +20,14 @@ function logout() {
ДомБюдж
Войти
- + +import { useAsyncState } from '@vueuse/core'; +import { inject } from 'vue'; +import { GroupService } from '../../core/services/group-service'; +import SpendingGroupManager from '../support/SpendingGroupManager.vue'; + +const groupService = inject(GroupService.name) as GroupService; + +const { state, isReady } = useAsyncState(() => groupService.getList(), []); +const columns = [ + { + title: "Название группы", + dataIndex: "name", + key: "name", + }, + { + title: "Планы группы", + dataIndex: "plans", + key: "plans", + } +] + +const refreshData = () => { + groupService.getList().then(data => { + state.value = data; + isReady.value = true; + }); +} + + + + + \ No newline at end of file diff --git a/front/src/components/pages/Home.vue b/front/src/components/pages/Home.vue index 6803de9..3bff76c 100644 --- a/front/src/components/pages/Home.vue +++ b/front/src/components/pages/Home.vue @@ -1,9 +1,45 @@ \ No newline at end of file diff --git a/front/src/components/pages/SignUp.vue b/front/src/components/pages/SignUp.vue index 4adbbc8..4e8ecc6 100644 --- a/front/src/components/pages/SignUp.vue +++ b/front/src/components/pages/SignUp.vue @@ -35,7 +35,7 @@ name="balance" :rules="[{ required: true, message: 'Пожалуйста, введите свой баланс' }]" > - + diff --git a/front/src/components/support/ChangeRecordManager.vue b/front/src/components/support/ChangeRecordManager.vue new file mode 100644 index 0000000..8041ed9 --- /dev/null +++ b/front/src/components/support/ChangeRecordManager.vue @@ -0,0 +1,92 @@ + + + diff --git a/front/src/components/support/PlanManager.vue b/front/src/components/support/PlanManager.vue new file mode 100644 index 0000000..2efe8cc --- /dev/null +++ b/front/src/components/support/PlanManager.vue @@ -0,0 +1,77 @@ + + + diff --git a/front/src/components/support/SpendingGroupManager.vue b/front/src/components/support/SpendingGroupManager.vue new file mode 100644 index 0000000..28a760a --- /dev/null +++ b/front/src/components/support/SpendingGroupManager.vue @@ -0,0 +1,53 @@ + + \ No newline at end of file diff --git a/front/src/core/api/Api.ts b/front/src/core/api/Api.ts index a9c2824..6e6cab0 100644 --- a/front/src/core/api/Api.ts +++ b/front/src/core/api/Api.ts @@ -124,6 +124,8 @@ export class Api extends HttpClient @@ -151,6 +153,8 @@ export class Api extends HttpClient @@ -175,6 +179,8 @@ export class Api extends HttpClient @@ -247,6 +253,8 @@ export class Api extends HttpClient @@ -269,6 +277,8 @@ export class Api extends HttpClient @@ -402,7 +412,7 @@ export class Api extends HttpClient { + const store = useUserStore(); + if (!store.user.id) return null; + + let UserId = store.user.id; + let result = await this._api.changeRecordFilterList({ UserId }); + + console.log(result); + return result.data; + } +} \ No newline at end of file diff --git a/front/src/core/services/group-service.ts b/front/src/core/services/group-service.ts new file mode 100644 index 0000000..53930a3 --- /dev/null +++ b/front/src/core/services/group-service.ts @@ -0,0 +1,27 @@ +import { useUserStore } from "../../store"; +import { Api } from "../api/Api"; +import { SpendingGroupDto, SpendingGroupViewModel } from "../api/data-contracts"; + +export class GroupService { + private readonly _api: Api; + constructor(api: Api) { + this._api = api; + } + + async getList(): Promise { + const store = useUserStore(); + console.log("get list " + store.user.id); + if (!store.user.id) return null; + + let UserId = store.user.id; + let result = await this._api.spendingGroupFilterList({ UserId }); + + console.log(result); + return result.data; + } + + async createGroup(data: SpendingGroupDto) { + let result = await this._api.spendingGroupCreate(data); + console.log(result); + } +} \ No newline at end of file diff --git a/front/src/core/services/plans-service.ts b/front/src/core/services/plans-service.ts new file mode 100644 index 0000000..d46dd34 --- /dev/null +++ b/front/src/core/services/plans-service.ts @@ -0,0 +1,18 @@ +import { Api } from "../api/Api"; +import { SpendingPlanDto, SpendingPlanViewModel } from "../api/data-contracts"; + +export class PlanService { + async createPlan(data: SpendingPlanDto) { + const result = await this._api.spendingPlanCreate(data); + console.log(result); + } + private readonly _api: Api + constructor(api: Api) { + this._api = api; + } + + async getList(groupId: string): Promise { + const result = await this._api.spendingGroupDetail(groupId); + return result.data.spendingPlans || null; + } +} \ No newline at end of file diff --git a/front/src/main.ts b/front/src/main.ts index 97fdbc8..f18efa1 100644 --- a/front/src/main.ts +++ b/front/src/main.ts @@ -5,6 +5,9 @@ import router from './router' import { Api } from './core/api/Api' import { createPinia } from 'pinia' import { AuthService } from './core/services/auth-service' +import { ChangeRecordService } from './core/services/change-record-service' +import { GroupService } from './core/services/group-service' +import { PlanService } from './core/services/plans-service' const app = createApp(App) @@ -13,6 +16,9 @@ app.use(createPinia()) // Di const api = new Api(); -app.provide(typeof(AuthService), new AuthService(api)) +app.provide(AuthService.name, new AuthService(api)); +app.provide(ChangeRecordService.name, new ChangeRecordService(api)); +app.provide(GroupService.name, new GroupService(api)); +app.provide(PlanService.name, new PlanService(api)); app.mount('#app') diff --git a/front/src/router.ts b/front/src/router.ts index 5da31ed..7ea7136 100644 --- a/front/src/router.ts +++ b/front/src/router.ts @@ -1,6 +1,7 @@ import { createRouter, createWebHistory } from 'vue-router'; +import { useUserStore } from './store'; -export default createRouter({ +const router = createRouter({ history: createWebHistory(), routes: [ { @@ -12,11 +13,34 @@ export default createRouter({ path: '/login', name: 'login', component: () => import('./components/pages/Login.vue'), + meta: { notRequiresAuth: true }, }, { path: '/signup', name: 'signup', component: () => import('./components/pages/SignUp.vue'), + meta: { notRequiresAuth: true }, + }, + { + path: '/groups', + name: 'groups', + component: () => import('./components/pages/Groups.vue'), + }, + { + path: '/plans/:groupId', + name: 'plans', + component: () => import('./components/pages/Plans.vue'), } ], -}) +}); + +router.beforeEach((to, from, next) => { + const store = useUserStore(); + if (!to.meta.notRequiresAuth && !store.user.id) { + next({ name: 'login' }); + } else { + next(); + } +}); + +export default router; \ No newline at end of file