refactor(components): 重构登录组件并优化测试页面
- 重构 CustomLogin 组件,添加表单校验规则和登录按钮禁用状态 - 更新 auth.js,将 TokenKey 改为 accessToken - 重写 TestView 组件,添加模拟数据请求和分页功能
This commit is contained in:
parent
29f6d2b0c9
commit
2d619ac69f
@ -1,88 +1,98 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'
|
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'
|
||||||
import { computed, reactive } from 'vue'
|
import { reactive, computed } from 'vue'
|
||||||
import router from '@/router/index.js'
|
import router from '@/router/index.js'
|
||||||
import { setToken } from '@/utils/auth.js'
|
import { setToken } from '@/utils/auth.js'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
|
||||||
|
// 表单状态
|
||||||
const formState = reactive({
|
const formState = reactive({
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
rememberMe: false
|
remember: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 表单校验规则
|
||||||
|
const rules = {
|
||||||
|
username: [{ required: true, message: '请输入账号' }],
|
||||||
|
password: [{ required: true, message: '请输入密码' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录按钮禁用状态
|
||||||
|
const isDisabled = computed(() => !formState.username || !formState.password)
|
||||||
|
|
||||||
|
// 表单提交
|
||||||
const onFinish = async () => {
|
const onFinish = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/auth/login', {
|
const response = await fetch('/api/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
cache: 'default',
|
headers: { 'Content-Type': 'application/json; charset=utf-8' },
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json; charset=utf-8'
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
body: JSON.stringify(formState)
|
body: JSON.stringify(formState)
|
||||||
})
|
})
|
||||||
|
|
||||||
const data = await response.json() // 解析响应体
|
const data = await response.json()
|
||||||
|
|
||||||
if (response.ok && data.code === 200) {
|
if (response.ok && data.code === 200) {
|
||||||
console.log(`formState.username: ${formState.username}`)
|
setToken(data?.data?.accessToken)
|
||||||
setToken(formState.username)
|
|
||||||
message.success('登录成功')
|
message.success('登录成功')
|
||||||
await router.push('/')
|
await router.push('/')
|
||||||
} else {
|
} else {
|
||||||
message.error(data.message || '登录失败')
|
message.error(data.message || '登录失败')
|
||||||
console.error('Login failed', data)
|
console.error('Login failed:', data)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
message.error('接口请求异常')
|
message.error('接口请求异常')
|
||||||
console.error(e)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onFinishFailed = () => {
|
// 表单提交失败
|
||||||
console.log('onFinishFailed')
|
const onFinishFailed = (errorInfo) => {
|
||||||
|
console.warn('表单验证失败:', errorInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
const disabled = computed(() => {
|
|
||||||
return !formState.username || !formState.password
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a-card class="login-container" :hoverable="true">
|
<a-card class="login-container" hoverable>
|
||||||
<a-form
|
<a-form
|
||||||
:model="formState"
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
name="login"
|
name="login"
|
||||||
class="login-form"
|
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
@finish="onFinish"
|
@finish="onFinish"
|
||||||
@finishFailed="onFinishFailed"
|
@finishFailed="onFinishFailed"
|
||||||
|
class="login-form"
|
||||||
>
|
>
|
||||||
<a-form-item name="username" :rules="[{ required: true, message: '请输入账号' }]">
|
<a-form-item name="username">
|
||||||
<a-input v-model:value="formState.username" placeholder="请输入账号">
|
<a-input v-model:value="formState.username" placeholder="请输入账号">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<UserOutlined class="site-form-item-icon" style="margin-right: 8px"></UserOutlined>
|
<UserOutlined class="site-form-item-icon" />
|
||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item name="password" :rules="[{ required: true, message: '请输入密码' }]">
|
<a-form-item name="password">
|
||||||
<a-input-password v-model:value="formState.password" placeholder="请输入密码">
|
<a-input-password v-model:value="formState.password" placeholder="请输入密码">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<LockOutlined class="site-form-item-icon" style="margin-right: 8px"></LockOutlined>
|
<LockOutlined class="site-form-item-icon" />
|
||||||
</template>
|
</template>
|
||||||
</a-input-password>
|
</a-input-password>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item name="remember" style="width: 100%">
|
<a-form-item>
|
||||||
<a-checkbox v-model:checked="formState.remember">记住我</a-checkbox>
|
<a-checkbox v-model:checked="formState.remember">记住我</a-checkbox>
|
||||||
<a class="login-form-forgot" href="">忘记密码?</a>
|
<a class="login-form-forgot" href="#">忘记密码?</a>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item style="width: 100%">
|
<a-form-item>
|
||||||
<a-button :disabled="disabled" type="primary" html-type="submit" class="login-form-button"
|
<a-button
|
||||||
>登录
|
:disabled="isDisabled"
|
||||||
|
type="primary"
|
||||||
|
html-type="submit"
|
||||||
|
class="login-form-button"
|
||||||
|
>
|
||||||
|
登录
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Cookies from 'js-cookie'
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
const TokenKey = 'account'
|
const TokenKey = 'accessToken'
|
||||||
|
|
||||||
export function getToken() {
|
export function getToken() {
|
||||||
return Cookies.get(TokenKey)
|
return Cookies.get(TokenKey)
|
||||||
|
|||||||
@ -1,80 +1,57 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import ButtonCounter from '@/components/ButtonCounter.vue'
|
import { message } from 'ant-design-vue'
|
||||||
import BlogPost from '@/components/BlogPost.vue'
|
|
||||||
import AlertBox from '@/components/AlertBox.vue'
|
|
||||||
import HomeView from './HomeView.vue'
|
|
||||||
import GameView from './GameView.vue'
|
|
||||||
import CustomMarkDown from '@/components/CustomMarkDown.vue'
|
|
||||||
import CustomModal from '@/components/CustomModal.vue'
|
|
||||||
import CustomTreeItem from '@/components/CustomTreeItem.vue'
|
|
||||||
|
|
||||||
const posts = ref([
|
const tableData = ref([])
|
||||||
{ id: 1, title: 'test01' },
|
const pagination = reactive({
|
||||||
{ id: 2, title: 'test02' },
|
current: 1,
|
||||||
{ id: 3, title: 'test03' }
|
pageSize: 10,
|
||||||
])
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
const postFontSize = ref(1)
|
// 模拟后端数据请求
|
||||||
|
const fetchTableData = async () => {
|
||||||
const currentTab = ref('HomeView')
|
try {
|
||||||
|
// 这里用假数据模拟请求
|
||||||
const tabs = {
|
const totalItems = 105
|
||||||
HomeView,
|
const items = Array.from({ length: pagination.pageSize }, (_, i) => ({
|
||||||
GameView
|
key: (pagination.current - 1) * pagination.pageSize + i + 1,
|
||||||
|
name: `用户 ${(pagination.current - 1) * pagination.pageSize + i + 1}`
|
||||||
|
}))
|
||||||
|
tableData.value = items
|
||||||
|
pagination.total = totalItems
|
||||||
|
} catch (e) {
|
||||||
|
message.error('数据加载失败')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showModal = ref(false)
|
// 页码或条数变化
|
||||||
|
const handlePageChange = (page, size) => {
|
||||||
|
pagination.current = page
|
||||||
|
pagination.pageSize = size
|
||||||
|
fetchTableData()
|
||||||
|
}
|
||||||
|
|
||||||
const modle = ref({
|
// 初始加载
|
||||||
name: 'Root',
|
onMounted(fetchTableData)
|
||||||
children: [
|
|
||||||
{ name: 'Child 1', children: [] },
|
|
||||||
{ name: 'Child 2', children: [{ name: 'Grandchild 1', children: [] }] }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1>this is test page</h1>
|
<a-table :dataSource="tableData" :pagination="false" rowKey="key">
|
||||||
<ButtonCounter title="test01" />
|
<a-table-column title="序号" dataIndex="key" />
|
||||||
|
<a-table-column title="姓名" dataIndex="name" />
|
||||||
|
</a-table>
|
||||||
|
|
||||||
<div :style="{ fontSize: postFontSize + 'em' }">
|
<a-pagination
|
||||||
<BlogPost
|
v-model:current="pagination.current"
|
||||||
v-for="post of posts"
|
:page-size="pagination.pageSize"
|
||||||
:key="post.id"
|
:total="pagination.total"
|
||||||
:id="post.id"
|
show-size-changer
|
||||||
:title="post.title"
|
show-quick-jumper
|
||||||
@enlarge-text="postFontSize += 0.1"
|
@change="handlePageChange"
|
||||||
></BlogPost>
|
@showSizeChange="handlePageChange"
|
||||||
</div>
|
style="margin-top: 16px; text-align: right"
|
||||||
|
/>
|
||||||
<AlertBox> test </AlertBox>
|
|
||||||
|
|
||||||
<div class="demo">
|
|
||||||
<button v-for="(_, tab) in tabs" :key="tab" @click="currentTab = tab">
|
|
||||||
{{ tab }}
|
|
||||||
</button>
|
|
||||||
<KeepAlive>
|
|
||||||
<component :is="tabs[currentTab]" />
|
|
||||||
</KeepAlive>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="editor">
|
|
||||||
<CustomMarkDown />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button id="show-modal" @click="showModal = true">Show Modal</button>
|
|
||||||
|
|
||||||
<Teleport to="body">
|
|
||||||
<CustomModal :show="showModal" @close="showModal = false">
|
|
||||||
<template #header>
|
|
||||||
<h3 style="color: #42b983">Custom Header</h3>
|
|
||||||
</template>
|
|
||||||
</CustomModal>
|
|
||||||
</Teleport>
|
|
||||||
|
|
||||||
<CustomTreeItem :module="modle" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user