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

第一个模块内容

上级 ade30e39
......@@ -2,4 +2,5 @@
ENV = 'development'
# 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 @@
"test:ci": "npm run lint && npm run test:unit"
},
"dependencies": {
"@riophae/vue-treeselect": "^0.4.0",
"axios": "0.18.1",
"clipboard": "2.0.4",
"codemirror": "5.45.0",
"core-js": "3.6.5",
"crypto-js": "^4.1.1",
"driver.js": "0.9.5",
"dropzone": "5.5.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'
export function getRoutes() {
......@@ -36,3 +42,54 @@ export function deleteRole(id) {
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'
// export function login(data) {
// return request({
// url: '/vue-element-admin/user/login',
// method: 'post',
// data
// })
// }
//登录
export function login(data) {
return request({
url: '/vue-element-admin/user/login',
url: '/api/auth/login',
method: 'post',
data
})
}
export function getInfo(token) {
//获取用户信息
export function getInfo() {
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',
params: { token }
})
}
export function logout() {
return request({
url: '/vue-element-admin/user/logout',
url: '/api/auth/logout',
method: 'post'
})
}
......@@ -37,7 +37,7 @@ export default {
const first = matched[0]
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)
......
<!--
* @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>
<div :class="{'has-logo':showLogo}">
<div :class="{ 'has-logo': showLogo }">
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="false"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<el-menu :default-active="activeMenu" :collapse="isCollapse" :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" />
</el-menu>
</el-scrollbar>
......@@ -32,6 +31,8 @@ export default {
'sidebar'
]),
activeMenu() {
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
......
......@@ -5,23 +5,36 @@
* @FilePath: \AdministrationHome\src\layout\index.vue
-->
<template>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<!-- <div :class="classObj" class="app-wrapper">
<Headerbar></Headerbar>
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" />
<div :class="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<div :class="{ hasTagsView: needTagsView }" class="main-container">
<div :class="{ 'fixed-header': fixedHeader }">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
</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>
</template>
<script>
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components';
import ResizeMixin from './mixin/ResizeHandler';
import { mapState } from 'vuex';
import Headerbar from './components/Headerbar/index.vue';
import Breadcrumb from '@/components/Breadcrumb';
export default {
name: 'Layout',
......@@ -30,7 +43,9 @@ export default {
Navbar,
Settings,
Sidebar,
TagsView
TagsView,
Headerbar,
Breadcrumb
},
mixins: [ResizeMixin],
computed: {
......@@ -50,19 +65,33 @@ export default {
}
}
},
created() {
},
mounted() {
this.header_box();
},
methods: {
handleClickOutside() {
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>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";
<!-- <style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";
.app-wrapper {
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
......@@ -72,9 +101,9 @@ export default {
position: fixed;
top: 0;
}
}
}
.drawer-bg {
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
......@@ -82,22 +111,33 @@ export default {
height: 100%;
position: absolute;
z-index: 999;
}
}
.fixed-header {
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
}
}
.hideSidebar .fixed-header {
.hideSidebar .fixed-header {
width: calc(100% - 54px)
}
}
.mobile .fixed-header {
.mobile .fixed-header {
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>
......@@ -26,6 +26,13 @@ import './utils/error-log' // error log
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
* you want to use MockJs for mock api
......@@ -34,10 +41,10 @@ import * as filters from './filters' // global filters
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {
const { mockXHR } = require('../mock')
mockXHR()
}
// if (process.env.NODE_ENV === 'production') {
// const { mockXHR } = require('../mock')
// mockXHR()
// }
Vue.use(Element, {
size: Cookies.get('size') || 'medium', // set element-ui default size
......
......@@ -8,9 +8,9 @@ import getPageTitle from '@/utils/get-page-title'
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
NProgress.start()
......@@ -27,24 +27,23 @@ router.beforeEach(async(to, from, next) => {
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else {
// determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
// const hasRoles = store.getters.roles && store.getters.roles.length > 0
const hasUser = store.getters.hasUser;
if (hasUser) {
next()
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
const { roles } = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
await store.dispatch('user/getInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes')
// console.log('路由数据');
// console.log(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 })
// setTimeout(() => {
// console.log('整个路由对象');
// console.log(router);
// }, 300);
// next()
} catch (error) {
// remove token and go to login page to re-login
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 Router from 'vue-router'
......@@ -43,7 +55,14 @@ export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
hidden: true,
meta: { title: '登录' }
},
{
path: '/retrieve',
component: () => import('@/views/retrieve/index'),
hidden: true,
meta: { title: '找回' }
},
{
path: '/404',
......@@ -55,6 +74,14 @@ export const constantRoutes = [
component: () => import('@/views/error-page/401'),
hidden: true
},
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
{
path: '/',
component: Layout,
......@@ -64,21 +91,146 @@ export const constantRoutes = [
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
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: '试题详情' },
},
]
},
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
export const asyncRoutes = [
{
path: 'test_results',
name: 'Test_results',
component: () => import('@/views/student/test_results/index.vue'),
meta: { title: '考试结果' },
redirect: '/student/test_results/list',
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 !!!
{ path: '*', redirect: '/404', hidden: true }
......
module.exports = {
title: 'Vue Element Admin',
title: '烟草质检管理',
/**
* @type {boolean} true | false
......
/*
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\store\getters.js
*/
const getters = {
sidebar: state => state.app.sidebar,
size: state => state.app.size,
......@@ -10,6 +16,7 @@ const getters = {
introduction: state => state.user.introduction,
roles: state => state.user.roles,
permission_routes: state => state.permission.routes,
errorLogs: state => state.errorLog.logs
errorLogs: state => state.errorLog.logs,
hasUser: state => state.user.hasUser,
}
export default getters
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
* @param roles
......@@ -45,16 +47,61 @@ const mutations = {
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
accessedRoutes = asyncRoutes || []
//处理路由地址 不能用 import。使用require,异步
function routerCom(view_path) {
return (resolve) => require([view_path], resolve);
}
//过滤数据 /转为树结构
function filterRouterData(list) {
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 {
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)
resolve(accessedRoutes)
})
......
......@@ -7,7 +7,8 @@ const state = {
name: '',
avatar: '',
introduction: '',
roles: []
roles: [],
hasUser: false
}
const mutations = {
......@@ -25,7 +26,10 @@ const mutations = {
},
SET_ROLES: (state, roles) => {
state.roles = roles
}
},
SET_HASUSER: (state, hasUser) => {
state.hasUser = hasUser
},
}
const actions = {
......@@ -33,10 +37,20 @@ const actions = {
login({ commit }, userInfo) {
const { username, password } = userInfo
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
commit('SET_TOKEN', data.token)
setToken(data.token)
commit('SET_TOKEN', response.access_token)
setToken(response.access_token)
resolve()
}).catch(error => {
reject(error)
......@@ -48,24 +62,28 @@ const actions = {
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
// console.log('获取用户信息@@@@@@@@@@@');
// console.log(response);
if (!data) {
reject('Verification failed, please Login again.')
}
commit('SET_HASUSER', true)
// const { data } = response
const { roles, name, avatar, introduction } = data
// if (!data) {
// reject('Verification failed, please Login again.')
// }
// roles must be a non-empty array
if (!roles || roles.length <= 0) {
reject('getInfo: roles must be a non-null array!')
}
// const { roles, name, avatar, introduction } = data
// // 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_NAME', name)
commit('SET_AVATAR', avatar)
commit('SET_INTRODUCTION', introduction)
resolve(data)
// commit('SET_ROLES', roles)
commit('SET_NAME', response.name);
// commit('SET_AVATAR', avatar)
// commit('SET_INTRODUCTION', introduction)
resolve(response)
}).catch(error => {
reject(error)
})
......@@ -74,10 +92,13 @@ const actions = {
// user logout
logout({ commit, state, dispatch }) {
console.log('退出登录');
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_HASUSER', false)
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
// commit('SET_ROLES', [])
removeToken()
resetRouter()
......@@ -95,6 +116,7 @@ const actions = {
// remove token
resetToken({ commit }) {
return new Promise(resolve => {
commit('SET_HASUSER', false)
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
......
......@@ -4,7 +4,7 @@
**/
/* theme color */
$--color-primary: #1890ff;
$--color-primary: #038D6E;
$--color-success: #13ce66;
$--color-warning: #ffba00;
$--color-danger: #ff4949;
......
@charset "UTF-8";
:export {
menuText: #bfcbd9;
menuActiveText: #409EFF;
subMenuActiveText: #f4f4f5;
menuBg: #304156;
menuHover: #263445;
subMenuBg: #1f2d3d;
subMenuHover: #001528;
sideBarWidth: 210px;
}
/* fade */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.28s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
/* fade-transform */
.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 transition */
.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;
}
/* 表格 行 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 .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;
}
: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 @@
@import './sidebar.scss';
@import './btn.scss';
p,
h1 {
margin: 0;
}
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
......@@ -189,3 +194,108 @@ aside {
.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__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
$blue:#324157;
$light-blue:#3A71A8;
$red:#C03639;
$blue: #324157;
$light-blue: #3A71A8;
$red: #C03639;
$pink: #E65D6E;
$green: #30B08F;
$tiffany: #4AB7BD;
$yellow:#FEC171;
$yellow: #FEC171;
$panGreen: #30B08F;
// sidebar
$menuText:#bfcbd9;
$menuActiveText:#409EFF;
$subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
$menuText: #bfcbd9;
$menuActiveText: #409EFF;
$subMenuActiveText: #f4f4f5; // https://github.com/ElemeFE/element/issues/12951
$menuBg:#304156;
$menuHover:#263445;
$menuBg: #304156;
$menuHover: #263445;
$subMenuBg:#1f2d3d;
$subMenuHover:#001528;
$subMenuBg: #1f2d3d;
$subMenuHover: #001528;
$sideBarWidth: 210px;
$themeColor: #038D6E;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
: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 { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import router from "@/router";
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
timeout: 0 // request timeout
})
// request interceptor
......@@ -19,7 +27,8 @@ service.interceptors.request.use(
// let each request carry token
// ['X-Token'] is a custom headers key
// 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
},
......@@ -44,37 +53,77 @@ service.interceptors.response.use(
*/
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 20000) {
// if (res.access_token || res.login_at || res.length > 0) {//登录和用户信息接口无状态码
// return res
// }
if (res.code && res.code !== 200) {
if (res.code === 422) {
if (typeof res.message === 'string') {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
} else {
let ps = res.message.map(item => {
return `<p>${item}</p>`
})
let html = `<div>${ps}</div>`
Message({
message: res.message && html || 'Error',
type: 'error',
duration: 5 * 1000
})
}
} else if (res.code === 401) {
Message({
message: 'License.认证已过期',
type: 'warning',
duration: 5 * 1000
})
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
return res
},
error => {
console.log('进入通行 错误判断');
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: error.message,
message: tipMsg || '网络错误',
type: 'error',
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 @@
<template>
<div class="dashboard-editor-container">
<div class=" clearfix">
<pan-thumb :image="avatar" style="float: left">
<!-- <pan-thumb :image="avatar" style="float: left">
Your roles:
<span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span>
</pan-thumb>
</pan-thumb> -->
<div class="info-container">
<span class="display_name">{{ name }}</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">
<component :is="currentRole" />
</div>
......@@ -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>
<style scoped></style>
<!--
* @Author: czj
* @Date: 2023-02-24 16:50:23
* @Description:
* @FilePath: \AdministrationHome\src\views\login\auth-redirect.vue
-->
<script>
console.log('重定向');
export default {
name: 'AuthRedirect',
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>
......@@ -6,51 +6,78 @@
-->
<template>
<div class="login-container">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
<div class="mask_container_background">
<div class="content_box">
<img src="/image/login/Vector.png" alt="" class="content_box_logo">
</div>
</div>
<div class="mask_container">
<img src="/image/log.svg" alt="" class="object_logo">
<div class="content_box">
<img src="/image/login/Vector.png" alt="" class="content_box_logo" style="opacity: 0;">
<div class="content_body">
<div class="content_body_left">
<h1>你好,</h1>
<h1>欢迎登录国家烟草质检中心</h1>
<div class="translated_text">National Tobacco Quality Inspection Center</div>
</div>
<div class="content_body_right">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on"
label-position="left">
<div class="title-container">
<h3 class="title">Login Form</h3>
<h3 class="title">账号登录</h3>
</div>
<el-form-item prop="username">
<el-input ref="username" v-model="loginForm.name" placeholder="Username" name="username" type="text"
tabindex="1" autocomplete="on">
<i slot="prefix" class="el-input__icon el-icon-user-solid"></i>
</el-input>
</el-form-item>
<el-tooltip v-model="capsTooltip" content="大写锁定打开" placement="right" manual>
<el-form-item prop="password">
<el-input :key="passwordType" ref="password" v-model="loginForm.password" :type="passwordType"
placeholder="Password" name="password" tabindex="2" autocomplete="on" @keyup.native="checkCapslock"
@blur="capsTooltip = false" @keyup.enter.native="handleLogin">
<i slot="prefix" class="el-input__icon el-icon-lock"></i>
<i slot="suffix" class="el-input__icon el-icon-view" @click="showPwd"></i>
</el-input>
</el-form-item>
</el-tooltip>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;"
@click.native.prevent="handleLogin">登录</el-button>
</el-form>
<div style="text-align: center;">
<el-button size="mini" @click="retrievePassword">忘记密码</el-button>
</div>
<!-- <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on"
label-position="left" v-if="false">
<div class="title-container">
<h3 class="title">账号登录</h3>
</div>
<el-form-item prop="username">
<span class="svg-container">
</span>
<el-input
ref="username"
v-model="loginForm.username"
placeholder="Username"
name="username"
type="text"
tabindex="1"
autocomplete="on"
/>
<el-input ref="username" v-model="loginForm.username" placeholder="Username" name="username" type="text"
tabindex="1" autocomplete="on" />
</el-form-item>
<el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
<el-tooltip v-model="capsTooltip" content="大写锁定打开" placement="right" manual>
<el-form-item prop="password">
<span class="svg-container">
</span>
<el-input
:key="passwordType"
ref="password"
v-model="loginForm.password"
:type="passwordType"
placeholder="Password"
name="password"
tabindex="2"
autocomplete="on"
@keyup.native="checkCapslock"
@blur="capsTooltip = false"
@keyup.enter.native="handleLogin"
/>
<el-input :key="passwordType" ref="password" v-model="loginForm.password" :type="passwordType"
placeholder="Password" name="password" tabindex="2" autocomplete="on" @keyup.native="checkCapslock"
@blur="capsTooltip = false" @keyup.enter.native="handleLogin" />
<span class="show-pwd" @click="showPwd">
图标
</span>
</el-form-item>
</el-tooltip>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;"
@click.native.prevent="handleLogin">Login</el-button>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
<div style="position:relative">
<div style="position:relative" v-if="false">
<div class="tips">
<span>Username : admin</span>
<span>Password : any</span>
......@@ -60,51 +87,57 @@
<span>Password : any</span>
</div>
<el-button class="thirdparty-button" type="primary" @click="showDialog=true">
<el-button class="thirdparty-button" type="primary" @click="showDialog = true">
Or connect with
</el-button>
</div>
</el-form>
<el-dialog title="Or connect with" :visible.sync="showDialog">
Can not be simulated on local, so please combine you own business simulation! ! !
<br>
<br>
<br>
<social-sign />
</el-dialog>
</el-form> -->
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { validUsername } from '@/utils/validate'
import SocialSign from './components/SocialSignin'
export default {
name: 'Login',
components: { SocialSign },
components: {},
data() {
const validateUsername = (rule, value, callback) => {
if (!validUsername(value)) {
callback(new Error('Please enter the correct user name'))
callback(new Error('请输入正确的用户名'))
} else {
callback()
}
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
callback(new Error('The password can not be less than 6 digits'))
callback(new Error('密码不能少于6位'))
} else {
callback()
}
}
return {
loginForm: {
username: 'admin',
password: '111111'
// username: 'admin',
// password: '111111'
// name: 'tobacco',
// password: '123456',
name: '',
password: '',
grant_type: 'password',
client_id: 2,
client_secret: 'yTahrwHlHby7JhKGHXjJ6mvqnSVZn2JOTnVNZK4Q'
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
name: [{ required: true, trigger: 'blur', validator: validateUsername }],
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
},
passwordType: 'password',
......@@ -117,7 +150,7 @@ export default {
},
watch: {
$route: {
handler: function(route) {
handler: function (route) {
const query = route.query
if (query) {
this.redirect = query.redirect
......@@ -159,9 +192,15 @@ export default {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
this.$store.dispatch('user/login', this.loginForm)
.then(() => {
let data = JSON.parse(JSON.stringify(this.loginForm));
let params = this.$removeProperty(data);
params.password = this.$Aesencrypt(params.password);
console.log('登录数据加密');
console.log(params);
this.$store.dispatch('user/login', params).then(() => {
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
/* this.$router.push('/') */
this.loading = false
})
.catch(() => {
......@@ -180,7 +219,7 @@ export default {
}
return acc
}, {})
}
},
// afterQRScan() {
// if (e.key === 'x-admin-oauth-code') {
// const code = getQueryObject(e.newValue)
......@@ -199,21 +238,28 @@ export default {
// }
// }
// }
//找回密码
retrievePassword() {
this.$router.push('/retrieve');
},
}
}
</script>
<style lang="scss">
<!-- <style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#fff;
$bg: #283443;
$light_gray: #fff;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
color: $cursor;
// color: $cursor;
background: url('/image/login_bg.webp') 0 0 no-repeat;
background-size: 100% 100%;
}
}
......@@ -248,25 +294,28 @@ $cursor: #fff;
color: #454545;
}
}
</style>
</style> -->
<style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
.login-container {
position: relative;
min-height: 100%;
width: 100%;
background-color: $bg;
// background-color: $bg;
background: url('/image/login/login_bg.webp') 0 0 no-repeat;
background-size: 100% 100%;
overflow: hidden;
.login-form {
position: relative;
width: 520px;
max-width: 100%;
padding: 160px 35px 0;
margin: 0 auto;
// padding: 160px 35px 0;
// margin: 0 auto;
overflow: hidden;
}
......@@ -295,7 +344,7 @@ $light_gray:#eee;
.title {
font-size: 26px;
color: $light_gray;
color: #333;
margin: 0px auto 40px auto;
text-align: center;
font-weight: bold;
......@@ -324,4 +373,100 @@ $light_gray:#eee;
}
}
}
.mask_container_background {
position: absolute;
left: 0;
right: 0;
width: 100%;
height: 100%;
background: linear-gradient(to bottom, #006851, #00A05D);
opacity: 0.7;
}
.mask_container {
position: absolute;
left: 0;
right: 0;
width: 100%;
height: 100%;
// background: linear-gradient(to bottom, #006851, #00A05D);
// opacity: 0.7;
z-index: 1;
}
.object_logo {
position: absolute;
top: 62px;
left: 70px;
width: 165px;
height: 50px;
}
.content_box {
position: absolute;
top: 30%;
left: 0;
width: 100%;
}
.content_box_logo {
width: 430px;
height: 470px;
margin-left: 200px;
}
.content_body {
position: absolute;
top: 0;
left: 300px;
right: 300px;
// width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
}
.content_body_left {
color: #fff;
h1 {
font-size: 55px;
margin-bottom: 15px;
}
.translated_text {
width: 80%;
border: 4px solid;
border-image: linear-gradient(to right, #E6A25D, #3d8362) 4;
border-left: none;
border-right: none;
border-top: none;
font-size: 24px;
font-weight: 200;
padding-bottom: 3px;
}
}
.content_body_right {
width: 400px;
box-sizing: border-box;
padding: 40px;
background-color: #fff;
border-radius: 8px;
overflow: hidden;
}
</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-06 10:39:05
* @Description:
* @FilePath: \AdministrationHome\src\views\student\area_breed\index.vue
-->
<template>
<div class="module_container">
<div class="module_container_left">
<el-tree :data="left_terr_data" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode"
ref="tree" :default-expand-all="false" @node-click="handleNodeClick" />
</div>
<div class="right_container">
<div class="card_container">
<el-card class="box-card">
<table-head :head_data="head_data" @search="searchEvent" @change="searchChange" @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="编号">
</el-table-column>
<el-table-column prop="name" label="品种名称">
</el-table-column>
<el-table-column prop="appearance_characteristics" label="外观特征">
<template slot-scope="scope">
<div v-for="(e, key, i) in scope.row.appearance_characteristics" :key="i">
<span>{{ key }}</span>
<span>{{ scope.row.appearance_characteristics[key] }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="image" label="图片信息">
<template slot-scope="scope">
<el-popover placement="right" trigger="click">
<div class="amplify_img_box">
<img :src="IP + scope.row.image" alt="">
</div>
<img class="small_picture" slot="reference" :src="IP + scope.row.image" alt="">
</el-popover>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注">
</el-table-column>
<el-table-column prop="created_at" label="创建时间">
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #000;"
@click="updataTobaccoInfo(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C;"
@click="deleteTobacco(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>
</div>
<el-dialog :title="is_updata_type == 'add' ? '新增品种信息' : '修改品种信息'" :visible.sync="is_dialogVisible" width="60%"
top="50px" :before-close="handleClose">
<Dialog :left_terr_data="left_terr_data" :ProvinceData="ProvinceData" :tobacco_infos="tobacco_info"
@handleClose="handleClose" @submitData="submitData" :key="new Date().getTime()"></Dialog>
</el-dialog>
</div>
</template>
<script>
import TableHead from '@/components/TableHead/index';
import Dialog from './components/dialog.vue';
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_breed_list } from '@/api/student';
const standard_template = {
name: '',
tobacco_breed_place: [
{
area: null,
province_id: null,
},
],
appearance_characteristics: {
"颜色": "绿色",
"大小": "50CM"
},
appearance_characteristics_vals: [
{ label: "颜色", value: '绿色' },
],
image: "",
remark: ""
}
export default {
data() {
return {
ProvinceData: {},
IP: process.env.VUE_APP_BASE_API,
//头部按钮
head_data: {
// search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-document-add',
event: 'add',
}
],
},
//初始化请求参数
request_params: {
area: '',
val: '',
page: 1,
limit: 10,
total: 1,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//左侧树数据
left_terr_data: [],
//树字段对应
defaultProps: {
children: "children",
label: "name"
},
//烟草信息
tobacco_info: {},
//省市区信息
treeprovince_list: [],
//产地下标
production_index: 0,
is_production: 1,
};
},
components: { TableHead, Dialog },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getTobaccoBreedList();
},
searchChange(val) {
console.log('change监听');
console.log(val);
this.request_params.val = val;
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = '';
this.getTobaccoBreedList();
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
if (val == 'add') this.addTobaccoInfo();
},
init() {
this.getTobaccoProvince();
// this.getTobaccoAllInfo();
this.getTobaccoBreedList();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData(val) {
console.log('提交的信息');
let params = this.$handleParams(val);
console.log(params);
if (this.is_updata_type == 'add') {
add_tobacco_breed(params).then(res => {
console.log('新增回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
// this.getTobaccoAllInfo();
this.getTobaccoBreedList();
}
})
} else {
let id = val.id;
updata_tobacco_breed(id, params).then(res => {
console.log('修改回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
// this.getTobaccoAllInfo();
this.getTobaccoBreedList();
}
})
}
},
//获取烟草区域信息
getTobaccoProvince() {
get_tobacco_province().then(res => {
console.log('烟草区域信息');
console.log(res);
this.left_terr_data = res || [];
for (let i in this.left_terr_data) {
this.selectProvince(this.left_terr_data[i].name)
}
})
},
//获取烟草列表
getTobaccoBreedList() {
this.is_loading = true;
let params = this.$removeProperty(this.request_params);
get_tobacco_breed_list(params).then(res => {
this.tableData = res.data || [];
this.request_params.total = res.total;
this.is_loading = false;
})
},
//获取烟草全部信息
getTobaccoAllInfo() {
this.is_loading = true;
get_tobacco_all_info().then(res => {
console.log('全部烟草信息');
console.log(res);
this.tableData = res || [];
this.is_loading = false;
})
},
//获取获取省市区信息
selectProvince(val, index) {
// //清除没有子节点的children
const removeNodeInTree = (list) => {
if (!list) return;
for (let i = 0; i < list.length; i++) {
if (list[i].children.length == 0) {
delete list[i].children;
} else {
removeNodeInTree(list[i].children)
}
}
return list
}
get_province_list({ area: val }).then(res => {
this.ProvinceData[val] = removeNodeInTree(res);
})
},
// 左侧树节点单击事件
handleNodeClick(data) {
console.log(data);
this.request_params.area = data.name;
this.getTobaccoBreedList();
},
// 筛选节点
filterNode(value, data) {
console.log(value);
console.log(data);
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
//新增 烟草信息
addTobaccoInfo() {
this.is_updata_type = 'add';
this.tobacco_info = { ...standard_template };
this.is_dialogVisible = true;
},
//修改 烟草信息
updataTobaccoInfo(item) {
console.log(item);
let items = JSON.parse(JSON.stringify(item));
this.is_updata_type = 'edit';
let id = items.id;
this.tobacco_info.id = items.id;
this.tobacco_info.name = items.name;
this.tobacco_info.appearance_characteristics = items.appearance_characteristics;
this.tobacco_info.appearance_characteristics_vals = [];
for (const key in items.appearance_characteristics) {
this.tobacco_info.appearance_characteristics_vals.push({
label: key,
value: items.appearance_characteristics[key]
});
}
this.tobacco_info['remark'] = items.remark;
this.tobacco_info['image'] = items.image;
this.tobacco_info.tobacco_breed_place = [];
get_tobacco_detail(id).then(res => {
res.tobacco_breed_place.forEach((element, index) => {
this.tobacco_info.tobacco_breed_place.push({ area: element.area, province_id: element.province_id })
});
this.is_dialogVisible = true;
})
},
//删除烟草信息
deleteTobacco(item) {
let id = item.id;
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_tobacco_breed(id).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.init();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
//分页
handleCurrentChange(val) {
this.request_params.page = val;
this.getTobaccoBreedList();
},
},
}
</script>
<style lang="scss" scoped>
.small_picture {
width: 40px;
height: 40px;
}
.right_container {
/* position: absolute;
left: 320px;
top: 0; */
margin-left: 320px;
width: 80%;
height: 100%;
}
.card_container {
margin: 0;
}
.amplify_img_box {
width: 290px;
height: 290px;
img {
width: 100%;
height: 100%;
}
}
</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>
<template>
<div class="module_container">
<div class="card_container">
<el-card class="box-card" style="margin-bottom: 10px;">
<examination-header :examination_questions="student_brief_introduction"
:key="new Date().getTime()"></examination-header>
</el-card>
<el-card class="box-card">
<table-head :head_data="head_data" @search="searchEvent" @resetting="resetting" @btnClick="btnClick"
@upload="uploadTestQuestions"></table-head>
<div class="table_container">
<el-table v-loading="is_loading" :data="table_list" style="width: 100%;margin-bottom: 20px;" height="500">
<el-table-column prop="id" label="编号" width="50">
<template slot-scope="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="breed_name" label="品种名称">
</el-table-column>
<el-table-column prop="grades_code" label="等级名称">
</el-table-column>
<el-table-column prop="place_of_production" label="生产地点">
<template slot-scope="scope">
<div>{{ scope.row.area }}.{{ scope.row.place_of_production }}</div>
</template>
</el-table-column>
<el-table-column prop="path" label="烟叶实物">
<template slot-scope="scope">
<el-popover placement="right" trigger="click">
<div class="amplify_img_box">
<img :src="IP + scope.row.image" alt="">
</div>
<img class="small_picture" slot="reference" :src="IP + scope.row.image" alt="">
</el-popover>
</template>
</el-table-column>
<el-table-column prop="created_at" 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.$index, 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>
</el-card>
</div>
<el-dialog :title="is_updata_type == 'add' ? '新增' : '修改'" :visible.sync="is_dialogVisible" width="60%"
:before-close="handleClose">
<div>
<table-moudel v-if="is_dialogVisible" ref="detail_info" :table_data="detailed_information"
:position_datas="position_data" :province_datas="province_data" :tobacco_all_lists="tobacco_all_lists"
:tobacco_grades_all_lists="tobacco_grades_all_lists" :is_updata_type="is_updata_type"></table-moudel>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</span>
</el-dialog>
<el-dialog title="图片批量上传" :visible.sync="is_picture_upload" width="60%" :before-close="handleClosePicture">
<div class="upload_picture_container">
<el-upload action="#" multiple accept="image/png,image/jpeg,image/jpg" :auto-upload="false"
:on-change="seletePicture">
<el-button size="small" type="primary">点击选择</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClosePicture">取 消</el-button>
<el-button type="primary" @click="subMitPictureList">提 交</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import ExaminationHeader from '@/components/ExaminationHeader/index';
import TableHead from '@/components/TableHead/index';
import TableMoudel from '../components/TableMoudel.vue';
import { get_examination_questions_detail, get_province_list, get_tobacco_all_info, upload_examination_question_image, get_tobacco_grades_all, add_examination_question_detail, delete_examination_question_detail, updata_examination_question_detail, examination_question_detail_upload, get_tobacco_province, batch_upload_of_pictures, get_image_path } from '@/api/student';
import { exportText } from '@/utils/tool';
const standard_template = {
area: "南方",
fraction: 3,
province_id: "70000",
breed_name: "中烟100",
grades_code: "C2F",
explain_in_detail: "fasfas",
image: "/"
}
export default {
data() {
return {
IP: process.env.VUE_APP_BASE_API,
examination_questions_id: null,//试题id
//头部按钮
head_data: {
search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '模板下载',
icon: 'el-icon-download',
event: 'template_download',
},
{
text: '试题上传',
icon: 'el-icon-upload2',
event: 'examination_questions_upload',
},
{
text: '图片批量上传',
icon: 'el-icon-upload2',
event: 'batch_upload',
},
{
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_picture_upload: false,
is_updata_type: 'add',
//详细信息
detailed_information: {},
//头部组件的数据
header_data: {},
//表格列表
table_list: [],
//省市区信息
province_list: [],
//烟草品种列表
tobacco_all_lists: [],
//烟草等级列表
tobacco_grades_all_lists: [],
//头部 学生简要 信息
student_brief_introduction: {},
//南方北方西部综合数据
position_data: [],
province_data: {},
//图片列表
picture_file_list: [],
};
},
components: { ExaminationHeader, TableHead, TableMoudel },
computed: {},
created() {
this.examination_questions_id = this.$route.query.id;
},
mounted() {
this.init()
},
methods: {
//多文件上传地址
action() {
return `${this.IP}/api/examination_question_detail/uploadimage/${this.examination_questions_id}`;
},
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getExaminationQuestionsDetail();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = '';
this.getExaminationQuestionsDetail();
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
if (val == 'add') this.addInformation();
if (val == 'template_download') this.templateDownload();
/* pictureBatchUpload */
if (val == 'batch_upload') this.pictureBatchUpload();
},
init() {
// this.getProvinceList();
this.getTobaccoProvince();
this.getTobaccoAll();
this.getTobaccoGradesAll();
this.getExaminationQuestionsDetail();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
handleClosePicture() {
this.is_picture_upload = false
},
//提交
submitData() {
let data = { ...this.$refs.detail_info.table_info };
data['examination_questions_id'] = this.examination_questions_id;
let params = this.$handleParams(data);
if (this.is_updata_type == 'add') {
add_examination_question_detail(params).then(res => {
console.log('新增试题详情');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getExaminationQuestionsDetail();
}
})
} else {
let id = this.detailed_information.id;
updata_examination_question_detail(id, params).then(res => {
console.log('修改试题详情');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getExaminationQuestionsDetail();
}
})
}
},
//获取详情
getExaminationQuestionsDetail() {
this.is_loading = true;
get_examination_questions_detail(this.examination_questions_id, { val: this.request_params.val }).then(res => {
console.log('详情');
console.log(res);
this.table_list = [...res.examination_question_detail];
//头部信息
this.student_brief_introduction.title = res.title;
this.student_brief_introduction.creat_user_name = res.user.name;
this.student_brief_introduction.duration = res.duration;
this.student_brief_introduction.begin_date = res.begin_date;
this.student_brief_introduction.test_number = res.examination_question_detail.length;
this.is_loading = false;
})
},
//获取方位
getTobaccoProvince() {
get_tobacco_province().then(res => {
console.log('烟草区域信息');
console.log(res);
this.position_data = res || [];
for (let i in res) {
this.getProvinceList(res[i].name)
}
})
},
//获取省市区列表
getProvinceList(val) {
//清除空children
const removeNodeInTree = (list) => {
if (!list) return;
for (let i = 0; i < list.length; i++) {
if (list[i].children.length == 0) {
delete list[i].children;
} else {
removeNodeInTree(list[i].children)
}
}
return list
}
/* { name_is_value: true } 获取汉字值的列表 */
get_province_list({ area: val }).then(res => {
console.log('获取省市区数据');
console.log(res);
if (res.length) {
// this.province_list = removeNodeInTree(res);
this.province_data[val] = removeNodeInTree(res);
} else {
// this.province_list = [];
this.province_data[val] = [];
}
})
},
//获取全部烟草等级
getTobaccoAll() {
get_tobacco_all_info().then(res => {
console.log('获取全部烟草品种');
console.log(res);
this.tobacco_all_lists = res || [];
})
},
//获取全部烟草等级
getTobaccoGradesAll() {
get_tobacco_grades_all().then(res => {
console.log('全部烟草等级');
console.log(res);
this.tobacco_grades_all_lists = res || [];
})
},
//新增信息
addInformation() {
this.is_updata_type = 'add';
this.detailed_information = { ...standard_template };
this.detailed_information['question_no'] = this.table_list.length + 1;
//获取当前试题配置图片
get_image_path(this.examination_questions_id).then(res => {
if (res.code == 200) {
this.detailed_information['image'] = res.message || '/';
this.is_dialogVisible = true;
}
})
},
//修改信息
updateInformation(index, item) {
this.is_updata_type = 'edit';
// let id = item.id;
console.log('item单条信息');
console.log(item);
//获取详情
let { id, area, fraction, province_id, breed_name, grades_code, explain_in_detail, image } = { ...item };
this.detailed_information = { id, area, fraction, province_id, breed_name, grades_code, explain_in_detail, image };
this.detailed_information['question_no'] = index + 1;
this.is_dialogVisible = true;
},
//删除
deleteInformation(item) {
let id = item.id;
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_examination_question_detail(id).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.init();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
//试题模版下载
templateDownload() {
let url = `${this.IP}/php_sours/tmpDoc/setThemeCard.docx`;
exportText(url, '模板.docx');
},
//试题上传
uploadTestQuestions(val) {
console.log('试题上传');
console.log(val);
const formData = new FormData();
formData.append('file', val)
let id = this.examination_questions_id;
examination_question_detail_upload(id, formData).then(res => {
console.log('试题上传');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.getExaminationQuestionsDetail();
}
})
},
//图片批量上传
pictureBatchUpload() {
this.is_picture_upload = true;
},
//选择文件监听
seletePicture(file, fileList) {
this.picture_file_list = fileList
},
//图片提交
subMitPictureList() {
console.log('当前文件列表');
console.log(this.picture_file_list);
let formData = new FormData();
this.picture_file_list.forEach(element => {
formData.append('image[]', element.raw);
});
setTimeout(() => {
batch_upload_of_pictures(this.examination_questions_id, '', formData).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.is_picture_upload = false;
this.getExaminationQuestionsDetail();
}
})
}, 300);
},
},
}
</script>
<style lang="scss" scoped>
.small_picture {
width: 40px;
height: 40px;
}
.amplify_img_box {
height: 200px;
img {
max-width: 100%;
max-height: 100%;
}
}
</style>
<!--
* @Author: czj
* @Date: 2023-03-07 11:13:39
* @Description:
* @FilePath: \AdministrationHome\src\views\student\test_questions\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 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="title" label="考试标题">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-document" style="color: #005FC2;"
@click="commentJump(scope.row)">{{ scope.row.title
}}</el-button>
</template>
</el-table-column>
<el-table-column prop="remarks" label="开考备注">
<template slot-scope="scope">
<div class="remark_box" :title="scope.row.remarks">{{ scope.row.remarks }}</div>
</template>
</el-table-column>
<el-table-column prop="begin_date" label="考试时间">
<template slot-scope="scope">
<div>{{ scope.row.begin_date }}</div>
</template>
</el-table-column>
<el-table-column prop="duration" label="考试时长" width="100">
<template slot-scope="scope">
<div>{{ scope.row.duration }}分钟</div>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间">
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<div>
<el-tag v-if="scope.row.status == 1" type="info">未发布</el-tag>
<el-tag v-if="scope.row.status == 2" type="success">已发布</el-tag>
<el-tag v-if="scope.row.status == 3" type="success">开始考试</el-tag>
<el-tag v-if="scope.row.status == 4" type="success">考试完成</el-tag>
<el-tag v-if="scope.row.status == 5" type="success">已点评</el-tag>
<el-tag v-if="scope.row.status == 6" type="danger">停止使用</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="260">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #000;" v-if="scope.row.status != '6'"
@click="updateInformation(scope.row)">修改</el-button>
<!-- <el-button size="mini" type="text" style="color: #000;" @click="commentJump(scope.row)">配置</el-button> -->
<el-button size="mini" type="text" style="color: #000;" title="试题复制"
@click="examinationQuestionsCopy(scope.row)">复制</el-button>
<el-button v-if="scope.row.status != '6'" size="mini" type="text" style="color: #000;"
@click="createAnswerCard(scope.row)" title="生成答题卡">下载</el-button>
<el-button v-if="scope.row.status == '1'" size="mini" type="text" style="color: #000;"
@click="examinationQuestionsPublish(scope.row)" title="试题发布">发布</el-button>
<el-button v-if="scope.row.status != '6'" 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="is_updata_type == 'add' ? '新增考试' : '修改考试'" :visible.sync="is_dialogVisible" width="60%"
:before-close="handleClose">
<div>
<el-form label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="考试标题">
<el-input v-model="detailed_information.title" placeholder="考试标题"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="烟叶类型">
<el-select v-model="detailed_information.type" placeholder="请选择">
<el-option :label="'把烟'" :value="'把烟'"></el-option>
<el-option :label="'片烟'" :value="'片烟'"></el-option>
<el-option :label="'甩把'" :value="'甩把'"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="开始时间">
<el-date-picker v-model="detailed_information.begin_date" type="datetime" placeholder="选择日期时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结束时间">
<el-date-picker v-model="detailed_information.end_date" type="datetime" placeholder="选择日期时间">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="考试时长">
<el-input v-model="detailed_information.duration" placeholder="考试时长" type="number" :min="30">
<template slot="append">分钟</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="考试人数上限">
<el-input v-model="detailed_information.examiners_max" placeholder="考试人数上限" type="number"
:min="1"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="考试提示">
<el-input v-model="detailed_information.opening_tip" placeholder="考试提示" type="textarea"
:rows="2"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="试题备注">
<el-input v-model="detailed_information.remarks" placeholder="试题备注" type="textarea" :rows="2"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</span>
</el-dialog>
<el-dialog title="预约" :visible.sync="is_reservation" width="60%" :before-close="reservationClose">
<div>
<el-form label-width="100px" v-if="is_reservation">
<el-form-item label="选择试题">
<el-select v-model="reservation_info.examination_questions_id" placeholder="请选择" style="width: 300px;">
<el-option v-for="item in examination_questions_all_list" :key="item.id" :label="item.title"
:value="item.id" :disabled="item.status != '2'">
</el-option>
</el-select>
</el-form-item>
</el-form>
<el-tabs v-model="activeName" v-if="reservation_info.examination_questions_id">
<el-tab-pane label="单独预约" name="single">
<el-select v-model="reservation_info.student_id" placeholder="请选择" style="width: 300px;">
<el-option v-for="item in student_all_list" :key="item.value" :label="item.name + '(' + item.idcard + ')'"
:value="item.student_id">
</el-option>
</el-select>
</el-tab-pane>
<el-tab-pane label="批量预约" name="batch">
<el-upload action="#" :auto-upload="false" :on-change="seletePicture">
<el-button size="small" type="primary">点击选择</el-button>
<!-- <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> -->
</el-upload>
</el-tab-pane>
</el-tabs>
</div>
<span slot="footer">
<el-button @click="reservationClose">取 消</el-button>
<el-button type="primary" @click="reservationSubMit">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import TableHead from '@/components/TableHead/index';
import { get_examination_questions_list, add_examination_questions, updata_examination_questions, create_answer_card, examination_questions_copy, examination_questions_publish, delete_examination_questions, get_examination_questions_all, get_student_all, examination_reservation, examination_batch_reservation } from '@/api/student';
import { exportText } from '@/utils/tool';
const standard_template = {
title: "河南把烟测试2",
type: "把烟",
opening_tip: " 1.考生按照省级承办机构公布的报名流程进行网。",
begin_date: "",
end_date: "",
duration: "240",
examiners_max: 100,
remarks: "a"
}
export default {
data() {
return {
activeName: "single",
IP: process.env.VUE_APP_BASE_API,
//头部按钮
head_data: {
// search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-document-add',
event: 'add',
},
{
text: '总评',
icon: 'el-icon-data-analysis',
event: 'analysis',
},
{
text: '预约',
event: 'reservation',
},
// {
// text: '批量预约',
// event: 'batch_reservation',
// }
],
},
//初始化请求参数
request_params: {
val: '',
page: 1,
limit: 10,
total: null,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//详细信息
detailed_information: {},
//预约
is_reservation: false,
//全部学生
student_all_list: [],
//全部试题
examination_questions_all_list: [],
//预约提交
reservation_info: {
examination_questions_id: null,
student_id: null,
},
//批量预约文件
batch_reservation_file: {},
};
},
components: { TableHead },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getListData();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = '';
this.getListData();
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
if (val == 'add') this.addInformation();
if (val == 'reservation') this.reservationFun();
},
init() {
this.getListData();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData() {
let params = this.$handleParams(this.detailed_information);
if (this.is_updata_type == 'add') {
add_examination_questions(params).then(res => {
console.log('新增回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getListData();
}
})
} else {
let id = this.detailed_information.id;
console.log(id);
updata_examination_questions(id, params).then(res => {
console.log('修改回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getListData();
}
})
}
},
//获取列表数据
getListData() {
this.is_loading = true;
let params = this.$removeProperty(this.request_params);
get_examination_questions_list(params).then(res => {
console.log('列表数据');
console.log(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_examination_questions(id).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.init();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
//跳转点评详情
commentJump(item) {
let id = item.id;
this.$router.push({
path: "/student/examination_questions/detail",
query: { id: id },
});
},
//生成答题卡
createAnswerCard(item) {
let id = item.id;
create_answer_card(id).then(res => {
console.log('下载答题卡回调');
console.log(res);
if (res.code == 200) {
let s = res.message.split('=');
let name = s[s.length - 1];
let url = `${this.IP}${res.message}`;
exportText(url, name)
}
})
},
//发布
examinationQuestionsPublish(item) {
let id = item.id;
examination_questions_publish(id).then(res => {
console.log('试题发布回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.getListData();
}
})
},
//试题复制
examinationQuestionsCopy(item) {
console.log('点击触发');
let id = item.id;
examination_questions_copy(id).then(res => {
console.log('试题复制回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.getListData();
}
})
},
//预约点击
//is_reservation
reservationFun() {
//获取全部试题
get_examination_questions_all().then(res => {
console.log('全部试题');
console.log(res);
if (res.length) this.examination_questions_all_list = res || [];
get_student_all().then(result => {
console.log('全部学生列表');
console.log(result);
if (result.length) this.student_all_list = result || [];
this.is_reservation = true;
})
})
},
//取消预约
reservationClose() {
this.is_reservation = false;
},
//选择文件监听
seletePicture(file, fileList) {
this.batch_reservation_file = file;
},
//预约提交
reservationSubMit() {
if (this.reservation_info.examination_questions_id) {
if (this.activeName == 'single') {//单个
let params = this.$handleParams(this.reservation_info);
examination_reservation(params).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.is_reservation = false;
}
})
} else {
let formData = new FormData();
formData.append('file', this.batch_reservation_file.raw);
examination_batch_reservation(this.reservation_info.examination_questions_id, formData).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.is_reservation = false;
}
})
}
} else {
this.$message.warning('请选择试题!');
}
},
},
}
</script>
<style lang="scss" scoped>
.remark_box {
width: 150px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>
<!-- -->
<template>
<router-view></router-view>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {}
}
</script>
<style scoped></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"
@upload="sliderRequest"></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="姓名" width="100">
</el-table-column>
<el-table-column prop="sex" label="性别" width="50">
</el-table-column>
<el-table-column prop="age" label="年龄" width="50">
</el-table-column>
<el-table-column prop="phone" label="手机号">
<template slot-scope="scope">
<div>{{ phoneEncryption(scope.row.phone) }}</div>
</template>
</el-table-column>
<el-table-column prop="idcard" label="证件号">
<template slot-scope="scope">
<div>{{ idcardEncryption(scope.row.idcard) }}</div>
</template>
</el-table-column>
<el-table-column prop="student_id" label="学号" width="80">
</el-table-column>
<el-table-column prop="created_at" label="创建时间">
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<div>
<el-tag v-if="scope.row.status == 1" type="success">正常</el-tag>
<el-tag v-if="scope.row.status == 2 || scope.row.status == 3" type="danger">禁止</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注">
<template slot-scope="scope">
<div class="remark_box" :title="scope.row.remark">{{ scope.row.remark }}
</div>
</template>
</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: #000;" @click="viewDetails(scope.row)">详情</el-button>
<el-button v-if="scope.row.status == 1" 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="is_updata_type == 'view' ? '查看学员' : (is_updata_type == 'add' ? '新增学员' : '修改学员')"
:visible.sync="is_dialogVisible" width="60%" :before-close="handleClose">
<div>
<el-form :model="detailed_information" :rules="rules" ref="ruleForm" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="姓名">
<el-input v-model="detailed_information.name" placeholder="姓名"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="性别">
<el-select v-model="detailed_information.sex" placeholder="请选择" :disabled="is_updata_type == 'view'">
<el-option :label="'男'" :value="'男'">
</el-option>
<el-option :label="'女'" :value="'女'">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="年龄">
<el-input v-model="detailed_information.age" placeholder="年龄"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="籍贯">
<el-input v-model="detailed_information.native_place" placeholder="籍贯" type="textarea" :rows="2"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="省市区">
<el-cascader v-if="province_list" :options="province_list" v-model="detailed_information.linkage_id"
:show-all-levels="false" @change="handleChange" clearable filterable
:disabled="is_updata_type == 'view'"></el-cascader>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工作信息">
<el-input v-model="detailed_information.work_info" placeholder="工作信息" type="textarea" :rows="2"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="证件号">
<el-input v-model="detailed_information.idcard" placeholder="证件号" type="number"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号">
<el-input v-model="detailed_information.phone" placeholder="手机号" type="number"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="邮箱">
<el-input v-model="detailed_information.email" placeholder="邮箱"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="detailed_information.status" :disabled="is_updata_type == 'view'">
<el-radio :label="1">正常</el-radio>
<!-- <el-radio :label="2">禁用</el-radio> -->
<el-radio :label="3">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="开始工作时间">
<el-date-picker v-model="detailed_information.start_working" type="date" placeholder="选择日期"
:disabled="is_updata_type == 'view'">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注">
<el-input v-model="detailed_information.remark" placeholder="备注" type="textarea" :rows="2"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="简介">
<el-input v-model="detailed_information.brief_introduction" placeholder="简介" type="textarea" :rows="2"
:disabled="is_updata_type == 'view'"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<span slot="footer" class="dialog-footer" v-if="is_updata_type != 'view'">
<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_province_list, get_student_list, add_student, delete_student, updat_student, get_student_detail, download_student_info, upload_student_info } from '@/api/student';
import { exportText } from '@/utils/tool.js';
const standard_template = {
name: "",
sex: null,
age: null,
native_place: null,
province: null,
city: null,
area: null,
work_info: null,
idcard: null,
phone: "",
email: "",
remark: null,
status: 1,
start_working: null,
brief_introduction: "",
linkage_id: [],//三级联动id
}
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',
},
{
text: '下载',
icon: 'el-icon-download',
event: 'download',
},
{
text: '上传',
icon: 'el-icon-upload2',
event: 'upload',
},
],
},
//初始化请求参数
request_params: {
val: '',
page: 1,
limit: 10,
total: null,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//全部省市区
province_list: [],
//详细信息
detailed_information: {},
//表单校验
rules: {
name: [
{ required: true, message: '请输入姓名名称', trigger: 'blur' },
],
},
};
},
components: { TableHead },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getListData();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = '';
this.getListData();
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
if (val == 'add') this.addInformation();
if (val == 'download') this.downloadFormwork();
},
init() {
this.getProvinceList();
this.getListData();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData() {
let params = this.$handleParams(this.detailed_information);
console.log('要提交的数据');
console.log(params);
if (this.is_updata_type == 'add') {
add_student(params).then(res => {
console.log('新增回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getListData();
}
})
} else {
let id = this.detailed_information.id;
updat_student(id, params).then(res => {
console.log('修改回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getListData();
}
})
}
},
//获取省市区泪飙
getProvinceList() {
//清除空children
const removeNodeInTree = (list) => {
if (!list) return;
for (let i = 0; i < list.length; i++) {
if (list[i].children.length == 0) {
delete list[i].children;
} else {
removeNodeInTree(list[i].children)
}
}
return list
}
get_province_list({ name_is_value: true }).then(res => {
if (res.length) {
this.province_list = removeNodeInTree(res);
} else {
this.province_list = [];
}
})
},
//获取列表数据
getListData() {
let params = this.$removeProperty(this.request_params);
this.is_loading = true;
get_student_list(params).then(res => {
console.log('列表数据');
console.log(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;
//获取详情
get_student_detail(id).then(res => {
console.log('详细信息');
console.log(res);
this.detailed_information = JSON.parse(JSON.stringify(res)) || {};
this.detailed_information['linkage_id'] = [res.province, res.city, res.area];
this.is_dialogVisible = true;
})
},
//查看详情
viewDetails(item) {
let id = item.id;
this.is_updata_type = 'view';
get_student_detail(id).then(res => {
this.detailed_information = JSON.parse(JSON.stringify(res)) || {};
this.detailed_information['linkage_id'] = [res.province, res.city, res.area];
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: '已取消删除'
});
});
},
//省市区选择监听
handleChange(val) {
console.log('选择的值');
console.log(val);
if (val.length == 3) {
this.detailed_information.province = val[0];//省
this.detailed_information.city = val[1];//市
this.detailed_information.area = val[2];//区
}
},
//下载
downloadFormwork() {
download_student_info({ val: this.request_params.val }).then(res => {
console.log('下载模板');
console.log(res);
if (res.code == 200) {
let str = res.message.split('=');
let url = `${this.IP}${res.message}`;
exportText(url, str[str.length - 1]);
}
})
},
//上传类型的按钮回调
sliderRequest(upload) {
console.log('文件数据');
console.log(upload);
if (upload.btn_code == 'upload') {
const formData = new FormData();
formData.append('file', upload.file)
upload_student_info(formData).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.getListData();
}
})
}
if (upload.btn_code == 'batch_reservation') {
console.log('批量上传');
}
},
//手机号加密
phoneEncryption(phone_number) {
let tel = "" + phone_number;
if (tel.length == 11) {
return tel.substr(0, 3) + "****" + tel.substr(7);
} else {
return phone_number
}
},
//身份证加密
idcardEncryption(id) {
let tel = "" + id;
if (tel.length == 18) {
return tel.substr(0, 4) + "**********" + tel.substr(14);
} else {
return id
}
},
},
}
</script>
<style lang="scss" scoped>
.remark_box {
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.avatar-uploader {
// display: none;
}
</style>
<template>
<div class="module_container">
<div class="card_container">
<el-card class="box-card" style="margin-bottom: 10px;">
<examination-header v-if="student_brief_introduction" :examination_questions="student_brief_introduction"
:key="new Date().getTime()"></examination-header>
</el-card>
<el-card class="box-card" v-if="questions_list.length > 0">
<div class="table_container">
<div class="header_box">
<div class="row_box" v-for="(item, index) in 5" :key="index">
<div class="left">序号</div>
<div class="right">结果</div>
</div>
</div>
<div class="lin_box" v-for="(items, index) in questions_list" :key="index">
<div class="row_box" v-for="(e, i) in items" :key="i">
<div class="left">{{ e.index_number + 1 }}</div>
<div class="right"
:class="e.grades_code && detailed_information.test_results[e.id] != e.grades_code ? 'wrong_answer' : ''">
<el-popover placement="right" trigger="click">
<div class="table_box">
<table border="1" cellspacing="0">
<tr>
<td class="title_box">
<div class="left_box">
我的结果
</div>
</td>
<td>
<div class="right_box"
:class="e.grades_code && detailed_information.test_results[e.id] != e.grades_code ? 'wrong_answer' : ''">
{{ detailed_information.test_results[e.id] || '暂无' }}
</div>
</td>
</tr>
<tr>
<td class="title_box">
<div class="left_box">
烟草区域
</div>
</td>
<td>
<div class="right_box">{{ e.place_of_production || '暂无' }}</div>
</td>
</tr>
<tr>
<td class="title_box">
<div class="left_box">
试题结论
</div>
</td>
<td>
<div class="right_box">{{ e.grades_code || '暂无' }}</div>
</td>
</tr>
<tr>
<td class="title_box">
<div class="left_box">
烟草品种
</div>
</td>
<td>
<div class="right_box">{{ e.breed_name || "暂无" }}</div>
</td>
</tr>
<tr>
<td class="title_box">
<div class="left_box">
试题详解
</div>
</td>
<td>
<div class="right_box">{{ e.explain_in_detail || '暂无' }}</div>
</td>
</tr>
<tr>
<td class="title_box">
<div class="left_box">
烟草实物
</div>
</td>
<td>
<div class="right_box">
<div v-if="e.image && e.image != '/'" class="image_box">
<img :src="IP + e.image" alt="">
</div>
<div v-else>暂无</div>
</div>
</td>
</tr>
</table>
</div>
<!-- <span slot="reference"> {{ e.grades_code || '暂无' }}</span> -->
<span slot="reference"> {{ detailed_information.test_results[e.id] || '暂无' }}</span>
</el-popover>
</div>
</div>
</div>
</div>
</el-card>
</div>
<el-dialog title="提示" :visible.sync="is_dialogVisible" width="60%">
<div class="table_box">
<!-- -->
</div>
<span slot="footer" class="dialog-footer">
<el-button>取 消</el-button>
<el-button type="primary">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import ExaminationHeader from '@/components/ExaminationHeader/index';
import { get_test_results_detail } from '@/api/student';
import { array_conversion } from '@/utils/tool';
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,
//初始化请求参数
request_params: {
val: '',
page: 1,
limit: 10,
total: null,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//头部信息
student_brief_introduction: null,
//详细信息
detailed_information: {},
//考试结果id
test_results_id: null,
//试题结果
questions_list: [],
};
},
components: { ExaminationHeader },
computed: {},
created() {
let id = this.$route.query.id;
if (id) this.test_results_id = id;
},
mounted() {
this.init()
},
methods: {
init() {
this.getTestResultsDetail();
},
//考试结果详情
getTestResultsDetail() {
get_test_results_detail(this.test_results_id).then(res => {
console.log('考试结果详情');
console.log(res);
this.student_brief_introduction = {
title: res.examination_questions_title || '',
user_name: res.name || '',
score: res.score || '',
duration: res.answer_duration || '',
status: res.status,
examination_status: [
{ id: 1, label: '预约完成', type: 'success' },
{ id: 2, label: '考试完成', type: 'success' },
{ id: 3, label: '已发布', type: 'success' },
{ id: 4, label: '取消', type: 'info' },
{ id: 5, label: '失效', type: 'danger' },
],
};
this.questions_list = [];
// if (res.examination_questions) this.questions_list = || [];
res.examination_questions.examination_question_detail.forEach((element, index) => {
let obj = JSON.parse(JSON.stringify(element))
element['index_number'] = index;//用来记录在原始数据中的索引
});
console.log('表格数据源');
console.log(res.examination_questions.examination_question_detail);
let new_arr = array_conversion(res.examination_questions.examination_question_detail, 5);
console.log('二维数据@@@');
console.log(new_arr);
this.questions_list = new_arr;
this.detailed_information = res;
})
},
},
}
</script>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.table_container {
width: 80%;
margin: 0 auto;
border: 1px solid #EBEEF5;
border-radius: 8px;
overflow: hidden;
.header_box {
background-color: $themeColor;
.row_box {
.left,
.right {
color: #fff !important;
}
}
}
.lin_box {
border-bottom: 1px solid #EBEEF5;
}
.row_box {
width: 20%;
float: left;
display: flex;
font-size: 14px;
color: #303133;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
border-right: 1px solid #EBEEF5;
.left {
width: 60px;
text-align: center;
padding: 15px 0;
}
.right {
width: calc(100% - 60px);
text-align: center;
padding: 15px 0;
border-right: 1px solid #EBEEF5;
}
}
}
.header_box::after,
.lin_box::after {
display: block;
content: "";
clear: both;
}
.lin_box .row_box .left {
border-right: 1px solid #EBEEF5;
}
.table_container .lin_box:last-child,
.lin_box .row_box:last-child,
.header_box .row_box:last-child {
border: none;
}
.table_box {
width: 100%;
table {
width: 100%;
border-top: 1px solid #E4E7ED;
border-left: 1px solid #E4E7ED;
border-collapse: collapse;
td {
margin: 0;
padding: 0;
border-bottom: 1px solid #E4E7ED;
border-right: 1px solid #E4E7ED;
}
.title_box {
width: 100px;
}
}
}
.left_box {
padding: 10px 10px;
color: #606266;
text-align: center;
}
.right_box {
width: 400px;
padding: 10px 10px;
color: #303133;
}
.image_box {
width: 100%;
height: 400px;
img {
max-width: 100%;
max-height: 100%;
}
}
.wrong_answer {
background-color: #fdf0f0;
}
</style>
<!-- -->
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {}
}
</script>
<style scoped></style>
<!--
* @Author: czj
* @Date: 2023-03-10 15:24:08
* @Description:
* @FilePath: \AdministrationHome\src\views\student\test_results\list\index.vue
-->
<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="examination_questions_title" label="考试标题">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-document" style="color: #005FC2;"
@click="toDetail(scope.row)">{{ scope.row.examination_questions_title }}</el-button>
</template>
</el-table-column>
<el-table-column prop="name" label="学员姓名">
<template slot-scope="scope">
<div>{{ scope.row.name }}({{ scope.row.student_id }})</div>
</template>
</el-table-column>
<el-table-column prop="begin_answer_time" label="开始时间">
</el-table-column>
<el-table-column prop="answer_duration" label="答题时间" width="100">
<template slot-scope="scope">
<div v-if="scope.row.answer_duration">{{ seconds_to_minutes(scope.row.answer_duration) }}</div>
<div v-else>暂无</div>
</template>
</el-table-column>
<el-table-column prop="score" label="得分">
</el-table-column>
<el-table-column prop="created_at" label="创建时间">
</el-table-column>
<el-table-column prop="path" label="状态">
<template slot-scope="scope">
<div>
<el-tag v-if="scope.row.status == 1" type="success">预约完成</el-tag>
<el-tag v-if="scope.row.status == 2" type="success">考试完成</el-tag>
<el-tag v-if="scope.row.status == 3" type="success">已发布</el-tag>
<el-tag v-if="scope.row.status == 4" type="info">取消</el-tag>
<el-tag v-if="scope.row.status == 6" type="danger">失效</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #F56C6C;" @click="cancelReservation(scope.row)"
v-if="scope.row.status == 1">取消预约</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_test_results_list, cancel_reservation } from '@/api/student';
import { secondsToMinutes } from '@/utils/tool';
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) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getListData();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = null;
this.getListData();
},
btnClick(val) {
console.log('右侧按钮');
console.log(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_test_results_list(params).then(res => {
console.log('列表数据');
console.log(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;
},
//取消预约
cancelReservation(item) {
this.$confirm('确认取消?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let id = item.id;
cancel_reservation(id).then(res => {
console.log('取消预约');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.getListData();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
});
});
},
//跳转详情
toDetail(item) {
console.log('跳转详情');
let id = item.id;
this.$router.push({
path: '/student/test_results/detail',
query: {
id: id
},
})
},
//秒转分
seconds_to_minutes(num) {
if (num) {
return secondsToMinutes(num);
} else {
return '暂无'
}
}
},
}
</script>
<style lang="scss" scoped></style>
<!--
* @Author: czj
* @Date: 2023-03-07 14:41:33
* @Description:
* @FilePath: \AdministrationHome\src\views\student\tobacco_grades\components\dialog.vue
-->
<!-- -->
<template>
<div>
<div style="max-height:700px;overflow-y: auto;">
<el-form label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item label="等级代号">
<el-input v-model="tobacco_grades_info.grade_code"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="代号名称">
<el-input v-model="tobacco_grades_info.grade_name"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="质量档次">
<el-input v-model="tobacco_grades_info.grade"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部位">
<el-input v-model="tobacco_grades_info.position"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="颜色">
<el-input v-model="tobacco_grades_info.color"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="大等级">
<el-input v-model="tobacco_grades_info.large_scale"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="部位+颜色(二等级)">
<el-input v-model="tobacco_grades_info.grade2"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注">
<el-input v-model="tobacco_grades_info.remark" type="textarea" :rows="2"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="同组别紧邻等级">
<div v-for="(item, index) in tobacco_grades_info.adjacent_grade" :key="index" class="input_box">
<el-input v-model="tobacco_grades_info.adjacent_grade[index]"
style="width: calc(100% - 100px);"></el-input>
<el-button v-if="index == tobacco_grades_info.adjacent_grade.length - 1" type="text"
icon="el-icon-circle-plus-outline" title="添加" @click="addData('group')"></el-button>
<el-button class="delete_breed" type="text" icon="el-icon-delete" title="删除"
@click="deleteDate(index, 'group')"></el-button>
</div>
<el-button v-if="tobacco_grades_info.adjacent_grade.length == 0" type="text"
icon="el-icon-circle-plus-outline" title="添加" @click="addData('group')"></el-button>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="外观质量相邻等级">
<div v-for="(item, index) in tobacco_grades_info.quality_adjacent" :key="index" class="input_box">
<el-input v-model="tobacco_grades_info.quality_adjacent[index]"
style="width: calc(100% - 100px);"></el-input>
<el-button v-if="index == tobacco_grades_info.quality_adjacent.length - 1" type="text"
icon="el-icon-circle-plus-outline" title="添加" @click="addData('appearance')"></el-button>
<el-button class="delete_breed" type="text" icon="el-icon-delete" title="删除"
@click="deleteDate(index, 'appearance')"></el-button>
</div>
<el-button v-if="tobacco_grades_info.quality_adjacent.length == 0" type="text"
icon="el-icon-circle-plus-outline" title="添加" @click="addData('appearance')"></el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-form label-width="100px">
<el-row>
<el-col :span="6">
<el-form-item label="一价区">
<el-input v-model="tobacco_grades_info.price1"></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="二价区">
<el-input v-model="tobacco_grades_info.price2"></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="三价区">
<el-input v-model="tobacco_grades_info.price3"></el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="四价区">
<el-input v-model="tobacco_grades_info.price4"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="外观特征">
<div v-for="(item, i) in tobacco_grades_info.appearance_characteristics_list" :key="i" class="input_box">
<el-input v-model="tobacco_grades_info.appearance_characteristics_list[i].label"
style="width: 100px;"></el-input> :
<el-input v-model="tobacco_grades_info.appearance_characteristics_list[i].value"
style="width: calc(100% - 200px)"></el-input>
<el-button v-if="i == tobacco_grades_info.appearance_characteristics_list.length - 1" type="text"
icon="el-icon-circle-plus-outline" title="添加" @click="addData('describe')"></el-button>
<el-button class="delete_breed" type="text" icon="el-icon-delete" title="删除"
@click="deleteDate(i, 'describe')"></el-button>
</div>
<el-button v-if="tobacco_grades_info.appearance_characteristics_list.length == 0" type="text"
icon="el-icon-circle-plus-outline" title="添加" @click="addData('describe')"></el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div style="text-align: right;">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</div>
</div>
</template>
<script>
export default {
props: ['tobacco_grades_infos'],
data() {
return {
tobacco_grades_info: {},//烟草信息
};
},
components: {},
computed: {},
created() {
this.tobacco_grades_info = JSON.parse(JSON.stringify(this.tobacco_grades_infos));
},
mounted() {
console.log('详情数据');
console.log(this.tobacco_grades_info);
},
methods: {
//取消
handleClose() {
this.$emit('handleClose');
},
//确认
submitData() {
const process_data = (list) => {
let data = { ...list };
delete data.appearance_characteristics_list;
data.appearance_characteristics = {};
if (list.appearance_characteristics_list.length > 0) {
list.appearance_characteristics_list.forEach(element => {
data.appearance_characteristics[element.label] = element.value || '';
});
}
return data;
}
let data = process_data(this.tobacco_grades_info);
this.$emit('submitData', data)
},
//添加数据
addData(type) {
if (type == 'group') {//同组
this.tobacco_grades_info.adjacent_grade.push('');
} else if (type == 'appearance') {//外观
this.tobacco_grades_info.quality_adjacent.push('');
} else if (type == 'describe') {//描述
this.tobacco_grades_info.appearance_characteristics_list.push({ label: '', value: '' });
}
},
//删除数据
deleteDate(index, type) {
if (type == 'group') {//同组
this.tobacco_grades_info.adjacent_grade.splice(index, 1);
} else if (type == 'appearance') {//外观
this.tobacco_grades_info.quality_adjacent.splice(index, 1);
} else if (type == 'describe') {//描述
this.tobacco_grades_info.appearance_characteristics_list.splice(index, 1);
}
},
}
}
</script>
<style scoped>
.input_box {
margin-bottom: 10px;
}
.delete_breed {
color: red;
}
</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="grade" label="品种等级">
<template slot-scope="scope">
<div>{{ scope.row.grade_code }}</div>
<div>{{ scope.row.grade_name }}</div>
</template>
</el-table-column>
<el-table-column prop="appearance_characteristics" label="等级外观特征">
<template slot-scope="scope">
<el-popover placement="right" trigger="hover">
<div v-for="(item, key, index) in scope.row.appearance_characteristics" :key="index">
<span>{{ key }}</span> :
<span>{{ scope.row.appearance_characteristics[key] }}</span>
</div>
<el-button slot="reference" type="text" size="mini" title="点击查看">. . .</el-button>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="price1" label="一价区" width="100">
<template slot-scope="scope"><span>¥{{ scope.row.price1 }}</span></template>
</el-table-column>
<el-table-column prop="price2" label="二价区" width="100">
<template slot-scope="scope"><span>¥{{ scope.row.price2 }}</span></template>
</el-table-column>
<el-table-column prop="price3" label="三价区" width="100">
<template slot-scope="scope"><span>¥{{ scope.row.price3 }}</span></template>
</el-table-column>
<el-table-column prop="remark" label="备注">
</el-table-column>
<el-table-column prop="adjacent_grade" label="同组别紧邻等级">
<template slot-scope="scope">
<div v-for="(item, index) in scope.row.adjacent_grade" :key="index">
<span>{{ item }},</span>
</div>
</template>
</el-table-column>
<el-table-column prop="quality_adjacent" label="外观质量相邻等级">
<template slot-scope="scope">
<div v-for="(item, index) in scope.row.quality_adjacent" :key="index">
<span>{{ item }},</span>
</div>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间">
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #000;"
@click="editTobaccoGrades(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C;"
@click="deleteTobaccoGrades(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="is_updata_type == 'add' ? '新增烟草品级' : '修改烟草品级'" :visible.sync="is_dialogVisible" width="60%"
top="50px" :before-close="handleClose">
<div>
<Dialog v-if="is_dialogVisible" :tobacco_grades_infos="tobacco_grades_info" @handleClose="handleClose"
@submitData="submitData"></Dialog>
</div>
</el-dialog>
</div>
</template>
<script>
import TableHead from '@/components/TableHead/index';
import Dialog from './components/dialog.vue';
import { get_tobacco_grades_all, get_tobacco_grades_list, add_tobacco_grades, delete_tobacco_grades, updata_tobacco_grades, get_tobacco_grades_detail } from '@/api/student';
const standard_template = {
grade_code: "",
grade_name: "",
grade: "",
position: "",
color: "",
large_scale: "",
grade2: "",
adjacent_grade: [],
quality_adjacent: [],
price1: "",
price2: "",
price3: "",
price4: "",
price_other: "",
appearance_characteristics: {},
appearance_characteristics_list: [],
remark: ""
}
export default {
data() {
return {
//头部按钮
head_data: {
// search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-plus',
event: 'add',
}
],
},
//初始化请求参数
request_params: {
val: "",
page: 1,
limit: 10,
total: null,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//烟草品级信息
tobacco_grades_info: {},
//全部烟草品级,用来选择
};
},
components: { TableHead, Dialog },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getTobaccoGradesList();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = null;
this.getTobaccoGradesList();
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
if (val == 'add') this.addTobaccoGrades();
},
init() {
// this.getTobaccoGradesAll();
this.getTobaccoGradesList();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData(val) {
console.log('接受到的数据');
console.log(val);
let params = this.$handleParams(val);
if (this.is_updata_type == 'add') {
add_tobacco_grades(params).then(res => {
console.log('新增');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getTobaccoGradesList();
}
})
} else {
let id = val.id;
updata_tobacco_grades(id, params).then(res => {
console.log('修改');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getTobaccoGradesList();
}
})
}
},
//获取全部烟草品级
getTobaccoGradesAll() {
get_tobacco_grades_all().then(res => {
console.log('全部烟草');
console.log(res);
let list = res.map(item => {
return { label: item.grade_name, value: item.grade_code }
})
console.log(list);
})
},
//获取列表
getTobaccoGradesList() {
this.is_loading = true;
let params = this.$removeProperty(this.request_params);
get_tobacco_grades_list(params).then(res => {
console.log('烟草等级列表');
console.log(res);
this.tableData = res.data || [];
this.request_params.total = res.total;
this.is_loading = false;
})
},
//分页
handleCurrentChange(val) {
this.request_params.page = val;
this.getTobaccoGradesList();
},
//新增
addTobaccoGrades() {
this.is_updata_type = 'add';
this.tobacco_grades_info = { ...standard_template };
this.is_dialogVisible = true;
},
//修改
editTobaccoGrades(item) {
this.is_updata_type = 'edit';
let id = item.id;
get_tobacco_grades_detail(id).then(res => {
console.log('获取详情');
console.log(res);
this.tobacco_grades_info = { ...res };
this.tobacco_grades_info.appearance_characteristics_list = [];
for (const key in res.appearance_characteristics) {
this.tobacco_grades_info.appearance_characteristics_list.push({ label: key, value: res.appearance_characteristics[key] })
}
this.is_dialogVisible = true;
})
},
//删除
deleteTobaccoGrades(item) {
let id = item.id;
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_tobacco_grades(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-28 18:37:15
* @Description:
* @FilePath: \AdministrationHome\src\views\system\administrators\index.vue
-->
<!-- -->
<template>
<div>
<div class="card_container">
<el-card class="box-card">
<!-- <table-head :add_text="'管理员'" :add_icon="'el-icon-s-custom'" @search="searchEvent" @resetting="resetting"
@add="infoUpdata(null)"></table-head> -->
<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="administrators_list" style="width: 100%" height="650">
<el-table-column prop="id" label="编号"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column prop="phone" label="手机号"></el-table-column>
<el-table-column prop="created_at" label="创建时间"></el-table-column>
<el-table-column prop="status" label="状态">
<template slot-scope="scope">
<div>
<el-tag v-if="scope.row.status == 1" type="success">正常</el-tag>
<el-tag v-if="scope.row.status == 2" type="danger">禁止</el-tag>
<el-tag v-if="scope.row.status == 3" type="info" color="#f4f4f5">失效</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="address" label="操作">
<template slot-scope="scope">
<div>
<el-button size="mini" type="text" style="color: #000;" @click="infoUpdata(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C;"
@click="deleteAdmin(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div style="text-align: right;">
<el-pagination @current-change="handleCurrentChange" :current-page.sync="params.page"
:page-size="params.limit" layout="total, prev, pager, next" :total="params.total">
</el-pagination>
</div>
</div>
</el-card>
</div>
<el-dialog :title="is_type == 'add' ? '新增管理员' : '编辑管理员'" :visible.sync="is_dialogVisible" width="1024px"
:before-close="handleClose" :class="is_type == 'add' ? 'add_dialog' : 'edit_dialog'">
<div>
<el-row>
<el-col :span="10" v-if="user_type == 1">
<div class="head_container">
<el-upload class="avatar-uploader" :action="upload_action" :show-file-list="false"
accept="image/png,image/jpeg,image/jpg" :http-request="sliderRequest">
<img v-if="administrators_info.image" :src="upload_action + administrators_info.image" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
<div class="prompt_text">只能上传jpg/png文件,且不超过500kb</div>
</div>
</el-col>
<el-col :span="14">
<el-form :model="administrators_info" :rules="info_rules" ref="ruleForm" label-width="100px"
class="demo-ruleForm">
<el-form-item label="用户类型" v-if="is_type == 'add'">
<el-radio-group v-model="user_type">
<el-radio :label="1">普通用户</el-radio>
<el-radio :label="2">老师</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="administrators_info.name" placeholder="请输入名称"
:disabled="is_type == 'add' ? false : true"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone" v-if="user_type == 1">
<el-input v-model="administrators_info.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email" v-if="user_type == 1">
<el-input v-model="administrators_info.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="administrators_info.password" placeholder="请输入密码" :type="passwordType">
<i slot="suffix" class="el-input__icon el-icon-view" @click="showPwd"></i>
</el-input>
</el-form-item>
<el-form-item label="状态" prop="password" v-if="user_type == 1">
<el-radio-group v-model="administrators_info.status">
<el-radio :label="1">正常</el-radio>
<el-radio :label="2">禁止</el-radio>
<el-radio :label="3">失效</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="角色" prop="password">
<el-select v-model="administrators_info.role_id" placeholder="请选择">
<el-option v-for="item in roles_list" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="submitInfo">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { get_administrators_list, add_administrators, delete_administrators, edit_administrators, get_administrators_detail, upload_head, create_temporary } from '@/api/system.js';
import { get_roles_all } from '@/api/role';
import TableHead from '@/components/TableHead/index';
const admin_info = {
id: null,
name: null,
phone: null,
email: null,
password: null,
role_id: 1,
image: '/php_sours/userimg/2023_03_02/16777479118474.jpg',
status: 1,
}
export default {
data() {
return {
//头部按钮
head_data: {
// search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-s-custom',
event: 'add',
}
],
},
is_loading: false,
params: {
val: '',
page: 1,
limit: 10,
total: 1,
},
administrators_list: [],
is_dialogVisible: false,
is_type: 'add',
administrators_info: {},
info_rules: {
name: [
{ required: true, message: '请输入名称', trigger: 'blur' },
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
],
// password: [
// { required: true, message: '请输入密码', trigger: 'blur' },
// ],
},
upload_action: `${process.env.VUE_APP_BASE_API}`,
passwordType: 'password',//输入框的类型,密码框
user_type: 1,//创建用户类型 老师,普通用户
roles_list: [],
};
},
components: { TableHead },
computed: {},
mounted() {
this.getAdministratorsList();
this.getRolesAll();
},
methods: {
//获取全部角色
getRolesAll() {
get_roles_all().then(res => {
console.log('获取全部角色');
console.log(res);
this.roles_list = res || [];
})
},
//获取管理员列表
getAdministratorsList() {
let params = {
val: this.params.val,
page: this.params.page,
limit: this.params.limit
}
this.is_loading = true;
get_administrators_list(params).then(res => {
console.log('获取管理员列表');
console.log(res);
if (res.data.length > 0) {
res.data.forEach(element => {
if (element.role.length > 0) {
element['role_id'] = element.role[0].id
} else {
element['role_id'] = null
}
});
}
this.administrators_list = res.data;
this.params.total = res.total;
this.is_loading = false;
})
},
//分页
handleCurrentChange(val) {
this.params.page = val;
this.getAdministratorsList();
},
//搜索
searchEvent(val) {
console.log('搜索内容');
console.log(val);
this.params.val = val;
this.getAdministratorsList();
},
//重置
resetting() {
this.params.val = null;
this.getAdministratorsList();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//新增修改
infoUpdata(item) {
console.log(item);
if (item) {//修改
this.is_type = 'edit';
this.user_type = 1;//控制用户类型
this.administrators_info = { ...item };
} else {//新增
this.is_type = 'add';
this.administrators_info = { ...admin_info };
}
this.is_dialogVisible = true;
},
btnClick() {
this.infoUpdata(null);
},
//删除
deleteAdmin(item) {
let id = item.id;
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_administrators(id).then(res => {
console.log('删除回调');
console.log(res);
if (res.code == 200) {
this.$message.success('删除成功!');
this.getAdministratorsList();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
//密码框和输入框切换
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = 'password'
}
},
//上传
sliderRequest(upload) {
console.log('上传');
console.log(upload);
const formData = new FormData();
formData.append('image', upload.file)
upload_head(formData).then(res => {
console.log('上传回调');
console.log(res);
if (res.err_code == 200) {
this.administrators_info.image = res.message;
this.$message.success('上传成功');
}
})
},
//提交
submitInfo() {
this.$refs['ruleForm'].validate((valid) => {
if (valid) {
let data = {
id: this.administrators_info.id,
name: this.administrators_info.name,
phone: this.administrators_info.phone,
email: this.administrators_info.email,
password: this.administrators_info.password,
roles: this.administrators_info.role_id,
image: this.administrators_info.image,
status: this.administrators_info.status,
}
let params = this.$handleParams(data);
if (this.is_type == 'add') {
console.log(params);
if (this.user_type == 1) {//创建普通用户
add_administrators(params).then(res => {
console.log('新增用户回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getAdministratorsList();
}
})
} else {//创建老师用户
let temporary = {
name: this.administrators_info.name,
password: this.administrators_info.password,
roles: this.administrators_info.role_id,
}
let temporary_data = this.$handleParams(temporary);
create_temporary(temporary_data).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getAdministratorsList();
}
})
}
} else {
let id = this.administrators_info.id;
edit_administrators(id, params).then(res => {
console.log('修改');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getAdministratorsList();
}
})
}
} else {
console.log('error submit!!');
return false;
}
});
},
}
}
</script>
<style lang="scss" scoped>
.search_box {
width: 200px;
margin-right: 15px;
}
.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;
}
}
.head_container {
text-align: center;
margin: 30px 0;
.prompt_text {
font-size: 12px;
color: #606266;
margin-top: 15px;
}
}
</style>
<!--
* @Author: czj
* @Date: 2023-02-28 18:37:15
* @Description:
* @FilePath: \AdministrationHome\src\views\system\department\index.vue
-->
<!-- -->
<template>
<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" border
row-key="id" default-expand-all :tree-props="{ children: 'children', hasChildren: '' }">
<el-table-column prop="department_name" label="部门名称">
</el-table-column>
<el-table-column prop="leader" label="部门领导">
</el-table-column>
<el-table-column prop="phone" label="电话">
</el-table-column>
<el-table-column prop="email" label="邮箱">
</el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template slot-scope="scope">
<el-tag v-if="scope.row.status == 1" type="success">正常</el-tag>
<el-tag v-if="scope.row.status == 2" type="info">失效</el-tag>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间">
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #000;" @click="addDepartment(scope.row)">新增</el-button>
<el-button size="mini" type="text" style="color: #000;" @click="editDepartment(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C;"
@click="deleteDepartment(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</div>
<el-dialog title="提示" :visible.sync="is_dialogVisible" width="60%" :before-close="handleClose">
<div>
<el-form label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item label="上级部门">
<treeselect v-model="department_info.department_id" :options="tree_select_list" :normalizer="normalizer"
:show-count="true" placeholder="选择上级菜单" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门名称">
<el-input placeholder="请输入部门名称" v-model="department_info.department_name" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="部门邮箱">
<el-input placeholder="请输入邮箱" v-model="department_info.email" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话">
<el-input placeholder="请输入电话" v-model="department_info.phone" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="领导姓名">
<el-input placeholder="请输入邮箱" v-model="department_info.leader" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="排序">
<el-input-number controls-position="right" :min="1" v-model="department_info.sort" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门状态">
<el-radio-group v-model="department_info.status">
<el-radio :label="1">正常</el-radio>
<el-radio :label="2">失效</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
</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';
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
const standard_template = {
department_id: -1,
department_name: null,
email: null,
phone: null,
leader: null,
sort: 0,
status: 1,
}
export default {
data() {
return {
//头部按钮
head_data: {
// search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-plus',
event: 'add',
}
],
},
//初始化请求参数
request_params: {
val: '',//搜索
page: 1,
limit: 10,
total: 1,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//树菜单选择
tree_select_list: [],
//部门信息
department_info: {},
};
},
components: { TableHead, Treeselect },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getDepartmentList();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = '';
this.getDepartmentList();
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
if (val == 'add') {
this.addDepartment(null);
}
},
init() {
this.getDepartmentList();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData() {
let data = {
department_id: this.department_info.department_id == -1 ? null : this.department_info.department_id,
department_name: this.department_info.department_name,
email: this.department_info.email,
phone: this.department_info.phone,
leader: this.department_info.leader,
sort: this.department_info.sort,
status: this.department_info.status,
}
let params = this.$handleParams(data);
if (this.is_updata_type == 'add') {
add_department(params).then(res => {
console.log('新增部门');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.init();
}
})
} else {
let id = this.department_info.id;
edit_department(id, params).then(res => {
console.log('修改回调');
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.init();
}
})
}
},
//获取部门列表
getDepartmentList() {
let params = this.$removeProperty(this.request_params);
console.log('请求参数');
console.log(params);
this.is_loading = true;
this.tree_select_list = [];
get_department_list(params).then(res => {
console.log('部门列表');
console.log(res);
this.tableData = res || [];
const menu = { id: -1, department_name: '主类目', children: [] };
menu.children = res;
this.tree_select_list.push(menu);
this.is_loading = false;
})
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) delete node.children;
return { id: node.id, label: node.department_name, children: node.children };
},
//新增
addDepartment(item) {
this.is_updata_type = 'add';
if (item) {
this.department_info = { ...standard_template };
this.department_info.department_id = item.id;
} else {
this.department_info = { ...standard_template };
}
this.is_dialogVisible = true;
},
//修改
editDepartment(item) {
this.is_updata_type = 'edit';
this.department_info = { ...item };
this.is_dialogVisible = true;
},
//删除
deleteDepartment(item) {
let id = item.id;
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_department(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-28 18:30:35
* @Description:
* @FilePath: \AdministrationHome\src\views\permission\index.vue
-->
<!-- -->
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {
};
},
components: {},
computed: {},
mounted() { },
methods: {}
}
</script>
<style scoped></style>
<!--
* @Author: czj
* @Date: 2023-02-28 18:37:15
* @Description:
* @FilePath: \AdministrationHome\src\views\system\log\index.vue
-->
<!-- -->
<template>
<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="id" label="序号">
</el-table-column>
<el-table-column prop="username" label="操作人">
</el-table-column>
<el-table-column prop="title" label="操作名称">
</el-table-column>
<el-table-column prop="intro" label="操作内容">
</el-table-column>
<el-table-column prop="created_at" label="操作时间">
</el-table-column>
<!-- <el-table-column label="操作" width="120">
<template slot-scope="scope">
</template>
</el-table-column> -->
</el-table>
<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>
</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_system_log, search_system_log } 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);
search_system_log({ val: val }).then(res => {
console.log('搜索');
console.log(res);
this.tableData = res.data;
this.request_params.total = res.total;
this.is_loading = false;
})
},
resetting(val) {
console.log('重置');
console.log(val);
search_system_log({ val: val }).then(res => {
console.log('搜索');
console.log(res);
this.tableData = res.data;
this.request_params.total = res.total;
this.is_loading = false;
})
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
},
init() {
this.getSystemLog();
},
//获取列表
getSystemLog() {
let params = {
page: this.request_params.page,
limit: this.request_params.limit
}
this.is_loading = true;
get_system_log(params).then(res => {
console.log('获取列表');
console.log(res);
this.tableData = res.data;
this.request_params.total = res.total;
this.is_loading = false;
})
},
//翻页
handleCurrentChange(val) {
this.request_params.page = val;
this.getSystemLog();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData() {
},
},
}
</script>
<style lang="scss" scoped></style>
<!--
* @Author: czj
* @Date: 2023-02-28 18:37:15
* @Description:
* @FilePath: \AdministrationHome\src\views\system\menu\index.vue
-->
<!-- -->
<template>
<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"
row-key="id" border default-expand-all :tree-props="{ children: 'children', hasChildren: '' }">
<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 prop="type" label="类型" width="80">
<template slot-scope="scope">
<div>
<el-tag v-if="scope.row.type == 1">菜单</el-tag>
<el-tag v-else type="info">按钮</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="80">
<template slot-scope="scope">
<div>
<el-tag v-if="scope.row.status == 1" type="success">正常</el-tag>
<el-tag v-if="scope.row.status == 2" type="danger">禁止</el-tag>
<el-tag v-if="scope.row.status == 3" type="info">失效</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" width="160"></el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #000;" v-if="scope.row.type == 1"
@click="addMenu(scope.row)">新增</el-button>
<el-button size="mini" type="text" style="color: #000;" @click="editMenu(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C;" @click="deleteMenu(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</div>
<el-dialog title="提示" :visible.sync="is_dialogVisible" width="60%" :before-close="handleClose">
<div>
<el-form label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item label="上级菜单">
<treeselect v-model="menu_info.father_id" :options="tree_select_list" :normalizer="normalizer"
:show-count="true" placeholder="选择上级菜单" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="展示为菜单">
<el-radio-group v-model="menu_info.is_show">
<el-radio :label="true">是</el-radio>
<el-radio :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="菜单类型:">
<el-radio-group v-model="menu_info.type">
<el-radio :label="1">菜单</el-radio>
<el-radio :label="2">按钮</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="menu_info.type == 1 ? '菜单状态:' : '按钮状态:'">
<el-radio-group v-model="menu_info.status">
<el-radio :label="1">正常</el-radio>
<el-radio :label="2">禁止</el-radio>
<el-radio :label="3">失效</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item :label="menu_info.type == 1 ? '菜单名称(中文):' : '按钮名称(中文):'">
<el-input placeholder="请输入菜单名称" v-model="menu_info.name_zh" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="menu_info.type == 1 ? '菜单名称(English):' : '按钮名称(English):'">
<el-input placeholder="请输入菜单名称" v-model="menu_info.name" />
</el-form-item>
</el-col>
</el-row>
<el-row v-if="menu_info.type == 1">
<el-col :span="12">
<el-form-item label="路由地址:">
<el-input placeholder="请输入路由地址" v-model="menu_info.path" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="组件地址:">
<el-input placeholder="请输入菜单名称" v-model="menu_info.view_path" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="显示排序">
<el-input-number controls-position="right" :min="0" v-model="menu_info.sort" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="icon:">
<el-input />
</el-form-item>
</el-col>
</el-row>
</el-form>
</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_permission_tree, get_permission_btn_menu, add_permission_menu, delete_permission_menu, edit_permission_menu } from '@/api/system';
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
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-plus',
event: 'add',
}
],
},
request_params: {
val: '',
},
is_loading: false,
tableData: [],
tree_select_list: [],//树状菜单选择
is_dialogVisible: false,
menu_info: {},
is_updata_type: 'add',
};
},
components: { Treeselect, TableHead },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getPermissionTree();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = '';
this.getPermissionTree();
},
btnClick(val) {
this.addMenu(null);
},
init() {
this.getPermissionTree();
this.getPermissionBtnMenu();
},
//获取树菜单
getPermissionTree() {
this.is_loading = true;
this.tree_select_list = [];
let params = this.$removeProperty(this.request_params);
get_permission_tree(params).then(res => {
console.log('树菜单数据');
console.log(res);
this.tableData = res || [];
//tree_select_list
const menu = { id: -1, name_zh: '主类目', type: 1, children: [] };
menu.children = res;
this.tree_select_list.push(menu);
this.is_loading = false;
})
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
if (node.type == 1) {
return {
id: node.id,
label: node.name_zh,
children: node.children
};
}
},
//获取菜单、按钮分类
getPermissionBtnMenu() {
get_permission_btn_menu().then(res => {
console.log('获取菜单、按钮分类》》》》》》》》》》》》》');
console.log(res);
})
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//新增
addMenu(item) {
this.is_updata_type = 'add';
if (item) {//有父级的新增
this.menu_info = { ...standard_template };
this.menu_info.father_id = item.id;
} else {
this.menu_info = { ...standard_template };
}
this.is_dialogVisible = true;
},
//编辑
editMenu(item) {
this.is_updata_type = 'edit';
this.menu_info = { ...item };
this.is_dialogVisible = true;
},
//提交
submitData() {
let data = {
id: this.menu_info.id,
father_id: this.menu_info.father_id,//父级id
is_show: this.menu_info.is_show,//是否展示为菜单
name: this.menu_info.name,//英文名称
name_zh: this.menu_info.name_zh,//中文名称
path: this.menu_info.path,//路由路径
sort: this.menu_info.sort,//排序
status: this.menu_info.status,//状态
type: this.menu_info.type,//类型:菜单/按钮
view_path: this.menu_info.view_path,//视图路径
// icon: this.menu_info.icon,//图标
}
if (data.father_id == -1) data.father_id = null;
console.log('需要提交的数据');
console.log(data);
let params = this.$handleParams(data);
if (this.is_updata_type == 'add') {
add_permission_menu(params).then(res => {
console.log('添加菜单回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.init();
}
})
} else {
let id = data.id;
console.log('修改提交的数据');
console.log(data);
edit_permission_menu(id, params).then(res => {
console.log('添加菜单回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.init();
}
})
}
},
//删除菜单
deleteMenu(item) {
let id = item.id;
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_permission_menu(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>
.search_box {
width: 200px;
margin-right: 15px;
}
.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;
}
}
.head_container {
text-align: center;
margin: 30px 0;
.prompt_text {
font-size: 12px;
color: #606266;
margin-top: 15px;
}
}
</style>
<!--
* @Author: czj
* @Date: 2023-02-28 18:37:15
* @Description:
* @FilePath: \AdministrationHome\src\views\system\roles\index.vue
-->
<!-- -->
<template>
<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="id" label="角色ID">
</el-table-column>
<el-table-column prop="name" label="角色名称">
</el-table-column>
<el-table-column prop="created_at" label="创建时间">
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #000;" @click="editRoles(scope.row)">编辑</el-button>
<el-button size="mini" type="text" style="color: #F56C6C;" @click="deleteRoles(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="600" :before-close="handleClose">
<div style="overflow-y: auto;height: 600px;">
<el-form label-width="100px">
<el-form-item label="角色ID" v-if="roles_info.id">
<el-input v-model="roles_info.id" disabled></el-input>
</el-form-item>
<el-form-item label="角色名称">
<el-input v-model="roles_info.name"></el-input>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="授权菜单">
<el-tree ref="routeTree" :data="router_tree" show-checkbox node-key="id"
:default-checked-keys="roles_info.permission" :props="defaultProps"
:key="new Date().getTime()"></el-tree>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="授权功能">
<el-tree ref="buttonTree" :data="button_tree" show-checkbox node-key="id"
:default-checked-keys="roles_info.permissionButton" :props="defaultProps"
:key="new Date().getTime()"></el-tree>
</el-form-item>
</el-col>
</el-row>
</el-form>
</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_permission_list, add_roles, delete_roles, edit_roles, get_permission_detail } from '@/api/role';
import { get_permission_btn_menu } from '@/api/system';
import { button_tree_add, route_tree_all } from '@/utils/route-handle';
const standard_template = {
id: null,
name: '',
permission: [],
permissionButton: [],
}
export default {
data() {
return {
//头部按钮
head_data: {
// search_placeholder: "学员姓名/手机号",
right_buttons: [
{
text: '新增',
icon: 'el-icon-user-solid',
event: 'add',
}
],
},
//初始化请求参数
request_params: {
val: '',//搜索
page: 1,
limit: 10,
total: 1,
},
is_loading: false,
tableData: [],
is_dialogVisible: false,
is_updata_type: 'add',
//角色信息
roles_info: {},
//路由树
router_tree: [],
//按钮树
button_tree: [],
defaultProps: {
children: 'children',
label: 'name_zh'
}
};
},
components: { TableHead },
computed: {},
mounted() {
this.init()
},
methods: {
searchEvent(val) {
console.log('搜索');
console.log(val);
this.request_params.val = val;
this.getPermissionList();
},
resetting(val) {
console.log('重置');
console.log(val);
this.request_params.val = '';
this.getPermissionList();
},
btnClick(val) {
console.log('右侧按钮');
console.log(val);
if (val == 'add') this.addRoles();
},
init() {
this.getPermissionBtnMenu();
this.getPermissionList();
},
//取消
handleClose() {
this.is_dialogVisible = false;
},
//提交
submitData() {
console.log('提交的数据');
console.log(this.roles_info);
let router_key = this.$refs.routeTree.getCheckedNodes(false, true);
let button_key = this.$refs.buttonTree.getCheckedNodes(false, true);
let route_ids = router_key.map(item => { return item.id });
let button_ids = button_key.map(item => { return item.id });
let data = this.$handleParams({
name: this.roles_info.name,
permission: router_key.map(item => { return item.id }),
permissionButton: button_key.map(item => { return item.id })
})
console.log('要提交的数据');
console.log(data);
if (this.is_updata_type == 'add') {
add_roles(data).then(res => {
console.log("新增角色回调");
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getPermissionList();
}
})
} else {
let id = this.roles_info.id;
edit_roles(id, data).then(res => {
console.log('修改角色回调');
console.log(res);
if (res.code == 200) {
this.$message.success(res.message);
this.is_dialogVisible = false;
this.getPermissionList();
}
})
}
},
//分页
handleCurrentChange(val) {
this.request_params.page = val;
this.getPermissionList();
},
//获取 全部 按钮/路由分类数据
getPermissionBtnMenu() {
get_permission_btn_menu().then(res => {
console.log('获取全部路由按钮数据');
console.log(res);
let permission = JSON.parse(JSON.stringify(res.permission)),
permissionButton = JSON.parse(JSON.stringify(res.permissionButton));
this.router_tree = route_tree_all(permission);
this.button_tree = button_tree_add(permissionButton, permission);
console.log('结构数据@@@@@@@@@@@@@@@@@@@@@');
console.log(this.router_tree);
console.log(this.button_tree);
})
},
//获取角色列表
getPermissionList() {
let params = this.$removeProperty({
val: this.request_params.val,
page: this.request_params.page,
limit: this.request_params.limit,
});
this.is_loading = true;
get_permission_list(params).then(res => {
console.log('角色列表');
console.log(res);
this.tableData = res.data || [];
this.request_params.total = res.total;
this.is_loading = false;
})
},
//新增
addRoles() {
this.is_updata_type = 'add';
this.is_dialogVisible = true;
this.roles_info = { ...standard_template };
},
//修改
editRoles(item) {
this.is_updata_type = 'edit';
//序号获取详情
get_permission_detail(item.id).then(res => {
this.roles_info = res;
})
this.is_dialogVisible = true;
},
//删除
deleteRoles(item) {
let id = item.id;
this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete_roles(id).then(res => {
if (res.code == 200) {
this.$message.success(res.message);
this.getPermissionList();
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
},
}
</script>
<style lang="scss" scoped></style>
......@@ -6,7 +6,7 @@ function resolve(dir) {
return path.join(__dirname, dir)
}
const name = defaultSettings.title || 'vue Element Admin' // page title
const name = defaultSettings.title || '烟草质检管理' // page title
// If your port is set to 80,
// use administrator privileges to execute the command line.
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论