<template>
<div class="common-layout">
<el-container>
<!--标头-->
<el-header><div>龙湾农业科技公司</div></el-header>
<el-container>
<!--导航栏-->
<Sidebar/>
<!--主体-->
<el-main>Main</el-main>
</el-container>
</el-container>
</div>
</template>
<script lang="ts" setup>
import Sidebar from './components/Sidebar.vue';
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
height: 100vh;
}
</style> <template>
<el-aside width="200px">
<el-row class="tac">
<el-menu :default-active="activeIndex" class="el-menu-vertical" background-color="#545c64" text-color="#fff"
active-text-color="#ffd04b" router>
<el-menu-item :index="v.url" v-for="v in items" :key="v.url">
<el-icon><icon-menu /></el-icon>
<template #title>{{v.name}}</template>
</el-menu-item>
</el-menu>
</el-row>
</el-aside>
</template>
<script lang="ts" setup>
import type { ISidebar } from '../utils/models'
import { useRoute } from 'vue-router'
import { reactive, ref } from 'vue'
const items = reactive<ISidebar[]>([
{name:'首页',url:'/frontpage'},
{name:'学生管理',url:'/student-management'},
{name:'卫生管理',url:'/hygiene-management'},
{name:'学生成绩',url:'/score-management'},
{name:'学生才艺',url:'/talent-management'},
])
const route = useRoute()
const activeIndex = ref(route.path)
</script>
<style scoped>
.el-menu-vertical {
height: 100vh;
border-right: none;
}
</style>
import { createRouter,createWebHashHistory,type RouteRecordRaw } from "vue-router";
const routes:Array<RouteRecordRaw> = [
{path:'/frontpage',//首页
name:'Frontpage',
component: ()=> import('../components/Frontpage.vue')
},
{
path: '/student-management',//学生管理
name: 'StudentManagement',
component: () => import('../components/StudentManagement.vue')
},
{
path: '/hygiene-management',//卫生管理
name: 'HygieneManagement',
component: () => import('../components/HygieneManagement.vue')
},
{
path: '/score-management',//学生成绩
name: 'ScoreManagement',
component: () => import('../components/ScoreManagement.vue')
},
{
path: '/talent-management',//学生才艺
name: 'TalentManagement',
component: () => import('../components/TalentManagement.vue')
},
{
path: '/',
redirect: '/student-management'
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router export interface ISidebar{
name:string;
url:string;
} /* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
position: relative;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition: color 0.5s, background-color 0.5s;
line-height: 1.6;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@import "./base.css";
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
a,
.green {
text-decoration: none;
color: hsla(160, 100%, 37%, 1);
transition: 0.4s;
}
@media (hover: hover) {
a:hover {
background-color: hsla(160, 100%, 37%, 0.2);
}
}
@media (min-width: 1024px) {
body {
display: flex;
place-items: center;
}
#app {
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
}
}
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'
import axios from 'axios'
// 配置axios基础URL
axios.defaults.baseURL = 'http://127.0.0.1:3000'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount('#app') <template>
<div class="student-management">
<el-card>
<template #header>
<div class="card-header">
<span>学生管理</span>
<el-button type="primary" @click="showDialog = true">添加学生</el-button>
</div>
</template>
<el-table :data="studentStore.students" v-loading="studentStore.loading" border>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="gender" label="性别" width="80">
<template #default="{ row }">
{{ row.gender === 'male' ? '男' : '女' }}
</template>
</el-table-column>
<el-table-column prop="age" label="年龄" width="80" />
<el-table-column prop="grade" label="年级" />
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog v-model="showDialog" :title="dialogTitle" width="30%">
<el-form :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="form.gender">
<el-radio label="male">男</el-radio>
<el-radio label="female">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="年龄">
<el-input-number v-model="form.age" :min="6" :max="30" />
</el-form-item>
<el-form-item label="年级">
<el-select v-model="form.grade" placeholder="请选择年级">
<el-option label="一年级" value="一年级" />
<el-option label="二年级" value="二年级" />
<el-option label="三年级" value="三年级" />
<el-option label="四年级" value="四年级" />
<el-option label="五年级" value="五年级" />
<el-option label="六年级" value="六年级" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showDialog = false">取消</el-button>
<el-button type="primary" @click="submitForm">确认</el-button>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { useStudentStore } from '../stores/studentStores'
import { ElMessageBox, ElMessage } from 'element-plus'
const studentStore = useStudentStore()
const showDialog = ref(false)
const isEditMode = ref(false)
const currentId = ref(0)
const form = reactive({
name: '',
gender: 'male',
age: 10,
grade: '一年级'
})
const dialogTitle = computed(() => isEditMode.value ? '编辑学生' : '添加学生')
onMounted(() => {
studentStore.fetchStudents()
})
const handleEdit = (student: any) => {
isEditMode.value = true
currentId.value = student.id
form.name = student.name
form.gender = student.gender
form.age = student.age
form.grade = student.grade
showDialog.value = true
}
const handleDelete = async (id: number) => {
try {
await ElMessageBox.confirm('确定要删除该学生吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
await studentStore.deleteStudent(id)
ElMessage.success('删除成功')
} catch (error) {
console.error(error)
}
}
const submitForm = async () => {
try {
if (isEditMode.value) {
await studentStore.updateStudent({
id: currentId.value,
...form
})
ElMessage.success('更新成功')
} else {
await studentStore.addStudent(form)
ElMessage.success('添加成功')
}
showDialog.value = false
resetForm()
} catch (error) {
console.error(error)
}
}
const resetForm = () => {
form.name = ''
form.gender = 'male'
form.age = 10
form.grade = '一年级'
isEditMode.value = false
currentId.value = 0
}
</script>
<style scoped>
.student-management {
padding: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style> import mysql from 'mysql2/promise'
const pool = mysql.createPool({
host: '127.0.0.1',
user: 'root',
password: '1234',
database: 'lei',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
export default pool import express from 'express'
import cors from 'cors'
import studentRoutes from './routes/students.js'
const app = express()
const port = 3000
// 中间件配置
app.use(cors())
app.use(express.json())
// 路由配置
app.use('/api/students', studentRoutes)
// 启动服务器
app.listen(port, () => {
console.log(`Server running at http://127.0.0.1:${port}`)
}) import express from 'express'
import db from '../db.js'
const router = express.Router()
// 获取所有学生
router.get('/', async (req, res) => {
try {
const [rows] = await db.query('SELECT * FROM students')
res.json(rows)
} catch (err) {
res.status(500).json({ error: err.message })
}
})
// 添加新学生
router.post('/', async (req, res) => {
const { name, gender, age, grade } = req.body
try {
const [result] = await db.query(
'INSERT INTO students (name, gender, age, grade) VALUES (?, ?, ?, ?)',
[name, gender, age, grade]
)
res.json({ id: result.insertId, name, gender, age, grade })
} catch (err) {
res.status(500).json({ error: err.message })
}
})
// 更新学生信息
router.put('/:id', async (req, res) => {
const { id } = req.params
const { name, gender, age, grade } = req.body
try {
await db.query(
'UPDATE students SET name=?, gender=?, age=?, grade=? WHERE id=?',
[name, gender, age, grade, id]
)
res.json({ id, name, gender, age, grade })
} catch (err) {
res.status(500).json({ error: err.message })
}
})
// 删除学生
router.delete('/:id', async (req, res) => {
const { id } = req.params
try {
await db.query('DELETE FROM students WHERE id=?', [id])
res.json({ message: 'Student deleted successfully' })
} catch (err) {
res.status(500).json({ error: err.message })
}
})
export default router 分析代码哪里出错了,页面空白