add: страница логина, переход с vuex на pinia

This commit is contained in:
mfnefd 2024-12-03 02:10:20 +04:00
parent bc5992552a
commit e8bb036d35
16 changed files with 231 additions and 48 deletions

View File

@ -20,9 +20,10 @@ if (app.Environment.IsDevelopment())
app.UseSwagger();
app.UseSwaggerUI();
}
app.MigrateDb();
app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
app.UseHttpsRedirection();
app.UseAuthorization();

22
front/components.d.ts vendored Normal file
View File

@ -0,0 +1,22 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AButton: typeof import('ant-design-vue/es')['Button']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
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']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SignUp: typeof import('./src/components/pages/SignUp.vue')['default']
}
}

View File

@ -9,9 +9,9 @@
"version": "0.0.0",
"dependencies": {
"ant-design-vue": "^4.2.6",
"pinia": "^2.2.8",
"vue": "^3.5.12",
"vue-router": "^4.5.0",
"vuex": "^4.1.0"
"vue-router": "^4.5.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.4",
@ -2135,6 +2135,58 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pinia": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.2.8.tgz",
"integrity": "sha512-NRTYy2g+kju5tBRe0oNlriZIbMNvma8ZJrpHsp3qudyiMEA8jMmPPKQ2QMHg0Oc4BkUyQYWagACabrwriCK9HQ==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^6.6.3",
"vue-demi": "^0.14.10"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"@vue/composition-api": "^1.4.0",
"typescript": ">=4.4.4",
"vue": "^2.6.14 || ^3.5.11"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/pkg-types": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz",
@ -2799,18 +2851,6 @@
"vue": "^3.0.0"
}
},
"node_modules/vuex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.1.0.tgz",
"integrity": "sha512-hmV6UerDrPcgbSy9ORAtNXDr9M4wlNP4pEFKye4ujJF8oqgFFuxDCdOLS3eNoRTtq5O3hoBDh9Doj1bQMYHRbQ==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^6.0.0-beta.11"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",

View File

