refactor(components): 重构登录组件并优化测试页面

- 重构 CustomLogin 组件,添加表单校验规则和登录按钮禁用状态
- 更新 auth.js,将 TokenKey 改为 accessToken
- 重写 TestView 组件,添加模拟数据请求和分页功能
This commit is contained in:
雨霖铃 2025-08-15 01:39:54 +08:00
parent 29f6d2b0c9
commit 2d619ac69f
3 changed files with 84 additions and 97 deletions

View File

@ -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>

View File

@ -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)

View File

@ -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>