add, fix: Я НЕ ЗНАЮ НАДО СРОЧНО ВСЕ ДЕЛАТЬ

This commit is contained in:
mfnefd 2024-12-03 18:37:22 +04:00
parent 9d2f2be6ee
commit dffe2a6655
32 changed files with 573 additions and 25 deletions

View File

@ -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; }
}

View File

@ -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;

View File

@ -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
};
}

View File

@ -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; }
}

View File

@ -4,4 +4,5 @@ public class SpendingGroupSearch
{
public Guid? Id { get; set; }
public string? Name { get; set; }
public Guid? UserId { get; set; }
}

View File

@ -6,6 +6,6 @@ namespace Contracts.Services;
public interface IAuthService
{
public Task<UserViewModel> Login(UserLoginDTO loginData);
public Task<UserViewModel> Login(UserLoginDto loginData);
public Task<UserViewModel> Register(UserDto user);
}

View File

@ -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;
}

View File

@ -18,7 +18,7 @@ public class AuthController : ControllerBase
}
[HttpPost]
public async Task<ActionResult<UserViewModel>> Login([FromBody] UserLoginDTO loginData)
public async Task<ActionResult<UserViewModel>> Login([FromBody] UserLoginDto loginData)
{
try
{

View File

@ -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<ChangeRecordDto?> Update(ChangeRecordDto changeRecord)

View File

@ -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);
}
}

View File

@ -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)

View File

@ -17,7 +17,7 @@ public class AuthService : IAuthService
_userRepo = userRepo;
}
public async Task<UserViewModel> Login(UserLoginDTO loginData)
public async Task<UserViewModel> Login(UserLoginDto loginData)
{
if (loginData == null || string.IsNullOrWhiteSpace(loginData.Name)
|| string.IsNullOrWhiteSpace(loginData.Password))

14
front/components.d.ts vendored
View File

@ -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']
}
}

View File

@ -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",

View File

@ -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"

View File

@ -6,16 +6,16 @@ import Header from './components/main/Header.vue';
<a-layout class="layout">
<Header />
<a-layout-content>
<RouterView />
<a-flex gap="middle" vertical>
<RouterView />
</a-flex>
</a-layout-content>
</a-layout>
</template>
<style scoped>
main {
display: flex;
justify-content: center;
align-items: center;
height: 80vh;
padding: 36px;
margin: 14px;
}
</style>

View File

@ -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() {
<div>ДомБюдж</div>
<nav>
<RouterLink :to="{ name: 'home' }">Главная</RouterLink>
<RouterLink :to="{ name: 'groups' }">Группы расходов</RouterLink>
</nav>
</div>
<div v-if="!store.user.id">
<RouterLink :to="{ name: 'login' }">Войти</RouterLink>
</div>
<div v-else>
<label for="logout">Привет, {{ store.user.name }}!</label>
<label for="logout">Привет, {{ store.user.name }}! Ваш текущий баланс: {{ store.user.balance }}</label>
<a-button
name="logout"
@click="logout()"

View File

@ -0,0 +1,47 @@
<script setup lang="ts">
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;
});
}
</script>
<template>
<SpendingGroupManager :refreshData="refreshData" />
<a-table :dataSource="state" :columns="columns" v-if="isReady">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'plans'">
<RouterLink :to="{ name: 'plans', params: { groupId: record.id } }" >Планы</RouterLink>
</template>
</template>
</a-table>
<div v-else>
<a-spin size="large" />
</div>
</template>
<style scoped>
</style>

View File

@ -1,9 +1,45 @@
<script setup lang="ts">
import { useAsyncState } from '@vueuse/core';
import ChangeRecordMenu from '../support/ChangeRecordManager.vue';
import { ChangeRecordService } from '../../core/services/change-record-service';
import { inject } from 'vue';
import { ChangeRecordViewModel } from '../../core/api/data-contracts';
const changeRecordService = inject(ChangeRecordService.name) as ChangeRecordService;
const { state, isReady } = useAsyncState(() => changeRecordService.getList(), []);
const columns = [
{
title: 'Дата',
dataIndex: 'changedAt',
key: 'changedAt',
},
{
title: 'Сумма',
dataIndex: 'sum',
key: 'sum',
},
{
title: 'Группа расходов',
dataIndex: 'spendingGroupName',
key: 'spendingGroupName',
}
]
const refreshData = () => {
changeRecordService.getList().then(data => {
state.value = data;
isReady.value = true;
});
}
</script>
<template>
test!
<ChangeRecordMenu :refreshData="refreshData" />
<a-table :dataSource="state" :columns="columns" v-if="isReady" />
<div v-else>
<a-spin size="large" />
</div>
</template>
<style scoped>

View File

