add: страница логина, переход с vuex на pinia
This commit is contained in:
parent
bc5992552a
commit
e8bb036d35
@ -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
22
front/components.d.ts
vendored
Normal 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']
|
||||
}
|
||||
}
|
68
front/package-lock.json
generated
68
front/package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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>
|
@ -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>
|
||||
|
76
front/src/components/pages/Login.vue
Normal file
76
front/src/components/pages/Login.vue
Normal 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>
|
0
front/src/components/pages/SignUp.vue
Normal file
0
front/src/components/pages/SignUp.vue
Normal 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",
|
||||
|
@ -82,7 +82,7 @@ export interface UserDto {
|
||||
balance?: number;
|
||||
}
|
||||
|
||||
export interface UserLoginDTO {
|
||||
export interface UserLoginDto {
|
||||
name?: string | null;
|
||||
password?: string | null;
|
||||
}
|
||||
|
@ -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>();
|
||||
|
25
front/src/core/services/auth-service.ts
Normal file
25
front/src/core/services/auth-service.ts
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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')
|
||||
|
@ -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'),
|
||||
}
|
||||
],
|
||||
})
|
||||
|
@ -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;
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
@ -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
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user