基础环境安装
pycharm
下载地址:
https://www.jetbrains.com/zh-cn/pycharm/download/?section=windows

vscode
下载地址
python
下载地址

Node.js(含npm)
下载地址
https://nodejs.org (推荐LTS版本)

后端项目

项目结构
api/
├── models/
│ ├── __init__.py
│ └── user_model.py
├── dao/
│ ├── __init__.py
│ └── user_dao.py
├── instance/
│ └── app.db
├── routes/
│ ├── __init__.py
│ └── user_route.py
├── utils/
│ ├── __init__.py
│ └── sqlite3_util.py
├── config.py
├── run.py
└── requirements.txt

requirements.txt
blinker1.8.2
click8.1.8colorama0.4.6
Flask3.0.0Flask-Cors5.0.0
Flask-SQLAlchemy3.1.1greenlet3.1.1
importlib_metadata8.5.0itsdangerous2.2.0
Jinja23.1.6MarkupSafe2.1.5
SQLAlchemy2.0.40typing_extensions4.13.2
Werkzeug3.0.1zipp==3.20.2
①生成 requirements.txtpip freeze > requirements.txt
②基于 requirements.txt 安装
pip install -r requirements.txt
daos/user_dao.py
python
import sqlite3
from werkzeug.security import generate_password_hash
class UserDAO:
@staticmethod
def get_connection():
return sqlite3.connect('instance/app.db')
@staticmethod
def get_all_users():
conn = UserDAO.get_connection()
cursor = conn.cursor()
cursor.execute("SELECT id, username FROM users")
users = cursor.fetchall()
conn.close()
return [{'id': row[0], 'username': row[1]} for row in users]
@staticmethod
def create_user(username, password):
conn = UserDAO.get_connection()
cursor = conn.cursor()
cursor.execute("SELECT id FROM users WHERE username = ?", (username,))
if cursor.fetchone():
conn.close()
return None
password_hash = generate_password_hash(password)
cursor.execute("INSERT INTO users (username, password_hash) VALUES (?, ?)", (username, password_hash))
conn.commit()
conn.close()
return {'username': username}
@staticmethod
def delete_user(user_id):
conn = UserDAO.get_connection()
cursor = conn.cursor()
cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
conn.commit()
success = cursor.rowcount > 0
conn.close()
return success
models/user_model.py
python
import sqlite3
def init_db():
conn = sqlite3.connect('instance/app.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL
)
''')
conn.commit()
conn.close()
routes/user_route.py
python
from flask import Blueprint, request, jsonify
from api.daos.user_dao import UserDAO
bp = Blueprint('user', __name__)
@bp.route('/users', methods=['GET'])
def get_users():
users = UserDAO.get_all_users()
return jsonify(users)
@bp.route('/register', methods=['POST'])
def register():
data = request.json
username = data.get('username')
password = data.get('password')
user = UserDAO.create_user(username, password)
if user:
return jsonify(user), 201
else:
return jsonify({'error': 'User already exists'}), 409
@bp.route('/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
success = UserDAO.delete_user(user_id)
if success:
return jsonify({'message': 'User deleted successfully'}), 200
else:
return jsonify({'error': 'User not found'}), 404
utils/sqlite3_util.py
python
import sqlite3
def init_db():
conn = sqlite3.connect('instance/app.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL
)
''')
conn.commit()
conn.close()
run.py
python
from flask import Flask
from flask_cors import CORS
from routes.user_route import bp as user_bp
from utils.sqlite3_util import init_db
app = Flask(__name__)
CORS(app, resources={r"/*": {"origins": "*"}})
app.config.from_object('config.Config')
app.register_blueprint(user_bp, url_prefix='/api')
if __name__ == '__main__':
init_db()
app.run(debug=True, host='0.0.0.0')
启动
python app.py // 或者直接右键该文件运行

前端项目
新建vue项目
python
npm create vue@latest
ui
cd ui
npm install
npm install vue-router@4 axios element-plus @element-plus/icons-vue

pycharm打开效果

