Commit 0ec38cbef3c2641681a6bb72806f7a945a0f7c2e
1 parent
2c62a85d
1、新增前端登陆、新增条件查询
Showing
7 changed files
with
329 additions
and
51 deletions
public/config.js
src/App.vue
| 1 | <script setup> | 1 | <script setup> |
| 2 | import { RouterLink, RouterView } from 'vue-router' | 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 | </script> | 12 | </script> |
| 5 | 13 | ||
| 6 | <template> | 14 | <template> |
| @@ -19,25 +27,6 @@ import { RouterLink, RouterView } from 'vue-router' | @@ -19,25 +27,6 @@ import { RouterLink, RouterView } from 'vue-router' | ||
| 19 | </div> | 27 | </div> |
| 20 | </header> --> | 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 | <RouterView /> | 31 | <RouterView /> |
| 43 | </template> | 32 | </template> |
| @@ -45,3 +34,4 @@ import { RouterLink, RouterView } from 'vue-router' | @@ -45,3 +34,4 @@ import { RouterLink, RouterView } from 'vue-router' | ||
| 45 | <style scoped> | 34 | <style scoped> |
| 46 | 35 | ||
| 47 | </style> | 36 | </style> |
| 37 | + |
src/api/api.js
| @@ -16,3 +16,17 @@ export const deleteSNsApi = { | @@ -16,3 +16,17 @@ export const deleteSNsApi = { | ||
| 16 | url: baseUrl + '/sn/delete_sn' | 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
| 1 | // import './assets/main.css' | 1 | // import './assets/main.css' |
| 2 | 2 | ||
| 3 | -import { createApp } from 'vue' | 3 | +import {createApp} from 'vue' |
| 4 | import App from './App.vue' | 4 | import App from './App.vue' |
| 5 | import router from './router' | 5 | import router from './router' |
| 6 | import ElementPlus from 'element-plus' | 6 | import ElementPlus from 'element-plus' |
src/router/index.js
| 1 | import { createRouter, createWebHistory } from 'vue-router' | 1 | import { createRouter, createWebHistory } from 'vue-router' |
| 2 | import HomeView from '../views/HomeView.vue' | 2 | import HomeView from '../views/HomeView.vue' |
| 3 | +import Login from "../views/Login.vue"; | ||
| 3 | 4 | ||
| 4 | const router = createRouter({ | 5 | const router = createRouter({ |
| 5 | history: createWebHistory(import.meta.env.BASE_URL), | 6 | history: createWebHistory(import.meta.env.BASE_URL), |
| @@ -9,17 +10,44 @@ const router = createRouter({ | @@ -9,17 +10,44 @@ const router = createRouter({ | ||
| 9 | name: 'home', | 10 | name: 'home', |
| 10 | component: HomeView, | 11 | component: HomeView, |
| 11 | meta: { | 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 | export default router | 53 | export default router |
src/views/HomeView.vue
| @@ -3,39 +3,108 @@ | @@ -3,39 +3,108 @@ | ||
| 3 | // import { FormInstance } from 'element-plus' | 3 | // import { FormInstance } from 'element-plus' |
| 4 | import axios from 'axios'; | 4 | import axios from 'axios'; |
| 5 | import { ElMessage } from 'element-plus' | 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 | const addFormRef = ref() | 8 | const addFormRef = ref() |
| 9 | const deleteFormRef = ref() | 9 | const deleteFormRef = ref() |
| 10 | + const conditionFormRef = ref() | ||
| 10 | 11 | ||
| 11 | //获取的SN内容 | 12 | //获取的SN内容 |
| 12 | - const SNsContent = ref('...') | 13 | + const SNsContent = ref('') |
| 13 | 14 | ||
| 14 | //当前显示的表单 1-添加SN 2-获取SN 3-删除SN | 15 | //当前显示的表单 1-添加SN 2-获取SN 3-删除SN |
| 15 | const currForm = ref('1'); | 16 | const currForm = ref('1'); |
| 17 | + | ||
| 18 | + // 条件查询表单 | ||
| 19 | + const conditionForm = reactive({ | ||
| 20 | + projectName: '', | ||
| 21 | + sns: '' | ||
| 22 | + }) | ||
| 23 | + | ||
| 16 | const changeForm = (tab, event) => { | 24 | const changeForm = (tab, event) => { |
| 17 | currForm.value = tab.props.name; | 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,14 +341,70 @@ | ||
| 272 | </el-form-item> | 341 | </el-form-item> |
| 273 | </el-form> | 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 | </el-tabs> | 405 | </el-tabs> |
| 281 | 406 | ||
| 282 | - | 407 | + |
| 283 | 408 | ||
| 284 | </div> | 409 | </div> |
| 285 | 410 | ||
| @@ -291,6 +416,15 @@ | @@ -291,6 +416,15 @@ | ||
| 291 | margin: 0px auto; | 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 | </style> | 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 | \ No newline at end of file | 113 | \ No newline at end of file |