完成部分页面UI
This commit is contained in:
58
src/views/admin/Dashboard.vue
Normal file
58
src/views/admin/Dashboard.vue
Normal 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
96
src/views/admin/Login.vue
Normal 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>
|
||||
116
src/views/admin/ProjectsCRUD.vue
Normal file
116
src/views/admin/ProjectsCRUD.vue
Normal 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>
|
||||
Reference in New Issue
Block a user