考试系统开发文档技术框架文件目录页面布局主面板登陆注册页面错误页面进入考试页面添加考试页面功能实现端口配置实例化路由配置状态管理设备状态日志状态权限状态系统状态标签状态用户状态API接口处理单一题库接口考试卷子接口卷子列表接口导入导出题目接口所有题库接口系统配置接口分离接口系统角色接口系统用户接口用户接口用户训练接口粘贴板功能权限功能通用状态过滤工具封装认证工具复制粘贴辅助提示工具错误日志工具获取页面标题工具打开窗口工具权限工具请求工具正则验证工具其他工具
考试系统开发文档
技术框架
前端框架
- axios: 基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境中发送 HTTP 请求。
- clipboard: 一个 JavaScript 库,用于复制文本到剪贴板。
- cos-js-sdk-v5: 腾讯云对象存储(COS)的 JavaScript SDK。
- dropzone: 一个用于文件上传的 JavaScript 库,支持拖放和文件预览等功能。
- element-ui: 一个基于 Vue.js 的 UI 组件库,提供了丰富的组件和模板,可以用于构建 Web 应用程序的前端界面。
- fuse.js: 一个用于模糊搜索和自动完成的 JavaScript 库。
- js-cookie: 一个简单的 JavaScript 库,用于读写浏览器 cookie。
- jsonlint: 一个用于验证和格式化 JSON 的 JavaScript 库。
- moment: 一个用于解析、验证、操作和显示日期和时间的 JavaScript 库。
- nprogress: 一个用于显示加载进度条的 JavaScript 库。
- path-to-regexp: 一个用于将路径字符串转换为正则表达式的 JavaScript 库。
- querystring: 一个用于解析和格式化查询字符串的 JavaScript 库。
- screenfull: 一个用于全屏显示的 JavaScript 库。
- showdown: 一个用于将 Markdown 转换为 HTML 的 JavaScript 库。
- sortablejs: 一个用于拖放排序的 JavaScript 库。
- tracking: 一个用于跟踪页面和用户行为的 JavaScript 库。
- vue: 一个用于构建用户界面的渐进式框架,提供了数据驱动的组件化架构和简单灵活的 API。
- vue-count-to: 一个用于数字滚动效果的 Vue.js 组件。
- vue-fullscreen: 一个用于全屏显示的 Vue.js 组件。
- vue-router: 一个用于 Vue.js 应用程序中的路由管理器。
- vue-splitpane: 一个用于创建分割面板布局的 Vue.js 组件。
- vue-uuid: 一个用于生成唯一标识符(UUID)的 Vue.js 插件。
- vue-visibility-change: 一个用于检测浏览器窗口是否可见的 Vue.js 插件。
- vuedraggable: 一个用于拖放排序的 Vue.js 组件。
- vuex: 一个用于 Vue.js 应用程序中的状态管理模式和库。
文件目录
vue.config.js端口配置
package.json依赖文件
build打包配置
public自动生成
src资源文件
-api接口
-assets静态资源
-components组件
directive
filters题目过滤
icons图片处理
layout布局
router路由布局
store状态管理
styles样式处理
utils工具类
views主页面
mainjs启动脚本
permissionjs权限
settingsjs其他配置
页面布局
主面板
elrow的gutter值为该单元格左右的padding之和,elcol的:span为每一列占的宽度,占24份的几分之几,这里两个col,都包含一个elcard,一个用来展示功能信息,大小为16,一个用来展示通知,大小为8
展示功能,公告等
登陆注册页面
登陆,用elformitem实现登陆输入,ellink实现注册跳转,登陆功能用dispatch传递到后端,push跳转到主面板
注册,同理,ellink跳转到登陆,dispatch之后push切换路由
错误页面
套用模板,401和404页面
进入考试页面
DataTable组件,
el-date-picker
el-select
el-option
el-table-column
实现考试信息,参加考试界面
选择类型,搜索,考试的基本信息,考试操作,跳转页面
handleExamDetail(examId)push到考试信息
handleUpdateExam(examId)push到更新考试
添加考试页面
RepoSelect组件
elcard
eltable
eltablecolumn
el-input-number
el-date-picker
el-radio-group
el-radio
el-alert
实现了设置考试分数,题目,树型控件 根据搜索框关键字,添加判断等
添加题库信息
开始考试页面
资料页面
设置题目页面
图库页面
系统设置页面
用户页面
功能实现
端口配置
在vue.config.js中,
路径
const path = require('path')
默认设置
const defaultSettings = require('./src/settings.js')
一个函数用来拼接路径
function resolve(dir) { return path.join(__dirname, dir) }
设置站点名称为
const name = defaultSettings.title || 'C语言考试系统'
设置端口号
const port = process.env.port || process.env.npm_config_port || 9527
设置一些参数
默认部署根路径,如果是com/isgood这种路径就换成/isgood/
publicPath: '/',
打包输出静态文件的位置
outputDir: 'dist',
静态资源的位置
assetsDir: 'static',
置是否在开发环境下每次保存代码时都启用 eslint验证,如果是开发环境就验证
lintOnSave: process.env.NODE_ENV === 'development',
productionSourceMap: 改成false后 所有打包生成的map文件都没有了,性能优化
productionSourceMap: false,
开发服务器,端口号,设置是否自动打开浏览器,当出错时warning不全屏,error全屏
devServer: { port: port, open: true, overlay: { warnings: false, errors: true }
注入正确的名字,
configureWebpack: { name: name, resolve: { alias: { '@': resolve('src') } } }
chainWebpack做高级配置,配置插件和元素
实例化
mainjs文件中
使用elementui
Vue.use(Element, { size: Cookies.get('size') || 'medium' // set element-ui default size })
注册全局过滤器
Object.keys(filters).forEach(key => { Vue.filter(key, filters[key]) })
减少生产提示
Vue.config.productionTip = false
build目录下面的index
设置脚本执行
路由配置
router的路由解析
constantRoutes 不需要判断权限的页面
重定向,登陆,注册,错误页面,主界面,题目详情,根据id,个人资料,
asyncRoutes需要动态添加的页面
开始考试,根据id,我的考试,考试管理,系统管理
状态管理
store状态管理
设置不同的模块,每个模块进行解析,添加,
getters获取数据
const getters = { sidebar: state => state.app.sidebar, size: state => state.app.size, device: state => state.app.device, visitedViews: state => state.tagsView.visitedViews, cachedViews: state => state.tagsView.cachedViews, token: state => state.user.token, avatar: state => state.user.avatar, userId: state => state.user.userId, name: state => state.user.name, realName: state => state.user.realName, introduction: state => state.user.introduction, roles: state => state.user.roles, permission_routes: state => state.permission.routes, errorLogs: state => state.errorLog.logs, siteData: state => state.settings.siteData } export default getters
module定义不同状态的数据
设备状态
app
定义侧边栏,设备,大小,侧边栏两个属性,是否开启,动画,设备只有一个属性,大小只有一个属性
同步方法
TOGGLE_SIDEBAR,切换open状态
CLOSE_SIDEBAR,关闭状态,设置动画
TOGGLE_DEVICE
SET_SIZE
异步方法
以上同步方法
日志状态
errorLog
错误日志,只有推送和清除
权限状态
用于配置动态路由
permission
和上面的AsyncRoutes结合使用,
SET_ROUTES动态添加路由和页面
generateRoutes生成路由
系统状态
settings
设置主题,是否展示设置,标签视图,修复头部,侧边logo,站点数据
CHANGE_SETTING改变设置,
SET_SITE_DATA设置站点数据
都需要actions获取数据提交,
标签状态
tagsview
用来管理点击的标签
有看过的,和缓存的
ADD_VISITED_VIEW异步获取的数据进行push,浅拷贝其他属性
ADD_CACHED_VIEW直接push
DEL_VISITED_VIEW迭代用splice删除
DEL_CACHED_VIEW通过indexOf和splice删除
DEL_OTHERS_VISITED_VIEWSfilter过滤只返回符合条件的
DEL_OTHERS_CACHED_VIEWSindexOf和if判断splice
DEL_ALL_VISITED_VIEWS直接filter
DEL_ALL_CACHED_VIEWS直接设置空数组
UPDATE_VISITED_VIEW迭代加浅拷贝
用户状态
users
管理token,id,name,头像,真名,介绍,角色
SET_TOKEN: (state, token) => { state.token = token }, SET_INTRODUCTION: (state, introduction) => { state.introduction = introduction }, SET_ID: (state, userId) => { state.userId = userId }, SET_NAME: (state, name) => { state.name = name }, SET_REAL_NAME: (state, realName) => { state.realName = realName }, SET_AVATAR: (state, avatar) => { state.avatar = avatar }, SET_ROLES: (state, roles) => { state.roles = roles }
异步方法
xxxxxxxxxx
login采取promise提交登陆数据,获取返回内容,设置token
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
和登陆一样
reg({ commit }, userInfo) {
const { userName, realName, password } = userInfo
return new Promise((resolve, reject) => {
reg({ userName: userName.trim(), realName: realName.trim(), password: password }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
获取返回数据,赋值,通过commit提交到mutations
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
if (!data) {
reject('校验失败,请重新登录!.')
}
const { id, roles, userName, realName, avatar, introduction } = data
if (!roles || roles.length <= 0) {
reject('用户角色不能为空!')
}
commit('SET_ID', id)
commit('SET_ROLES', roles)
commit('SET_REAL_NAME', realName)
commit('SET_NAME', userName)
commit('SET_AVATAR', avatar)
commit('SET_INTRODUCTION', introduction)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
登出,把数据置空
logout({ commit, state, dispatch }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resetRouter()
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
}).catch(error => {
reject(error)
})
})
},
重置token
resetToken({ commit }) {
return new Promise(resolve => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resolve()
})
},
改变角色,设置token获取角色,重置路由生成路由
changeRoles({ commit, dispatch }, role) {
return new Promise(async resolve => {
const token = role + '-token'
commit('SET_TOKEN', token)
setToken(token)
const { roles } = await dispatch('getInfo')
resetRouter()
const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
router.addRoutes(accessRoutes)
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
})
}
}
API接口处理
单一题库接口
fetchDetail(id) post根据id调取/exam/api/exam/exam/detail
saveData(data)post把data保存到/exam/api/exam/exam/save
fetchList()post获取题目列表
考试卷子接口
都是post
createPaper(data)创建试卷
paperDetail(data)试卷详情
createPaper(data)题目详情
fillAnswer(data)填充答案
paperResult(data)试卷结果
training(data)错题训练
checkProcess()检查是否有考试
卷子列表接口
listPaper(userId, examId)获取试卷列表
导入导出题目接口
fetchDetail(id)题库详情post
saveData(data)保存题库post
exportExcel(data)导出excel,download
importTemplate()导入模板download
所有题库接口
fetchDetail(data)获取所有题库
saveData(data)保存题库
fetchPaging(data)保存题库
batchAction(data)批量操作
系统配置接口
fetchDetail()获取用户协议
saveData(data)保存
分离接口
pagingTree(data)获取页面结构
fetchTree(data)获取页面结构
fetchDetail(id)获取详情
deleteData(ids)删除
saveData(data)保存
sortData(id, sort)排序
系统角色接口
fetchList()获取角色列表
系统用户接口
updateData(data)更新数据
saveData(data)保存
userReg(data)注册
用户接口
nextQu(examId, quId)获取题库详情
login(data)登陆
getInfo(token)获取信息
logout()注销
reg(data)注册
用户训练接口
startTrain(mode, repoId, userId, clear)开始训练
fillResult(id, answers, isRight)填充结果
hasTrain(mode, repoId, userId)判断是否在训练
listCard(mode, repoId, userId)答题卡
nextQu(mode, repoId, userId, sequence)下一题
粘贴板功能
导入,Clipboard,绑定,更新,解绑
clipboard
Clipboard = require('clipboard')
bind(el, binding)判断binding的状态,成功或者失败,赋不同的值,如果不是这两种,新建clipboard,text文本赋值,action返回操作,on监听成功失败,
update(el, binding)更新同理,执行text和action方法,
unbind(el, binding)解除,成功就执行delete,否则删除错误,都不是,直接执行destroy操作,然后删除
权限功能
inserted(el, binding, vnode)
通用状态过滤
stateFilter(value)通用状态过滤,01
quTypeFilter(value)题目类型过滤123
paperStateFilter(value)考试状态过滤0123
examOpenType(value)考试权限过滤12
examStateFilter(value)考试时间过滤0123
工具封装
认证工具
获取删除设置token
import Cookies from 'js-cookie'
getToken()
setToken(token)
removeToken()
复制粘贴辅助提示工具
import Clipboard from 'clipboard'
clipboardSuccess()调用vue的message返回成功
clipboardError()返回失败
handleClipboard(text, event)监听,成功失败,和点击
错误日志工具
checkNeed()检查是不是开发环境,然后通过nextTick和dispatch调取内容,错误信息,实例,描述内容,错误所在地
获取页面标题工具
getPageTitle(title, pageTitle),字符串拼接
打开窗口工具
openWindow(url, title, w, h)获取位置,大小,执行window的open
权限工具
checkPermission(value)通过store获取所有角色跟value比较,没角色报错,返回有没有权限的判断值
请求工具
axios实例,interceptors.request.use实现请求过滤器,一个config,获取store的token,设置到config的headers里面,传递出去,一个error执行Promise的reject
interceptors.response.use响应拦截,获取返回值,如果下载文件直接返回,然后是响应码的判断,如果登陆超时,执行MessageBox方法,其他错误用reject
upload(url, file, data)上传文件,通过FormData()添加文件,在promise里执行request操作,
download(url, data, fileName)下载,promise执行request和
let link = document.createElement('a') link.href = URL.createObjectURL(blob) link.setAttribute('download', fileName) link.click() link = null
post(url, data = {})封装post请求,在promise里面执行post
正则验证工具
url,大小写,邮箱,字符串,字符串
其他工具
parseTime(time, cFormat),指定格式,获取年月日等,然后执行转换,
formatTime(time, option)格式化
getQueryObject(url)
byteLength(str)
cleanArray(actual)
param(json)
param2Obj(url)
html2Text(val)
objectMerge(target, source)
toggleClass(element, className)
getTime(type)
debounce(func, wait, immediate)
deepClone(source)
uniqueArr(arr)
createUniqueString()
hasClass(ele, cls)
addClass(ele, cls
removeClass(ele, cls)