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 |