From f22ce91e1ad4a17199aecfe4aa1ce5a0fdeed64c Mon Sep 17 00:00:00 2001 From: wzclm <2855471171@qq.com> Date: Sat, 22 Feb 2025 14:57:43 +0800 Subject: [PATCH] Enhance application structure with new modules and login improvements - Add new menu sections for Activity Management and User Feedback - Update router configuration with new route paths - Refactor login API and user store for better error handling - Modify login view to improve navigation and error logging - Update patrol tasks view with more detailed table columns - Fix import paths for SCSS variables in patrol views --- src/api/activity/course.js | 87 ++ src/api/activity/knowledge.js | 95 ++ src/api/activity/study.js | 91 ++ src/api/feedback/index.js | 120 +++ src/api/login/index.js | 13 +- src/api/system/carousel.js | 84 ++ src/layout/AdminLayout.vue | 25 +- src/router/index.js | 42 + src/stores/user.js | 44 +- src/views/activity/course/index.vue | 964 ++++++++++++++++++ src/views/activity/knowledge/index.vue | 844 ++++++++++++++++ src/views/activity/study/index.vue | 757 ++++++++++++++ src/views/feedback/satisfaction/index.vue | 1101 +++++++++++++++++++++ src/views/feedback/suggestions/index.vue | 645 ++++++++++++ src/views/login/index.vue | 14 +- src/views/patrol/events/index.vue | 16 + src/views/patrol/points/index.vue | 2 +- src/views/patrol/records/index.vue | 2 +- src/views/patrol/tasks/index.vue | 16 +- src/views/system/carousel/index.vue | 549 ++++++++++ 20 files changed, 5473 insertions(+), 38 deletions(-) create mode 100644 src/api/activity/course.js create mode 100644 src/api/activity/knowledge.js create mode 100644 src/api/activity/study.js create mode 100644 src/api/feedback/index.js create mode 100644 src/api/system/carousel.js create mode 100644 src/views/activity/course/index.vue create mode 100644 src/views/activity/knowledge/index.vue create mode 100644 src/views/activity/study/index.vue create mode 100644 src/views/feedback/satisfaction/index.vue create mode 100644 src/views/feedback/suggestions/index.vue create mode 100644 src/views/patrol/events/index.vue create mode 100644 src/views/system/carousel/index.vue diff --git a/src/api/activity/course.js b/src/api/activity/course.js new file mode 100644 index 0000000..73ff61a --- /dev/null +++ b/src/api/activity/course.js @@ -0,0 +1,87 @@ +import request from '@/utils/request' + +/** + * 获取课程列表 + * @param {Object} params - 查询参数 + * @param {number} [params.page=1] - 页码 + * @param {number} [params.pageSize=10] - 每页条数 + * @param {string} [params.title] - 课程标题 + * @param {string} [params.category] - 课程类型 + * @param {number} [params.status] - 状态 + * @returns {Promise} 返回课程列表数据 + */ +export function getCourseList(params = {}) { + return request.get('/api/education/courses', { + params: { + page_num: params.page || 1, + page_size: params.pageSize || 10, + title: params.title || undefined, + category: params.category || undefined, + status: params.status === '' ? undefined : params.status + } + }) +} + +/** + * 创建课程 + * @param {Object} data - 课程数据 + * @returns {Promise} 返回创建结果 + */ +export function createCourse(data) { + return request.post('/api/education/courses', data) +} + +/** + * 获取课程详情 + * @param {string|number} id - 课程ID + * @returns {Promise} 返回课程详情数据 + */ +export function getCourseDetail(id) { + return request.get(`/api/education/courses/${id}`) +} + +/** + * 更新课程 + * @param {string|number} id - 课程ID + * @param {Object} data - 更新数据 + * @returns {Promise} 返回更新结果 + */ +export function updateCourse(id, data) { + return request.put(`/api/education/courses/${id}`, data) +} + +/** + * 删除课程 + * @param {string|number} id - 课程ID + * @returns {Promise} 返回删除结果 + */ +export function deleteCourse(id) { + return request.delete(`/api/education/courses/${id}`) +} + +/** + * 更新课程状态 + * @param {string|number} id - 课程ID + * @param {number} status - 状态值:1-进行中,0-已结束 + * @returns {Promise} 返回状态更新结果 + */ +export function updateCourseStatus(id, status) { + return request.put(`/api/education/courses/${id}/status`, { + status: status === 1 ? 1 : 0 // 确保只发送 1 或 0 + }) +} + +/** + * 获取热门课程 + * @param {Object} params - 查询参数 + * @param {number} [params.limit=5] - 获取数量 + * @returns {Promise} 返回热门课程列表 + */ +export function getHotCourses(params = {}) { + return request.get('/api/education/courses/hot', { + params: { + limit: 5, + ...params + } + }) +} \ No newline at end of file diff --git a/src/api/activity/knowledge.js b/src/api/activity/knowledge.js new file mode 100644 index 0000000..e2878b6 --- /dev/null +++ b/src/api/activity/knowledge.js @@ -0,0 +1,95 @@ +import request from '@/utils/request' + +/** + * 创建知识条目 + * @param {Object} data - 知识条目数据 + * @returns {Promise} 返回创建结果 + */ +export function createKnowledge(data) { + return request.post('/api/education/knowledge', data) +} + +/** + * 获取知识列表 + * @param {Object} params - 查询参数 + * @param {number} [params.page=1] - 页码 + * @param {number} [params.pageSize=10] - 每页条数 + * @param {string} [params.title] - 标题搜索 + * @param {string} [params.category] - 分类筛选 + * @param {number} [params.status] - 状态筛选 + * @returns {Promise} 返回知识列表数据 + */ +export function getKnowledgeList(params = {}) { + const { page = 1, pageSize = 10, ...restParams } = params + return request.get('/api/education/knowledge', { + params: { + page_size: pageSize, + page_num: page, + ...Object.fromEntries( + Object.entries(restParams).filter(([_, value]) => value !== '') + ) + } + }) +} + +/** + * 获取知识详情 + * @param {string|number} id - 知识条目ID + * @returns {Promise} 返回知识详情数据 + */ +export function getKnowledgeDetail(id) { + return request.get(`/api/education/knowledge/${id}`) +} + +/** + * 更新知识条目 + * @param {string|number} id - 知识条目ID + * @param {Object} data - 更新数据 + * @returns {Promise} 返回更新结果 + */ +export function updateKnowledge(id, data) { + return request.put(`/api/education/knowledge/${id}`, data) +} + +/** + * 更新知识状态 + * @param {string|number} id - 知识条目ID + * @param {number} status - 状态值:0-草稿,1-已发布 + * @returns {Promise} 返回状态更新结果 + */ +export function updateKnowledgeStatus(id, status) { + return request.put(`/api/education/knowledge/${id}/status`, { + status: status === 1 ? 1 : 0 // 确保只发送 1 或 0 + }) +} + +/** + * 批量更新知识状态 + * @param {Array} ids - 知识条目ID列表 + * @param {number} status - 状态值:0-草稿,1-已发布 + * @returns {Promise} 返回批量状态更新结果 + */ +export function batchUpdateKnowledgeStatus(ids, status) { + return request.put('/api/education/knowledge/batch/status', { + ids, + status: status === 1 ? 1 : 0 + }) +} + +/** + * 批量删除知识 + * @param {Array} ids - 知识条目ID列表 + * @returns {Promise} 返回批量删除结果 + */ +export function batchDeleteKnowledge(ids) { + return request.post('/api/education/knowledge/batch/delete', { ids }) +} + +/** + * 删除知识条目 + * @param {string|number} id - 知识条目ID + * @returns {Promise} 返回删除结果 + */ +export function deleteKnowledge(id) { + return request.delete(`/api/education/knowledge/${id}`) +} \ No newline at end of file diff --git a/src/api/activity/study.js b/src/api/activity/study.js new file mode 100644 index 0000000..f73ad22 --- /dev/null +++ b/src/api/activity/study.js @@ -0,0 +1,91 @@ +import request from '@/utils/request' + +/** + * 创建研学活动 + * @param {Object} data - 活动数据 + * @returns {Promise} 返回创建结果 + */ +export function createActivity(data) { + return request.post('/api/education/activities', data) +} + +/** + * 获取研学活动列表 + * @returns {Promise} 返回活动列表数据 + */ +export function getActivityList() { + return request.get('/api/education/activities') +} + +/** + * 获取研学活动详情 + * @param {string|number} id - 活动ID + * @returns {Promise} 返回活动详情数据 + */ +export function getActivityDetail(id) { + return request.get(`/api/education/activities/${id}`) +} + +/** + * 取消研学活动 + * @param {string|number} id - 活动ID + * @returns {Promise} 返回取消结果 + */ +export function cancelActivity(id) { + return request.post(`/api/education/activities/${id}/cancel`) +} + +/** + * 批量取消研学活动 + * @param {Array} ids - 活动ID列表 + * @returns {Promise} 返回批量取消结果 + */ +export function batchCancelActivities(ids) { + return request.post('/api/education/activities/batch/cancel', { ids }) +} + +/** + * 更新研学活动 + * @param {string|number} id - 活动ID + * @param {Object} data - 更新数据 + * @returns {Promise} 返回更新结果 + */ +export function updateActivity(id, data) { + return request.put(`/api/education/activities/${id}`, data) +} + +/** + * 更新研学活动状态 + * @param {string|number} id - 活动ID + * @param {number} status - 状态值 + * @returns {Promise} 返回状态更新结果 + */ +export function updateActivityStatus(id, status) { + return request.put(`/api/education/activities/${id}/status`, { status }) +} + +/** + * 检查研学活动容量 + * @param {string|number} id - 活动ID + * @returns {Promise} 返回容量检查结果 + */ +export function checkActivityCapacity(id) { + return request.get(`/api/education/activities/${id}/capacity`) +} + +/** + * 获取指定分类的研学活动 + * @param {Object} params - 查询参数 + * @param {number} [params.page=1] - 页码 + * @param {number} [params.pageSize=10] - 每页条数 + * @returns {Promise} 返回分类活动列表 + */ +export function getCategoryActivities(params = {}) { + return request.get('/api/education/activities/category/field_study', { + params: { + page: 1, + pageSize: 10, + ...params + } + }) +} \ No newline at end of file diff --git a/src/api/feedback/index.js b/src/api/feedback/index.js new file mode 100644 index 0000000..bf51d2a --- /dev/null +++ b/src/api/feedback/index.js @@ -0,0 +1,120 @@ +import request from '@/utils/request' + +/** + * 获取意见反馈列表 + * @param {Object} params - 查询参数 + * @param {number} [params.page=1] - 页码 + * @param {number} [params.page_size=10] - 每页条数 + * @param {string} [params.keyword] - 搜索关键词 + * @param {string} [params.feedback_type] - 反馈类型 + * @param {number} [params.status] - 状态筛选 + * @param {string} [params.start_date] - 开始日期 + * @param {string} [params.end_date] - 结束日期 + * @returns {Promise} 返回反馈列表数据 + */ +export function getFeedbackList(params = {}) { + return request.get('/api/admin/feedbacks', { + params: { + page: params.page || 1, + page_size: params.page_size || 10, + keyword: params.keyword || undefined, + feedback_type: params.feedback_type || undefined, + status: params.status === '' ? undefined : params.status, + start_date: params.start_date || undefined, + end_date: params.end_date || undefined + } + }) +} + +/** + * 获取反馈详情 + * @param {string|number} id - 反馈ID + * @returns {Promise} 返回反馈详情数据 + */ +export function getFeedbackDetail(id) { + return request.get(`/api/admin/feedbacks/${id}`) +} + +/** + * 更新反馈状态和处理结果 + * @param {string|number} id - 反馈ID + * @param {number} status - 状态值:0-待处理,1-处理中,2-已处理,3-已关闭 + * @param {string} [handling_result] - 处理结果,仅在status为2时需要 + * @returns {Promise} 返回更新结果 + */ +export function updateFeedbackStatus(id, status, handling_result) { + const data = { status } + + // 当状态为已处理(2)时,需要包含处理结果 + if (status === 2 && handling_result) { + data.handling_result = handling_result + } + + return request.put(`/api/admin/feedbacks/${id}/status`, data) +} + +/** + * 获取满意度调查列表 + * @param {Object} params - 查询参数 + * @param {number} [params.page=1] - 页码 + * @param {number} [params.page_size=10] - 每页条数 + * @param {string} [params.keyword] - 搜索关键词 + * @param {number} [params.satisfaction_level] - 满意度等级 + * @param {string} [params.start_date] - 开始日期 + * @param {string} [params.end_date] - 结束日期 + * @returns {Promise} 返回满意度调查列表数据 + */ +export function getSatisfactionList(params = {}) { + return request.get('/api/admin/surveys', { + params: { + page: params.page || 1, + page_size: params.page_size || 10, + keyword: params.keyword || undefined, + satisfaction_level: params.satisfaction_level || undefined, + start_date: params.start_date || undefined, + end_date: params.end_date || undefined + } + }) +} + +/** + * 创建满意度调查 + * @param {Object} data - 调查数据 + * @param {string} data.user_name - 用户名称 + * @param {string} data.contact - 联系方式 + * @param {string} data.course_name - 课程名称 + * @param {number} data.satisfaction_level - 满意度等级(1-5) + * @param {string} data.comment - 评价内容 + * @returns {Promise} 返回创建结果 + */ +export function createSurvey(data) { + return request.post('/api/admin/surveys', data) +} + +/** + * 更新满意度调查 + * @param {string|number} id - 调查ID + * @param {Object} data - 更新数据 + * @returns {Promise} 返回更新结果 + */ +export function updateSurvey(id, data) { + return request.put(`/api/admin/surveys/${id}`, data) +} + +/** + * 获取满意度调查详情 + * @param {string|number} id - 调查ID + * @returns {Promise} 返回调查详情数据 + */ +export function getSurveyDetail(id) { + return request.get(`/api/admin/surveys/${id}`) +} + +/** + * 删除满意度调查 + * @param {string|number} id - 调查ID + * @returns {Promise} 返回删除结果 + */ +export function deleteSurvey(id) { + return request.delete(`/api/admin/surveys/${id}`) +} \ No newline at end of file diff --git a/src/api/login/index.js b/src/api/login/index.js index ddc01d1..969aae0 100644 --- a/src/api/login/index.js +++ b/src/api/login/index.js @@ -8,13 +8,8 @@ import request from '@/utils/request' * @returns {Promise} 返回包含token和用户信息的Promise */ export function login(data) { - return request.post('/api/users/login', data) -} - -/** - * 退出登录 - * @returns {Promise} - */ -export function logout() { - return request.post('/api/users/logout') + return request.post('/api/users/login', { + username: data.username, + password: data.password + }) } diff --git a/src/api/system/carousel.js b/src/api/system/carousel.js new file mode 100644 index 0000000..45673a7 --- /dev/null +++ b/src/api/system/carousel.js @@ -0,0 +1,84 @@ +import request from '@/utils/request' + +/** + * 获取轮播图列表 + * @returns {Promise} 返回轮播图列表数据 + */ +export function getCarouselList() { + return request.get('/api/admin/carousels') +} + +/** + * 创建轮播图 + * @param {Object} data - 轮播图数据 + * @returns {Promise} 返回创建结果 + */ +export function createCarousel(data) { + return request.post('/api/admin/carousels', data) +} + +/** + * 更新轮播图 + * @param {string|number} id - 轮播图ID + * @param {Object} data - 更新数据 + * @returns {Promise} 返回更新结果 + */ +export function updateCarousel(id, data) { + return request.put(`/api/admin/carousels/${id}`, data) +} + +/** + * 删除轮播图 + * @param {string|number} id - 轮播图ID + * @returns {Promise} 返回删除结果 + */ +export function deleteCarousel(id) { + return request.delete(`/api/admin/carousels/${id}`) +} + +/** + * 获取轮播图详情 + * @param {string|number} id - 轮播图ID + * @returns {Promise} 返回轮播图详情 + */ +export function getCarouselDetail(id) { + return request.get(`/api/admin/carousels/${id}`) +} + +/** + * 批量更新轮播图排序 + * @param {Array<{id: number|string, sort_order: number}>} sortData - 排序数据 + * @returns {Promise} 返回排序更新结果 + */ +export function batchUpdateCarouselSort(sortData) { + if (!Array.isArray(sortData) || sortData.length === 0) { + return Promise.reject(new Error('排序数据不能为空')) + } + return request.put('/api/admin/carousels/sort/batch', { + sorts: sortData.map(item => ({ + id: item.id, + sort_order: Number(item.sort_order) + })) + }) +} + +/** + * 更新轮播图状态 + * @param {string|number} id - 轮播图ID + * @param {number} status - 状态值:0-禁用,1-启用 + * @returns {Promise} 返回状态更新结果 + */ +export function updateCarouselStatus(id, status) { + return request.put(`/api/admin/carousels/${id}/status`, { + status: status === 1 ? 1 : 0 + }) +} + +/** + * 批量删除轮播图 + * @param {Array} ids - 轮播图ID列表 + * @returns {Promise} 返回批量删除结果 + */ +export function batchDeleteCarousels(ids) { + return request.post('/api/admin/carousels/batch/delete', { ids }) +} \ No newline at end of file diff --git a/src/layout/AdminLayout.vue b/src/layout/AdminLayout.vue index 3e497f7..4534706 100644 --- a/src/layout/AdminLayout.vue +++ b/src/layout/AdminLayout.vue @@ -15,6 +15,7 @@ import { Tools, Document, DataLine, + Collection, } from "@element-plus/icons-vue"; const router = useRouter(); @@ -34,7 +35,8 @@ const icons = { DataBoard: markRaw(DataBoard), Tools: markRaw(Tools), Document: markRaw(Document), - DataLine: markRaw(DataLine) + DataLine: markRaw(DataLine), + Collection: markRaw(Collection), }; // 监听路由变化 @@ -111,6 +113,7 @@ const handleLogout = () => { 系统设置 系统日志 数据管理 + 轮播图管理 @@ -129,6 +132,7 @@ const handleLogout = () => { 巡护任务 巡护记录 + 安防事件 @@ -141,6 +145,25 @@ const handleLogout = () => { 分析报告 项目背景 + + + + 课程管理 + 研学管理 + 知识库管理 + + + + + 意见反馈 + 满意度调查 + diff --git a/src/router/index.js b/src/router/index.js index 600fab0..d508240 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -64,6 +64,11 @@ const router = createRouter({ name: 'PatrolTasks', component: () => import('../views/patrol/tasks/index.vue') }, + { + path: 'patrol/events', + name: 'PatrolEvents', + component: () => import('../views/patrol/events/index.vue') + }, { path: 'patrol/records', name: 'PatrolRecords', @@ -108,6 +113,43 @@ const router = createRouter({ path: 'system/data', name: 'DataManagement', component: () => import('../views/system/data/index.vue') + }, + { + path: 'system/carousel', + name: 'SystemCarousel', + component: () => import('../views/system/carousel/index.vue'), + meta: { title: '轮播图管理', icon: 'picture' } + }, + { + path: 'activity/course', + name: 'CourseManagement', + component: () => import('../views/activity/course/index.vue') + }, + { + path: 'activity/study', + name: 'StudyManagement', + component: () => import('../views/activity/study/index.vue') + }, + { + path: 'activity/knowledge', + name: 'KnowledgeManagement', + component: () => import('../views/activity/knowledge/index.vue') + }, + { + path: 'feedback/suggestions', + name: 'FeedbackSuggestions', + component: () => import('../views/feedback/suggestions/index.vue') + }, + { + path: 'feedback/satisfaction', + name: 'FeedbackSatisfaction', + component: () => import('../views/feedback/satisfaction/index.vue') + }, + { + path: 'data', + name: 'SystemData', + component: () => import('@/views/system/data/index.vue'), + meta: { title: '数据管理', icon: 'data' } } ] } diff --git a/src/stores/user.js b/src/stores/user.js index 3eb95d1..1accb8e 100644 --- a/src/stores/user.js +++ b/src/stores/user.js @@ -1,5 +1,6 @@ import { defineStore } from 'pinia' -import { login as loginApi, logout as logoutApi } from '@/api/login' +import { login as loginApi } from '@/api/login' +import { ElMessage } from 'element-plus' // 安全的 JSON 解析函数 const safeJSONParse = (str, defaultValue = null) => { @@ -31,36 +32,47 @@ export const useUserStore = defineStore('user', { async login(username, password) { try { // 调用登录接口 - const { token, userInfo } = await loginApi({ username, password }) + const response = await loginApi({ username, password }) + + // 检查响应状态 + if (!response.success) { + console.error('登录失败:', response.message) + ElMessage.error(response.message || '用户名或密码错误') + return false + } + + // 从响应中获取token和用户信息 + const { user, token } = response.data + + if (!token) { + console.error('登录失败: 未获取到token') + ElMessage.error('登录失败,请稍后重试') + return false + } // 保存token和用户信息 this.token = token - this.userInfo = userInfo + this.userInfo = user // 持久化存储 localStorage.setItem('token', token) - localStorage.setItem('userInfo', JSON.stringify(userInfo)) + localStorage.setItem('userInfo', JSON.stringify(user)) return true } catch (error) { console.error('登录失败:', error) + ElMessage.error(error.response?.data?.message || '登录失败,请稍后重试') return false } }, // 退出登录 - async logout() { - try { - await logoutApi() - } catch (error) { - console.error('退出登录失败:', error) - } finally { - // 无论是否成功调用退出接口,都清除本地存储 - this.token = null - this.userInfo = null - localStorage.removeItem('token') - localStorage.removeItem('userInfo') - } + logout() { + // 清除本地存储 + this.token = null + this.userInfo = null + localStorage.removeItem('token') + localStorage.removeItem('userInfo') } }, diff --git a/src/views/activity/course/index.vue b/src/views/activity/course/index.vue new file mode 100644 index 0000000..4238764 --- /dev/null +++ b/src/views/activity/course/index.vue @@ -0,0 +1,964 @@ + + + + + \ No newline at end of file diff --git a/src/views/activity/knowledge/index.vue b/src/views/activity/knowledge/index.vue new file mode 100644 index 0000000..7c88008 --- /dev/null +++ b/src/views/activity/knowledge/index.vue @@ -0,0 +1,844 @@ + + + + + \ No newline at end of file diff --git a/src/views/activity/study/index.vue b/src/views/activity/study/index.vue new file mode 100644 index 0000000..27df4ba --- /dev/null +++ b/src/views/activity/study/index.vue @@ -0,0 +1,757 @@ + + + + + \ No newline at end of file diff --git a/src/views/feedback/satisfaction/index.vue b/src/views/feedback/satisfaction/index.vue new file mode 100644 index 0000000..6b03668 --- /dev/null +++ b/src/views/feedback/satisfaction/index.vue @@ -0,0 +1,1101 @@ + + + + + \ No newline at end of file diff --git a/src/views/feedback/suggestions/index.vue b/src/views/feedback/suggestions/index.vue new file mode 100644 index 0000000..932d702 --- /dev/null +++ b/src/views/feedback/suggestions/index.vue @@ -0,0 +1,645 @@ + + + + + \ No newline at end of file diff --git a/src/views/login/index.vue b/src/views/login/index.vue index 191be04..61ff984 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -66,9 +66,19 @@ const handleLogin = async (formEl) => { duration: 2000 }); - // 获取重定向地址 + // 等待一下确保状态更新完成 + await new Promise(resolve => setTimeout(resolve, 100)); + + // 获取重定向地址并等待导航完成 const redirect = route.query.redirect; - router.push(redirect || "/dashboard"); + try { + // 使用replace而不是push,这样不会留下历史记录 + await router.replace(redirect || "/dashboard"); + } catch (navigationError) { + console.error('导航错误:', navigationError); + // 如果导航失败,尝试强制刷新页面 + window.location.replace(redirect || "/dashboard"); + } } else { // 记录失败日志 systemLogStore.addLog({ diff --git a/src/views/patrol/events/index.vue b/src/views/patrol/events/index.vue new file mode 100644 index 0000000..2b43303 --- /dev/null +++ b/src/views/patrol/events/index.vue @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/src/views/patrol/points/index.vue b/src/views/patrol/points/index.vue index 21aaef4..339bc1d 100644 --- a/src/views/patrol/points/index.vue +++ b/src/views/patrol/points/index.vue @@ -318,7 +318,7 @@ const pointTypes = [ \ No newline at end of file