完成部分页面UI

This commit is contained in:
2025-04-24 16:59:40 +08:00
parent 6b9faa702b
commit f1de79863e
27 changed files with 2435 additions and 47 deletions

View File

@@ -0,0 +1,58 @@
<template>
<a-layout>
<a-page-header title="数据看板" class="p-4 bg-white"/>
<a-layout-content class="p-4">
<a-row :gutter="[16, 16]">
<!-- 统计卡片 -->
<a-col :span="6">
<a-card>
<div class="flex items-center">
<div class="text-2xl font-bold mr-4">12</div>
<div class="text-gray-500">进行中项目</div>
</div>
</a-card>
</a-col>
<a-col :span="6">
<a-card>
<div class="flex items-center">
<div class="text-2xl font-bold mr-4">86%</div>
<div class="text-gray-500">完成率</div>
</div>
</a-card>
</a-col>
</a-row>
<!-- 图表区域 -->
<a-card class="mt-4">
<div id="chart-container" style="height: 400px">
<!-- 图表占位 -->
<div class="flex items-center justify-center h-full text-gray-400">
图表加载中...
</div>
</div>
</a-card>
</a-layout-content>
</a-layout>
</template>
<script setup>
import { onMounted } from 'vue'
import { Layout, PageHeader, Card, Row, Col } from 'ant-design-vue'
const [ALayout, ALayoutContent, APageHeader, ACard, ARow, ACol] = [
Layout,
Layout.Content,
PageHeader,
Card,
Row,
Col
]
</script>
<style lang="scss" scoped>
:deep(.ant-page-header) {
border-bottom: 1px solid #f0f0f0;
}
</style>

96
src/views/admin/Login.vue Normal file
View File

@@ -0,0 +1,96 @@
<script setup>
import { reactive } from 'vue'
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import { useUserStore } from '@/stores/user'
import { useRouter } from 'vue-router'
const router = useRouter()
const userStore = useUserStore()
const formState = reactive({
username: '',
password: '',
remember: true
})
const rules = {
username: [{
required: true,
message: '请输入用户名',
trigger: 'blur'
}],
password: [{
required: true,
message: '请输入密码',
trigger: 'blur'
}]
}
const handleLogin = async () => {
try {
await userStore.login({
username: formState.username,
password: formState.password
})
message.success('登录成功')
router.push('/admin/dashboard')
} catch (e) {
message.error('登录失败:' + e.message)
}
}
</script>
<template>
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<a-card class="w-full max-w-md shadow-lg" :bordered="false">
<h2 class="text-2xl font-bold mb-6 text-center">后台管理系统</h2>
<a-form
:model="formState"
:rules="rules"
@finish="handleLogin"
layout="vertical"
>
<a-form-item name="username">
<a-input
v-model:value="formState.username"
placeholder="用户名"
size="large"
>
<template #prefix><UserOutlined /></template>
</a-input>
</a-form-item>
<a-form-item name="password">
<a-input-password
v-model:value="formState.password"
placeholder="密码"
size="large"
>
<template #prefix><LockOutlined /></template>
</a-input-password>
</a-form-item>
<a-form-item>
<a-button
type="primary"
html-type="submit"
size="large"
class="w-full"
>
立即登录
</a-button>
</a-form-item>
</a-form>
</a-card>
</div>
</template>
<style lang="scss" scoped>
:deep(.ant-input-affix-wrapper) {
@apply rounded-lg px-3 py-2;
}
:deep(.ant-btn-primary) {
@apply rounded-lg;
}
</style>

View File

@@ -0,0 +1,116 @@
<script setup>
import { ref } from 'vue'
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
import { Table, Modal } from 'ant-design-vue'
const dataSource = ref([
{
id: 1,
title: '电商平台',
category: 'Web应用',
tags: ['Vue3', 'Node.js'],
author: 'Admin',
createdAt: '2024-03-20'
}
])
const columns = [
{
title: '项目名称',
dataIndex: 'title',
key: 'title',
width: 200,
},
{
title: '分类',
dataIndex: 'category',
key: 'category',
width: 120,
},
{
title: '标签',
key: 'tags',
customRender: ({ text }) => text.join(', ')
},
{
title: '操作',
key: 'action',
fixed: 'right',
width: 120,
slots: { customRender: 'action' }
}
]
const visible = ref(false)
const currentItem = ref(null)
const showModal = (item = null) => {
currentItem.value = item || { tags: [] }
visible.value = true
}
const handleDelete = (id) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除这个项目吗?',
onOk: () => {
dataSource.value = dataSource.value.filter(item => item.id !== id)
}
})
}
</script>
<template>
<div class="bg-white p-6 rounded-lg">
<div class="mb-4 flex justify-between items-center">
<h2 class="text-xl font-semibold">项目管理</h2>
<a-button type="primary" @click="showModal">
<template #icon><PlusOutlined /></template>
新建项目
</a-button>
</div>
<a-table
:columns="columns"
:data-source="dataSource"
:scroll="{ x: 800 }"
bordered
>
<template #action="{ record }">
<a-space>
<a-tooltip title="编辑">
<a-button type="link" @click="showModal(record)">
<EditOutlined />
</a-button>
</a-tooltip>
<a-tooltip title="删除">
<a-button type="link" danger @click="handleDelete(record.id)">
<DeleteOutlined />
</a-button>
</a-tooltip>
</a-space>
</template>
</a-table>
<a-modal
v-model:visible="visible"
:title="currentItem.id ? '编辑项目' : '新建项目'"
width="800px"
>
<!-- 项目表单内容 -->
<template #footer>
<a-button @click="visible = false">取消</a-button>
<a-button type="primary">确认</a-button>
</template>
</a-modal>
</div>
</template>
<style lang="scss" scoped>
:deep(.ant-table-thead > tr > th) {
@apply bg-gray-50;
}
:deep(.ant-table-tbody > tr:hover td) {
@apply bg-gray-100;
}
</style>