@ -11,9 +11,9 @@
},
"dependencies": {
"ant-design-vue": "^4.2.6",
"pinia": "^2.2.8",
"vue": "^3.5.12",
"vue-router": "^4.5.0",
"vuex": "^4.1.0"
"vue-router": "^4.5.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.4",

View File

@ -10,5 +10,10 @@ import Header from './components/main/Header.vue';
</template>
<style scoped>
main {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
</style>

View File

@ -2,15 +2,7 @@
</script>
<template>
<header>
<nav class="flex items-center justify-between p-4">
<a href="/" class="text-2xl font-bold">Мои финансы</a>
<ul class="flex items-center space-x-4">
<li><a href="/change-records" class="text-lg">Домашняя страница</a></li>
<li><a href="/spending-groups" class="text-lg">Группы расходов</a></li>
</ul>
</nav>
</header>
<div>Header</div>
</template>
<style scoped>

View File

@ -0,0 +1,76 @@
<template>
<a-form
:model="formState"
name="login"
class="login-form"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item
label="Логин"
name="name"
:rules="[{ required: true, message: 'Пожалуйста, введите свой логин' }]"
>
<a-input v-model:value="formState.name">
<template #prefix>
<UserOutlined class="site-form-item-icon" />
</template>
</a-input>
</a-form-item>
<a-form-item
label="Пароль"
name="password"
:rules="[{ required: true, message: 'Пароль тоже нужен!' }]"
>
<a-input-password v-model:value="formState.password">
<template #prefix>
<LockOutlined class="site-form-item-icon" />
</template>
</a-input-password>
</a-form-item>
<a-form-item>
<a-button :disabled="disabled" type="primary" html-type="submit" class="login-form-button">
Войти
</a-button>
Или
<RouterLink to="/register">зарегестрироваться</RouterLink>
</a-form-item>
</a-form>
</template>
<script lang="ts" setup>
import { reactive, computed, inject } from 'vue';
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue';
import { UserLoginDto } from '../../core/api/data-contracts';
import { RouterLink } from 'vue-router';
import { AuthService } from '../../core/services/auth-service';
import router from '../../router';
const formState = reactive<UserLoginDto>({
name: '',
password: '',
});
const authService = inject(typeof(AuthService)) as AuthService;
// Логика формы
const onFinish = (values: any) => {
console.log('Success:', values);
authService.login(formState);
router.push({ name: 'home' });
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
const disabled = computed(() => {
return !(formState.name && formState.password);
});
</script>
<style scoped>
.login-form {
max-width: 300px;
}
.login-form-button {
width: 100%;
}
</style>

View File

View File

@ -17,7 +17,7 @@ import {
SpendingPlanDto,
SpendingPlanViewModel,
UserDto,
UserLoginDTO,
UserLoginDto,
UserViewModel,
} from "./data-contracts";
import { ContentType, HttpClient, RequestParams } from "./http-client";
@ -31,7 +31,7 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
* @request POST:/api/Auth
* @response `200` `UserViewModel` Success
*/
authCreate = (data: UserLoginDTO, params: RequestParams = {}) =>
auth = (data: UserLoginDto, params: RequestParams = {}) =>
this.request<UserViewModel, any>({
path: `/api/Auth`,
method: "POST",
@ -48,7 +48,7 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
* @request POST:/api/Auth/register
* @response `200` `UserViewModel` Success
*/
authRegisterCreate = (data: UserDto, params: RequestParams = {}) =>
authRegister = (data: UserDto, params: RequestParams = {}) =>
this.request<UserViewModel, any>({
path: `/api/Auth/register`,
method: "POST",

View File

@ -82,7 +82,7 @@ export interface UserDto {
balance?: number;
}
export interface UserLoginDTO {
export interface UserLoginDto {
name?: string | null;
password?: string | null;
}

View File

@ -55,7 +55,7 @@ export enum ContentType {
}
export class HttpClient<SecurityDataType = unknown> {
public baseUrl: string = "";
public baseUrl: string = "http://localhost:5125";
private securityData: SecurityDataType | null = null;
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
private abortControllers = new Map<CancelToken, AbortController>();

View File

@ -0,0 +1,25 @@
import { useUserStore } from "../../store";
import { Api } from "../api/Api";
import { UserDto, UserLoginDto } from "../api/data-contracts";
export class AuthService {
private readonly _api: Api;
constructor(api: Api) {
this._api = api;
}
async login(data: UserLoginDto) {
let result = await this._api.auth(data);
console.log(result);
const store = useUserStore();
store.updateUser(result.data);
}
async register(data: UserDto) {
let result = await this._api.authRegister(data);
const store = useUserStore();
store.updateUser(result.data);
}
}

View File

@ -1,12 +1,18 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { key, store } from './store'
import router from './router'
import { Api } from './core/api/Api'
import { createPinia } from 'pinia'
import { AuthService } from './core/services/auth-service'
const app = createApp(App)
app.use(store, key)
app.use(router)
app.use(createPinia())
// Di
const api = new Api();
app.provide(typeof(AuthService), new AuthService(api))
app.mount('#app')

View File

@ -5,7 +5,13 @@ export default createRouter({
routes: [
{
path: '/',
name: 'home',
component: () => import('./components/pages/Home.vue'),
},
{
path: '/login',
name: 'login',
component: () => import('./components/pages/Login.vue'),
}
],
})

View File

@ -1,20 +1,19 @@
import { InjectionKey } from 'vue'
import { createStore, Store } from 'vuex'
import { UserViewModel } from './core/api/data-contracts'
import { defineStore } from 'pinia'
export interface State {
user: UserViewModel | null
user: UserViewModel
}
export const key: InjectionKey<Store<State>> = Symbol()
export const useUserStore = defineStore('user', {
state: (): State => ({
user: {} as UserViewModel
}),
actions: {
updateUser(payload: UserViewModel) {
if (!payload) return;
export const store = createStore<State>({
state: {
user: null
},
mutations: {
setUser(state: any, user: UserViewModel) {
state.user = user
}
this.user = payload;
},
}
})
})

View File

@ -1,7 +1,18 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
plugins: [
vue(),
Components({
resolvers: [
AntDesignVueResolver({
importStyle: false, // css in js
}),
],
}),
],
})