App.vue代码:<!–
@fenghua: 2401_87008233 3024798541@qq.com
@Date: 2025-09-05 18:56:30
@LastEditors: 2401_87008233 3024798541@qq.com
@LastEditTime: 2025-09-08 19:08:38
@FilePath: \NanChange:\Vue代码\hou_tai\src\App.vue
@Description:
Copyright © 2025 by ${fenghua}, All Rights Reserved.
–>
<script setup lang="ts"> import { ref, computed, onMounted } from 'vue' import { Search } from '@element-plus/icons-vue' import { ElMessageBox } from 'element-plus'; import { tableData } from './comm/ts' const input1 = ref('') import './comm/css.css'; import axios from 'axios'; // 新增 axios 库 // 初始化表格数据 const tableDataRef = ref<any[]>([]); const pageSize4 = ref(10) const currentPage4 = ref(1) const nextId = ref(1); // 新增:从数据库获取数据 const fetchData = async () => { try { const response = await axios.get('http://localhost:3000/api/administrators'); const data = response.data; // 转换数据结构 const convertedData = data.map((item: any, index: number) => ({ date: (index + 1).toString(), name: item.admin_name, status: true, // 默认启用状态 address: new Date(item.login_time).toLocaleString().replace(/\//g, '-'), id: item.id // 保留数据库ID })); tableDataRef.value = convertedData; nextId.value = convertedData.length + 1; } catch (error) { console.error('获取数据失败:', error); ElMessageBox.alert('数据库连接失败,请检查后端服务', '错误', { type: 'error' }); } }; // 挂载时获取数据 onMounted(() => { fetchData(); }); // 计算属性,过滤后的数据 const filteredData = computed(() => { if (!input1.value.trim()) { return tableDataRef.value; } const searchTerm = input1.value.trim().toLowerCase(); return tableDataRef.value.filter(item => item.name.toLowerCase().includes(searchTerm) ); }); // 计算属性,分页后的数据 const pagedData = computed(() => { const start = (currentPage4.value - 1) * pageSize4.value; const end = start + pageSize4.value; return filteredData.value.slice(start, end); }); // 数据函数 const handleCreate = () => { ElMessageBox.prompt('请输入角色类型名称', '新建角色', { confirmButtonText: '确定', cancelButtonText: '取消', inputPattern: /\S+/, // 非空验证 inputErrorMessage: '角色类型不能为空' }).then(({ value }) => { // 创建新数据对象 const newItem = { date: nextId.value.toString(), // 序号 name: value, // 角色类型 status: true, // 默认启用状态 address: new Date().toLocaleString().replace(/\//g, '-') }; // 添加到表格数据开头 tableDataRef.value.unshift(newItem); // 重新排序所有数据 reindexData(); }).catch(() => { // 用户取消操作 }); } // 删除函数 const handleDelete = (rowDate: string) => { ElMessageBox.confirm('确定删除该条数据吗?', '警告', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { // 查找要删除项的索引 const index = tableDataRef.value.findIndex(item => item.date === rowDate); if (index !== -1) { // 从数据源中删除该项 tableDataRef.value.splice(index, 1); // 重新排序所有数据 reindexData(); } }).catch(() => { // 用户取消操作 }); } // 重新排序数据的函数 const reindexData = () => { // 重新排序所有数据的序号 tableDataRef.value.forEach((item, index) => { item.date = (index + 1).toString(); }); // 更新下一个ID值 nextId.value = tableDataRef.value.length + 1; // 重置搜索条件和分页 input1.value = ''; currentPage4.value = 1; } // 页码改变处理函数 const handleSizeChange = (val: number) => { pageSize4.value = val; currentPage4.value = 1; } // 编辑函数 const handleEdit = (rowDate: string) => { const row = tableDataRef.value.find(item => item.date === rowDate); if (!row) return; ElMessageBox.prompt('请输入新的角色类型名称', '编辑角色', { confirmButtonText: '确定', cancelButtonText: '取消', inputValue: row.name, // 预填充当前值 inputPattern: /\S+/, // 非空验证 inputErrorMessage: '角色类型不能为空' }).then(({ value }) => { // 更新角色名称 row.name = value; // 更新操作时间为当前时间 row.address = formatDate(new Date()); }).catch(() => { // 用户取消操作 }); } // 格式化日期 const formatDate = (date: Date): string => { const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); const seconds = date.getSeconds().toString().padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } const handleCurrentChange = (val: number) => { console.log(`current page: ${val}`) currentPage4.value = val; } const parentBorder = ref(false) const preserveExpanded = ref(false) </script> <template> <div class="template"> <div class="common-layout"> <el-container> <el-header class="header"> <!-- 左侧输入框 --> <el-input v-model="input1" style="width: 300px" size="large" placeholder="请输入租户名称" :suffix-icon="Search" clearable @keyup.enter="currentPage4 = 1" /> <!-- 右侧新建框 --> <el-button type="primary" @click="handleCreate">十 新建</el-button> </el-header> <!-- /主题内容 --> <el-main class="zhuti"> <!-- 响应式数据 --> <el-table :data="pagedData" height="550" style="width: 100%"> <el-table-column prop="date" label="序号" width="100" /> <el-table-column prop="name" label="角色类型" width="180" /> <el-table-column label="用户组状态" width="340" align="center"> <template #default="scope"> <el-switch v-model="scope.row.status" /> </template> </el-table-column> <el-table-column prop="address" label="操作时间" width="280" /> <el-table-column label="操作" width="300" class="tupian"> <template v-slot="scope"> <!-- 修改这里获取行数据 --> <img src="/image/bianji.png" alt="编辑" width="20px" style="margin-right: 30px; cursor: pointer;" @click="handleEdit(scope.row.date)"> <img src="/image/qunzu.png" alt="" width="20px" style="margin-right: 30px;"> <img src="/image/zengjia.png" alt="" width="20px" style="margin-right: 30px;"> <!-- 为删除图标添加点击事件 --> <img src="/image/shanchu.png" alt="删除" width="20px" style="margin-right: 30px; cursor: pointer;" @click="handleDelete(scope.row.date)"> </template> </el-table-column> <el-table-column :border="parentBorder" :preserve-expanded-content="preserveExpanded" /> </el-table> <!-- 分页器 --> <div class="demo-pagination-block fenyeqi"> <el-pagination background v-model:current-page="currentPage4" v-model:page-size="pageSize4" :page-sizes="[10, 20, 50, 100]" :total="filteredData.length" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> </div> </el-main> </el-container> </div> </div> </template> <style scoped></style>
server.js代码:/*
@fenghua: 2401_87008233 3024798541@qq.com
@Date: 2025-09-08 19:11:03
@LastEditors: 2401_87008233 3024798541@qq.com
@LastEditTime: 2025-09-08 20:11:04
@FilePath: \NanChange:\Vue代码\hou_tai\src\server.js
@Description:
Copyright © 2025 by ${fenghua}, All Rights Reserved.
*/
const express = require(‘express’);
const mysql = require(‘mysql2’);
const cors = require(‘cors’);
const app = express();
app.use(cors());
// 数据库连接配置
const pool = mysql.createPool({
host: ‘localhost:14482’,
port: 3306,
user: ‘root’,
password: ‘123456’,
database: ‘admin_system’,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
// 管理员数据API
app.get(‘/admin_system/administrators’, async (res) => {
try {
const [rows] = await pool.promise().query( SELECT id, admin_name, login_time FROM administrators ORDER BY login_time DESC );
res.json(rows);
} catch (error) {
console.error(‘数据库查询错误:’, error);
res.status(500).json({ error: ‘数据库查询失败’ });
}
});
// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
console.log(后端服务运行在 http://localhost:${PORT});
});
数据格式要这样的:/*
* @fenghua: 2401_87008233 3024798541@qq.com
* @Date: 2025-09-05 19:41:38
* @LastEditors: 2401_87008233 3024798541@qq.com
* @LastEditTime: 2025-09-06 22:50:08
* @FilePath: \NanChange:\Vue代码\hou_tai\src\comm\ts.ts
* @Description:
*
* Copyright (c) 2025 by ${fenghua}, All Rights Reserved.
*/
// 生成指定范围内的随机整数
function getRandomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// 生成2022年的随机时间戳
function generateRandomDate(): string {
const month = getRandomInt(1, 12);
const maxDays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
const day = getRandomInt(1, maxDays);
const hours = getRandomInt(0, 23).toString().padStart(2, '0');
const minutes = getRandomInt(0, 59).toString().padStart(2, '0');
const seconds = getRandomInt(0, 59).toString().padStart(2, '0');
return `
2022-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')} ${hours}:${minutes}:${seconds}`;
}
// 生成随机管理员名称
function generateRandomName(): string {
const adminTypes = [
"系统管理员",
"超级系统管理员",
"网络管理员",
"数据库管理员",
"安全管理员",
"应用管理员",
"服务器管理员",
"高级系统管理员",
'蔡徐坤',
'程立农',
'一只小风华'
];
return adminTypes[getRandomInt(0, adminTypes.length - 1)];
}
// 生成测试数据
export const tableData = Array.from({ length: 100 }, (_, index) => ({
date: (index + 1).toString(),
name: index === 0 ? "系统管理员:超级管理员" : generateRandomName(), // 确保第一条有特殊格式
address: generateRandomDate()
}));
请按照以上代码详细的创建一个数据库并能使用