first commit.

This commit is contained in:
2023-01-04 10:20:18 +08:00
commit 919fcf5ba9
39 changed files with 4196 additions and 0 deletions

15
src/shared/api.ts Normal file
View File

@@ -0,0 +1,15 @@
import http from "../utils/http";
export function login(data: { username: string; password: string }) {
return http.post("login", data);
}
export function logout() {
return http.get("logout");
}
export function getUserInfo(username: string) {
return http.get("profile", {
params: { username },
});
}

View File

@@ -0,0 +1,16 @@
import { defineStore } from "pinia";
import { ref } from "vue";
export const useLoginStore = defineStore("login", () => {
const visible = ref(false);
function show() {
visible.value = true;
}
function hide() {
visible.value = false;
}
return { visible, show, hide };
});

51
src/shared/stores/user.ts Normal file
View File

@@ -0,0 +1,51 @@
import { defineStore } from "pinia";
import { computed, ref } from "vue";
import {
PROBLEM_PERMISSION,
STORAGE_KEY,
USER_TYPE,
} from "../../utils/constants";
import storage from "../../utils/storage";
import { getUserInfo } from "../api";
export const useUserStore = defineStore("user", () => {
const profile = ref<any>({});
const isLoaded = ref(false);
const user = computed(() => profile.value.user || {});
const isAuthed = computed(() => !!user.value.email);
const isAdminRole = computed(
() =>
user.value.admin_type === USER_TYPE.ADMIN ||
user.value.admin_type === USER_TYPE.SUPER_ADMIN
);
const isSuperAdmin = computed(
() => user.value.admin_type === USER_TYPE.SUPER_ADMIN
);
const hasProblemPermission = computed(
() => user.value.problem_permission !== PROBLEM_PERMISSION.NONE
);
async function getMyProfile() {
isLoaded.value = false;
const res = await getUserInfo("");
isLoaded.value = true;
profile.value = res.data || {};
storage.set(STORAGE_KEY.AUTHED, !!user.value.email);
}
function clearMyProfile() {
profile.value = {};
storage.clear();
}
return {
profile,
isLoaded,
user,
isAdminRole,
isSuperAdmin,
hasProblemPermission,
isAuthed,
getMyProfile,
clearMyProfile,
};
});

93
src/shared/user/login.vue Normal file
View File

@@ -0,0 +1,93 @@
<script setup lang="ts">
import { FormInstance } from "element-plus";
import { reactive, ref } from "vue";
import { useSignupStore } from "../../oj/stores/signup";
import { login } from "../../shared/api";
import { useLoginStore } from "../stores/login";
import { useUserStore } from "../stores/user";
const loginStore = useLoginStore();
const signupStore = useSignupStore();
const userStore = useUserStore();
const loading = ref(false);
const errorMessage = ref("");
const loginRef = ref<FormInstance>();
const form = reactive({
username: "",
password: "",
});
const rules = reactive({
username: [{ required: true, message: "用户名必填", trigger: "blur" }],
password: [
{ required: true, message: "密码必填", trigger: "blur" },
{ min: 6, max: 20, message: "长度在6到20位之间", trigger: "change" },
],
});
async function submit() {
if (!loginRef.value) return;
await loginRef.value.validate(async (valid) => {
if (valid) {
loading.value = true;
errorMessage.value = "";
try {
await login(form);
loginStore.hide();
await userStore.getMyProfile();
} catch (err) {
errorMessage.value = "用户名或密码不正确";
}
loading.value = false;
}
});
}
function goSignup() {
loginStore.hide();
signupStore.show();
}
</script>
<template>
<el-dialog
style="max-width: 400px"
:close-on-click-modal="false"
:close-on-press-escape="false"
v-model="loginStore.visible"
title="登录"
>
<el-form
ref="loginRef"
:model="form"
:rules="rules"
label-position="right"
label-width="70px"
>
<el-form-item label="用户名" required prop="username">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码" required prop="password">
<el-input
v-model="form.password"
type="password"
show-password
@change="submit"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="loading" @click="submit"
>登录</el-button
>
<el-button @click="goSignup">没有账号立即注册</el-button>
</el-form-item>
<el-alert
v-if="errorMessage"
:title="errorMessage"
show-icon
type="error"
/>
</el-form>
</el-dialog>
</template>
<style scoped></style>