@ -50,8 +50,8 @@ const formState = reactive<UserLoginDto>({
name: '',
password: '',
});
const authService = inject(typeof(AuthService)) as AuthService;
const authService = inject(AuthService.name) as AuthService;
console.log(authService);
// Логика формы
const onFinish = async (values: any) => {
console.log('Success:', values);

View File

@ -0,0 +1,52 @@
<script setup lang="ts">
import { useAsyncState } from '@vueuse/core';
import { inject } from 'vue';
import { PlanService } from '../../core/services/plans-service';
import { useRoute } from 'vue-router';
import PlanManager from '../support/PlanManager.vue';
const planService = inject(PlanService.name) as PlanService;
const groupId = useRoute().params.groupId as string;
const { state, isReady } = useAsyncState(() => planService.getList(groupId), []);
const columns = [
{
title: "Планируемые расходы",
dataIndex: "sum",
key: "sum",
},
{
title: "Начало плана",
dataIndex: "startAt",
key: "startAt",
},
{
title: "Конец плана",
dataIndex: "endAt",
key: "endAt",
}
]
const refreshData = () => {
planService.getList(groupId).then(data => {
state.value = data;
isReady.value = true;
});
};
</script>
<template>
<h1>Планы группы </h1>
<PlanManager :groupId="groupId" :refreshData="refreshData"/>
<a-table :dataSource="state" :columns="columns" v-if="isReady">
</a-table>
<div v-else>
<a-spin size="large" />
</div>
</template>
<style scoped>
</style>

View File

@ -35,7 +35,7 @@
name="balance"
:rules="[{ required: true, message: 'Пожалуйста, введите свой баланс' }]"
>
<a-input-number prefix="₽" v-model:value="formState.balance" />
<a-input-number prefix="₽" v-model:value="formState.balance" min="0"/>
</a-form-item>
<a-form-item>

View File

@ -0,0 +1,92 @@
<style scoped>
</style>
<template>
<a-space direction="vertical" :size="10">
<label for="change-record">Записать изменения баланса</label>
<a-form
:model="formState"
name="change-record"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item
label="Сумма"
name="sum"
:rules="[{ required: true, message: 'Пожалуйста, введите сумму' }]"
>
<a-input-number v-model:value="formState.sum" />
</a-form-item>
<a-form-item
label="Группа расходов"
name="spendingGroupId"
v-if="isReady"
>
<a-select v-model:value="formState.spendingGroupId" :disabled="disabled">
<a-select-option v-for="group in groupList" :key="group.id" :value="group.id">
{{ group.name }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item v-else>
<a-spin size="small" />
</a-form-item>
<a-form-item
name="changedAt"
label="Дата"
>
<a-date-picker v-model:value="pickedChangedAt" />
</a-form-item>
<a-form-item>
<a-button html-type="submit" type="primary">Сохранить</a-button>
</a-form-item>
</a-form>
</a-space>
</template>
<script setup lang="ts">
import { computed, inject, reactive, ref } from 'vue';
import { ChangeRecordDto, SpendingGroupViewModel } from '../../core/api/data-contracts';
import { useUserStore } from '../../store';
import router from '../../router';
import { ChangeRecordService } from '../../core/services/change-record-service';
import { GroupService } from '../../core/services/group-service';
import { useAsyncState } from '@vueuse/core';
import type { Dayjs } from 'dayjs';
interface IProps {
refreshData: () => void
}
const { refreshData } = defineProps<IProps>();
const store = useUserStore();
// Сервисы
const changeRecordService = inject(ChangeRecordService.name) as ChangeRecordService;
const groupService = inject(GroupService.name) as GroupService;
const { state: groupList, isReady } = useAsyncState(() => groupService.getList(), []);
const pickedChangedAt = ref<Dayjs>();
const formState = reactive<ChangeRecordDto>({
userId: store.user.id,
sum: 0,
changedAt: new Date().toISOString(),
spendingGroupId: null
});
// Логика формы
const onFinish = async (values: any) => {
console.log('Success:', values);
formState.changedAt = pickedChangedAt.value?.toISOString();
await changeRecordService.createRecord(formState);
refreshData();
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
const disabled = computed(() => {
return formState.sum && formState.sum >= 0;
});
</script>

View File

@ -0,0 +1,77 @@
<style scoped>
</style>
<template>
<a-space direction="vertical" :size="10">
<label for="change-record">Добавить план расходов</label>
<a-form
:model="formState"
name="change-record"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item
label="Сумма"
name="sum"
:rules="[{ required: true, message: 'Пожалуйста, введите сумму' }]"
>
<a-input-number v-model:value="formState.sum" />
</a-form-item>
<a-form-item
name="startAt"
label="Дата начала плана"
:rules="[{ required: true, message: 'Пожалуйста, введите дату начала плана' }]"
>
<a-date-picker v-model:value="startAt" />
</a-form-item>
<a-form-item
name="endAt"
label="Дата окончания плана"
:rules="[{ required: true, message: 'Пожалуйста, введите дату окончания плана' }]"
>
<a-date-picker v-model:value="endAt" />
</a-form-item>
<a-form-item>
<a-button html-type="submit" type="primary">Добавить</a-button>
</a-form-item>
</a-form>
</a-space>
</template>
<script setup lang="ts">
import { inject, reactive, ref } from 'vue';
import { SpendingPlanDto } from '../../core/api/data-contracts';
import { ChangeRecordService } from '../../core/services/change-record-service';
import { Dayjs } from 'dayjs';
import { PlanService } from '../../core/services/plans-service';
interface IProps {
groupId: string,
refreshData: () => void
}
const { groupId, refreshData } = defineProps<IProps>();
// Сервисы
const planService = inject(PlanService.name) as PlanService;
const startAt = ref<Dayjs>();
const endAt = ref<Dayjs>();
const formState = reactive<SpendingPlanDto>({
sum: 0,
startAt: new Date().toISOString(),
endAt: new Date().toISOString(),
spendingGroupId: groupId
});
// Логика формы
const onFinish = async (values: any) => {
console.log('Success:', values);
formState.startAt = startAt.value?.toISOString();
formState.endAt = endAt.value?.toISOString();
await planService.createPlan(formState);
refreshData();
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
</script>

View File

@ -0,0 +1,53 @@
<template>
<a-space direction="vertical" :size="10">
<label for="spending-group">Создать группу расходов</label>
<a-form
:model="formState"
name="spending-group"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item
label="Название"
name="name"
:rules="[{ required: true, message: 'Пожалуйста, введите название' }]"
>
<a-input v-model:value="formState.name" />
</a-form-item>
<a-form-item>
<a-button html-type="submit" type="primary">Сохранить</a-button>
</a-form-item>
</a-form>
</a-space>
</template>
<script setup lang="ts">
import { inject, reactive } from 'vue';
import { useUserStore } from '../../store';
import { GroupService } from '../../core/services/group-service';
import { SpendingGroupDto } from '../../core/api/data-contracts';
interface IProps {
refreshData: () => void
}
const { refreshData } = defineProps<IProps>();
const store = useUserStore();
// Сервисы
const groupService = inject(GroupService.name) as GroupService;
const formState = reactive<SpendingGroupDto>({
userId: store.user.id,
name: '',
});
// Логика формы
const onFinish = async (values: any) => {
console.log('Success:', values);
await groupService.createGroup(formState);
refreshData();
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
</script>

View File

@ -124,6 +124,8 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
From?: string;
/** @format date-time */
To?: string;
/** @format uuid */
UserId?: string;
},
params: RequestParams = {},
) =>
@ -151,6 +153,8 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
From?: string;
/** @format date-time */
To?: string;
/** @format uuid */
UserId?: string;
},
params: RequestParams = {},
) =>
@ -175,6 +179,8 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
/** @format uuid */
Id?: string;
Name?: string;
/** @format uuid */
UserId?: string;
},
params: RequestParams = {},
) =>
@ -247,6 +253,8 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
/** @format uuid */
Id?: string;
Name?: string;
/** @format uuid */
UserId?: string;
},
params: RequestParams = {},
) =>
@ -269,6 +277,8 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
/** @format uuid */
Id?: string;
Name?: string;
/** @format uuid */
UserId?: string;
},
params: RequestParams = {},
) =>
@ -402,7 +412,7 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
* @request GET:/api/User
* @response `200` `UserViewModel` Success
*/
userList = (
userGet = (
query?: {
/** @format uuid */
Id?: string;

View File

@ -16,6 +16,7 @@ export interface ChangeRecordDto {
userId?: string;
/** @format uuid */
spendingGroupId?: string | null;
spendingGroupName?: string | null;
/** @format double */
sum?: number;
/** @format date-time */
@ -29,6 +30,7 @@ export interface ChangeRecordViewModel {
sum?: number;
/** @format date-time */
changedAt?: string;
spendingGroupName?: string | null;
}
export interface SpendingGroupDto {

View File

@ -0,0 +1,30 @@
import { useUserStore } from "../../store";
import { Api } from "../api/Api";
import { ChangeRecordDto, ChangeRecordViewModel } from "../api/data-contracts";
export class ChangeRecordService {
private readonly _api: Api
constructor(api: Api) {
this._api = api;
}
async createRecord(data: ChangeRecordDto) {
let result = await this._api.changeRecordCreate(data);
const store = useUserStore();
let updatedUser = await this._api.userGet({ Id: store.user.id });
store.updateUser(updatedUser.data);
console.log(result);
}
async getList(): Promise<ChangeRecordViewModel[] | null> {
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;
}
}

View File

@ -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<SpendingGroupViewModel[] | null> {
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);
}
}

View File

@ -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<SpendingPlanViewModel[] | null> {
const result = await this._api.spendingGroupDetail(groupId);
return result.data.spendingPlans || null;
}
}

View File

@ -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')

View File

@ -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;