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 | ... | ... |