Commit 0ec38cbef3c2641681a6bb72806f7a945a0f7c2e
1 parent
2c62a85d
1、新增前端登陆、新增条件查询
Showing
7 changed files
with
329 additions
and
51 deletions
public/config.js
src/App.vue
| 1 | 1 | <script setup> | 
| 2 | 2 | import { RouterLink, RouterView } from 'vue-router' | 
| 3 | +import {onMounted} from "vue"; | |
| 3 | 4 | |
| 5 | +onMounted(() => { | |
| 6 | + window.addEventListener('beforeunload', () => { | |
| 7 | + sessionStorage.removeItem('isAuthenticated') | |
| 8 | + }) | |
| 9 | + | |
| 10 | + | |
| 11 | +}) | |
| 4 | 12 | </script> | 
| 5 | 13 | |
| 6 | 14 | <template> | 
| ... | ... | @@ -19,25 +27,6 @@ import { RouterLink, RouterView } from 'vue-router' | 
| 19 | 27 | </div> | 
| 20 | 28 | </header> --> | 
| 21 | 29 | |
| 22 | - <el-menu | |
| 23 | - default-active="1" | |
| 24 | - class="el-menu-demo" | |
| 25 | - mode="horizontal" | |
| 26 | - background-color="#545c64" | |
| 27 | - text-color="#fff" | |
| 28 | - active-text-color="#ffd04b" | |
| 29 | - | |
| 30 | - > | |
| 31 | - <!-- <el-menu-item index="1"> | |
| 32 | - <RouterLink to="/">主页</RouterLink> | |
| 33 | - </el-menu-item> --> | |
| 34 | - <!-- <el-menu-item index="2"> | |
| 35 | - <RouterLink to="/login.html">登录</RouterLink> | |
| 36 | - </el-menu-item> --> | |
| 37 | - | |
| 38 | - | |
| 39 | - </el-menu> | |
| 40 | - | |
| 41 | 30 | |
| 42 | 31 | <RouterView /> | 
| 43 | 32 | </template> | 
| ... | ... | @@ -45,3 +34,4 @@ import { RouterLink, RouterView } from 'vue-router' | 
| 45 | 34 | <style scoped> | 
| 46 | 35 | |
| 47 | 36 | </style> | 
| 37 | + | ... | ... | 
src/api/api.js
| ... | ... | @@ -16,3 +16,17 @@ export const deleteSNsApi = { | 
| 16 | 16 | url: baseUrl + '/sn/delete_sn' | 
| 17 | 17 | } | 
| 18 | 18 | |
| 19 | +export const getSNsByConditionApi = { | |
| 20 | + method: 'post', | |
| 21 | + url: baseUrl + '/sn/get_by_condition_sn' | |
| 22 | +} | |
| 23 | + | |
| 24 | +export const listProjectSelectApi = { | |
| 25 | + method: 'post', | |
| 26 | + url: baseUrl + '/sn/list_product_select' | |
| 27 | +} | |
| 28 | + | |
| 29 | +export const loginApi = { | |
| 30 | + method: 'post', | |
| 31 | + url: baseUrl + '/auth/login' | |
| 32 | +} | ... | ... | 
src/main.js
src/router/index.js
| 1 | 1 | import { createRouter, createWebHistory } from 'vue-router' | 
| 2 | 2 | import HomeView from '../views/HomeView.vue' | 
| 3 | +import Login from "../views/Login.vue"; | |
| 3 | 4 | |
| 4 | 5 | const router = createRouter({ | 
| 5 | 6 | history: createWebHistory(import.meta.env.BASE_URL), | 
| ... | ... | @@ -9,17 +10,44 @@ const router = createRouter({ | 
| 9 | 10 | name: 'home', | 
| 10 | 11 | component: HomeView, | 
| 11 | 12 | meta: { | 
| 12 | - title: 'SN管理' | |
| 13 | + title: 'SN管理', | |
| 14 | + requiresAuth: true // 添加这行,标记该路由需要认证 | |
| 15 | + } | |
| 16 | + | |
| 17 | + }, | |
| 18 | + { | |
| 19 | + path: '/login', | |
| 20 | + name: 'Login', | |
| 21 | + component: Login, | |
| 22 | + meta: { | |
| 23 | + requiresAuth: false // 明确表示登录页不需要认证 | |
| 13 | 24 | } | 
| 14 | 25 | } | 
| 15 | 26 | ] | 
| 16 | 27 | }) | 
| 17 | 28 | |
| 18 | -router.beforeEach((to,from,next)=>{//beforeEach是router的钩子函数,在进入路由前执行 | |
| 19 | - if(to.meta.title){//判断是否有标题 | |
| 20 | - document.title = to.meta.title | |
| 29 | +// 路由守卫 | |
| 30 | +router.beforeEach((to, from, next) => { | |
| 31 | + const isAuthenticated = sessionStorage.getItem('isAuthenticated') | |
| 32 | + | |
| 33 | + if (to.path === '/login' && !isAuthenticated) { | |
| 34 | + return next('/login') | |
| 35 | + } | |
| 36 | + | |
| 37 | + // 需要认证但未登录 → 跳转登录页 | |
| 38 | + if (to.meta.requiresAuth && !isAuthenticated) { | |
| 39 | + return next('/login') | |
| 21 | 40 | } | 
| 22 | - next() //执行进入路由,如果不写就不会进入目标页 | |
| 41 | + | |
| 42 | + // 已登录但访问登录页 → 跳转首页 | |
| 43 | + if (to.path === '/login' && isAuthenticated) { | |
| 44 | + return next('/') | |
| 45 | + } | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + next() | |
| 23 | 50 | }) | 
| 24 | 51 | |
| 52 | + | |
| 25 | 53 | export default router | ... | ... | 
src/views/HomeView.vue
| ... | ... | @@ -3,39 +3,108 @@ | 
| 3 | 3 | // import { FormInstance } from 'element-plus' | 
| 4 | 4 | import axios from 'axios'; | 
| 5 | 5 | import { ElMessage } from 'element-plus' | 
| 6 | - import { addSNsApi, getSNsApi, deleteSNsApi } from '../api/api'; | |
| 6 | + import {addSNsApi, getSNsApi, deleteSNsApi, getSNsByConditionApi , listProjectSelectApi} from '../api/api'; | |
| 7 | 7 | |
| 8 | 8 | const addFormRef = ref() | 
| 9 | 9 | const deleteFormRef = ref() | 
| 10 | + const conditionFormRef = ref() | |
| 10 | 11 | |
| 11 | 12 | //获取的SN内容 | 
| 12 | - const SNsContent = ref('...') | |
| 13 | + const SNsContent = ref('') | |
| 13 | 14 | |
| 14 | 15 | //当前显示的表单 1-添加SN 2-获取SN 3-删除SN | 
| 15 | 16 | const currForm = ref('1'); | 
| 17 | + | |
| 18 | + // 条件查询表单 | |
| 19 | + const conditionForm = reactive({ | |
| 20 | + projectName: '', | |
| 21 | + sns: '' | |
| 22 | + }) | |
| 23 | + | |
| 16 | 24 | const changeForm = (tab, event) => { | 
| 17 | 25 | currForm.value = tab.props.name; | 
| 18 | - //把SN数据查出来 | |
| 19 | - if (currForm.value == 3) { | |
| 20 | - axios({ | |
| 21 | - method: getSNsApi.method, | |
| 22 | - url: getSNsApi.url | |
| 23 | - }).then(response => { | |
| 24 | - if (response.data.code == 200) { | |
| 25 | - SNsContent.value = response.data.data; | |
| 26 | + if (currForm.value === '3') { | |
| 27 | + fetchProjectOptions() | |
| 28 | + } | |
| 29 | + // //把SN数据查出来 | |
| 30 | + // if (currForm.value == 3) { | |
| 31 | + // axios({ | |
| 32 | + // method: getSNsApi.method, | |
| 33 | + // url: getSNsApi.url | |
| 34 | + // }).then(response => { | |
| 35 | + // if (response.data.code == 200) { | |
| 36 | + // SNsContent.value = response.data.data; | |
| 37 | + // | |
| 38 | + // } else { | |
| 39 | + // ElMessage({ | |
| 40 | + // message: response.data.message, | |
| 41 | + // type: 'error', | |
| 42 | + // }) | |
| 43 | + // } | |
| 44 | + // | |
| 45 | + // }).catch(err => { | |
| 46 | + // ElMessage.error(err) | |
| 47 | + // }) | |
| 48 | + // } | |
| 49 | + // | |
| 50 | + } | |
| 26 | 51 | |
| 27 | - } else { | |
| 28 | - ElMessage({ | |
| 29 | - message: response.data.message, | |
| 30 | - type: 'error', | |
| 31 | - }) | |
| 32 | - } | |
| 52 | + // 项目名称下拉选项 | |
| 53 | + const projectOptions = ref([]) | |
| 54 | + const loadingProjects = ref(false) | |
| 33 | 55 | |
| 34 | - }).catch(err => { | |
| 35 | - ElMessage.error(err) | |
| 56 | + // 获取项目名称下拉列表 | |
| 57 | + const fetchProjectOptions = async () => { | |
| 58 | + try { | |
| 59 | + loadingProjects.value = true | |
| 60 | + const response = await axios({ | |
| 61 | + method: listProjectSelectApi.method, | |
| 62 | + url: listProjectSelectApi.url | |
| 36 | 63 | }) | 
| 64 | + if (response.data.code === 200) { | |
| 65 | + projectOptions.value = response.data.data || [] | |
| 66 | + } | |
| 67 | + } catch (err) { | |
| 68 | + ElMessage.error('获取项目列表失败') | |
| 69 | + } finally { | |
| 70 | + loadingProjects.value = false | |
| 37 | 71 | } | 
| 38 | - | |
| 72 | + } | |
| 73 | + | |
| 74 | + | |
| 75 | + // 提交条件查询 | |
| 76 | + const submitConditionForm = async (formInstance) => { | |
| 77 | + if (!formInstance) return | |
| 78 | + | |
| 79 | + try { | |
| 80 | + await formInstance.validate() | |
| 81 | + const response = await axios({ | |
| 82 | + method: getSNsByConditionApi.method, | |
| 83 | + url: getSNsByConditionApi.url, | |
| 84 | + data: { | |
| 85 | + projectName: conditionForm.projectName, | |
| 86 | + sns: conditionForm.sns | |
| 87 | + } | |
| 88 | + }) | |
| 89 | + | |
| 90 | + if (response.data.code === 200) { | |
| 91 | + SNsContent.value = response.data.data | |
| 92 | + ElMessage.success('查询成功') | |
| 93 | + } else { | |
| 94 | + ElMessage.error(response.data.message || '查询失败') | |
| 95 | + } | |
| 96 | + } catch (err) { | |
| 97 | + if (err.name !== 'Error') { // 不是表单验证错误 | |
| 98 | + ElMessage.error(err.message || '查询异常') | |
| 99 | + } | |
| 100 | + } | |
| 101 | + } | |
| 102 | + | |
| 103 | + // 重置条件表单 | |
| 104 | + const resetConditionForm = (formInstance) => { | |
| 105 | + if (!formInstance) return | |
| 106 | + formInstance.resetFields() | |
| 107 | + SNsContent.value = '...' | |
| 39 | 108 | } | 
| 40 | 109 | |
| 41 | 110 | |
| ... | ... | @@ -272,14 +341,70 @@ | 
| 272 | 341 | </el-form-item> | 
| 273 | 342 | </el-form> | 
| 274 | 343 | |
| 275 | - <el-text class="mx-1" v-show="currForm == 3? true : false"> | |
| 276 | - {{ SNsContent }} | |
| 277 | - </el-text> | |
| 278 | - | |
| 279 | - | |
| 344 | +<!-- <el-text class="mx-1" v-show="currForm == 3? true : false">--> | |
| 345 | +<!-- {{ SNsContent }}--> | |
| 346 | +<!-- </el-text>--> | |
| 347 | + | |
| 348 | + <!-- 条件查询表单 --> | |
| 349 | + <el-form | |
| 350 | + ref="conditionFormRef" | |
| 351 | + style="max-width: 600px" | |
| 352 | + :model="conditionForm" | |
| 353 | + label-width="auto" | |
| 354 | + class="demo-dynamic" | |
| 355 | + v-show="currForm == 3" | |
| 356 | + > | |
| 357 | + <el-form-item | |
| 358 | + prop="projectName" | |
| 359 | + label="项目名称" | |
| 360 | + > | |
| 361 | + <el-select | |
| 362 | + v-model="conditionForm.projectName" | |
| 363 | + filterable | |
| 364 | + clearable | |
| 365 | + placeholder="请选择或输入项目名称" | |
| 366 | + :loading="loadingProjects" | |
| 367 | + style="width: 100%" | |
| 368 | + > | |
| 369 | + <el-option | |
| 370 | + v-for="item in projectOptions" | |
| 371 | + :key="item" | |
| 372 | + :label="item" | |
| 373 | + :value="item" | |
| 374 | + /> | |
| 375 | + </el-select> | |
| 376 | + </el-form-item> | |
| 377 | + | |
| 378 | + <el-form-item | |
| 379 | + prop="sns" | |
| 380 | + label="设备码" | |
| 381 | + > | |
| 382 | + <el-input v-model="conditionForm.sns" placeholder="输入设备码" /> | |
| 383 | + </el-form-item> | |
| 384 | + | |
| 385 | + <el-form-item> | |
| 386 | + <el-button type="primary" @click="submitConditionForm(conditionFormRef)">查询</el-button> | |
| 387 | + <el-button @click="resetConditionForm(conditionFormRef)">重置</el-button> | |
| 388 | + </el-form-item> | |
| 389 | + </el-form> | |
| 390 | + | |
| 391 | + <!-- 查询结果显示 --> | |
| 392 | + <div v-show="currForm == 3" style="margin-top: 20px;"> | |
| 393 | + <el-card> | |
| 394 | + <template #header> | |
| 395 | + <div class="card-header"> | |
| 396 | + <span>查询结果</span> | |
| 397 | + </div> | |
| 398 | + </template> | |
| 399 | + <el-text class="mx-1"> | |
| 400 | + <pre>{{ SNsContent }}</pre> | |
| 401 | + </el-text> | |
| 402 | + </el-card> | |
| 403 | + </div> | |
| 404 | + | |
| 280 | 405 | </el-tabs> | 
| 281 | 406 | |
| 282 | - | |
| 407 | + | |
| 283 | 408 | |
| 284 | 409 | </div> | 
| 285 | 410 | |
| ... | ... | @@ -291,6 +416,15 @@ | 
| 291 | 416 | margin: 0px auto; | 
| 292 | 417 | } | 
| 293 | 418 | |
| 419 | + .card-header { | |
| 420 | + font-weight: bold; | |
| 421 | + } | |
| 422 | + | |
| 423 | + pre { | |
| 424 | + white-space: pre-wrap; | |
| 425 | + word-wrap: break-word; | |
| 426 | + } | |
| 427 | + | |
| 294 | 428 | </style> | 
| 295 | 429 | |
| 296 | 430 | ... | ... | 
src/views/Login.vue
0 → 100644
| 1 | +<script setup> | |
| 2 | +import { ref, reactive } from 'vue' | |
| 3 | +import { useRouter } from 'vue-router' | |
| 4 | +import axios from 'axios' | |
| 5 | +import { ElMessage } from 'element-plus' | |
| 6 | +import { loginApi } from '../api/api' | |
| 7 | + | |
| 8 | +const router = useRouter() | |
| 9 | + | |
| 10 | +const loginFormRef = ref() | |
| 11 | +const loading = ref(false) | |
| 12 | + | |
| 13 | +const loginForm = reactive({ | |
| 14 | + username: '', | |
| 15 | + password: '' | |
| 16 | +}) | |
| 17 | + | |
| 18 | +const rules = reactive({ | |
| 19 | + username: [{ required: true, message: '请输入用户名', trigger: 'blur' }], | |
| 20 | + password: [{ required: true, message: '请输入密码', trigger: 'blur' }] | |
| 21 | +}) | |
| 22 | + | |
| 23 | +const submitLogin = async () => { | |
| 24 | + try { | |
| 25 | + loading.value = true | |
| 26 | + await loginFormRef.value.validate() | |
| 27 | + | |
| 28 | + const response = await axios({ | |
| 29 | + method: loginApi.method, | |
| 30 | + url: loginApi.url, | |
| 31 | + data: { | |
| 32 | + username: loginForm.username, | |
| 33 | + password: loginForm.password | |
| 34 | + } | |
| 35 | + }) | |
| 36 | + | |
| 37 | + if (response.data.code === 200) { | |
| 38 | + ElMessage.success('登录成功') | |
| 39 | + // 存储登录状态 | |
| 40 | + sessionStorage.setItem('isAuthenticated', 'true') | |
| 41 | + // 跳转到首页 | |
| 42 | + router.push('/') | |
| 43 | + } else { | |
| 44 | + ElMessage.error(response.data.message || '登录失败') | |
| 45 | + } | |
| 46 | + } catch (error) { | |
| 47 | + ElMessage.error(error.message || '登录异常') | |
| 48 | + } finally { | |
| 49 | + loading.value = false | |
| 50 | + } | |
| 51 | +} | |
| 52 | +</script> | |
| 53 | + | |
| 54 | +<template> | |
| 55 | + <div class="login-container"> | |
| 56 | + <el-card class="login-card"> | |
| 57 | + <h2 class="login-title">SN系统登陆</h2> | |
| 58 | + <el-form | |
| 59 | + ref="loginFormRef" | |
| 60 | + :model="loginForm" | |
| 61 | + :rules="rules" | |
| 62 | + label-width="80px" | |
| 63 | + label-position="top" | |
| 64 | + > | |
| 65 | + <el-form-item label="用户名" prop="username"> | |
| 66 | + <el-input v-model="loginForm.username" placeholder="" /> | |
| 67 | + </el-form-item> | |
| 68 | + <el-form-item label="密码" prop="password"> | |
| 69 | + <el-input | |
| 70 | + v-model="loginForm.password" | |
| 71 | + type="password" | |
| 72 | + placeholder="" | |
| 73 | + show-password | |
| 74 | + /> | |
| 75 | + </el-form-item> | |
| 76 | + <el-form-item> | |
| 77 | + <el-button | |
| 78 | + type="primary" | |
| 79 | + @click="submitLogin" | |
| 80 | + :loading="loading" | |
| 81 | + style="width: 100%" | |
| 82 | + > | |
| 83 | + 登录 | |
| 84 | + </el-button> | |
| 85 | + </el-form-item> | |
| 86 | + </el-form> | |
| 87 | + </el-card> | |
| 88 | + </div> | |
| 89 | +</template> | |
| 90 | + | |
| 91 | +<style scoped> | |
| 92 | +.login-container { | |
| 93 | + display: flex; | |
| 94 | + justify-content: center; | |
| 95 | + align-items: center; | |
| 96 | + height: 100vh; | |
| 97 | + background-color: #f0f2f5; | |
| 98 | +} | |
| 99 | + | |
| 100 | +.login-card { | |
| 101 | + width: 400px; | |
| 102 | + padding: 20px; | |
| 103 | + border-radius: 8px; | |
| 104 | + box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); | |
| 105 | +} | |
| 106 | + | |
| 107 | +.login-title { | |
| 108 | + text-align: center; | |
| 109 | + margin-bottom: 20px; | |
| 110 | + color: #333; | |
| 111 | +} | |
| 112 | +</style> | |
| 0 | 113 | \ No newline at end of file | ... | ... |