提交 ddc79f3a authored 作者: wangjialong209's avatar wangjialong209

第一个模块内容

上级 ade30e39
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
ENV = 'development' ENV = 'development'
# base api # base api
VUE_APP_BASE_API = '/dev-api' #VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API = 'http://192.168.0.147:9202'
...@@ -15,10 +15,12 @@ ...@@ -15,10 +15,12 @@
"test:ci": "npm run lint && npm run test:unit" "test:ci": "npm run lint && npm run test:unit"
}, },
"dependencies": { "dependencies": {
"@riophae/vue-treeselect": "^0.4.0",
"axios": "0.18.1", "axios": "0.18.1",
"clipboard": "2.0.4", "clipboard": "2.0.4",
"codemirror": "5.45.0", "codemirror": "5.45.0",
"core-js": "3.6.5", "core-js": "3.6.5",
"crypto-js": "^4.1.1",
"driver.js": "0.9.5", "driver.js": "0.9.5",
"dropzone": "5.5.1", "dropzone": "5.5.1",
"echarts": "4.2.1", "echarts": "4.2.1",
......
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 294.11 90.15"><defs><style>.cls-1{fill:#009143;fill-rule:evenodd;}.cls-2{fill:#231815;}</style></defs><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M52.68,13.19c-4.81,5.15-4.9,11.56-3,16.78,2.9,8,11.59,13,21.71,9.13,2.74-1.05,8.39-5.42,9.21-11.6,1-7.12-.68-11.2-5.62-16.14S62,2.32,53.33.72A46.37,46.37,0,0,0,29.84,2.6C12.87,8.79,1,25.36.08,41.81A45.36,45.36,0,0,0,36.79,89.42,45.41,45.41,0,0,0,83.14,69.16L63.86,46.61S65.39,65.36,52.2,75a24,24,0,0,0-1-14.88c-3.54-8.28-10.44-14.7-10.63-24.57a22.42,22.42,0,0,1,6-15.78A22.35,22.35,0,0,0,38,39c.62,11.66,10,18.19,10.78,29.53.38,5.72-1,11-4.69,13.53l-1.52-1.51a5.68,5.68,0,0,0,.24-7.36c-1.39-2-6.14-4.86-10.25-10A30.27,30.27,0,0,1,26.11,48a32,32,0,0,1,6.74-23.38c4.57-5.75,11.42-9.75,19.83-11.42Z"/><path class="cls-2" d="M106.34,74.67c-2.59,2-4.93,3-7.06,3a6.55,6.55,0,0,1-4.93-2A6.62,6.62,0,0,1,92.55,71a7.58,7.58,0,0,1,4.12-6.8A9.08,9.08,0,0,1,101.41,63a14.85,14.85,0,0,1,4.56.68V67h-.87a3.18,3.18,0,0,0-1.6-2.49,6,6,0,0,0-3.19-.81,5.3,5.3,0,0,0-4.25,1.84,6.22,6.22,0,0,0-1.42,4.17,6.48,6.48,0,0,0,1.6,4.43,5.72,5.72,0,0,0,4.54,1.93A9.51,9.51,0,0,0,106.34,74Z"/><path class="cls-2" d="M124.65,77.34h-6v-.52a2.23,2.23,0,0,0,1.47-.39,1.91,1.91,0,0,0,.38-1.36V70h-7.44v5c0,1.13.62,1.72,1.86,1.75v.52h-6v-.52a2.16,2.16,0,0,0,1.47-.39,1.91,1.91,0,0,0,.38-1.36V65.58a1.85,1.85,0,0,0-.38-1.34,2.33,2.33,0,0,0-1.47-.39v-.52h6v.52a2.31,2.31,0,0,0-1.48.39,1.85,1.85,0,0,0-.38,1.34v3.76h7.44V65.58a1.9,1.9,0,0,0-.37-1.34,2.35,2.35,0,0,0-1.48-.39v-.52h6v.52a2.29,2.29,0,0,0-1.47.39,1.8,1.8,0,0,0-.39,1.34v9.49a1.85,1.85,0,0,0,.39,1.37,2.18,2.18,0,0,0,1.47.38Z"/><path class="cls-2" d="M133.52,77.34h-6v-.52a2.14,2.14,0,0,0,1.48-.39,1.86,1.86,0,0,0,.38-1.36V65.58a1.8,1.8,0,0,0-.38-1.34,2.31,2.31,0,0,0-1.48-.39v-.52h6v.52a2.27,2.27,0,0,0-1.47.39,1.85,1.85,0,0,0-.38,1.34v9.49c0,1.13.61,1.71,1.85,1.75Z"/><path class="cls-2" d="M152.26,63.85c-1.48.13-2.24,2.33-2.24,6.59v7.41h-.56L138.93,65.07v4.08a28.38,28.38,0,0,0,.22,4.26c.32,2.15,1,3.29,2,3.41v.52h-5.3v-.52c1.49-.21,2.23-2.72,2.23-7.55V65.49a1.62,1.62,0,0,0-.41-1.27,2.33,2.33,0,0,0-1.42-.37v-.52h4L149.15,74V70.79c0-4.49-.74-6.79-2.22-6.94v-.52h5.33Z"/><path class="cls-2" d="M168.72,77.34h-4.38v-.52h.27c.15,0,.22-.13.22-.36a.79.79,0,0,0-.05-.25l-1.47-3.81H158a9.74,9.74,0,0,0-.83,3.16,1.17,1.17,0,0,0,.4.92,1.53,1.53,0,0,0,1,.34h.65v.52h-5.47v-.52c.91,0,1.75-.91,2.49-2.62l5-11.45H162L166.3,74a8.08,8.08,0,0,0,.84,1.76,2,2,0,0,0,1.58,1.11ZM163,71.73l-2.22-5.83-2.56,5.83Z"/><path class="cls-2" d="M190.29,67h-.86c0-2.1-1.26-3.15-3.71-3.15h-.66V75.07c0,1.13.62,1.72,1.85,1.75v.52h-6v-.52a2.17,2.17,0,0,0,1.48-.39,1.91,1.91,0,0,0,.38-1.36V63.85H182q-3.39,0-3.49,3.15h-.85V62.83h.53c.11.33.27.5.48.5H189.3c.28,0,.4-.17.4-.5h.59Z"/><path class="cls-2" d="M208.93,69.67a7.22,7.22,0,0,1-1.37,4.14,8.56,8.56,0,0,1-3.53,3,9.73,9.73,0,0,1-4.11.9,7.56,7.56,0,0,1-5.25-1.91A6.09,6.09,0,0,1,192.54,71a7.43,7.43,0,0,1,2.64-5.62A8.89,8.89,0,0,1,201.36,63a7.59,7.59,0,0,1,6.38,3A5.86,5.86,0,0,1,208.93,69.67Zm-2.07,1.93a8,8,0,0,0-.93-3.79,6.59,6.59,0,0,0-2.84-2.88,7,7,0,0,0-3.26-.9,4.94,4.94,0,0,0-5.22,5.17,7.61,7.61,0,0,0,1.88,5.11,6.62,6.62,0,0,0,5.22,2.38,5,5,0,0,0,5.15-5.09Z"/><path class="cls-2" d="M223.77,72.4a4.32,4.32,0,0,1-2,3.56,7.06,7.06,0,0,1-4.25,1.38H211.8v-.52a2.08,2.08,0,0,0,1.46-.39,1.86,1.86,0,0,0,.39-1.36V65.58a1.8,1.8,0,0,0-.39-1.34,2.24,2.24,0,0,0-1.46-.39v-.52h7.38a6.24,6.24,0,0,1,2.69.44,2.09,2.09,0,0,1,1.18,2c0,1.5-1.15,2.87-3.45,4.08a7.83,7.83,0,0,1,2.85.42A2.1,2.1,0,0,1,223.77,72.4Zm-2.91-5.12a3.81,3.81,0,0,0-.73-2.33,2.74,2.74,0,0,0-2.3-1.11,3.26,3.26,0,0,0-1.92.52v5.11h2.38C220,69.47,220.86,68.74,220.86,67.28Zm.56,6.47A3.47,3.47,0,0,0,220.26,71a4.53,4.53,0,0,0-3.11-1h-1.24v5.77a4.51,4.51,0,0,0,2.62.9,2.71,2.71,0,0,0,2.89-2.89Z"/><path class="cls-2" d="M241,77.34h-4.38v-.52h.27c.15,0,.21-.13.21-.36a.79.79,0,0,0-.05-.25l-1.46-3.81H230.2a9.83,9.83,0,0,0-.84,3.16,1.14,1.14,0,0,0,.41.92,1.52,1.52,0,0,0,1,.34h.65v.52H226v-.52c.91,0,1.75-.91,2.48-2.62l5-11.45h.73L238.52,74a9.14,9.14,0,0,0,.84,1.76A2,2,0,0,0,241,76.82Zm-5.68-5.61-2.22-5.83-2.56,5.83Z"/><path class="cls-2" d="M256.94,74.67q-3.87,3-7.06,3A6.51,6.51,0,0,1,243.15,71a7.58,7.58,0,0,1,4.12-6.8A9.1,9.1,0,0,1,252,63a14.8,14.8,0,0,1,4.56.68V67h-.87a3.17,3.17,0,0,0-1.61-2.49,5.86,5.86,0,0,0-3.17-.81,5.31,5.31,0,0,0-4.26,1.84,6.22,6.22,0,0,0-1.42,4.17,6.44,6.44,0,0,0,1.6,4.43,5.74,5.74,0,0,0,4.54,1.93A9.49,9.49,0,0,0,256.94,74Z"/><path class="cls-2" d="M273.56,74.67c-2.59,2-4.93,3-7.06,3a6.53,6.53,0,0,1-4.93-2,6.62,6.62,0,0,1-1.8-4.67,7.56,7.56,0,0,1,4.12-6.8A9.08,9.08,0,0,1,268.63,63a14.85,14.85,0,0,1,4.56.68V67h-.87a3.17,3.17,0,0,0-1.61-2.49,5.92,5.92,0,0,0-3.18-.81,5.3,5.3,0,0,0-4.25,1.84,6.22,6.22,0,0,0-1.42,4.17,6.48,6.48,0,0,0,1.59,4.43A5.75,5.75,0,0,0,268,76.07,9.51,9.51,0,0,0,273.56,74Z"/><path class="cls-2" d="M292.75,69.67a7.08,7.08,0,0,1-1.37,4.14,8.41,8.41,0,0,1-3.52,3,9.73,9.73,0,0,1-4.11.9,7.59,7.59,0,0,1-5.25-1.91A6,6,0,0,1,276.38,71,7.46,7.46,0,0,1,279,65.42,8.87,8.87,0,0,1,285.19,63a7.58,7.58,0,0,1,6.38,3A5.85,5.85,0,0,1,292.75,69.67Zm-2.06,1.93a8,8,0,0,0-.92-3.79,6.61,6.61,0,0,0-2.85-2.88,7.06,7.06,0,0,0-3.26-.9,5,5,0,0,0-5.22,5.17,7.56,7.56,0,0,0,1.88,5.11,6.59,6.59,0,0,0,5.23,2.38,5,5,0,0,0,3.75-1.54A4.93,4.93,0,0,0,290.69,71.6Z"/><path class="cls-2" d="M95.08,40.71V15.89h17.29V8h7.49v7.9h17.28V40.52h-7.48V38.14h-9.8V52.29h-7.49V38.14h-9.79v2.57Zm7.5-18.2v9h9.79v-9Zm27.08,0h-9.8v9h9.8Z"/><path class="cls-2" d="M146.32,52.11V9.64h43V52.11H182v-2.2H153.42v2.2Zm7.1-36.58v29H182v-29ZM155,23.25V17.73h25.35v5.52h-9.79v2.94h9V31.7h-3.26c1.15,1.11,2.36,2.21,3.64,3.32l-2.1,1.65h2.87v5.71H154.77V36.67h9v-5h-7.88V26.19h7.88V23.25Zm19.78,13.42c-.39-.37-1-1-1.73-1.84l-1.15-1.1,2.31-2h-3.65v5Z"/><path class="cls-2" d="M198.32,30.41q-.37-2.94-2.11-10.47c-.25-1.11-.44-2-.57-2.57l4.41-.93c.26,1.23.58,2.94,1,5.16.51,2.69.9,4.72,1.15,6.07V25.82c.13-2.82.19-5.51.19-8.09V8.35h6.34v9.94A21.32,21.32,0,0,1,210,16.63c.51-.74.89-1.29,1.15-1.65l1.54,1.65V9.82h28.42V52.11h-6.34v-2H219.07v2h-6.34V43.66l-2.49,3.13-4.05-5.15c-.76,2.45-2.68,6-5.76,10.65-1.53-1.71-3.07-3.31-4.6-4.77A29.42,29.42,0,0,0,202,29.69ZM207.73,35c.64.61,1.54,1.53,2.69,2.74,1,1,1.79,1.73,2.31,2.22V21.78a15.39,15.39,0,0,1-2.12,2c-.89,1-1.6,1.73-2.11,2.22A84.45,84.45,0,0,1,207.73,35ZM220,27.29V22h4c.12-1.71.19-3.43.19-5.15H230V22h3.85v5.33h-4a7.19,7.19,0,0,1-.39,2.4c1,1.22,2.37,2.93,4,5.14.64.73,1.08,1.28,1.34,1.65V15.53H219.07V37.76c3.06-3.42,4.67-6.91,4.8-10.47Zm11.91,15.44c-1.53-2.21-3.07-4.4-4.6-6.62a33.77,33.77,0,0,1-5,7.36L219.07,40v4.78h15.74V39.61Z"/><path class="cls-2" d="M247.82,16.63V11.11h11.92V8.17h6.72v2.94h9.21V8.17h6.73v2.94h11.71v5.52H282.4v2.2h-6.73v-2.2h-9.21v2.2h-6.72v-2.2Zm4.43,22.61V19.75H289.7V39.24h-15v2.4h19.39v5.15H274.72v5.32h-7.3V46.79h-19.6V41.64h19.6v-2.4Zm7.1-14.52v2.57h23.24V24.72Zm0,6.8V34.1h23.24V31.52Z"/></g></g></svg>
\ No newline at end of file
/*
* @Author: czj
* @Date: 2023-02-24 16:50:22
* @Description:
* @FilePath: \AdministrationHome\src\api\role.js
*/
import request from '@/utils/request' import request from '@/utils/request'
export function getRoutes() { export function getRoutes() {
...@@ -36,3 +42,54 @@ export function deleteRole(id) { ...@@ -36,3 +42,54 @@ export function deleteRole(id) {
method: 'delete' method: 'delete'
}) })
} }
/**
* 角色权限
*
* */
//后去分页权限列表
export function get_permission_list(params) {
return request({
url: `/api/roles`,
method: 'get',
params
})
}
//获取全部角色
export function get_roles_all() {
return request({
url: '/api/roles/all',
method: 'get'
})
}
//角色-添加
export function add_roles(data) {
return request({
url: '/api/roles',
method: 'post',
data
})
}
//角色-删除
export function delete_roles(id) {
return request({
url: `/api/roles/${id}`,
method: 'delete'
})
}
//角色-修改
export function edit_roles(id, data) {
return request({
url: `/api/roles/${id}`,
method: 'put',
data
})
}
//获取角色-详情
export function get_permission_detail(id) {
return request({
url: `/api/roles/${id}`,
method: 'get',
})
}
/*
* @Author: czj
* @Date: 2023-03-06 13:50:05
* @Description:
* @FilePath: \AdministrationHome\src\api\student.js
*/
import request from '@/utils/request'
/*
//公共接口
*/
//获取省市区信息
export function get_province_list(data) {
return request({
url: '/api/treeprovince',
method: 'post',
data
})
}
/**
*
* 烟草区域与品种
* */
//烟草品种信息-区域信息获取
export function get_tobacco_province() {
return request({
url: '/api/tobacco_breed/getProvince',
method: 'get',
})
}
//烟草品种信息-获取 分页
export function get_tobacco_breed_list(params) {
return request({
url: '/api/tobacco_breed',
method: 'get',
params
})
}
//烟草品种信息-全部
export function get_tobacco_all_info() {
return request({
url: '/api/tobacco_breed/all',
method: 'get',
})
}
//烟草品种信息-添加
export function add_tobacco_breed(data) {
return request({
url: '/api/tobacco_breed',
method: 'post',
data
})
}
//烟草品种信息-删除
export function delete_tobacco_breed(id) {
return request({
url: `/api/tobacco_breed/${id}`,
method: 'delete',
})
}
//烟草品种信息-修改
export function updata_tobacco_breed(id, data) {
return request({
url: `/api/tobacco_breed/${id}`,
method: 'put',
data
})
}
//烟草品种信息-详情
export function get_tobacco_detail(id) {
return request({
url: `/api/tobacco_breed/${id}`,
method: 'get',
})
}
//烟草品种信息-获取
export function get_tobacco_info(params) {
return request({
url: `/api/tobacco_breed`,
method: 'get',
params
})
}
//烟草图片上传
export function tobacco_img_upload(data) {
return request({
url: '/api/upload/breedimage',
method: 'post',
data
})
}
/*
试题管理配置
*/
//试题信息管理-全部
export function get_examination_questions_all() {
return request({
url: `/api/examination_questions/all`,
method: 'get',
})
}
//试题信息管理-分页数据
export function get_examination_questions_list(params) {
return request({
url: `/api/examination_questions`,
method: 'get',
params
})
}
//试题信息管理-新增
export function add_examination_questions(data) {
return request({
url: `/api/examination_questions`,
method: 'post',
data
})
}
//试题信息管理-修改
export function updata_examination_questions(id, data) {
return request({
url: `/api/examination_questions/${id}`,
method: 'put',
data
})
}
//试题信息管理-详情
export function get_examination_questions_detail(id, params) {
return request({
url: `/api/examination_questions/${id}`,
method: 'get',
})
}
//试题信息管理详情-图片上传
export function upload_examination_question_image(data) {
return request({
url: `/api/upload/examinationQuestionImage`,
method: 'post',
data
})
}
//试题信息管理详情-新增
export function add_examination_question_detail(data) {
return request({
url: `/api/examination_question_detail`,
method: 'post',
data
})
}
//试题信息管理详情-删除
export function delete_examination_question_detail(id) {
return request({
url: `/api/examination_question_detail/${id}`,
method: 'delete',
})
}
//试题信息管理详情-修改
export function updata_examination_question_detail(id, data) {
return request({
url: `/api/examination_question_detail/${id}`,
method: 'put',
data
})
}
//试题信息管理-答题卡生成
export function create_answer_card(id) {
return request({
url: `/api/examination_questions/dowAnswerCard/${id}`,
method: 'get',
})
}
//试题信息管理-试题复制
export function examination_questions_copy(id) {
return request({
url: `/api/examination_questions/copy/${id}`,
method: 'get',
})
}
//试题信息管理-试题发布
export function examination_questions_publish(id) {
return request({
url: `/api/examination_questions/publish/${id}`,
method: 'get',
})
}
//试题信息管理-停止使用/删除
export function delete_examination_questions(id) {
return request({
url: `/api/examination_questions/${id}`,
method: 'delete',
})
}
//试题模板文件下载
// export function
//试题模板文件上传-快速配置
export function examination_question_detail_upload(id, data) {
return request({
url: `/api/examination_question_detail/upload/${id}`,
method: 'post',
data
})
}
//多图片上传
export function batch_upload_of_pictures(father_id, id, data) {
return request({
url: `/api/examination_question_detail/uploadimage/${father_id}?id=${id}`,
method: 'post',
data
})
}
//获取当前试题配置图片
export function get_image_path(id) {
return request({
url: `/api/examination_question_detail/getImagepath/${id}`,
method: 'get',
})
}
/**
* 烟草等级
* */
//烟草等级信息-全部信息
export function get_tobacco_grades_all() {
return request({
url: `/api/tobacco_grades/all`,
method: 'get',
})
}
//烟草等级信息-分页查询
export function get_tobacco_grades_list(params) {
return request({
url: `/api/tobacco_grades`,
method: 'get',
params
})
}
//烟草等级信息-新增
export function add_tobacco_grades(data) {
return request({
url: `/api/tobacco_grades`,
method: 'post',
data
})
}
//烟草等级信息-删除
export function delete_tobacco_grades(id) {
return request({
url: `/api/tobacco_grades/${id}`,
method: 'delete',
})
}
//烟草等级信息-修改
export function updata_tobacco_grades(id, data) {
return request({
url: `/api/tobacco_grades/${id}`,
method: 'put',
data
})
}
//烟草等级信息-详细信息
export function get_tobacco_grades_detail(id) {
return request({
url: `/api/tobacco_grades/${id}`,
method: 'get',
})
}
/**
* 学生管理
* */
//学员信息-全部
export function get_student_all() {
return request({
url: `/api/student/all`,
method: 'get',
})
}
//学员信息-分页查询
export function get_student_list(params) {
return request({
url: `/api/student`,
method: 'get',
params
})
}
//学员信息-新增
export function add_student(data) {
return request({
url: `/api/student`,
method: 'post',
data
})
}
//学员信息-删除
export function delete_student(id) {
return request({
url: `/api/student/${id}`,
method: 'delete',
})
}
//学员信息-修改
export function updat_student(id, data) {
return request({
url: `/api/student/${id}`,
method: 'put',
data
})
}
//学员信息-详情
export function get_student_detail(id) {
return request({
url: `/api/student/${id}`,
method: 'get',
})
}
//学员信息-导出
export function download_student_info(data) {
return request({
url: `/api/student/download`,
method: 'post',
data
})
}
//学员信息-上传
export function upload_student_info(data) {
return request({
url: `/api/student/upload`,
method: 'post',
data
})
}
/**
*
* 考试结果
* * */
//学员考试结果-分页
export function get_test_results_list(params) {
return request({
url: `/api/test_results`,
method: 'get',
params
})
}
//学员考试-预约
export function examination_reservation(data) {
return request({
url: `/api/test_results`,
method: 'post',
data
})
}
//学员考试-取消预约
export function cancel_reservation(id, data) {
return request({
url: `/api/test_results/${id}`,
method: 'put',
data
})
}
//学员考试-批量预约
export function examination_batch_reservation(id, data) {
return request({
url: `/api/test_results/upload/${id}`,
method: 'post',
data
})
}
//学员考试-学员考试详情
export function get_test_results_detail(id) {
return request({
url: `/api/test_results/${id}`,
method: 'get',
})
}
import request from '@/utils/request'
/**
*
* 管理员管理
* */
//管理员-全部
export function get_administrators_all() {
return request({
url: '/api/users',
method: 'get',
})
}
//管理员-列表
export function get_administrators_list(params) {
return request({
url: '/api/users',
method: 'get',
params
})
}
//管理员-新增
export function add_administrators(data) {
return request({
url: `/api/users`,
method: 'post',
data
})
}
//老师用户新增
export function create_temporary(data) {
return request({
url: `/api/users/createTemporary`,
method: 'post',
data
})
}
//管理员-删除
export function delete_administrators(id) {
return request({
url: `/api/users/${id}`,
method: 'delete',
})
}
//管理员-修改
export function edit_administrators(id, data) {
return request({
url: `/api/users/${id}`,
method: 'put',
data
})
}
//管理员-详情
export function get_administrators_detail(id) {
return request({
url: `/api/users/${id}`,
method: 'get',
})
}
//上传头像
export function upload_head(data) {
return request({
url: `/api/upload/userimg`,
method: 'post',
data
})
}
/**
*
* 菜单接口
* */
//树状菜单
export function get_permission_tree(params) {
return request({
url: `/api/permission_tree/2`,
method: 'get',
params
})
}
//获取菜单、按钮分类
export function get_permission_btn_menu() {
return request({
url: `/api/permission`,
method: 'get',
})
}
//新增菜单、功能(按钮)
export function add_permission_menu(data) {
return request({
url: `/api/permission`,
method: 'post',
data
})
}
//删除菜单、功能(按钮)
export function delete_permission_menu(id) {
return request({
url: `/api/permission/${id}`,
method: 'delete',
})
}
//修改菜单、功能(按钮)
export function edit_permission_menu(id, data) {
return request({
url: `/api/permission/${id}`,
method: 'put',
data
})
}
/**
* 部门管理
* */
//部门信息获取
export function get_department_list(params) {
return request({
url: `/api/department`,
method: 'get',
params
})
}
//部门管理-新增
export function add_department(data) {
return request({
url: `/api/department`,
method: 'post',
data
})
}
//部门管理-删除
export function delete_department(id) {
return request({
url: `/api/department/${id}`,
method: 'delete',
})
}
//部门管理-修改
export function edit_department(id, data) {
return request({
url: `/api/department/${id}`,
method: 'put',
data
})
}
/**
*
* 系统日志
*/
//获取系统日志
export function get_system_log(params) {
return request({
url: `/api/system_log`,
method: 'get',
params
})
}
//搜索系统日志
export function search_system_log(data) {
return request({
url: `/api/system_log/search`,
method: 'post',
data
})
}
import request from '@/utils/request' import request from '@/utils/request'
// export function login(data) {
// return request({
// url: '/vue-element-admin/user/login',
// method: 'post',
// data
// })
// }
//登录
export function login(data) { export function login(data) {
return request({ return request({
url: '/vue-element-admin/user/login', url: '/api/auth/login',
method: 'post', method: 'post',
data data
}) })
} }
export function getInfo(token) { //获取用户信息
export function getInfo() {
return request({ return request({
url: '/vue-element-admin/user/info', url: '/api/user',
method: 'get',
// params: { token }
})
}
//获取权限菜单
export function getMenu() {
return request({
url: '/api/permission_tree/2',
method: 'get', method: 'get',
params: { token }
}) })
} }
export function logout() { export function logout() {
return request({ return request({
url: '/vue-element-admin/user/logout', url: '/api/auth/logout',
method: 'post' method: 'post'
}) })
} }
...@@ -37,7 +37,7 @@ export default { ...@@ -37,7 +37,7 @@ export default {
const first = matched[0] const first = matched[0]
if (!this.isDashboard(first)) { if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched) // matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
} }
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
......
<!--
* @Author: czj
* @Date: 2023-03-08 15:31:58
* @Description:
* @FilePath: \AdministrationHome\src\components\ExaminationHeader\index.vue
-->
<!-- -->
<template>
<div>
<div>
<el-button type="text" icon="el-icon-arrow-left" size="mini" class="back_btn" @click="back">返回</el-button>
<h2 class="title_box">{{ info_data.title }}</h2>
<span v-for="(item, index) in info_data.examination_status" :key="index">
<el-tag :type="item.type" v-if="info_data.status == item.id">{{ item.label }}</el-tag>
</span>
</div>
<div style="margin-top: 15px;">
<div class="person_attribute_box" v-for="(item, index) in data_keys" :key="index"
v-show="info_data[item.key] != undefined">
<span class="label">{{ item.label }}</span>
<span class="value">{{ info_data[item.key] || '暂无' }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['examination_questions'],
data() {
return {
info_data: {},
data_keys: [
{ label: '创建人', key: 'creat_user_name' },
{ label: '题目数量', key: 'test_number' },
{ label: '用户名', key: 'user_name' },
{ label: '成绩', key: 'score' },
{ label: '考试时长', key: 'duration' },
],
strong_keys: ['user_name', 'score'],
};
},
components: {},
computed: {},
created() {
this.info_data = { ...this.examination_questions };
},
mounted() { },
methods: {
back() {
this.$router.go(-1);
}
}
}
</script>
<style lang="scss" scoped>
.back_btn {
/* font-size: 16px; */
color: #303133;
border-right: 1px solid #DCDFE6;
padding: 3px 10px 3px 0;
border-radius: none;
}
.title_box {
display: inline-block;
vertical-align: middle;
margin: 0 20px;
}
.person_attribute_box {
display: inline-block;
vertical-align: middle;
margin-right: 50px;
font-size: 14px;
.label {
color: #303133;
vertical-align: middle;
margin-right: 12px;
}
.value {
color: #606266;
vertical-align: middle;
}
.strong {
color: #000;
font-size: 20px;
font-weight: 800;
}
}
</style>
<!--
* @Author: czj
* @Date: 2023-03-03 10:41:57
* @Description:
* @FilePath: \AdministrationHome\src\components\TableHead\index.vue
-->
<!-- -->
<template>
<div>
<el-row :gutter="20">
<el-col :span="9">
<span>搜索:</span>
<el-input placeholder="输入名称" class="search_box" v-model="search_val"
:placeholder="!head_data.search_placeholder ? '搜索' : head_data.search_placeholder" @change="searchChange"></el-input>
<el-button type="warning" size="small" @click="search">搜索</el-button>
<el-button size="small" @click="resetting">重置</el-button>
</el-col>
<el-col :span="15" style="text-align: right;">
<span v-for="(item, index) in head_data.right_buttons" :key="index" style="margin: 0 8px;">
<el-button v-if="upload_btns.indexOf(item.event) == -1" type="primary" :icon="item.icon"
@click="btnClick(item.event)">{{
item.text }}</el-button>
<el-upload v-else id="upload_moudel" class="avatar-uploader" action="#" :show-file-list="false" accept=""
:http-request="sliderRequest">
<el-button type="primary" :icon="item.icon" @click="uploadCode(item.event)">{{ item.text }}</el-button>
</el-upload>
</span>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
props: ['head_data'],
data() {
return {
search_val: '',
upload_btns: ['upload', 'examination_questions_upload', 'batch_reservation'],
btn_code: '',
};
},
components: {},
computed: {},
mounted() { },
methods: {
search() {
this.$emit('search', this.search_val);
},
searchChange(){
this.$emit('change', this.search_val);
},
resetting() {
this.search_val = null
this.$emit('resetting', null);
},
addEvent() {
this.$emit('add');
},
//右侧按钮事件
btnClick(val) {
this.$emit('btnClick', val);
},
uploadCode(val) {
this.btn_code = val;
},
// 上传代理
sliderRequest(upload) {
let uploads = { ...upload }
uploads['btn_code'] = this.btn_code
this.$emit('upload', uploads)
},
}
}
</script>
<style scoped>
.search_box {
width: 200px;
margin-right: 15px;
}
.avatar-uploader {
display: inline-block;
}
</style>
<template>
<div class="module_container">
<div class="card_container">
<el-card class="box-card">
<table-head :head_data="head_data" @search="searchEvent" @resetting="resetting" @btnClick="btnClick"></table-head>
<div class="table_container">
<el-table v-loading="is_loading" :data="tableData" style="width: 100%;margin-bottom: 20px;" height="650">
<el-table-column prop="id" label="编号" width="50">
</el-table-column>
<el-table-column prop="name" label="英文名称">
</el-table-column>
<el-table-column prop="view_path" label="组件地址">
</el-table-column>
<el-table-column prop="path" label="路由地址">
</el-table-column>
<el-table-column prop="path" label="路由地址">
</el-table-column>
<el-table-column prop="path" label="路由地址">
</el-table-column>
<el-table-column prop="path" label="路由地址">
</el-table-column>
<el-table-column prop="path" label="路由地址">
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #000;"
@click="updateInformation(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C;"
@click="deleteInformation(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div style="text-align: right;">
<el-pagination @current-change="handleCurrentChange" :current-page.sync="request_params.page"
:page-size="request_params.limit" layout="total, prev, pager, next" :total="request_params.total">
</el-pagination>
</div>
</el-card>
</div>
<el-dialog title="提示" :visible.sync="is_dialogVisible" width="60%" :before-close="handleClose">
<div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import TableHead from '@/components/TableHead/index';
import { get_student_list, add_student, delete_student, updat_student, get_student_detail, download_student_info, upload_student_info } from '@/api/student';
const standard_template = {
id: null,
father_id: -1,//父级id
is_show: false,//是否展示为菜单
name: null,//英文名称
name_zh: null,//中文名称
path: null,//路由路径
sort: null,//排序
status: 1,//状态
type: 1,//类型:菜单/按钮
view_path: null,//视图路径
icon: null,//图标
}
export default {
data() {
return {
IP: process.env.VUE_APP_BASE_API,
//头部按钮
head_data: {
search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-document-add',
event: 'add',
}
],
},
//初始化请求参数
request_params: {
val: '',
page: 1,
limit: 10,
total: null,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//详细信息
detailed_information: {},
};
},
components: { TableHead },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
this.request_params.val = val;
this.getListData();
},
resetting(val) {
this.request_params.val = '';
this.getListData();
},
btnClick(val) {
if (val == 'add') this.addInformation();
},
init() {
this.getListData();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData() {
},
//获取列表数据
getListData() {
let params = this.$removeProperty(this.request_params);
this.is_loading = true;
get_student_list(params).then(res => {
this.tableData = res.data || [];
this.request_params.total = res.total;
this.is_loading = false;
})
},
//分页
handleCurrentChange(val) {
this.request_params.page = val;
this.getListData();
},
//新增信息
addInformation() {
this.is_updata_type = 'add';
this.detailed_information = { ...standard_template };
this.is_dialogVisible = true;
},
//修改信息
updateInformation(item) {
this.is_updata_type = 'edit';
let id = item.id;
//获取详情
this.detailed_information = { ...item };
this.is_dialogVisible = true;
},
//删除
deleteInformation(item) {
let id = item.id;
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_student(id).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.init();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
},
}
</script>
<style lang="scss" scoped></style>
<!--
* @Author: czj
* @Date: 2023-02-27 17:50:39
* @Description:
* @FilePath: \AdministrationHome\src\layout\components\Headerbar\Logo.vue
-->
<!-- -->
<template>
<div>
<img src="/image/log.svg" alt="" class="object_logo">
</div>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {}
}
</script>
<style scoped>
.object_logo {
width: 95px;
height: 30px;
}
</style>
<!-- -->
<template>
<div>
<!-- <el-menu :default-active="activeMenu" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<menu-item v-for="(item, index) in permission_routes" :key="index" :item_data="item"
:base_path="item.path"></menu-item>
</el-menu> -->
<el-menu :default-active="activeMenu" class="el-menu-demo" mode="horizontal" @select="handleSelect">
<el-menu-item index="/dashboard">首页</el-menu-item>
<el-submenu index="/student">
<template slot="title">学员考试</template>
<el-menu-item index="/student/examination_questions/list">试题管理配置</el-menu-item>
<el-menu-item index="/student/test_results/list">考试结果</el-menu-item>
<el-menu-item index="/student/personnel">学员管理</el-menu-item>
<el-menu-item index="/student/area_breed">烟草区域与品种</el-menu-item>
<el-menu-item index="/student/tobacco_grades">烟草等级</el-menu-item>
</el-submenu>
<!-- <el-submenu index="/business">
<template slot="title">工商交接</template>
<el-menu-item index="/business/display_board">展板统计</el-menu-item>
<el-menu-item index="/business/raw_data">原始数据</el-menu-item>
<el-menu-item index="/business/road">渠道管理</el-menu-item>
</el-submenu> -->
<el-submenu index="/system">
<template slot="title">系统管理</template>
<el-menu-item index="/system/administrators">管理员</el-menu-item>
<el-menu-item index="/system/roles">权限配置</el-menu-item>
<el-menu-item index="/system/menu">菜单查看</el-menu-item>
<el-menu-item index="/system/department">部门区域</el-menu-item>
<el-menu-item index="/system/log">系统日志</el-menu-item>
</el-submenu>
</el-menu>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import MenuItem from './MenuItem.vue';
export default {
data() {
return {
activeIndex: '1',
};
},
components: { MenuItem },
computed: {
...mapGetters([
'permission_routes',
'sidebar'
]),
activeMenu() {
const route = this.$route;
const { meta, path } = route;
if (meta.activeMenu) {
return meta.activeMenu
}
return path
},
},
mounted() {
},
methods: {
handleSelect(key, keyPath) {
console.log(key, keyPath);
this.activeIndex = key;
this.$router.push({
path: key,
})
}
}
}
</script>
<style scoped></style>
<!--
* @Author: czj
* @Date: 2023-02-27 18:40:00
* @Description:
* @FilePath: \AdministrationHome\src\layout\components\Headerbar\MenuItem.vue
-->
<!-- -->
<template>
<div v-if="!item_data.hidden" :class="item_data.children ? 'single_menu' : ''">
<template
v-if="hasOneShowingChild(item_data.children, item_data) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item_data.alwaysShow">
<el-menu-item :index="resolvePath(onlyOneChild.path)">
{{ onlyOneChild.meta.title }}
</el-menu-item>
</template>
<el-submenu v-else :index="resolvePath(item_data.path)">
<template slot="title">{{ item_data.meta.title }}</template>
<menu-item v-for="(item, index) in item_data.children" :key="index" :item_data="item"
:base_path="resolvePath(item.path)"></menu-item>
</el-submenu>
</div>
</template>
<script>
import path from 'path'
import { isExternal } from '@/utils/validate'
export default {
name: 'MenuItem',
data() {
this.onlyOneChild = null
return {
};
},
props: {
item_data: {
type: Object,
required: true
},
base_path: {
type: String,
default: ''
}
},
components: {},
computed: {},
mounted() {
},
methods: {
hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => {
if (item.hidden) {
return false
} else {
// Temp set(will be used if only has one showing child)
this.onlyOneChild = item
return true
}
})
// When there is only one child router, the child router is displayed by default
if (showingChildren.length === 1) {
return true
}
// Show parent if there are no child router to display
if (showingChildren.length === 0) {
this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
return true
}
return false
},
resolvePath(routePath) {;
if (isExternal(routePath)) {
return routePath
}
if (isExternal(this.base_path)) {
return this.base_path
}
return path.resolve(this.base_path, routePath)
}
}
}
</script>
<style scoped>
.single_menu {
display: inline-block;
}
</style>
<!-- -->
<template>
<div>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<div class="avatar-wrapper" :title="user_name">
{{ user_name.slice(0, 1) || '' }}
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item divided @click.native="logout">
<span style="display:block;">退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data() {
return {
user_name: null,
};
},
components: {},
computed: {},
created() {
this.user_name = this.$store.state.user.name;
},
mounted() { },
methods: {
async logout() {
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
}
}
}
</script>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.avatar-wrapper {
text-align: center;
width: 32px;
height: 32px;
border-radius: 100%;
border: 1px solid $themeColor;
cursor: pointer;
line-height: 32px;
overflow: hidden;
background-color: #ccd5e2;
color: #fff;
}
</style>
<!--
* @Author: czj
* @Date: 2023-02-27 17:37:06
* @Description:
* @FilePath: \AdministrationHome\src\layout\components\Headerbar\index.vue
-->
<!-- -->
<template>
<div class="header_container">
<Logo></Logo>
<Menu></Menu>
<Nav></Nav>
</div>
</template>
<script>
import Logo from './Logo.vue';
import Menu from './Menu.vue';
import Nav from './Nav.vue';
export default {
data() {
return {
};
},
components: { Logo, Menu, Nav },
computed: {},
mounted() { },
methods: {}
}
</script>
<style scoped>
.header_container {
display: flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
padding: 0 15px;
border-bottom: 1px solid #e0e0e0;
}
</style>
<!--
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\layout\components\Sidebar\index.vue
-->
<template> <template>
<div :class="{'has-logo':showLogo}"> <div :class="{ 'has-logo': showLogo }">
<logo v-if="showLogo" :collapse="isCollapse" /> <logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper"> <el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu <el-menu :default-active="activeMenu" :collapse="isCollapse" :background-color="variables.menuBg"
:default-active="activeMenu" :text-color="variables.menuText" :unique-opened="false" :active-text-color="variables.menuActiveText"
:collapse="isCollapse" :collapse-transition="false" mode="vertical">
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="false"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" /> <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu> </el-menu>
</el-scrollbar> </el-scrollbar>
...@@ -32,6 +31,8 @@ export default { ...@@ -32,6 +31,8 @@ export default {
'sidebar' 'sidebar'
]), ]),
activeMenu() { activeMenu() {
const route = this.$route const route = this.$route
const { meta, path } = route const { meta, path } = route
// if set path, the sidebar will highlight the path you set // if set path, the sidebar will highlight the path you set
......
...@@ -5,23 +5,36 @@ ...@@ -5,23 +5,36 @@
* @FilePath: \AdministrationHome\src\layout\index.vue * @FilePath: \AdministrationHome\src\layout\index.vue
--> -->
<template> <template>
<div :class="classObj" class="app-wrapper"> <!-- <div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> <Headerbar></Headerbar>
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" /> <sidebar class="sidebar-container" />
<div :class="{hasTagsView:needTagsView}" class="main-container"> <div :class="{ hasTagsView: needTagsView }" class="main-container">
<div :class="{'fixed-header':fixedHeader}"> <div :class="{ 'fixed-header': fixedHeader }">
<navbar /> <navbar />
<tags-view v-if="needTagsView" /> <tags-view v-if="needTagsView" />
</div> </div>
<app-main /> <app-main />
</div> </div>
</div> -->
<div>
<Headerbar id="header_box"></Headerbar>
<div id="content_box" class="content_container">
<div class="crumbs_box">
<Breadcrumb></Breadcrumb>
</div>
<router-view></router-view>
</div>
</div> </div>
</template> </template>
<script> <script>
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components' import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components';
import ResizeMixin from './mixin/ResizeHandler' import ResizeMixin from './mixin/ResizeHandler';
import { mapState } from 'vuex' import { mapState } from 'vuex';
import Headerbar from './components/Headerbar/index.vue';
import Breadcrumb from '@/components/Breadcrumb';
export default { export default {
name: 'Layout', name: 'Layout',
...@@ -30,7 +43,9 @@ export default { ...@@ -30,7 +43,9 @@ export default {
Navbar, Navbar,
Settings, Settings,
Sidebar, Sidebar,
TagsView TagsView,
Headerbar,
Breadcrumb
}, },
mixins: [ResizeMixin], mixins: [ResizeMixin],
computed: { computed: {
...@@ -50,19 +65,33 @@ export default { ...@@ -50,19 +65,33 @@ export default {
} }
} }
}, },
created() {
},
mounted() {
this.header_box();
},
methods: { methods: {
handleClickOutside() { handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
} },
//计算盒子高度
header_box() {
let head = document.getElementById("header_box");
let head_height = head.offsetHeight;
// height: calc(100vh - 60px);
document.getElementById("content_box").style.height = "calc(50% -" + head_height + "px)";
},
} }
} }
</script> </script>
<style lang="scss" scoped> <!-- <style lang="scss" scoped>
@import "~@/styles/mixin.scss"; @import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss"; @import "~@/styles/variables.scss";
.app-wrapper { .app-wrapper {
@include clearfix; @include clearfix;
position: relative; position: relative;
height: 100%; height: 100%;
...@@ -72,9 +101,9 @@ export default { ...@@ -72,9 +101,9 @@ export default {
position: fixed; position: fixed;
top: 0; top: 0;
} }
} }
.drawer-bg { .drawer-bg {
background: #000; background: #000;
opacity: 0.3; opacity: 0.3;
width: 100%; width: 100%;
...@@ -82,22 +111,33 @@ export default { ...@@ -82,22 +111,33 @@ export default {
height: 100%; height: 100%;
position: absolute; position: absolute;
z-index: 999; z-index: 999;
} }
.fixed-header { .fixed-header {
position: fixed; position: fixed;
top: 0; top: 0;
right: 0; right: 0;
z-index: 9; z-index: 9;
width: calc(100% - #{$sideBarWidth}); width: calc(100% - #{$sideBarWidth});
transition: width 0.28s; transition: width 0.28s;
} }
.hideSidebar .fixed-header { .hideSidebar .fixed-header {
width: calc(100% - 54px) width: calc(100% - 54px)
} }
.mobile .fixed-header { .mobile .fixed-header {
width: 100%; width: 100%;
} }
</style> -->
<style lang="scss" scoped>
.content_container {
// background-color: red;
width: 100%;
height: calc(100vh - 63px);
overflow-y: auto;
background-color: #ebedf0;
padding-bottom: 30px;
}
</style> </style>
...@@ -26,6 +26,13 @@ import './utils/error-log' // error log ...@@ -26,6 +26,13 @@ import './utils/error-log' // error log
import * as filters from './filters' // global filters import * as filters from './filters' // global filters
import { Aesencrypt, Aesdecrypt, removeProperty, handleParams } from '@/utils/cryptoJS';
Vue.prototype.$Aesencrypt = Aesencrypt;//加密
Vue.prototype.$Aesdecrypt = Aesdecrypt;//揭秘
Vue.prototype.$removeProperty = removeProperty;//清除空值
Vue.prototype.$handleParams = handleParams;//封装机密格式的参数
/** /**
* If you don't want to use mock-server * If you don't want to use mock-server
* you want to use MockJs for mock api * you want to use MockJs for mock api
...@@ -34,10 +41,10 @@ import * as filters from './filters' // global filters ...@@ -34,10 +41,10 @@ import * as filters from './filters' // global filters
* Currently MockJs will be used in the production environment, * Currently MockJs will be used in the production environment,
* please remove it before going online ! ! ! * please remove it before going online ! ! !
*/ */
if (process.env.NODE_ENV === 'production') { // if (process.env.NODE_ENV === 'production') {
const { mockXHR } = require('../mock') // const { mockXHR } = require('../mock')
mockXHR() // mockXHR()
} // }
Vue.use(Element, { Vue.use(Element, {
size: Cookies.get('size') || 'medium', // set element-ui default size size: Cookies.get('size') || 'medium', // set element-ui default size
......
...@@ -8,9 +8,9 @@ import getPageTitle from '@/utils/get-page-title' ...@@ -8,9 +8,9 @@ import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist const whiteList = ['/login', '/retrieve', '/auth-redirect'] // no redirect whitelist
router.beforeEach(async(to, from, next) => { router.beforeEach(async (to, from, next) => {
// start progress bar // start progress bar
NProgress.start() NProgress.start()
...@@ -27,24 +27,23 @@ router.beforeEach(async(to, from, next) => { ...@@ -27,24 +27,23 @@ router.beforeEach(async(to, from, next) => {
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939 NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else { } else {
// determine whether the user has obtained his permission roles through getInfo // determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0 // const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) { const hasUser = store.getters.hasUser;
if (hasUser) {
next() next()
} else { } else {
try { try {
// get user info await store.dispatch('user/getInfo')
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor'] const accessRoutes = await store.dispatch('permission/generateRoutes')
const { roles } = await store.dispatch('user/getInfo') // console.log('路由数据');
// console.log(accessRoutes);
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
router.addRoutes(accessRoutes) router.addRoutes(accessRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true }) next({ ...to, replace: true })
// setTimeout(() => {
// console.log('整个路由对象');
// console.log(router);
// }, 300);
// next()
} catch (error) { } catch (error) {
// remove token and go to login page to re-login // remove token and go to login page to re-login
await store.dispatch('user/resetToken') await store.dispatch('user/resetToken')
......
/*
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\router\index.js
*/
/*
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\router\index.js
*/
import Vue from 'vue' import Vue from 'vue'
import Router from 'vue-router' import Router from 'vue-router'
...@@ -43,7 +55,14 @@ export const constantRoutes = [ ...@@ -43,7 +55,14 @@ export const constantRoutes = [
{ {
path: '/login', path: '/login',
component: () => import('@/views/login/index'), component: () => import('@/views/login/index'),
hidden: true hidden: true,
meta: { title: '登录' }
},
{
path: '/retrieve',
component: () => import('@/views/retrieve/index'),
hidden: true,
meta: { title: '找回' }
}, },
{ {
path: '/404', path: '/404',
...@@ -55,6 +74,14 @@ export const constantRoutes = [ ...@@ -55,6 +74,14 @@ export const constantRoutes = [
component: () => import('@/views/error-page/401'), component: () => import('@/views/error-page/401'),
hidden: true hidden: true
}, },
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
{ {
path: '/', path: '/',
component: Layout, component: Layout,
...@@ -64,21 +91,146 @@ export const constantRoutes = [ ...@@ -64,21 +91,146 @@ export const constantRoutes = [
path: 'dashboard', path: 'dashboard',
component: () => import('@/views/dashboard/index'), component: () => import('@/views/dashboard/index'),
name: 'Dashboard', name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'dashboard', affix: true } meta: { title: '首页', icon: 'dashboard', affix: true }
} },
{
path: 'student',
name: 'Studen',
component: () => import('@/views/student/index'),
meta: { title: '学员考试' },
redirect: '/student/examination_questions',
children: [
{
path: 'examination_questions',
name: 'Examination_questions',
component: () => import('@/views/student/examination_questions/index.vue'),
redirect: '/student/examination_questions/list',
meta: { title: '试题管理配置' },
children: [
{
path: 'list',
name: 'Examination_questions_list',
component: () => import('@/views/student/examination_questions/list/index.vue'),
meta: { title: '试题列表' },
},
{
path: 'detail',
name: 'Examination_questions_detail',
component: () => import('@/views/student/examination_questions/detail/index.vue'),
meta: { title: '试题详情' },
},
] ]
}, },
] {
path: 'test_results',
/** name: 'Test_results',
* asyncRoutes component: () => import('@/views/student/test_results/index.vue'),
* the routes that need to be dynamically loaded based on user roles meta: { title: '考试结果' },
*/ redirect: '/student/test_results/list',
export const asyncRoutes = [ children: [
{
path: 'list',
name: 'Test_results_list',
component: () => import('@/views/student/test_results/list/index.vue'),
meta: { title: '结果列表' },
},
{
path: 'detail',
name: 'Test_results_detail',
component: () => import('@/views/student/test_results/detail/index.vue'),
meta: { title: '结果详情' },
},
],
},
{
path: 'personnel',
name: 'Personnel',
component: () => import('@/views/student/personnel/index.vue'),
meta: { title: '学员管理' },
},
{
path: 'area_breed',
name: 'Area_breed',
component: () => import('@/views/student/area_breed/index.vue'),
meta: { title: '烟草区域与品种' },
},
{
path: 'tobacco_grades',
name: 'Tobacco_grades',
component: () => import('@/views/student/tobacco_grades/index.vue'),
meta: { title: '烟草等级' },
}
],
},
{
path: 'business',
name: 'Business',
component: () => import('@/views/business/index.vue'),
meta: { title: '工商交接' },
redirect: '/business/display_board',
children: [
{
path: 'display_board',
name: 'Display_board',
component: () => import('@/views/business/display_board/index.vue'),
meta: { title: '展板统计' },
},
{
path: 'raw_data',
name: 'Raw_data',
component: () => import('@/views/business/raw_data/index.vue'),
meta: { title: '原始数据' },
},
{
path: 'road',
name: 'Road',
component: () => import('@/views/business/road/index.vue'),
meta: { title: '渠道管理' },
},
]
},
{
path: 'system',
component: () => import('@/views/system/index'),
name: 'System',
meta: { title: '系统管理' },
redirect: '/system/administrators',
children: [
{
path: 'administrators',
component: () => import('@/views/system/administrators/index'),
name: 'Administrators',
meta: { title: '管理员' },
},
{
path: 'roles',
component: () => import('@/views/system/roles/index'),
name: 'Roles',
meta: { title: '权限配置' },
},
{
path: 'menu',
component: () => import('@/views/system/menu/index'),
name: 'Menu',
meta: { title: '菜单查看' },
},
{
path: 'department',
component: () => import('@/views/system/department/index'),
name: 'Department',
meta: { title: '部门区域' },
},
{
path: 'log',
component: () => import('@/views/system/log/index'),
name: 'Log',
meta: { title: '系统日志' },
},
]
}
]
},
// 404 page must be placed at the end !!! // 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
......
module.exports = { module.exports = {
title: 'Vue Element Admin', title: '烟草质检管理',
/** /**
* @type {boolean} true | false * @type {boolean} true | false
......
/*
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\store\getters.js
*/
const getters = { const getters = {
sidebar: state => state.app.sidebar, sidebar: state => state.app.sidebar,
size: state => state.app.size, size: state => state.app.size,
...@@ -10,6 +16,7 @@ const getters = { ...@@ -10,6 +16,7 @@ const getters = {
introduction: state => state.user.introduction, introduction: state => state.user.introduction,
roles: state => state.user.roles, roles: state => state.user.roles,
permission_routes: state => state.permission.routes, permission_routes: state => state.permission.routes,
errorLogs: state => state.errorLog.logs errorLogs: state => state.errorLog.logs,
hasUser: state => state.user.hasUser,
} }
export default getters export default getters
import { asyncRoutes, constantRoutes } from '@/router' import { asyncRoutes, constantRoutes } from '@/router'
import { getMenu } from '@/api/user';
import { get_permission_tree, get_permission_btn_menu } from '@/api/system';
import { route_tree_all } from '@/utils/route-handle';
/** /**
* Use meta.role to determine if the current user has permission * Use meta.role to determine if the current user has permission
* @param roles * @param roles
...@@ -45,16 +47,61 @@ const mutations = { ...@@ -45,16 +47,61 @@ const mutations = {
state.routes = constantRoutes.concat(routes) state.routes = constantRoutes.concat(routes)
} }
} }
//处理路由地址 不能用 import。使用require,异步
const actions = { function routerCom(view_path) {
generateRoutes({ commit }, roles) { return (resolve) => require([view_path], resolve);
return new Promise(resolve => { }
let accessedRoutes //过滤数据 /转为树结构
if (roles.includes('admin')) { function filterRouterData(list) {
accessedRoutes = asyncRoutes || [] let result = []
let map = {}
if (!Array.isArray(list)) return [];
list.forEach(item => {
map[item.id] = {
id: item.id,
father_id: item.father_id,
is_show: item.is_show,
path: item.path,
name: item.name,
component: routerCom(item.view_path),
meta: { title: item.name_zh }
}
});
list.forEach(item => {
let parent = map[item.father_id], elememt = {
id: item.id,
father_id: item.father_id,
is_show: item.is_show,
path: item.path,
name: item.name,
component: routerCom(item.view_path),
meta: { title: item.name_zh }
};
if (parent) {
// console.log('进入判断');
// console.log((parent.children || (parent.children = [])));
(parent.children || (parent.children = [])).push(elememt)
} else { } else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) result.push(elememt)
} }
})
return result
}
const actions = {
generateRoutes({ commit }) {
return new Promise(async resolve => {
let response = await get_permission_btn_menu()
/* route_tree_all(permission); //转为树结构 */
let route_list = filterRouterData(response.permission);
// console.log('<<<<<<<<<<<<<<<<<<组装好的路由列表>>>>>>>>>>>>>>>>>>>>>>>>');
// console.log(route_list);
// console.log('权限菜单数据>>>>>>>>>>');
// console.log(response);
// console.log('本地路由数据@@@@@@@@@@');
// console.log(asyncRoutes);
// asyncRoutes[0].children = route_list
let accessedRoutes = asyncRoutes || [];
commit('SET_ROUTES', accessedRoutes) commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes) resolve(accessedRoutes)
}) })
......
...@@ -7,7 +7,8 @@ const state = { ...@@ -7,7 +7,8 @@ const state = {
name: '', name: '',
avatar: '', avatar: '',
introduction: '', introduction: '',
roles: [] roles: [],
hasUser: false
} }
const mutations = { const mutations = {
...@@ -25,7 +26,10 @@ const mutations = { ...@@ -25,7 +26,10 @@ const mutations = {
}, },
SET_ROLES: (state, roles) => { SET_ROLES: (state, roles) => {
state.roles = roles state.roles = roles
} },
SET_HASUSER: (state, hasUser) => {
state.hasUser = hasUser
},
} }
const actions = { const actions = {
...@@ -33,10 +37,20 @@ const actions = { ...@@ -33,10 +37,20 @@ const actions = {
login({ commit }, userInfo) { login({ commit }, userInfo) {
const { username, password } = userInfo const { username, password } = userInfo
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password }).then(response => { // login({ username: username.trim(), password: password }).then(response => {
// const { data } = response
// commit('SET_TOKEN', data.token)
// setToken(data.token)
// resolve()
// }).catch(error => {
// reject(error)
// })
login(userInfo).then(response => {
console.log('登录接口返回数据');
console.log(response);
const { data } = response const { data } = response
commit('SET_TOKEN', data.token) commit('SET_TOKEN', response.access_token)
setToken(data.token) setToken(response.access_token)
resolve() resolve()
}).catch(error => { }).catch(error => {
reject(error) reject(error)
...@@ -48,24 +62,28 @@ const actions = { ...@@ -48,24 +62,28 @@ const actions = {
getInfo({ commit, state }) { getInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo(state.token).then(response => { getInfo(state.token).then(response => {
const { data } = response // console.log('获取用户信息@@@@@@@@@@@');
// console.log(response);
if (!data) { commit('SET_HASUSER', true)
reject('Verification failed, please Login again.') // const { data } = response
}
const { roles, name, avatar, introduction } = data // if (!data) {
// reject('Verification failed, please Login again.')
// }
// roles must be a non-empty array // const { roles, name, avatar, introduction } = data
if (!roles || roles.length <= 0) {
reject('getInfo: roles must be a non-null array!') // // roles must be a non-empty array
} // if (!roles || roles.length <= 0) {
// reject('getInfo: roles must be a non-null array!')
// }
commit('SET_ROLES', roles) // commit('SET_ROLES', roles)
commit('SET_NAME', name) commit('SET_NAME', response.name);
commit('SET_AVATAR', avatar) // commit('SET_AVATAR', avatar)
commit('SET_INTRODUCTION', introduction) // commit('SET_INTRODUCTION', introduction)
resolve(data) resolve(response)
}).catch(error => { }).catch(error => {
reject(error) reject(error)
}) })
...@@ -74,10 +92,13 @@ const actions = { ...@@ -74,10 +92,13 @@ const actions = {
// user logout // user logout
logout({ commit, state, dispatch }) { logout({ commit, state, dispatch }) {
console.log('退出登录');
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token).then(() => { logout(state.token).then(() => {
commit('SET_HASUSER', false)
commit('SET_TOKEN', '') commit('SET_TOKEN', '')
commit('SET_ROLES', []) // commit('SET_ROLES', [])
removeToken() removeToken()
resetRouter() resetRouter()
...@@ -95,6 +116,7 @@ const actions = { ...@@ -95,6 +116,7 @@ const actions = {
// remove token // remove token
resetToken({ commit }) { resetToken({ commit }) {
return new Promise(resolve => { return new Promise(resolve => {
commit('SET_HASUSER', false)
commit('SET_TOKEN', '') commit('SET_TOKEN', '')
commit('SET_ROLES', []) commit('SET_ROLES', [])
removeToken() removeToken()
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
**/ **/
/* theme color */ /* theme color */
$--color-primary: #1890ff; $--color-primary: #038D6E;
$--color-success: #13ce66; $--color-success: #13ce66;
$--color-warning: #ffba00; $--color-warning: #ffba00;
$--color-danger: #ff4949; $--color-danger: #ff4949;
......
差异被折叠。
:export{menuText:#bfcbd9;menuActiveText:#409EFF;subMenuActiveText:#f4f4f5;menuBg:#304156;menuHover:#263445;subMenuBg:#1f2d3d;subMenuHover:#001528;sideBarWidth:210px}.fade-enter-active,.fade-leave-active{transition:opacity 0.28s}.fade-enter,.fade-leave-active{opacity:0}.fade-transform-leave-active,.fade-transform-enter-active{transition:all .5s}.fade-transform-enter{opacity:0;transform:translateX(-30px)}.fade-transform-leave-to{opacity:0;transform:translateX(30px)}.breadcrumb-enter-active,.breadcrumb-leave-active{transition:all .5s}.breadcrumb-enter,.breadcrumb-leave-active{opacity:0;transform:translateX(20px)}.breadcrumb-move{transition:all .5s}.breadcrumb-leave-active{position:absolute}.el-breadcrumb__inner,.el-breadcrumb__inner a{font-weight:400 !important}.el-upload input[type="file"]{display:none !important}.el-upload__input{display:none}.cell .el-tag{margin-right:0px}.small-padding .cell{padding-left:5px;padding-right:5px}.fixed-width .el-button--mini{padding:7px 10px;min-width:60px}.status-col .cell{padding:0 10px;text-align:center}.status-col .cell .el-tag{margin-right:0px}.el-dialog{transform:none;left:0;position:relative;margin:0 auto}.upload-container .el-upload{width:100%}.upload-container .el-upload .el-upload-dragger{width:100%;height:200px}.el-dropdown-menu a{display:block}.el-range-editor.el-input__inner{display:inline-flex !important}.el-range-separator{box-sizing:content-box}#app .main-container{min-height:100%;transition:margin-left .28s;margin-left:210px;position:relative}#app .sidebar-container{transition:width 0.28s;width:210px !important;background-color:#304156;height:100%;position:fixed;font-size:0px;top:0;bottom:0;left:0;z-index:1001;overflow:hidden}#app .sidebar-container .horizontal-collapse-transition{transition:0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out}#app .sidebar-container .scrollbar-wrapper{overflow-x:hidden !important}#app .sidebar-container .el-scrollbar__bar.is-vertical{right:0px}#app .sidebar-container .el-scrollbar{height:100%}#app .sidebar-container.has-logo .el-scrollbar{height:calc(100% - 50px)}#app .sidebar-container .is-horizontal{display:none}#app .sidebar-container a{display:inline-block;width:100%;overflow:hidden}#app .sidebar-container .svg-icon{margin-right:16px}#app .sidebar-container .sub-el-icon{margin-right:12px;margin-left:-2px}#app .sidebar-container .el-menu{border:none;height:100%;width:100% !important}#app .sidebar-container .submenu-title-noDropdown:hover,#app .sidebar-container .el-submenu__title:hover{background-color:#263445 !important}#app .sidebar-container .is-active>.el-submenu__title{color:#f4f4f5 !important}#app .sidebar-container .nest-menu .el-submenu>.el-submenu__title,#app .sidebar-container .el-submenu .el-menu-item{min-width:210px !important;background-color:#1f2d3d !important}#app .sidebar-container .nest-menu .el-submenu>.el-submenu__title:hover,#app .sidebar-container .el-submenu .el-menu-item:hover{background-color:#001528 !important}#app .hideSidebar .sidebar-container{width:54px !important}#app .hideSidebar .main-container{margin-left:54px}#app .hideSidebar .submenu-title-noDropdown{padding:0 !important;position:relative}#app .hideSidebar .submenu-title-noDropdown .el-tooltip{padding:0 !important}#app .hideSidebar .submenu-title-noDropdown .el-tooltip .svg-icon{margin-left:20px}#app .hideSidebar .submenu-title-noDropdown .el-tooltip .sub-el-icon{margin-left:19px}#app .hideSidebar .el-submenu{overflow:hidden}#app .hideSidebar .el-submenu>.el-submenu__title{padding:0 !important}#app .hideSidebar .el-submenu>.el-submenu__title .svg-icon{margin-left:20px}#app .hideSidebar .el-submenu>.el-submenu__title .sub-el-icon{margin-left:19px}#app .hideSidebar .el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}#app .hideSidebar .el-menu--collapse .el-submenu>.el-submenu__title>span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}#app .el-menu--collapse .el-menu .el-submenu{min-width:210px !important}#app .mobile .main-container{margin-left:0px}#app .mobile .sidebar-container{transition:transform .28s;width:210px !important}#app .mobile.hideSidebar .sidebar-container{pointer-events:none;transition-duration:0.3s;transform:translate3d(-210px, 0, 0)}#app .withoutAnimation .main-container,#app .withoutAnimation .sidebar-container{transition:none}.el-menu--vertical>.el-menu .svg-icon{margin-right:16px}.el-menu--vertical>.el-menu .sub-el-icon{margin-right:12px;margin-left:-2px}.el-menu--vertical .nest-menu .el-submenu>.el-submenu__title:hover,.el-menu--vertical .el-menu-item:hover{background-color:#263445 !important}.el-menu--vertical>.el-menu--popup{max-height:100vh;overflow-y:auto}.el-menu--vertical>.el-menu--popup::-webkit-scrollbar-track-piece{background:#d3dce6}.el-menu--vertical>.el-menu--popup::-webkit-scrollbar{width:6px}.el-menu--vertical>.el-menu--popup::-webkit-scrollbar-thumb{background:#99a9bf;border-radius:20px}:export{menuText:#bfcbd9;menuActiveText:#409EFF;subMenuActiveText:#f4f4f5;menuBg:#304156;menuHover:#263445;subMenuBg:#1f2d3d;subMenuHover:#001528;sideBarWidth:210px}.blue-btn{background:#324157}.blue-btn:hover{color:#324157}.blue-btn:hover:before,.blue-btn:hover:after{background:#324157}.light-blue-btn{background:#3A71A8}.light-blue-btn:hover{color:#3A71A8}.light-blue-btn:hover:before,.light-blue-btn:hover:after{background:#3A71A8}.red-btn{background:#C03639}.red-btn:hover{color:#C03639}.red-btn:hover:before,.red-btn:hover:after{background:#C03639}.pink-btn{background:#E65D6E}.pink-btn:hover{color:#E65D6E}.pink-btn:hover:before,.pink-btn:hover:after{background:#E65D6E}.green-btn{background:#30B08F}.green-btn:hover{color:#30B08F}.green-btn:hover:before,.green-btn:hover:after{background:#30B08F}.tiffany-btn{background:#4AB7BD}.tiffany-btn:hover{color:#4AB7BD}.tiffany-btn:hover:before,.tiffany-btn:hover:after{background:#4AB7BD}.yellow-btn{background:#FEC171}.yellow-btn:hover{color:#FEC171}.yellow-btn:hover:before,.yellow-btn:hover:after{background:#FEC171}.pan-btn{font-size:14px;color:#fff;padding:14px 36px;border-radius:8px;border:none;outline:none;transition:600ms ease all;position:relative;display:inline-block}.pan-btn:hover{background:#fff}.pan-btn:hover:before,.pan-btn:hover:after{width:100%;transition:600ms ease all}.pan-btn:before,.pan-btn:after{content:'';position:absolute;top:0;right:0;height:2px;width:0;transition:400ms ease all}.pan-btn::after{right:inherit;top:inherit;left:0;bottom:0}.custom-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#fff;color:#fff;-webkit-appearance:none;text-align:center;box-sizing:border-box;outline:0;margin:0;padding:10px 15px;font-size:14px;border-radius:4px}p,h1{margin:0}body{height:100%;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-family:Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif}label{font-weight:700}html{height:100%;box-sizing:border-box}#app{height:100%}*,*:before,*:after{box-sizing:inherit}.no-padding{padding:0px !important}.padding-content{padding:4px 0}a:focus,a:active{outline:none}a,a:focus,a:hover{cursor:pointer;color:inherit;text-decoration:none}div:focus{outline:none}.fr{float:right}.fl{float:left}.pr-5{padding-right:5px}.pl-5{padding-left:5px}.block{display:block}.pointer{cursor:pointer}.inlineBlock{display:block}.clearfix:after{visibility:hidden;display:block;font-size:0;content:" ";clear:both;height:0}aside{background:#eef1f6;padding:8px 24px;margin-bottom:20px;border-radius:2px;display:block;line-height:32px;font-size:16px;font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;color:#2c3e50;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}aside a{color:#337ab7;cursor:pointer}aside a:hover{color:#20a0ff}.app-container{padding:20px}.components-container{margin:30px 50px;position:relative}.pagination-container{margin-top:30px}.text-center{text-align:center}.sub-navbar{height:50px;line-height:50px;position:relative;width:100%;text-align:right;padding-right:20px;transition:600ms ease position;background:linear-gradient(90deg, #20b6f9 0%, #20b6f9 0%, #2178f1 100%, #2178f1 100%)}.sub-navbar .subtitle{font-size:20px;color:#fff}.sub-navbar.draft{background:#d0d0d0}.sub-navbar.deleted{background:#d0d0d0}.link-type,.link-type:focus{color:#337ab7;cursor:pointer}.link-type:hover,.link-type:focus:hover{color:#20a0ff}.filter-container{padding-bottom:10px}.filter-container .filter-item{display:inline-block;vertical-align:middle;margin-bottom:10px}.multiselect{line-height:16px}.multiselect--active{z-index:1000 !important}.add_dialog .el-dialog .el-dialog__header{background-color:#E6A23C}.el-dialog{border-radius:8px;overflow:hidden}.el-dialog .el-dialog__header{text-align:center;background-color:#34a575;border-radius:8px 8px 0 0}.el-dialog .el-dialog__header .el-dialog__title,.el-dialog .el-dialog__header .el-dialog__headerbtn .el-dialog__close{color:#fff}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#fbf6ec !important}.table_container{margin-top:20px}.module_container{position:relative;width:100%;height:calc(100% - 50px);box-sizing:border-box}.module_container .module_container_left{position:absolute;left:0;top:-50px;bottom:0;width:300px;background-color:#fff;box-sizing:border-box;padding:15px}.crumbs_box{position:relative;z-index:10;width:1260px;height:50px;line-height:50px;margin:0 auto}.card_container{position:relative;z-index:1;width:1260px;margin:0 auto}.el-tree-node__content:hover{background-color:#b5e7db}.el-tree-node.is-current>.el-tree-node__content{background-color:#b5e7db}.el-card{border-radius:8px}.select_container .el-input__inner{border:none}.select_container .el-textarea__inner{border:none}.upload_picture_container .el-upload-list{max-height:400px;overflow-y:auto}
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
@import './sidebar.scss'; @import './sidebar.scss';
@import './btn.scss'; @import './btn.scss';
p,
h1 {
margin: 0;
}
body { body {
height: 100%; height: 100%;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
...@@ -189,3 +194,108 @@ aside { ...@@ -189,3 +194,108 @@ aside {
.multiselect--active { .multiselect--active {
z-index: 1000 !important; z-index: 1000 !important;
} }
/* 弹窗 设置 */
.add_dialog {
.el-dialog {
.el-dialog__header {
background-color: #E6A23C;
}
}
}
.el-dialog {
border-radius: 8px;
overflow: hidden;
.el-dialog__header {
text-align: center;
background-color: #34a575;
border-radius: 8px 8px 0 0;
.el-dialog__title,
.el-dialog__headerbtn .el-dialog__close {
color: #fff;
}
}
}
/* 表格 行 hover */
.el-table--enable-row-hover .el-table__body tr:hover>td {
background-color: #fbf6ec !important;
}
.table_container {
margin-top: 20px;
}
/* 页面布局样式 */
.module_container {
position: relative;
width: 100%;
height: calc(100% - 50px); //减去面包屑的高度
box-sizing: border-box;
.module_container_left {
position: absolute;
left: 0;
top: -50px;
bottom: 0;
width: 300px;
background-color: #fff;
box-sizing: border-box;
padding: 15px;
}
}
.crumbs_box {
//面包屑
position: relative;
z-index: 10;
width: 1260px;
height: 50px;
line-height: 50px;
margin: 0 auto;
}
.card_container {
position: relative;
z-index: 1;
width: 1260px;
margin: 0 auto;
}
/* 树图选中 */
.el-tree-node__content:hover {
background-color: #b5e7db;
}
.el-tree-node.is-current>.el-tree-node__content {
background-color: #b5e7db;
}
/* 卡片样式 */
.el-card {
border-radius: 8px;
}
/* 选择框 */
.select_container {
.el-input__inner {
border: none;
}
.el-textarea__inner {
border: none;
}
}
/* 上传组件 */
.upload_picture_container {
.el-upload-list {
max-height: 400px;
overflow-y: auto;
}
}
:export {
menuText: #bfcbd9;
menuActiveText: #409EFF;
subMenuActiveText: #f4f4f5;
menuBg: #304156;
menuHover: #263445;
subMenuBg: #1f2d3d;
subMenuHover: #001528;
sideBarWidth: 210px;
}
:export{menuText:#bfcbd9;menuActiveText:#409EFF;subMenuActiveText:#f4f4f5;menuBg:#304156;menuHover:#263445;subMenuBg:#1f2d3d;subMenuHover:#001528;sideBarWidth:210px}
// base color // base color
$blue:#324157; $blue: #324157;
$light-blue:#3A71A8; $light-blue: #3A71A8;
$red:#C03639; $red: #C03639;
$pink: #E65D6E; $pink: #E65D6E;
$green: #30B08F; $green: #30B08F;
$tiffany: #4AB7BD; $tiffany: #4AB7BD;
$yellow:#FEC171; $yellow: #FEC171;
$panGreen: #30B08F; $panGreen: #30B08F;
// sidebar // sidebar
$menuText:#bfcbd9; $menuText: #bfcbd9;
$menuActiveText:#409EFF; $menuActiveText: #409EFF;
$subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951 $subMenuActiveText: #f4f4f5; // https://github.com/ElemeFE/element/issues/12951
$menuBg:#304156; $menuBg: #304156;
$menuHover:#263445; $menuHover: #263445;
$subMenuBg:#1f2d3d; $subMenuBg: #1f2d3d;
$subMenuHover:#001528; $subMenuHover: #001528;
$sideBarWidth: 210px; $sideBarWidth: 210px;
$themeColor: #038D6E;
// the :export directive is the magic sauce for webpack // the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export { :export {
......
/*
* @Author: czj
* @Date: 2023-02-28 11:54:28
* @Description:
* @FilePath: \AdministrationHome\src\utils\cryptoJS.js
*/
/*
* @Author: czj
* @Date: 2023-02-28 11:54:28
* @Description:
* @FilePath: \AdministrationHome\src\utils\cryptoJS.js
*/
import CryptoJS from 'crypto-js'
//此处的密钥随机生成,可自行修改
const key = CryptoJS.enc.Utf8.parse('TOBACCO23ZGYCANX');//十六位十六进制数作为密钥
const iv = CryptoJS.enc.Utf8.parse('ZGYC23TOBACCOANX');//十六位十六进制数作为密钥偏移量
// 加密函数
export function Aesencrypt(str) {
var encrypted = CryptoJS.AES.encrypt(str, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
//解密
export function Aesdecrypt(str) {
var decrypt = CryptoJS.AES.decrypt(str, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypt.toString(CryptoJS.enc.Utf8);
}
//去除对象里的空属性
export function removeProperty(obj) {
Object.keys(obj).forEach(item => {
if (obj[item] === null || obj[item] === undefined || obj[item] === '' || obj[item] === "") {
delete obj[item]
}
})
return obj
}
//接口参数加密 统一处理
export function handleParams(data) {
let params = removeProperty(data);
let s = Aesencrypt(JSON.stringify(params));
return { data: params, sign: s }
}
/*
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\utils\request.js
*/
import axios from 'axios' import axios from 'axios'
import { MessageBox, Message } from 'element-ui' import { MessageBox, Message } from 'element-ui'
import store from '@/store' import store from '@/store'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import router from "@/router";
// create an axios instance // create an axios instance
const service = axios.create({ const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests // withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout timeout: 0 // request timeout
}) })
// request interceptor // request interceptor
...@@ -19,7 +27,8 @@ service.interceptors.request.use( ...@@ -19,7 +27,8 @@ service.interceptors.request.use(
// let each request carry token // let each request carry token
// ['X-Token'] is a custom headers key // ['X-Token'] is a custom headers key
// please modify it according to the actual situation // please modify it according to the actual situation
config.headers['X-Token'] = getToken() // config.headers['X-Token'] = getToken()
config.headers['Authorization'] = 'Bearer ' + getToken()
} }
return config return config
}, },
...@@ -44,37 +53,77 @@ service.interceptors.response.use( ...@@ -44,37 +53,77 @@ service.interceptors.response.use(
*/ */
response => { response => {
const res = response.data const res = response.data
// if (res.access_token || res.login_at || res.length > 0) {//登录和用户信息接口无状态码
// if the custom code is not 20000, it is judged as an error. // return res
if (res.code !== 20000) { // }
if (res.code && res.code !== 200) {
if (res.code === 422) {
if (typeof res.message === 'string') {
Message({ Message({
message: res.message || 'Error', message: res.message || 'Error',
type: 'error', type: 'error',
duration: 5 * 1000 duration: 5 * 1000
}) })
} else {
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; let ps = res.message.map(item => {
if (res.code === 50008 || res.code === 50012 || res.code === 50014) { return `<p>${item}</p>`
// to re-login })
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { let html = `<div>${ps}</div>`
confirmButtonText: 'Re-Login', Message({
cancelButtonText: 'Cancel', message: res.message && html || 'Error',
type: 'warning' type: 'error',
}).then(() => { duration: 5 * 1000
})
}
} else if (res.code === 401) {
Message({
message: 'License.认证已过期',
type: 'warning',
duration: 5 * 1000
})
store.dispatch('user/resetToken').then(() => { store.dispatch('user/resetToken').then(() => {
location.reload() location.reload()
}) })
})
} }
return Promise.reject(new Error(res.message || 'Error')) return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
} }
return res
}, },
error => { error => {
console.log('进入通行 错误判断');
console.log('err' + error) // for debug console.log('err' + error) // for debug
console.log(error);
let tipMsg = ''
if (error.response) {
let errRes = error.response;
if (errRes.status === 500) {
tipMsg = '500'
// router.push({ name: 'Dashboard' });
return;
} else if (errRes.status === 429) {
tipMsg = '请勿频繁操作,请在1分钟后尝试操作!!'
} else if (errRes.status === 401) {
tipMsg = errRes.data && errRes.data.message ? errRes.data.message : '401'
} else if (errRes.status === 404) {
tipMsg = '非法请求!!'
router.push({ name: 'Dashboard' });
} else if (errRes.status === 422) {
let errData = error.response.data
if (Array.isArray(errData.message) && errData.message.length) {
tipMsg = errData.message.join(';')
} else {
tipMsg = errData.message
}
} else if (errRes.status === 403) {
tipMsg = errRes.data.message
} else {
tipMsg = errRes.status
}
} else {
tipMsg = error.message || '网络错误'
}
Message({ Message({
message: error.message, message: tipMsg || '网络错误',
type: 'error', type: 'error',
duration: 5 * 1000 duration: 5 * 1000
}) })
......
//权限按钮列表转为树结构
export function button_tree_add(btn, route) {
let data = [...route, ...btn];
let raw_data = JSON.parse(JSON.stringify(data));
let result = []
let map = {}
if (!Array.isArray(raw_data)) return [];
raw_data.forEach(item => {
map[item.id] = item
})
raw_data.forEach(item => {
let parent = map[item.father_id]
if (parent) {
(parent.children || (parent.children = [])).push(item)
} else {
result.push(item)
}
})
return result //数组里的对象和data是共享的
}
//路由列表转为树结构
export function route_tree_all(data) {
console.log('是否进入转化方法?????');
let raw_data = JSON.parse(JSON.stringify(data));
let result = []
let map = {}
if (!Array.isArray(raw_data)) {//验证data是不是数组类型
return []
}
raw_data.forEach(item => {//建立每个数组元素id和该对象的关系
map[item.id] = item //这里可以理解为浅拷贝,共享引用
})
console.log(map);
raw_data.forEach(item => {
let parent = map[item.father_id] //找到data中每一项item的爸爸
if (parent) {//说明元素有爸爸,把元素放在爸爸的children下面
(parent.children || (parent.children = [])).push(item)
} else {//说明元素没有爸爸,是根节点,把节点push到最终结果中
result.push(item) //item是对象的引用
}
})
return result //数组里的对象和data是共享的
}
/*
* @Author: czj
* @Date: 2023-03-08 10:00:45
* @Description:
* @FilePath: \AdministrationHome\src\utils\tool.js
*/
//通过a标签下载
export function exportText(url, file_name) {
// const blob = new Blob([url])
// let date = new Date();
const fileName = `${file_name}`
const link = document.createElement('a') // 创建a标签
link.download = fileName // a标签添加属性
link.style.display = 'none'
// link.href = URL.createObjectURL(blob)
link.href = url
document.body.appendChild(link)
link.click() // 执行下载
URL.revokeObjectURL(link.href) // 释放url
document.body.removeChild(link) // 释放标签
}
//一维转换二维数组
export function array_conversion(arr, nums) {
const length = arr.length;
const n = nums // 假设每段显示n个
const Num = length % n === 0 ? length / n : Math.floor((length / n) + 1) //得出多少份
const res = [] //定义数组接受最终的数据
for (let i = 0; i < Num; i++) {
// slice() 方法返回一个从开始到结束(不包括结束)的数组。且原始数组不会被修改。
const newArr = arr.slice(i * n, i * n + n) //得到每份的数据
res.push(JSON.parse(JSON.stringify(newArr))) //往res数组里加数据
}
return res;
}
//秒数转为分秒
export function secondsToMinutes(s) {
const totalSeconds = s;
// ? 获取完整分钟数
const minutes = Math.floor(totalSeconds / 60);
// ? 获得剩余的秒数
const seconds = totalSeconds % 60;
const padTo2Digits = (num) => {
return num.toString().padStart(2, '0');
}
let result = `${padTo2Digits(minutes)}分${padTo2Digits(seconds)}秒`;
return result
}
<template>
<div class="module_container">
<div class="module_container_left">
11111
</div>
<div class="card_container">
<el-card class="box-card">
<table-head :head_data="head_data" @search="searchEvent" @resetting="resetting" @btnClick="btnClick"></table-head>
<div class="table_container">
<el-table v-loading="is_loading" :data="tableData" style="width: 100%;margin-bottom: 20px;" height="650">
<el-table-column prop="name_zh" label="中文名称">
</el-table-column>
<el-table-column prop="name" label="英文名称">
</el-table-column>
<el-table-column prop="view_path" label="组件地址">
</el-table-column>
<el-table-column prop="path" label="路由地址">
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</div>
<el-dialog title="提示" :visible.sync="is_dialogVisible" width="60%" :before-close="handleClose">
<div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import TableHead from '@/components/TableHead/index';
import { get_department_list, add_department, delete_department, edit_department } from '@/api/system';
const standard_template = {
id: null,
father_id: -1,//父级id
is_show: false,//是否展示为菜单
name: null,//英文名称
name_zh: null,//中文名称
path: null,//路由路径
sort: null,//排序
status: 1,//状态
type: 1,//类型:菜单/按钮
view_path: null,//视图路径
icon: null,//图标
}
export default {
data() {
return {
//头部按钮
head_data: {
// search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-document-add',
event: 'add',
}
],
},
//初始化请求参数
request_params: {
page: 1,
limit: 10,
total: 1,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//
};
},
components: { TableHead },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
},
resetting(val) {
console.log('重置');
console.log(val);
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
},
init() {
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData() {
},
},
}
</script>
<style lang="scss" scoped></style>
<!--
* @Author: czj
* @Date: 2023-03-06 10:06:06
* @Description:
* @FilePath: \AdministrationHome\src\views\business\index.vue
-->
<!-- -->
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {}
}
</script>
<style scoped></style>
<!-- -->
<template>
<div>原始数据</div>
</template>
<script>
export default {
data () {
return {
};
},
components: {},
computed: {},
mounted(){},
methods: {}
}
</script>
<style scoped>
</style>
<!-- -->
<template>
<div>渠道管理</div>
</template>
<script>
export default {
data () {
return {
};
},
components: {},
computed: {},
mounted(){},
methods: {}
}
</script>
<style scoped>
</style>
\ No newline at end of file
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
<template> <template>
<div class="dashboard-editor-container"> <div class="dashboard-editor-container">
<div class=" clearfix"> <div class=" clearfix">
<pan-thumb :image="avatar" style="float: left"> <!-- <pan-thumb :image="avatar" style="float: left">
Your roles: Your roles:
<span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span> <span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span>
</pan-thumb> </pan-thumb> -->
<div class="info-container"> <div class="info-container">
<span class="display_name">{{ name }}</span> <span class="display_name">{{ name }}</span>
<span style="font-size:20px;padding-top:20px;display:inline-block;">Editor's Dashboard</span> <span style="font-size:20px;padding-top:20px;display:inline-block;">Editor's Dashboard</span>
......
<template> <!--
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\views\dashboard\index.vue
-->
<!-- <template>
<div class="dashboard-container"> <div class="dashboard-container">
<component :is="currentRole" /> <component :is="currentRole" />
</div> </div>
...@@ -28,4 +34,29 @@ export default { ...@@ -28,4 +34,29 @@ export default {
} }
} }
} }
</script> -->
<!-- -->
<template>
<div style="text-align: center;">首页内容待开发...</div>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {}
}
</script> </script>
<style scoped></style>
<!--
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\views\login\auth-redirect.vue
-->
<script> <script>
console.log('重定向');
export default { export default {
name: 'AuthRedirect', name: 'AuthRedirect',
created() { created() {
......
<template>
<div class="social-signup-container">
<div class="sign-btn" @click="wechatHandleClick('wechat')">
<span class="wx-svg-container"></span>
WeChat
</div>
<div class="sign-btn" @click="tencentHandleClick('tencent')">
<span class="qq-svg-container"></span>
QQ
</div>
</div>
</template>
<script>
// import openWindow from '@/utils/open-window'
export default {
name: 'SocialSignin',
methods: {
wechatHandleClick(thirdpart) {
alert('ok')
// this.$store.commit('SET_AUTH_TYPE', thirdpart)
// const appid = 'xxxxx'
// const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/auth-redirect')
// const url = 'https://open.weixin.qq.com/connect/qrconnect?appid=' + appid + '&redirect_uri=' + redirect_uri + '&response_type=code&scope=snsapi_login#wechat_redirect'
// openWindow(url, thirdpart, 540, 540)
},
tencentHandleClick(thirdpart) {
alert('ok')
// this.$store.commit('SET_AUTH_TYPE', thirdpart)
// const client_id = 'xxxxx'
// const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/auth-redirect')
// const url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' + client_id + '&redirect_uri=' + redirect_uri
// openWindow(url, thirdpart, 540, 540)
}
}
}
</script>
<style lang="scss" scoped>
.social-signup-container {
margin: 20px 0;
.sign-btn {
display: inline-block;
cursor: pointer;
}
.icon {
color: #fff;
font-size: 24px;
margin-top: 8px;
}
.wx-svg-container,
.qq-svg-container {
display: inline-block;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
padding-top: 1px;
border-radius: 4px;
margin-bottom: 20px;
margin-right: 5px;
}
.wx-svg-container {
background-color: #24da70;
}
.qq-svg-container {
background-color: #6BA2D6;
margin-left: 50px;
}
}</style>
差异被折叠。
<!--
* @Author: czj
* @Date: 2023-02-27 15:16:58
* @Description:
* @FilePath: \AdministrationHome\src\views\retrieve\index.vue
-->
<!-- -->
<template>
<div class="retrieve_container">
<img src="/image/log.svg" alt="" class="object_logo">
<div class="content_box">
<div class="content_body">
<h1 class="content_title">国家烟草质检中心系统</h1>
<div>
<el-card>
<div class="write_container">
<h3 style="margin-bottom: 40px;">忘记密码</h3>
<el-form ref="retrieveForm" class="login-form" autocomplete="on" label-position="left">
<el-form-item prop="username">
<span>手机号</span>
<el-input></el-input>
</el-form-item>
<el-form-item prop="username">
<span>手机号</span>
<el-row>
<el-col :span="13">
<el-input></el-input>
</el-col>
<el-col :span="11" style="text-align: right;">
<el-button type="primary">发送短信(59)</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item prop="username">
<span>新密码</span>
<el-input>
<i slot="suffix" class="el-input__icon el-icon-view"></i>
</el-input>
</el-form-item>
<el-form-item prop="username">
<span>确认密码</span>
<el-input>
<i slot="suffix" class="el-input__icon el-icon-view"></i>
</el-input>
</el-form-item>
</el-form>
<div style="margin-top: 20px;">
<el-button type="primary" style="width:100%;">重置密码</el-button>
</div>
<div style="text-align: right;">
<el-button type="text" size="mini" @click="toLogin">返回登陆</el-button>
</div>
</div>
</el-card>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {
toLogin() {
this.$router.go(-1);
},
}
}
</script>
<style lang="scss" scoped>
.retrieve_container {
position: relative;
background-color: #f2fcf5;
height: 100vh;
}
.object_logo {
position: absolute;
top: 62px;
left: 70px;
width: 165px;
height: 50px;
}
.content_box {
position: absolute;
top: 62px;
left: 0;
width: 100%;
.content_body {
width: 500px;
margin: 0 auto;
.content_title {
font-size: 32px;
text-align: center;
margin-bottom: 50px;
}
}
}
.write_container {
width: 70%;
margin: 0 auto;
h3 {
text-align: center;
}
}
.el-form-item {
margin-bottom: 10px;
}
</style>
<!-- -->
<template>
<div>
<div style="height: 600px;overflow-y: auto;">
<el-form label-width="100px">
<el-form-item label="品种名称">
<el-input v-model="tobacco_info.name" style="width: 200px;"></el-input>
</el-form-item>
<el-form-item label="生产地点">
<div v-for="(item, index) in tobacco_info.tobacco_breed_place" :key="is_production + index"
class="tobacco_breed_box">
<span>方位:</span>
<el-select v-model="item.area" placeholder="请选择" @change="selectProvince(item.area, index)">
<el-option v-for="obj in left_terr_data" :key="obj.id" :label="obj.name" :value="obj.name">
</el-option>
</el-select>
<span style="margin-left: 15px;">地址:</span>
<el-cascader :options="item.province_list" v-model="item.province_id" :props="{ checkStrictly: true }"
:show-all-levels="false" @change="cascadeChange" clearable :key="new Date().getTime()"></el-cascader>
<el-button type="text" icon="el-icon-circle-plus-outline"
v-if="index == tobacco_info.tobacco_breed_place.length - 1" title="添加产地"
@click="addPlaceofproduction"></el-button>
<el-button class="delete_breed" type="text" icon="el-icon-delete" title="删除产地"></el-button>
</div>
</el-form-item>
<el-form-item label="外观特征">
<span v-for="(e, k, i) in tobacco_info.appearance_characteristics" :key="i" style="margin-right: 15px;">
<span>{{ k }}:</span>
<el-input v-model="tobacco_info.appearance_characteristics[k]" style="width: 200px;"></el-input>
</span>
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="tobacco_info.remark">
</el-input>
</el-form-item>
<!-- 图片信息 -->
<el-form-item label="图片信息">
<el-upload class="avatar-uploader" :action="IP + '/api/upload/breedimage'" :show-file-list="false"
accept="image/png,image/jpeg,image/jpg" :http-request="sliderRequest">
<img v-if="tobacco_info.image" :src="IP + tobacco_info.image" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</span>
</div>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {}
}
</script>
<style scoped></style>
<!--
* @Author: czj
* @Date: 2023-03-06 19:13:45
* @Description:
* @FilePath: \AdministrationHome\src\views\student\area_breed\components\dialog.vue
-->
<!-- -->
<template>
<div v-if="is_show">
<div style="height: 600px;overflow-y: auto;">
<el-form label-width="100px">
<el-form-item label="品种名称">
<el-input v-model="tobacco_info.name" style="width: 200px;"></el-input>
</el-form-item>
<el-form-item label="生产地点">
<div v-for="(item, index) in tobacco_info.tobacco_breed_place" :key="index" class="tobacco_breed_box">
<span>方位:</span>
<el-select v-model="item.area" placeholder="请选择">
<el-option v-for="obj in left_terr_data" :key="obj.id" :label="obj.name" :value="obj.name">
</el-option>
</el-select>
<span style="margin-left: 15px;">地址:</span>
<el-cascader v-if="item.area" :options="ProvinceData[item.area]" v-model="item.province_id"
:props="{ checkStrictly: true }" :show-all-levels="false" clearable filterable></el-cascader>
<el-button type="text" icon="el-icon-circle-plus-outline"
v-if="index == tobacco_info.tobacco_breed_place.length - 1" title="添加产地"
@click="addPlaceofproduction"></el-button>
<el-button class="delete_breed" type="text" icon="el-icon-delete" title="删除产地"
@click="deletePlaceofproduction(index)"></el-button>
</div>
<el-button type="text" icon="el-icon-circle-plus-outline" v-if="tobacco_info.tobacco_breed_place.length == 0"
title="添加产地" @click="addPlaceofproduction"></el-button>
</el-form-item>
<el-form-item label="外观特征">
<div v-for="(item, index) in tobacco_info.appearance_characteristics_vals" :key="index"
style="margin-bottom: 10px;">
<el-input style="width: 100px;" v-model="item.label"></el-input> :
<el-input style="width: 390px;" v-model="item.value"></el-input>
<el-button type="text" icon="el-icon-circle-plus-outline"
v-if="index == tobacco_info.appearance_characteristics_vals.length - 1" title="添加描述"
@click="addDescribe"></el-button>
<el-button class="delete_breed" type="text" icon="el-icon-delete" title="删除描述"
@click="deleteDescribe(index)"></el-button>
</div>
<el-button type="text" icon="el-icon-circle-plus-outline"
v-if="tobacco_info.appearance_characteristics_vals.length == 0" title="添加描述" @click="addDescribe"></el-button>
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="tobacco_info.remark">
</el-input>
</el-form-item>
<!-- 图片信息 -->
<el-form-item label="图片信息">
<el-upload class="avatar-uploader" :action="IP + '/api/upload/breedimage'" :show-file-list="false"
accept="image/png,image/jpeg,image/jpg" :http-request="sliderRequest">
<img v-if="tobacco_info.image" :src="IP + tobacco_info.image" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
</div>
<div slot="footer" style="text-align: right;">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</div>
</div>
</template>
<script>
import { get_province_list, get_tobacco_province, get_tobacco_all_info, add_tobacco_breed, delete_tobacco_breed, updata_tobacco_breed, get_tobacco_detail, get_tobacco_info, tobacco_img_upload } from '@/api/student';
export default {
props: ['left_terr_data', 'tobacco_infos', 'ProvinceData'],
data() {
return {
tobacco_info: {},
IP: process.env.VUE_APP_BASE_API,
//产地下标
production_index: 0,
//
tobacco_details: {},
is_show: true,
};
},
components: {},
computed: {},
created() {
this.tobacco_info = JSON.parse(JSON.stringify(this.tobacco_infos));
},
mounted() { },
methods: {
//省市区联动选择
cascadeChange(val) {
console.log(val);
// this.tobacco_info.tobacco_breed_place[this.production_index].province_id = val[val.length - 1];
},
//烟草图片上传
sliderRequest(upload) {
console.log('上传');
console.log(upload);
const formData = new FormData();
formData.append('image', upload.file)
tobacco_img_upload(formData).then(res => {
console.log('上传回调');
console.log(res);
if (res.err_code == 200) {
this.tobacco_info.image = res.message;
this.$message.success('上传成功');
}
})
},
//添加产地
addPlaceofproduction() {
this.tobacco_info.tobacco_breed_place.push({
area: '',
province_id: null,
});
},
//添加描述
addDescribe() {
this.tobacco_info.appearance_characteristics_vals.push({
label: null,
value: null
});
},
//删除产地
deletePlaceofproduction(i) {
this.tobacco_info.tobacco_breed_place.splice(i, 1);
},
//删除描述
deleteDescribe(i) {
this.tobacco_info.appearance_characteristics_vals.splice(i, 1);
},
//取消
handleClose() {
this.$emit('handleClose');
},
//提交
submitData() {
const process_data = (data) => {
let obj = { ...data };
delete obj.appearance_characteristics_vals
obj.tobacco_breed_place = [];
obj.appearance_characteristics = {};
data.tobacco_breed_place.forEach(element => {
if (element.province_id instanceof Array) {
obj.tobacco_breed_place.push({
area: element.area,
province_id: element.province_id[element.province_id.length - 1]
})
} else {
obj.tobacco_breed_place.push(element)
}
});
data.appearance_characteristics_vals.forEach(element => {
obj.appearance_characteristics[element.label] = element.value || '';
});
return obj
}
let params = process_data(this.tobacco_info);
this.$emit('submitData', params)
},
}
}
</script>
<style lang="scss" scoped>
.delete_breed {
color: red;
}
.tobacco_breed_box {
margin-bottom: 10px;
}
.avatar-uploader {
display: inline-block;
border: 1px dashed #8c939d;
.el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 148px;
height: 148px;
line-height: 148px;
text-align: center;
}
.avatar {
width: 148px;
height: 148px;
display: block;
}
}
</style>
差异被折叠。
<!--
* @Author: czj
* @Date: 2023-03-08 16:15:08
* @Description:
* @FilePath: \AdministrationHome\src\views\student\examination_questions\components\TableMoudel.vue
-->
<!-- -->
<template>
<div>
<table cellspacing="1" cellpadding="0">
<tr>
<td colspan="6">
<div class="table_line">
<div>题号 : {{ table_info.question_no }}</div>
<div>
<!-- <el-button type="text" icon="el-icon-delete" style="color: #606266;">删除</el-button> -->
</div>
</div>
</td>
</tr>
<tr>
<td style="width: 100px;">烟草方位</td>
<td>
<div class="select_container">
<el-select placeholder="请选择" style="width: 100%;" v-model="table_info.area">
<el-option v-for="item in position_data" :key="item.id" :label="item.name" :value="item.name">
</el-option>
</el-select>
</div>
</td>
<td style="width: 100px;">
<div class="table_line_title_box">烟草区域</div>
</td>
<td>
<div class="select_container">
<el-cascader style="width: 100%;" v-if="province_data" v-model="table_info.province_id"
:options="province_data[table_info.area]" :show-all-levels="false" :props="{ checkStrictly: true }"
@change="handleChange" clearable filterable></el-cascader>
</div>
</td>
<td rowspan="4">烟叶实物</td>
<td rowspan="4" style="padding: 10px;">
<div class="image_box">
<el-upload class="upload-demo" drag action="#" multiple accept="image/png,image/jpeg,image/jpg" :limit="1"
:http-request="sliderRequest" :before-upload="beforeAvatarUpload">
<i class="el-icon-upload" v-if="!table_info.image || table_info.image == '/'"></i>
<div class="el-upload__text" v-if="!table_info.image || table_info.image == '/'">将文件拖到此处,或<em>点击上传</em>
</div>
<div class="el-upload__tip" slot="tip" v-if="!table_info.image || table_info.image == '/'">
只能上传jpg/png文件,且不超过20MB</div>
<div class="imng_view_box" v-if="table_info.image && table_info.image != '/'">
<img :src="IP + table_info.image" alt="">
</div>
</el-upload>
</div>
</td>
</tr>
<tr>
<td>
<div class="table_line_title_box">试题结论</div>
</td>
<td style="width: 150px;">
<div class="select_container">
<el-select placeholder="请选择" style="width: 100%;" v-model="table_info.grades_code">
<el-option v-for="item in tobacco_grades_all_list" :key="item.id" :label="item.grade_code"
:value="item.grade_code">
</el-option>
</el-select>
</div>
</td>
<td>得分</td>
<td style="width: 150px;">
<div class="select_container">
<el-input placeholder="请输入得分" v-model="table_info.fraction" type="number" :min="3">
</el-input>
</div>
</td>
</tr>
<tr>
<td colspan="1">
<div class="table_line_title_box">烟草品种</div>
</td>
<td colspan="3">
<div class="select_container">
<el-select v-model="table_info.breed_name" placeholder="请选择" style="width: 100%;" filterable allow-create>
<el-option v-for="item in tobacco_all_list" :key="item.id" :label="item.name" :value="item.name">
</el-option>
</el-select>
</div>
</td>
</tr>
<tr>
<td style="height: 110px;" colspan="1">
<div class="table_line_title_box">试题详解</div>
</td>
<td style="padding: 0;" colspan="3">
<div class="select_container">
<el-input type="textarea" :rows="5" placeholder="请输入内容" v-model="table_info.explain_in_detail">
</el-input>
</div>
</td>
</tr>
</table>
</div>
</template>
<script>
import { upload_examination_question_image, batch_upload_of_pictures } from '@/api/student';
export default {
props: ['table_data', 'position_datas', 'province_datas', 'tobacco_all_lists', 'tobacco_grades_all_lists', 'is_updata_type', 'btn_key'],
data() {
return {
IP: process.env.VUE_APP_BASE_API,
father_id: null,
table_info: {},
// province_list: [],
position_data: [],
province_data: {},
tobacco_all_list: [],
tobacco_grades_all_list: [],
};
},
components: {},
computed: {},
created() {
this.father_id = this.$route.query.id;
this.position_data = JSON.parse(JSON.stringify(this.position_datas));
this.province_data = JSON.parse(JSON.stringify(this.province_datas));
this.tobacco_all_list = JSON.parse(JSON.stringify(this.tobacco_all_lists));
this.tobacco_grades_all_list = JSON.parse(JSON.stringify(this.tobacco_grades_all_lists));
this.table_info = JSON.parse(JSON.stringify(this.table_data));
},
mounted() {
},
methods: {
handleChange(val) {
console.log('联动选择的值');
console.log(val);
this.table_info.province_id = val[val.length - 1];
},
//上传文件监听
beforeAvatarUpload(file) {
// const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 20;
// if (!isJPG) {
// this.$message.error('上传头像图片只能是 JPG 格式!');
// }
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 20MB!');
}
// return isJPG && isLt2M;
return isLt2M;
},
sliderRequest(upload) {
console.log('上传');
console.log(upload);
const formData = new FormData();
formData.append('image', upload.file)
let id = this.table_info.id || '';//修改有id,新增没有id
console.log(this.father_id, id);
batch_upload_of_pictures(this.father_id, id, formData).then(res => {
console.log('上传回调');
console.log(res);
if (res.err_code == 200) {
this.table_info.image = res.message;
this.$message.success('上传成功');
}
})
// upload_examination_question_image(formData).then(res => {
// console.log('上传回调');
// console.log(res);
// if (res.err_code == 200) {
// this.table_info.image = res.message;
// this.$message.success('上传成功');
// }
// })
},
}
}
</script>
<style lang="scss" scoped>
table {
width: 100%;
border-top: 1px solid #E4E7ED;
border-left: 1px solid #E4E7ED;
border-spacing: 0;
}
table td {
color: #303133;
font-size: 14px;
padding: 0 10px;
height: 30px;
border-bottom: 1px solid #E4E7ED;
border-right: 1px solid #E4E7ED;
}
.table_line {
display: flex;
justify-content: space-between;
align-items: center;
}
.table_line_title_box {
font-size: 14px;
color: #606266;
}
.imng_view_box {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
img {
max-width: 100%;
max-height: 100%;
}
}
</style>
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论