修改 src/assets/main.css
css
/* 导入基础样式文件 */
@import './base.css';
/*
* 主应用容器样式
* 作用:包裹整个Vue应用的根容器
*/
#app {
margin: 0 auto; /* 水平居中 */
padding: 2rem; /* 内边距(会被下方规则覆盖) */
font-weight: normal; /* 继承基础样式字体粗细 */
display: block !important; /* 强制覆盖可能的grid布局,使用块级布局 */
width: 100%; /* 撑满可用宽度 */
grid-template-columns: 1fr 1fr; /* 网格列定义(实际被block覆盖无效) */
padding: 0 2rem; /* 重定义左右内边距(覆盖上方padding) */
}
/*
* 链接及特殊文本样式
* 作用:统一超链接和.green类元素的视觉效果
*/
a,
.green {
text-decoration: none; /* 去除下划线 */
color: hsla(160, 100%, 37%, 1); /* Vue品牌绿色 (HSL格式) */
transition: 0.4s; /* 颜色过渡动画时长 */
padding: 3px; /* 内边距增强可点击区域 */
}
/*
* 悬停效果媒体查询
* 作用:只在支持hover的设备上应用悬停效果
*/
@media (hover: hover) {
a:hover {
background-color: hsla(160, 100%, 37%, 0.2); /* 半透明绿色背景 */
}
}
修改 src/main.js
javascript
/*
* 样式资源导入
* 作用:引入全局基础样式文件
*/
import './assets/main.css';
/*
* Vue核心依赖导入
* 作用:引入Vue框架核心功能
*/
import { createApp } from 'vue'; // 引入应用构造器
/*
* 应用组件导入
* 作用:引入根组件作为应用入口
*/
import App from './App.vue'; // 主应用组件
/*
* 路由配置导入
* 作用:引入路由管理系统
*/
import router from './router'; // 路由实例
/*
* UI组件库导入
* 作用:引入Element Plus及其样式
*/
import ElementPlus from 'element-plus'; // UI库核心
import 'element-plus/dist/index.css'; // UI库样式
/*
* 应用初始化
* 作用:创建并配置Vue应用实例
*/
const app = createApp(App); // 创建应用实例
/*
* 插件注册
* 作用:集成路由功能
*/
app.use(router); // 安装路由插件
/*
* UI库注册
* 作用:集成Element Plus组件库
*/
app.use(ElementPlus); // 安装UI组件库
/*
* 应用挂载
* 作用:将应用渲染到DOM
*/
app.mount('#app'); // 挂载到DOM节点
修改 src/App.vue
清空默认内容,改为空白模板
javascript
<template>
<!--
* 路由视图容器
* 作用:渲染当前路由匹配的组件
* 技术:Vue Router 核心组件
-->
<router-view />
</template>
<script>
export default {
/*
* 组件标识
* 作用:用于开发者工具调试和递归组件引用
* 命名规范:通常使用帕斯卡命名法(PascalCase)
*/
name: 'App'
};
</script>
<style>
/*
* 全局基础样式
* 作用:影响整个应用的默认样式重置
*/
/*
* 主体样式重置
* 作用:清除浏览器默认样式,设置基准字体
*/
body {
margin: 0; /* 清除默认外边距 */
font-family: Arial, /* 首选字体 */
sans-serif; /* 通用字体族后备 */
}
</style>
src/views/Dashboard.vue
javascript
<template>
<div class="dashboard-container">
<!-- 顶部导航菜单 -->
<el-menu
mode="horizontal"
:default-active="activeMenu"
:collapse="isCollapsed"
class="el-menu-horizontal-demo"
@select="handleMenuSelect"
background-color="#ffffff"
text-color="#606266"
active-text-color="#409EFF"
>
<!-- 1. 三维数据平台 -->
<el-sub-menu index="1">
<template #title>
<i class="el-icon-location"></i>
<span v-show="!isCollapsed">三维数据平台</span>
</template>
<el-menu-item index="1-1" @click="goToModelRelease">
<i class="el-icon-monitor"></i>
<span>模型发布对比</span>
</el-menu-item>
<el-menu-item index="1-2" @click="goToParseInfo">
<i class="el-icon-connection"></i>
<span>获取解析异常信息</span>
</el-menu-item>
</el-sub-menu>
<!-- 2. 测试管理 -->
<el-sub-menu index="2">
<template #title>
<i class="el-icon-cpu"></i>
<span v-show="!isCollapsed">测试管理</span>
</template>
<el-menu-item index="2-1" @click="goToTestFlow">
<i class="el-icon-guide"></i>
<span>测试流程</span>
</el-menu-item>
<el-menu-item index="2-2" @click="goToTaskReminder">
<i class="el-icon-guide"></i>
<span>任务提醒</span>
</el-menu-item>
</el-sub-menu>
<!-- 3. 工具集 -->
<el-sub-menu index="3">
<template #title>
<i class="el-icon-s-tools"></i>
<span v-show="!isCollapsed">实用工具</span>
</template>
<el-menu-item index="3-1" @click="goToJsonFormat">
<i class="el-icon-document"></i>
<span>JSON格式化</span>
</el-menu-item>
<el-menu-item index="3-2" @click="goToKafkaManager">
<i class="el-icon-document"></i>
<span>Kafka连接测试</span>
</el-menu-item>
</el-sub-menu>
<!-- 4. 学生管理 -->
<el-sub-menu index="4">
<template #title>
<i class="el-icon-user"></i>
<span v-show="!isCollapsed">学生管理</span>
</template>
<el-menu-item index="4-1" @click="goToStudentList">
<i class="el-icon-user-solid"></i>
<span>学生列表</span>
</el-menu-item>
<el-menu-item index="4-2" @click="goToStudentStats">
<i class="el-icon-data-analysis"></i>
<span>学生统计</span>
</el-menu-item>
</el-sub-menu>
<!-- 5. 新增的系统管理菜单 -->
<el-sub-menu index="5">
<template #title>
<i class="el-icon-setting"></i>
<span v-show="!isCollapsed">系统管理</span>
</template>
<el-menu-item index="5-1" @click="goToUserManage">
<i class="el-icon-user"></i>
<span>用户管理</span>
</el-menu-item>
<el-menu-item index="5-2" @click="goToRoleManage">
<i class="el-icon-s-custom"></i>
<span>角色管理</span>
</el-menu-item>
<el-menu-item index="5-3" @click="goToSystemLog">
<i class="el-icon-document"></i>
<span>系统日志</span>
</el-menu-item>
<el-menu-item index="5-4" @click="goToSystemConfig">
<i class="el-icon-operation"></i>
<span>系统配置</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
<!-- 主内容区域 -->
<div class="content">
<el-card class="welcome-card">
<h1>{{ welcomeTitle }}</h1>
<p>{{ welcomeMessage }}</p>
<!-- 快捷访问区域 -->
<div v-if="showQuickAccess" class="quick-access">
<h3>常用功能</h3>
<el-space wrap>
<el-tag
v-for="(action, index) in quickActions"
:key="index"
type="info"
effect="plain"
class="quick-tag"
@click="action.handler"
>
<i :class="action.icon"></i>
{{ action.label }}
</el-tag>
</el-space>
</div>
</el-card>
</div>
</div>
</template>
<script>
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { useRouter } from 'vue-router'
export default {
setup() {
const router = useRouter()
// 响应式状态
const activeMenu = ref('1-1')
const isCollapsed = ref(false)
const showQuickAccess = ref(true)
const welcomeTitle = ref('欢迎使用管理系统')
const welcomeMessage = ref('请从上方菜单选择您需要的功能')
// 路由跳转方法
const goToModelRelease = () => router.push('/model_release')
const goToParseInfo = () => router.push('/parse_info')
const goToTestFlow = () => router.push('/TestFlow')
const goToTaskReminder = () => router.push('/task_reminder')
const goToStudentList = () => router.push('/StudentList')
const goToStudentStats = () => router.push('/StudentStats')
const goToDbCompare = () => router.push('/dbcompare')
const goToJsonFormat = () => router.push('/json_format')
const goToKafkaManager = () => router.push('/kafka_manager')
// 新增的系统管理路由方法
const goToUserManage = () => router.push('/user-manage')
const goToRoleManage = () => router.push('/role-manage')
const goToSystemLog = () => router.push('/system-log')
const goToSystemConfig = () => router.push('/system-config')
// 快捷操作列表(包含新增的系统管理快捷方式)
const quickActions = computed(() => [
{ icon: 'el-icon-monitor', label: '模型发布数据对比', handler: goToModelRelease },
{ icon: 'el-icon-user-solid', label: '测试流程', handler: goToTestFlow },
{ icon: 'el-icon-document', label: '待办任务', handler: goToTaskReminder },
{ icon: 'el-icon-setting', label: 'Json格式化', handler: goToJsonFormat }
])
// 响应式处理屏幕尺寸变化
const checkScreen = () => {
isCollapsed.value = window.innerWidth < 768
showQuickAccess.value = window.innerWidth > 576
}
// 菜单选择处理
const handleMenuSelect = (index) => {
activeMenu.value = index
}
// 生命周期钩子
onMounted(() => {
window.addEventListener('resize', checkScreen)
checkScreen() // 初始化检查
})
onUnmounted(() => {
window.removeEventListener('resize', checkScreen)
})
return {
activeMenu,
isCollapsed,
showQuickAccess,
welcomeTitle,
welcomeMessage,
quickActions,
handleMenuSelect,
// 三维数据平台
goToModelRelease,
goToParseInfo,
// 测试管理
goToTestFlow,
goToTaskReminder,
// 实用工具
goToJsonFormat,
goToKafkaManager,
// 学生管理
goToStudentList,
goToStudentStats,
goToDbCompare,
// 系统管理
goToUserManage,
goToRoleManage,
goToSystemLog,
goToSystemConfig
}
}
}
</script>
<style scoped>
/* 主容器样式 */
.dashboard-container {
padding: 10px;
}
/* 导航菜单样式 */
.el-menu-horizontal-demo {
height: 36px;
line-height: 36px;
border-bottom: 1px solid #e6e6e6;
margin-bottom: 20px;
}
.el-menu-item.is-active {
background-color: var(--el-color-primary-light-9) !important;
border-bottom: 2px solid var(--el-color-primary) !important;
}
/* 内容区域布局 */
.content {
padding: 20px;
display: flex;
justify-content: center;
min-height: calc(100vh - 160px);
}
/* 欢迎卡片样式 */
.welcome-card {
width: 100%;
max-width: 800px;
text-align: center;
padding: 40px;
border-radius: 8px;
}
/* 快捷访问区域 */
.quick-access {
margin-top: 30px;
padding-top: 20px;
border-top: 1px dashed #eee;
}
.quick-tag {
cursor: pointer;
padding: 0 15px;
height: 32px;
line-height: 32px;
transition: all 0.3s;
}
.quick-tag:hover {
color: #409EFF;
border-color: #409EFF;
transform: translateY(-2px);
}
/* 响应式设计 */
@media (max-width: 768px) {
.el-menu-item,
.el-submenu__title {
padding: 0 12px !important;
}
.welcome-card {
padding: 20px;
}
}
@media (max-width: 576px) {
.dashboard-container {
padding: 10px;
}
.content {
min-height: calc(100vh - 120px);
}
}
</style>
src/views/User.vue
javascript
<template>
<div>
<h1>用户注册</h1>
<el-form @submit.prevent="handleSubmit" inline>
<el-form-item>
<el-input v-model="username" placeholder="用户名"></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="password" type="password" placeholder="密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSubmit">注册</el-button>
</el-form-item>
</el-form>
<h2>已注册用户</h2>
<el-table :data="users" style="width: 100%">
<el-table-column prop="id" label="ID" width="50"></el-table-column>
<el-table-column prop="username" label="用户名" width="180"></el-table-column>
<el-table-column label="操作" width="120">
<template #default="scope">
<el-button type="text" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'
import 'element-plus/dist/index.css'
const username = ref('')
const password = ref('')
const users = ref([])
const fetchUsers = async () => {
const response = await axios.get('http://192.168.1.138:5000/api/users')
users.value = response.data
}
const handleSubmit = async () => {
await axios.post('http://192.168.1.138:5000/api/register', {
username: username.value,
password: password.value
})
username.value = ''
password.value = ''
await fetchUsers()
}
const handleDelete = async (id) => {
await axios.delete(`http://192.168.1.138:5000/api/users/${id}`)
await fetchUsers()
}
onMounted(() => {
fetchUsers()
})
</script>
src/router/index.js
javascript
import { createRouter, createWebHistory } from 'vue-router'
import Dashboard from '../views/Dashboard.vue'
import User from '../views/User.vue'
const routes = [
{ path: '/', redirect: '/Dashboard' }, // 默认重定向
{ path: '/dashboard', component: Dashboard },
{ path: '/user', component: User },
// 其他路由...
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
前端运行测试
npm run dev

前端启动后默认跳转的效果

用户注册
使用navicat连接查看数据库
