合并发布:接入全系统角色专属职业正装头像体系

This commit is contained in:
wangzhibiao committed 2026-10-10 08:59:51 +00:00
commit 9a62ac8536
152 files changed
+102 -198

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

+4 -3
View File
@@ -32,6 +32,7 @@ import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import { getRoleAvatar } from '@/utils/avatar'
export default {
components: {
@@ -41,7 +42,6 @@ export default {
},
data() {
return {
defaultAvatar: require('@/assets/images/profile.jpg'),
avatarLoadFailed: false
}
},
@@ -49,11 +49,12 @@ export default {
...mapGetters([
'sidebar',
'avatar',
'device'
'device',
'roles'
]),
avatarSrc() {
if (this.avatarLoadFailed || !this.avatar) {
return this.defaultAvatar
return getRoleAvatar(this.roles)
}
return this.avatar
},
+7 -1
View File
@@ -1,5 +1,6 @@
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken, setDpToken } from '@/utils/auth'
import { getRoleAvatar } from '@/utils/avatar'
import axios from 'axios'
import {setting} from "@/config";
@@ -85,7 +86,12 @@ const user = {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.user
const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
const isBrokenAvatar = user.avatar && user.avatar.includes('899d3f8e438f427eac6aeec76e489b52')
const avatar = (user.avatar == "" || user.avatar == null || isBrokenAvatar)
? getRoleAvatar(res.roles)
: (user.avatar.indexOf('http') === 0 || user.avatar.indexOf('data:') === 0
? user.avatar
: process.env.VUE_APP_BASE_API + user.avatar);
// 先写入业务身份标志,保证角色就绪时自服务判定已同步到位;后端未返回时按无身份处理
commit('SET_SELF_SERVICE', res.selfService)
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
+66
View File
@@ -0,0 +1,66 @@
import defaultAvatar from '@/assets/images/avatars/default.jpg'
import adminAvatar from '@/assets/images/avatars/admin.jpg'
import trainAdminAvatar from '@/assets/images/avatars/train_admin.jpg'
import teacherAvatar from '@/assets/images/avatars/teacher.jpg'
import studentAvatar from '@/assets/images/avatars/student.jpg'
export {
defaultAvatar,
adminAvatar,
trainAdminAvatar,
teacherAvatar,
studentAvatar
}
/**
* 根据用户角色判定合适的职业默认头像
* @param {Array|string} roles 用户角色数组或角色key
* @returns {string} 头像资源路径
*/
export function getRoleAvatar(roles) {
if (!roles) return defaultAvatar
const roleList = Array.isArray(roles) ? roles : [roles]
if (roleList.includes('admin')) {
return adminAvatar
}
if (roleList.includes('train_admin')) {
return trainAdminAvatar
}
if (roleList.includes('train_teacher')) {
return teacherAvatar
}
if (roleList.includes('train_student')) {
return studentAvatar
}
return defaultAvatar
}
/**
* 获取教师头像 (空或404死链时返回专业讲师头像)
* @param {string} avatar 数据库中的头像路径
* @returns {string}
*/
export function getTeacherAvatar(avatar) {
if (!avatar || avatar.trim() === '' || avatar.includes('899d3f8e438f427eac6aeec76e489b52')) {
return teacherAvatar
}
if (avatar.indexOf('http') === 0 || avatar.indexOf('data:') === 0) {
return avatar
}
return process.env.VUE_APP_BASE_API + avatar
}
/**
* 获取学员头像 (空或404死链时返回专业学员工装头像)
* @param {string} avatar 数据库中的头像路径
* @returns {string}
*/
export function getStudentAvatar(avatar) {
if (!avatar || avatar.trim() === '' || avatar.includes('899d3f8e438f427eac6aeec76e489b52')) {
return studentAvatar
}
if (avatar.indexOf('http') === 0 || avatar.indexOf('data:') === 0) {
return avatar
}
return process.env.VUE_APP_BASE_API + avatar
}
@@ -58,6 +58,7 @@ import store from '@/store'
import { VueCropper } from 'vue-cropper'
import { uploadAvatar } from '@/api/system/user'
import { debounce } from '@/utils'
import { getRoleAvatar } from '@/utils/avatar'
export default {
components: { VueCropper },
@@ -75,7 +76,7 @@ export default {
// 弹出层标题
title: '修改头像',
options: {
img: store.getters.avatar, // 裁剪图片的地址
img: store.getters.avatar || getRoleAvatar(store.getters.roles), // 裁剪图片的地址
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
@@ -88,7 +89,7 @@ export default {
},
methods: {
handleAvatarError() {
this.options.img = require('@/assets/images/profile.jpg')
this.options.img = getRoleAvatar(store.getters.roles)
},
// 编辑头像
editCropper() {
@@ -35,7 +35,7 @@
<div v-loading="profileLoading">
<div v-if="studentProfile" class="profile-detail">
<div class="profile-avatar">
<el-avatar :size="72" icon="el-icon-user" style="background-color: #409eff;" />
<el-avatar :size="72" :src="studentAvatarSrc" icon="el-icon-user" style="background-color: #409eff;" />
<div class="name-block">{{ studentProfile.sName }}</div>
<div class="id-block">学号:{{ studentProfile.sId }}</div>
</div>
@@ -307,6 +307,7 @@
</template>
<script>
import { getStudentAvatar } from '@/utils/avatar'
import * as echarts from 'echarts'
import {
getStudentProfile,
@@ -356,6 +357,9 @@ export default {
attendanceAbnormalCount() {
if (!this.attendanceList || this.attendanceList.length === 0) return 0
return this.attendanceList.filter(i => i.checkinStatus != null && i.checkinStatus !== 1).length
},
studentAvatarSrc() {
return getStudentAvatar(this.studentProfile && this.studentProfile.avatar)
}
},
created() {
@@ -35,7 +35,7 @@
<div v-loading="profileLoading">
<div v-if="teacherProfile" class="profile-detail">
<div class="profile-avatar">
<el-avatar :size="72" icon="el-icon-user-solid" style="background-color: #1890ff;" />
<el-avatar :size="72" :src="teacherAvatarSrc" icon="el-icon-user-solid" style="background-color: #1890ff;" />
<div class="name-block">{{ teacherProfile.tName }}</div>
<div class="id-block">工号:{{ teacherProfile.tId }}</div>
</div>
@@ -268,6 +268,7 @@
</template>
<script>
import { getTeacherAvatar } from '@/utils/avatar'
import {
getTeacherProfile,
getMyPlans,
@@ -278,6 +279,11 @@ import {
export default {
name: 'TeacherWorkbench',
computed: {
teacherAvatarSrc() {
return getTeacherAvatar(this.teacherProfile && this.teacherProfile.avatar)
}
},
data() {
return {
activeTab: 'plans',
+3 -8
View File
@@ -379,6 +379,7 @@ import {addTeacher, updateTeacher} from "@/api/train/teacher";
import {listPlan} from "@/api/train/plan";
import {listPlanEnrollments} from "@/api/train/enrollment";
import {getActiveAccommodation} from "@/api/train/accommodation";
import { getStudentAvatar } from '@/utils/avatar';
export default {
name: 'Student',
components: { studentAvatar, Treeselect },
@@ -879,15 +880,9 @@ export default {
this.$refs.createForm.clearValidate('avatar')
}
},
// 头像地址解析:补全 baseApi,空值使用默认头像
// 头像地址解析:补全 baseApi,空值使用专业学员工装默认头像
avatarUrl(avatar) {
if (!avatar) {
return require('@/assets/images/profile.jpg')
}
if (avatar.indexOf('http') === 0 || avatar.indexOf('data:') === 0) {
return avatar
}
return process.env.VUE_APP_BASE_API + avatar
return getStudentAvatar(avatar)
},
submitCreate() {
/*this.$refs.createForm.validate(valid => {
@@ -58,8 +58,10 @@ import { VueCropper } from 'vue-cropper'
import request from '@/utils/request'
import { debounce } from '@/utils'
// 默认头像
const DEFAULT_AVATAR = require('@/assets/images/profile.jpg')
import { studentAvatar } from '@/utils/avatar'
// 默认学员职业头像
const DEFAULT_AVATAR = studentAvatar
export default {
components: { VueCropper },
+3 -8
View File
@@ -349,6 +349,7 @@ import {listDept} from "@/api/system/dept";
// 复用学员头像上传组件(通用:props.user 传入 {avatar},上传成功后抛出 success 事件)
import studentAvatar from '@/views/train/student/studentAvatar'
import request from '@/utils/request'
import { getTeacherAvatar } from '@/utils/avatar'
export default {
name: 'Teacher',
components: { Treeselect, studentAvatar },
@@ -690,15 +691,9 @@ export default {
this.$refs.form.clearValidate('avatar')
}
},
/** 头像地址解析:补全 baseApi,空值使用默认头像 */
/** 头像地址解析:补全 baseApi,空值使用专业讲师默认头像 */
avatarUrl(avatar) {
if (!avatar) {
return require('@/assets/images/profile.jpg')
}
if (avatar.indexOf('http') === 0 || avatar.indexOf('data:') === 0) {
return avatar
}
return process.env.VUE_APP_BASE_API + avatar
return getTeacherAvatar(avatar)
},
/** 搜索按钮操作 */
handleQuery() {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1021 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,79 +0,0 @@
/*需要全屏的时候*/
*{ margin: 0; padding:0; }
html,body{ width: 100%; height: 100%; font: "Mcriosofte Yahei"; background:#0D152A; }
.text-center{ text-align: center; }
.text-ellipsis{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.outwrap{ width: 100%; height: 100%; }
.pageLoading{ text-align: center; color:#fff; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background:#000; z-index: 1; }
.pageLoading .layui-icon{ font-size: 60px; margin-top:20%; }
/*结构块*/
.bp-inline,
.bp-inline .bp-img,
.bp-inline .bp-label,
.bp-inline .bp-label .bp-i{ display: inline-block; vertical-align: middle; margin:0 4px; }
/*系统管理页面布局结构*/
.sylogo{ height:16px; }
.wrapper{ position:absolute; left:0; right:0; top:0; bottom:0;overflow:hidden; }
.bp-header{ height: 40px; background:#1972C6; color:#F9F7F5; position: relative; }
.top-logo{ margin-top: 6px; letter-spacing: 2px; }
.bp-body{ background:#191B2B;
position:absolute;
left:0; top:40px; bottom:0; right:0;
overflow:hidden;
}
.bp-main{
position:absolute; left:0; top:0; right:0; bottom:0;
overflow:hidden;
}
.bp-board{
position:absolute;left:0px;right:0px;top:0;bottom:0px; }
.usercenter{ height: 40px; padding-top: 6px; position: absolute; top: 0; right: 10px; }
.user-avatar{ width:22px; height:22px; text-align: center; background:#3296F5;
position:relative; flex-shrink:0; margin-left:5px;margin-right:5px; border-radius: 22px;}
.usercenter a{ color: #fff; }
.bp-classic .bp-board{background:#020B1E url(../images/boardbg.jpg) center bottom no-repeat;}
.sessionPane{ background:#fff; border-radius:6px; padding:10px; margin:20px; }
.banseo{width: 80%; max-width: 500px; height: 34px; left: 0; right: 0; margin:0 auto; position: absolute; top:20%; }
.seoicn {
position: absolute;
left: 20px;
bottom: -64px;
color: #b0bec5;
font-size: 18px;
}
.bantxt { width: 100%; height: 60px; opacity: 1; background-color: #eceff1; border-radius: 5px; border: 0px; padding-left: 50px; color: #000; padding-right: 20px; outline: none; box-sizing: border-box; font-size: 16px; font-weight: bold;
}
.banbutt{height: 60px;
width: 173px;
background-color: #ec4d1c;
border: 0px;
color: #fff;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
transition: all .7s ease 0s;
font-size: 15px;
background: -webkit-linear-gradient(top,#f4511e 0,#d84315 100%);
background: linear-gradient(to bottom,#f4511e 0,#d84315 100%);
position: absolute; right: 0px; background-color: transparent;
border-width: 0px; outline: none;
}
/*自定义主题*/
.layui-field-title small,
.layui-form-label small{ color:#888; }
.layui-form-label .zlabel-name{display: block; margin-top: -8px; font-size: 16px; font-weight: bold;
}
.layui-field-title{ margin-top: 20px; margin-bottom:40px; text-align: center; }
.layui-form-label{ min-width:26%; }
.layui-form-item .layui-input-inline{ width:45%; }
.hide{ display: none; }
@@ -1,93 +0,0 @@
/* 图表模版内使用字体配置 */
var fntxt = 12,
fntit = 20;
var ww = $(window).width();
if(ww>2000){
fntxt = 18;
fntit = 30;
}
/* 修改字符串,每几个字换行 \n 换行 */
function tempChartBr(str,type, long) {
var res = '';
var length = str.length;
var long = long?long:7;
var num = long;
//console.log(str)
length <= long ? num = length : (length <= 20 ? num = Math.ceil(length / 2) : num = Math.ceil(length / 3));
if (length > long) {
var reg = new RegExp("(.{" + num + "})", "g")
if(type){
res = str.replace(reg, '$1<br>').replace(/<br>$/, "");
}else{
res = str.replace(reg, '$1\n').replace(/\n$/, "");
}
//res = str.replace(reg, '$1\n').replace(/\n$/, "");
//str.replace(reg, '$1\n').replace(/\n$/,"");
} else {
res = str;
}
//console.log(res)
return res;
}
var defaultsBar = {
title:{
x:'50%',
textAlign: 'center',
textStyle:{ color:'#fff'}
},
tooltip:{trigger: 'axis', axisPointer:{type:'shadow'} ,textStyle:{ fontSize: fntxt } },
grid:{top:'14%',left:'3%',right:'4%',bottom:'3%',containLabel:true},
xAxis: {
axisLabel:{ textStyle:{ color:"#f8f8f8", fontSize : fntxt} , rotate:40},
},
yAxis: {
axisLabel:{ textStyle:{ color:"#f8f8f8", fontSize : fntxt} }
},
series:[{
type:'bar',
barWidth:'15',
label:{
show:true,
textStyle:{ color:"#f8f8f8", fontSize :fntxt},
position:'outside',
//rotate:17
},
itemStyle:{normal:{barBorderRadius:30,color:new echarts.graphic.LinearGradient(0,0,0,1,[{offset:0,color:'#00feff'},{offset:0.5,color:'#027eff'},{offset:1,color:'#0286ff'}])}},
}]
}
var defaultsStackBar = {
color:['#031C9E','#0058AA','#016CC7','#007DE3','#01B2F8','#00CAFC','#00CAFC','#031C9E','#0058AA','#016CC7','#007DE3','#01B2F8','#00CAFC','#031C9E','#016CC7','#007DE3','#01B2F8','#00CAFC','#031C9E'],
tooltip:{
trigger: 'axis',
axisPointer : { type : 'shadow' },
textStyle:{ fontSize: fntxt },
position:function(point, params, dom, rect, size){
return [point[1],0];
},
},
toolbox:{
feature: {
saveAsImage: {
backgroundColor:"#050A18"
}
}
},
xAxis: {
axisLabel:{ textStyle:{ color:"#f8f8f8", fontSize : fntxt} , rotate:40},
},
yAxis: {
axisLabel:{ textStyle:{ color:"#f8f8f8", fontSize : fntxt} }
},
grid: {
top: '8%',
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Loaded 100 of 152 files, more files were not shown because too many files have changed in this diff. Show more