上传文件至 src/views
This commit is contained in:
60
src/views/SystemAdmin.vue
Normal file
60
src/views/SystemAdmin.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
<UserMenu />
|
||||||
|
|
||||||
|
<div class="random-image-page">
|
||||||
|
<img v-if="currentImage" :src="currentImage" class="image" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import UserMenu from "../components/UserMenu.vue";
|
||||||
|
|
||||||
|
const images = [
|
||||||
|
"/image/nekoA.jpg",
|
||||||
|
"/image/nekoB.jpg",
|
||||||
|
"/image/nekoC.jpg",
|
||||||
|
"/image/nekoD.jpg",
|
||||||
|
"/image/nekoE.jpg",
|
||||||
|
"/image/nekoF.jpg",
|
||||||
|
"/image/nekoG.jpg",
|
||||||
|
"/image/nekoH.jpg",
|
||||||
|
];
|
||||||
|
|
||||||
|
const currentImage = ref(null);
|
||||||
|
|
||||||
|
const changeImage = () => {
|
||||||
|
const index = Math.floor(Math.random() * images.length);
|
||||||
|
currentImage.value = images[index];
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
changeImage();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@import "@/assets/common.css";
|
||||||
|
|
||||||
|
.page-container {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.random-image-page {
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
max-width: auto;
|
||||||
|
max-height: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
</style>
|
137
src/views/UserLogin.vue
Normal file
137
src/views/UserLogin.vue
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<div class="login-wrapper">
|
||||||
|
<el-form
|
||||||
|
:model="loginForm"
|
||||||
|
class="login-form"
|
||||||
|
@keydown.enter.prevent="handleEnter"
|
||||||
|
>
|
||||||
|
<el-form-item label="ユーザーID">
|
||||||
|
<el-input
|
||||||
|
v-model="loginForm.id"
|
||||||
|
placeholder="ユーザーIDを入力"
|
||||||
|
ref="idInput"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="パスワード">
|
||||||
|
<el-input
|
||||||
|
v-model="loginForm.password"
|
||||||
|
type="password"
|
||||||
|
placeholder="パスワードを入力"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label-width="0">
|
||||||
|
<div style="display: flex; justify-content: center; width: 100%">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="login"
|
||||||
|
:loading="isLoading"
|
||||||
|
class="login-btn"
|
||||||
|
size="default"
|
||||||
|
>
|
||||||
|
ログイン
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="loginForm.messageflag">
|
||||||
|
<el-alert
|
||||||
|
:title="loginForm.message"
|
||||||
|
type="error"
|
||||||
|
show-icon
|
||||||
|
:closable="false"
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const loginForm = ref({
|
||||||
|
id: "",
|
||||||
|
password: "",
|
||||||
|
message: "",
|
||||||
|
messageflag: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const isLoading = ref(false);
|
||||||
|
const idInput = ref();
|
||||||
|
|
||||||
|
const handleEnter = () => {
|
||||||
|
if (!isLoading.value) login();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
idInput.value?.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
const login = async () => {
|
||||||
|
isLoading.value = true;
|
||||||
|
loginForm.value.messageflag = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axios.post("/api/login", {
|
||||||
|
id: loginForm.value.id,
|
||||||
|
password: loginForm.value.password,
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = res.data;
|
||||||
|
|
||||||
|
if (!response.success) {
|
||||||
|
loginForm.value.messageflag = true;
|
||||||
|
loginForm.value.message = response.message || "ログインエラー";
|
||||||
|
} else {
|
||||||
|
const { redirect, user } = response.data;
|
||||||
|
sessionStorage.setItem("loginInfo", JSON.stringify(user));
|
||||||
|
router.push(redirect);
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
loginForm.value.messageflag = true;
|
||||||
|
loginForm.value.message =
|
||||||
|
error.response?.data?.message || "サーバーエラーが発生しました";
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.login-wrapper {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 80px auto;
|
||||||
|
padding: 24px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
::v-deep(.el-alert) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
::v-deep(.el-alert__icon) {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
::v-deep(.el-alert__icon svg) {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
Reference in New Issue
Block a user