1bus.js
javascript
import Vue from 'vue';
// 使用 Event Bus
const bus = new Vue();
export default bus;
2directives.js
javascript
import Vue from 'vue';
// v-dialogDrag: 弹窗拖拽属性
Vue.directive('dialogDrag', {
bind(el, binding, vnode, oldVnode) {
const dialogHeaderEl = el.querySelector('.el-dialog__header');
const dragDom = el.querySelector('.el-dialog');
dialogHeaderEl.style.cssText += ';cursor:move;'
dragDom.style.cssText += ';top:0px;'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = (() => {
if (window.document.currentStyle) {
return (dom, attr) => dom.currentStyle[attr];
} else {
return (dom, attr) => getComputedStyle(dom, false)[attr];
}
})()
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - dialogHeaderEl.offsetLeft;
const disY = e.clientY - dialogHeaderEl.offsetTop;
const screenWidth = document.body.clientWidth; // body当前宽度
const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取)
const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
const dragDomheight = dragDom.offsetHeight; // 对话框高度
const minDragDomLeft = dragDom.offsetLeft;
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
const minDragDomTop = dragDom.offsetTop;
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
// 获取到的值带px 正则匹配替换
let styL = sty(dragDom, 'left');
let styT = sty(dragDom, 'top');
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (styL.includes('%')) {
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100);
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100);
} else {
styL = +styL.replace(/\px/g, '');
styT = +styT.replace(/\px/g, '');
};
document.onmousemove = function (e) {
// 通过事件委托,计算移动的距离
let left = e.clientX - disX;
let top = e.clientY - disY;
// 边界处理
if (-(left) > minDragDomLeft) {
left = -(minDragDomLeft);
} else if (left > maxDragDomLeft) {
left = maxDragDomLeft;
}
if (-(top) > minDragDomTop) {
top = -(minDragDomTop);
} else if (top > maxDragDomTop) {
top = maxDragDomTop;
}
// 移动当前元素
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
};
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
}
}
})
3header.vue
html
<template>
<div class="header">
<!-- 折叠按钮 -->
<div class="collapse-btn" @click="collapseChage">
<i v-if="!collapse" class="el-icon-s-fold"></i>
<i v-else class="el-icon-s-unfold"></i>
</div>
<div class="logo">在线考试管理系统</div>
<div class="header-right">
<div class="header-user-con">
<!-- 全屏显示 -->
<div class="btn-fullscreen" @click="handleFullScreen">
<el-tooltip effect="dark" :content="fullscreen?`取消全屏`:`全屏`" placement="bottom">
<i class="el-icon-rank"></i>
</el-tooltip>
</div>
<!-- 用户头像 -->
<div class="user-avator">
<img :src="getAvatar(form.avatar)" alt="User Avatar">
</div>
<!-- 用户名下拉菜单 -->
<el-dropdown class="user-name" trigger="click" @command="handleCommand">
<span class="el-dropdown-link">
{{username}}
<i class="el-icon-caret-bottom"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="updatePassword">个人中心</el-dropdown-item>
<el-button @click="openDialog">待办事件</el-button>
<el-dropdown-item command="loginout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<el-dialog title="个人中心&&信息查看的同时修改密码&&修改头像" :modal="false" :visible.sync="addVisible" width="33%" :before-close="clearAddForm">
<el-form label-position="left" ref="addForm" label-width="80px" :model="form" >
<el-form-item label="用户名">
<el-input v-model="form.userName"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password"></el-input>
</el-form-item>
<el-form-item label="真实姓名">
<el-input v-model="form.realName"></el-input>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="form.phone"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="clearAddForm">取 消</el-button>
<el-button type="primary" @click="saveAndUpdateUserInfo">确 定</el-button>
</span>
</el-dialog>
<el-dialog title="待办事件" :visible.sync="addVisible2" width="72%" style="margin-left: 155px;" :before-close="clearAddForm">
<div v-for="(todo, index) in todoList" :key="index" class="todo-item">
<el-input v-model="todo.theme" placeholder="事件标题" style="width: 18%; margin-left: 42px;"></el-input>
<el-input type="textarea" v-model="todo.content" placeholder="事件详情" rows="1" style="width: 40%;"></el-input>
<el-input
style="width: 9%;"
v-model="todo.remainDay"
type="number"
placeholder="天数"
></el-input>
<el-input v-model="todo.stopTimeStr" placeholder="截止日期" style="width: 14%;" disabled></el-input>
<el-select v-model="todo.status" placeholder="状态" style="width: 10%;">
<el-option label="待办" value="0"></el-option>
<el-option label="进行中" value="1"></el-option>
<el-option label="完成" value="2"></el-option>
</el-select>
<el-button style="margin-left: 30px;" type="danger" icon="el-icon-delete" @click="removeTodo(index)">删除</el-button>
</div>
<el-button type="primary" icon="el-icon-plus" @click="addTodo">新增待办事件</el-button>
<span slot="footer" class="dialog-footer">
<el-button @click="clearAddForm">取消</el-button>
<el-button type="primary" @click="saveTodos">保存</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import bus from '../common/bus';
import { getNoticeList, getUserList, saveAndUpdateEmployeeInfo, saveAndUpdateUserInfo } from '../../api/user';
import { getUpcomeList, addUpcome, updateUpcome, deleteUpcome,saveUpcome } from '@/api/upcome';
export default {
data() {
return {
form:{
id:sessionStorage.getItem("userId"),
},
userId:sessionStorage.getItem("userId"),
addVisible:false,
collapse: false,
addVisible2:false,
todoList: [],
fullscreen: false,
name: 'wahah',
systemTitle:'',
list:[],
};
},
computed: {
username() {
let username = sessionStorage.getItem('realName');
return username ? username : this.name;
},
},
created() {
this.getUserInfo();
},
methods: {
fetchUpcomeList() {
const userId = sessionStorage.getItem("userId");
getUpcomeList(userId).then(response => {
this.todoList = response.data.list; // 直接使用后端返回的数据
});
},
openDialog() {
this.addVisible2 = true;
this.fetchUpcomeList();
},
// 添加待办事件
addTodo() {
const userId = sessionStorage.getItem("userId");
this.todoList.push({ userId: userId, theme: "", stop_time: new Date().toLocaleString('en-US', { hour12: false }), content: "" });
},
// 删除待办事件
removeTodo(index) {
const todo = this.todoList[index];
if (todo.id) {
// 假设您有一个变量 `userId` 存储当前用户的ID
const payload = { id: todo.id, userId: this.userId };
deleteUpcome(payload).then(() => {
this.todoList.splice(index, 1);
});
} else {
this.todoList.splice(index, 1);
}
},
// 保存待办事件列表
saveTodos() {
const userId = sessionStorage.getItem("userId");
Promise.all(this.todoList.map(todo => saveUpcome({ ...todo, userId: userId }))).then(() => {
console.log("保存的待办事件列表:", this.todoList);
this.clearAddForm();
});
},
getAvatar(avatarFilename) {
// 确保路径正确,并且文件确实存在于 src/assets/img 目录中
return 'http://localhost:9000/img/' + avatarFilename;
},
getUserInfo(){
getUserList({id:sessionStorage.getItem("userId")}).then(res =>{
this.form = res.data.list[0];
console.log(this.form)
});
},
// 用户名下拉菜单选择事件
handleCommand(command) {
if (command === 'loginout') {
// localStorage.removeItem('ms_username');
sessionStorage.clear();
window.location.reload();
this.$router.push('/login');
}
if (command === 'updatePassword'){
this.addVisible = true;
}
if (command === 'myNotice'){
this.addVisible2 = true;
}
},
clearAddForm(){
this.addVisible = false;
this.addVisible2 = false;
},
saveAndUpdateUserInfo(){
saveAndUpdateUserInfo(this.form).then(res =>{
if (res.code === 1){
this.$message.success('修改成功,即将跳转登录界面');
this.addVisible = false;
setTimeout(() =>{
this.$router.push('/login');
},2000)
}else {
this.$message.error('修改失败')
}
})
},
// 侧边栏折叠
collapseChage() {
this.collapse = !this.collapse;
bus.$emit('collapse', this.collapse);
},
// 全屏事件
handleFullScreen() {
let element = document.documentElement;
if (this.fullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
// IE11
element.msRequestFullscreen();
}
}
this.fullscreen = !this.fullscreen;
},
},
filters: {
formatDate(date) {
const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' };
return new Date(date).toLocaleDateString('en-US', options);
}
},
mounted() {
const that = this;
if (document.body.clientWidth < 1500) {
this.collapseChage();
}
},
};
</script>
<style scoped>
.todo-item {
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 10px;
}
.header {
position: relative;
box-sizing: border-box;
width: 100%;
height: 70px;
font-size: 22px;
color: #fff;
}
.collapse-btn {
float: left;
padding: 0 21px;
cursor: pointer;
line-height: 70px;
}
.header .logo {
float: left;
width: 280px;
line-height: 70px;
}
.header-right {
float: right;
padding-right: 50px;
}
.header-user-con {
display: flex;
height: 70px;
align-items: center;
}
.btn-fullscreen {
transform: rotate(45deg);
margin-right: 5px;
font-size: 24px;
}
.btn-bell,
.btn-fullscreen {
position: relative;
width: 30px;
height: 30px;
text-align: center;
border-radius: 15px;
cursor: pointer;
}
.btn-bell-badge {
position: absolute;
right: 0;
top: -2px;
width: 8px;
height: 8px;
border-radius: 4px;
background: #f56c6c;
color: #fff;
}
.btn-bell .el-icon-bell {
color: #fff;
}
.user-name {
margin-left: 10px;
}
.user-avator {
margin-left: 20px;
}
.user-avator img {
display: block;
width: 40px;
height: 40px;
border-radius: 50%;
}
.el-dropdown-link {
color: #fff;
cursor: pointer;
}
.el-dropdown-menu__item {
text-align: center;
}
</style>
4home.vue
html
<template>
<div class="wrapper">
<v-head></v-head>
<v-sidebar></v-sidebar>
<div class="content-box" :class="{'content-collapse':collapse}">
<v-tags></v-tags>
<div class="content">
<transition name="move" mode="out-in">
<keep-alive :include="tagsList">
<router-view></router-view>
</keep-alive>
</transition>
<el-backtop target=".content"></el-backtop>
</div>
</div>
</div>
</template>
<script>
import vHead from './Header.vue';
import vSidebar from './Sidebar.vue';
import vTags from './Tags.vue';
import bus from './bus';
export default {
data() {
return {
tagsList: [],
collapse: false
};
},
components: {
vHead,
vSidebar,
vTags
},
created() {
bus.$on('collapse-content', msg => {
this.collapse = msg;
});
// 只有在标签页列表里的页面才使用keep-alive,即关闭标签之后就不保存到内存中了。
bus.$on('tags', msg => {
let arr = [];
for (let i = 0, len = msg.length; i < len; i++) {
msg[i].name && arr.push(msg[i].name);
}
this.tagsList = arr;
});
}
};
</script>
5i18m.js
javascript
export const messages = {
'zh': {
i18n: {
breadcrumb: '国际化产品',
tips: '通过切换语言按钮,来改变当前内容的语言。',
btn: '切换英文',
title1: '常用用法',
p1: '要是你把你的秘密告诉了风,那就别怪风把它带给树。',
p2: '没有什么比信念更能支撑我们度过艰难的时光了。',
p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。',
title2: '组件插值',
info: 'Element组件需要国际化,请参考 {action}。',
value: '文档'
}
},
'en': {
i18n: {
breadcrumb: 'International Products',
tips: 'Click on the button to change the current language. ',
btn: 'Switch Chinese',
title1: 'Common usage',
p1: "If you reveal your secrets to the wind you should not blame the wind for revealing them to the trees.",
p2: "Nothing can help us endure dark times better than our faith. ",
p3: "If you can do what you do best and be happy, you're further along in life than most people.",
title2: 'Component interpolation',
info: 'The default language of Element is Chinese. If you wish to use another language, please refer to the {action}.',
value: 'documentation'
}
}
}
6index.vue
html
<template>
<div class="app-container">
<div class="filter-container">
<slot name="filter-content" />
<el-row>
<el-col>
<el-button v-if="options.addRoute" type="primary" icon="el-icon-plus" @click="handleAdd">添加</el-button>
</el-col>
</el-row>
</div>
<div v-show="multiShow && options.multiActions" class="filter-container">
<el-select v-model="multiNow" :placeholder="selectedLabel" class="filter-item" style="width: 130px" @change="handleOption">
<el-option
v-for="item in options.multiActions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<el-table
v-loading="listLoading"
:data="dataList.records"
border
fit
highlight-current-row
:header-cell-style="{'background':'#f2f3f4', 'color':'#555', 'font-weight':'bold', 'line-height':'32px'}"
@selection-change="handleSelection"
>
<el-table-column
v-if="options.multi"
align="center"
type="selection"
width="55"
/>
<slot name="data-columns" />
</el-table>
<pagination v-show="dataList.total>0" :total="dataList.total" :page.sync="listQuery.current" :limit.sync="listQuery.size" @pagination="getList" />
</div>
</template>
<script>
import { fetchList, deleteData, changeState } from '@/api/common'
import Pagination from '@/components/Pagination'
export default {
name: 'PagingTable',
components: { Pagination },
// 组件入参
props: {
options: {
type: Object,
default: () => {
return {
// 批量操作
multiActions: [],
// 列表请求URL
listUrl: '/exam/api',
// 删除请求URL
deleteUrl: '',
// 启用禁用
stateUrl: '',
// 可批量操作
multi: false
}
}
},
// 列表查询参数
listQuery: {
type: Object,
default: () => {
return {
current: 1,
size: 10,
params: {},
t: 0
}
}
}
},
data() {
return {
// 接口数据返回
dataList: {
total: 0
},
// 数据加载标识
listLoading: true,
// 选定和批量操作
selectedIds: [],
selectedObjs: [],
// 显示已中多少项
selectedLabel: '',
// 显示批量操作
multiShow: false,
// 批量操作的标识
multiNow: ''
}
},
watch: {
// 检测查询变化
listQuery: {
handler() {
this.getList()
},
deep: true
}
},
created() {
this.getList()
},
methods: {
/**
* 添加数据跳转
*/
handleAdd() {
if (this.options.addRoute) {
this.$router.push({ name: this.options.addRoute, params: {}})
return
}
console.log('未设置添加数据跳转路由!')
},
/**
* 查询数据列表
*/
getList() {
this.listLoading = true
this.listQuery.t = new Date().getTime()
fetchList(this.options.listUrl, this.listQuery).then(response => {
this.dataList = response.data
this.listLoading = false
})
},
/**
* 搜索
*/
handleFilter() {
// 重新搜索
this.getList()
},
/**
* 批量操作回调
*/
handleOption(v) {
this.multiNow = ''
// 内部消化的操作
if (v === 'delete') {
this.handleDelete()
return
}
if (v === 'enable') {
this.handleState(0)
return
}
if (v === 'disable') {
this.handleState(1)
return
}
// 向外回调的操作
this.$emit('multi-actions', { opt: v, ids: this.selectedIds })
},
/**
* 修改状态,启用禁用
*/
handleState(state) {
// 修改状态
changeState(this.options.stateUrl, this.selectedIds, state).then(response => {
if (response.code === 0) {
this.$message({
type: 'success',
message: '状态修改成功!'
})
// 重新搜索
this.getList()
}
})
},
/**
* 删除数据
*/
handleDelete() {
if (this.selectedIds.length === 0) {
this.$message({
message: '请至少选择一条数据!',
type: 'warning'
})
return
}
// 删除
this.$confirm('确实要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteData(this.options.deleteUrl, this.selectedIds).then(() => {
this.$message({
type: 'success',
message: '删除成功!'
})
this.getList()
})
})
},
/**
* 列表多选操作
* @param val
*/
handleSelection(val) {
const ids = []
val.forEach(row => {
ids.push(row.id)
})
this.selectedObjs = val
this.selectedIds = ids
this.multiShow = ids.length > 0
this.selectedLabel = '已选' + ids.length + '项'
this.$emit('select-changed', { ids: this.selectedIds, objs: this.selectedObjs })
}
}
}
</script>
<style>
.filter-container .filter-item{
margin-left: 5px;
}
.filter-container .filter-item:first-child{
margin-left: 0px;
}
</style>
7sidebar.vue
html
<template>
<div class="sidebar">
<el-menu
class="sidebar-el-menu"
:default-active="onRoutes"
:collapse="collapse"
background-color="#324157"
text-color="#bfcbd9"
active-text-color="#20a0ff"
unique-opened
router
>
<template v-for="item in items">
<template v-if="item.subs">
<!-- 一级菜单-->
<el-submenu :index="item.index" :key="item.index">
<template slot="title">
<i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</template>
<template v-for="subItem in item.subs">
<el-submenu
v-if="subItem.subs"
:index="subItem.index"
:key="subItem.index"
>
<template slot="title"><i :class="subItem.icon"></i>{{ subItem.title }}</template>
<!-- 二级菜单-->
<el-menu-item
v-for="(threeItem,i) in subItem.subs"
:key="i"
:index="threeItem.index"
><i :class="threeItem.icon"></i>{{ threeItem.title }}</el-menu-item>
</el-submenu>
<!-- :key="subItem.index" 删掉的39行 -->
<el-menu-item
v-else
:index="subItem.index"
><i :class="subItem.icon"></i>{{ subItem.title }}</el-menu-item>
</template>
</el-submenu>
</template>
<template v-else>
<el-menu-item :index="item.index" :key="item.index">
<i :class="item.icon"></i>
<span slot="title">{{ item.title }}</span>
</el-menu-item>
</template>
</template>
</el-menu>
</div>
</template>
<script>
import bus from '../common/bus';
export default {
data() {
return {
collapse: false,
items:[],
//管理员菜单userType=0
itemList3: [
{
"id":4,
"pid":1,
"icon":"el-icon-s-order",
"index":"3",
"title":"统一管理",
"subs":[
{
"id":9,
"pid":4,
"icon":"el-icon-plus",
"index":"user",
"title":"用户管理",
"subs":null
},
{
"id":10,
"pid":4,
"icon":"el-icon-plus",
"index":"test",
"title":"题库管理",
"subs":null
},
{
"id":11,
"pid":4,
"icon":"el-icon-plus",
"index":"question2",
"title":"选题管理",
"subs":null
},
{
"id":11,
"pid":4,
"icon":"el-icon-plus",
"index":"report",
"title":"成绩管理",
"subs":null
},
{
"id":12,
"pid":4,
"icon":"el-icon-plus",
"index":"parent",
"title":"家长管理",
"subs":null
},
]
},
],
//教师菜单userType=1
itemList: [
{
"id":4,
"pid":1,
"icon":"el-icon-s-order",
"index":"3",
"title":"统一管理",
"subs":[
{
"id":9,
"pid":4,
"icon":"el-icon-plus",
"index":"user", //对应就是 /user路径,即在router中是对应user.vue
"title":"用户管理",
"subs":null
},
{
"id":10,
"pid":4,
"icon":"el-icon-plus",
"index":"test",
"title":"题库管理",
"subs":null
},
{
"id":11,
"pid":4,
"icon":"el-icon-plus",
"index":"question2",
"title":"选题管理",
"subs":null
},
{
"id":11,
"pid":4,
"icon":"el-icon-plus",
"index":"report",
"title":"成绩管理",
"subs":null
},
{
"id":12,
"pid":4,
"icon":"el-icon-plus",
"index":"parent",
"title":"家长管理",
"subs":null
},
{
"id":12,
"pid":4,
"icon":"el-icon-plus",
"index":"test2",
"title":"测试2",
"subs":null
},
]
},
],
//学生菜单userType=2
itemList2:[
{
"id":5,
"pid":1,
"icon":"el-icon-s-data",
"index":"6",
"title":"我的管理",
"subs":[
{
"id":10,
"pid":4,
"icon":"el-icon-plus",
"index":"test",
"title":"题库管理",
"subs":null
},
{
"id":11,
"pid":4,
"icon":"el-icon-plus",
"index":"report",
"title":"成绩管理",
"subs":null
},
{
"id":11,
"pid":4,
"icon":"el-icon-plus",
"index":"collect",
"title":"错题管理",
"subs":null
},
{
"id":12,
"pid":4,
"icon":"el-icon-plus",
"index":"parent",
"title":"家长管理",
"subs":null
},
]
}
],
};
},
computed: {
onRoutes() {
return this.$route.path.replace('/', '');
},
},
created() {
// 通过 Event Bus 进行组件间通信,来折叠侧边栏
bus.$on('collapse', msg => {
this.collapse = msg;
bus.$emit('collapse-content', msg);
});
//初始化menuList
if ("1" === sessionStorage.getItem('userType')){
this.items = this.itemList; //学生的菜单
}else if ("2" === sessionStorage.getItem('userType')){
this.items = this.itemList2; //教师的菜单
}else {
this.items = this.itemList3; //管理员的菜单
}
}
};
</script>
<style scoped>
.sidebar {
display: block;
position: absolute;
left: 0;
top: 70px;
bottom: 0;
overflow-y: scroll;
}
.sidebar::-webkit-scrollbar {
width: 0;
}
.sidebar-el-menu:not(.el-menu--collapse) {
width: 250px;
}
.sidebar > ul {
height: 100%;
}
</style>
8singleupload.vue
html
<template>
<div>
<el-upload
action="http://gulimall-psw.oss-cn-hangzhou.aliyuncs.com"
:data="dataObj"
list-type="picture"
:multiple="false" :show-file-list="showFileList"
:file-list="fileList"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="handleUploadSuccess"
:on-preview="handlePreview">
<el-button size="small" type="primary">点击上传</el-button>
<!-- <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>-->
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="50%" :src="fileList[0].url" alt="">
</el-dialog>
</div>
</template>
<script>
import { getUUID, policy } from '../../api/policy';
export default {
name: 'singleUpload',
props: {
value: String
},
computed: {
imageUrl() {
return this.value;
},
imageName() {
if (this.value != null && this.value !== '') {
return this.value.substr(this.value.lastIndexOf("/") + 1);
} else {
return null;
}
},
fileList() {
return [{
name: this.imageName,
url: this.imageUrl
}]
},
showFileList: {
get: function () {
return this.value !== null && this.value !== ''&& this.value!==undefined;
},
set: function (newValue) {
}
}
},
data() {
return {
dataObj: {
policy: '',
signature: '',
key: '',
ossaccessKeyId: '',
dir: '',
host: '',
// callback:'',
},
dialogVisible: false
};
},
methods: {
emitInput(val) {
this.$emit('input', val)
},
handleRemove(file, fileList) {
this.emitInput('');
},
handlePreview(file) {
this.dialogVisible = true;
},
beforeUpload(file) {
let _self = this;
return new Promise((resolve, reject) => {
policy().then(response => {
console.log(response)
_self.dataObj.policy = response.policy;
_self.dataObj.signature = response.signature;
_self.dataObj.ossaccessKeyId = response.accessid;
_self.dataObj.key = response.dir + '/'+getUUID()+'_${filename}';
_self.dataObj.dir = response.dir;
_self.dataObj.host = response.host;
resolve(true)
}).catch(err => {
reject(false)
})
})
},
handleUploadSuccess(res, file) {
console.log("上传成功...")
this.showFileList = true;
this.fileList.pop();
this.fileList.push({name: file.name, url: this.dataObj.host + '/' + this.dataObj.key.replace("${filename}",file.name) });
this.emitInput(this.fileList[0].url);
}
}
}
</script>
<style>
</style>
9Tags.vue
html
<template>
<div class="tags" v-if="showTags">
<ul>
<li class="tags-li" v-for="(item,index) in tagsList" :class="{'active': isActive(item.path)}" :key="index" v-if="item.title !=='开始考试'">
<router-link :to="item.path" class="tags-li-title">
{{item.title}}
</router-link>
<!-- <span class="tags-li-icon" @click="closeTags(index)"><i class="el-icon-close"></i></span> -->
<!-- 只有当标题不是"系统首页"时才关闭按钮 -->
<span v-if="item.title !== '系统首页'" class="tags-li-icon" @click="closeTags(index)"><i class="el-icon-close"></i></span>
</li>
</ul>
<div class="tags-close-box">
<el-dropdown @command="handleTags">
<el-button size="mini" type="primary">
标签选项<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu size="small" slot="dropdown">
<el-dropdown-item command="other">关闭其他</el-dropdown-item>
<el-dropdown-item command="all">关闭所有</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
import bus from './bus';
export default {
data() {
return {
tagsList: []
}
},
methods: {
isActive(path) {
return path === this.$route.fullPath;
},
// 关闭单个标签
closeTags(index) {
const delItem = this.tagsList.splice(index, 1)[0];
const item = this.tagsList[index] ? this.tagsList[index] : this.tagsList[index - 1];
if (item) {
delItem.path === this.$route.fullPath && this.$router.push(item.path);
}else{
// if (sessionStorage.getItem('userType') === '1'){
// this.$router.push('/');
// }else {
// this.$router.push('/test');
// }
this.$router.push('/'); //如果关闭了最后一个标签页,则到根路径去
}
},
// 关闭全部标签
closeAll(){
this.tagsList = [];
this.$router.push('/');
},
// 关闭其他标签
closeOther(){
const curItem = this.tagsList.filter(item => {
return item.path === this.$route.fullPath;
})
this.tagsList = curItem;
},
// 设置标签
setTags(route){
const isExist = this.tagsList.some(item => {
return item.path === route.fullPath;
})
if(!isExist){
if(this.tagsList.length >= 8){
this.tagsList.shift();
}
this.tagsList.push({
title: route.meta.title,
path: route.fullPath,
name: route.matched[1].components.default.name
})
}
bus.$emit('tags', this.tagsList);
},
handleTags(command){
command === 'other' ? this.closeOther() : this.closeAll();
}
},
computed: {
showTags() {
return this.tagsList.length > 0;
}
},
watch:{
$route(newValue, oldValue){
this.setTags(newValue);
}
},
created(){
this.setTags(this.$route);
// 监听关闭当前页面的标签页
bus.$on('close_current_tags', () => {
for (let i = 0, len = this.tagsList.length; i < len; i++) {
const item = this.tagsList[i];
if(item.path === this.$route.fullPath){
if(i < len - 1){
this.$router.push(this.tagsList[i+1].path);
}else if(i > 0){
this.$router.push(this.tagsList[i-1].path);
}else{
this.$router.push('/');
}
this.tagsList.splice(i, 1);
break;
}
}
})
}
}
</script>
<style>
.tags {
position: relative;
height: 30px;
overflow: hidden;
background: #ffffff;
padding-right: 120px;
box-shadow: 0 5px 10px #d1faff;
}
.tags ul {
box-sizing: border-box;
width: 100%;
height: 100%;
}
.tags-li {
float: left;
margin: 3px 5px 2px 3px;
border-radius: 3px;
font-size: 12px;
overflow: hidden;
cursor: pointer;
height: 23px;
line-height: 23px;
border: 1px solid #e9eaec;
background: #ffffff;
padding: 0 5px 0 12px;
vertical-align: middle;
color: #666;
-webkit-transition: all .3s ease-in;
-moz-transition: all .3s ease-in;
transition: all .3s ease-in;
}
.tags-li:not(.active):hover {
background: #e97e84;
}
.tags-li.active {
color: #000000;
}
.tags-li-title {
float: left;
max-width: 80px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-right: 5px;
color: #000000;
font-weight: bolder;
}
.tags-li.active .tags-li-title {
color: #fdfdfd;
font-weight: bolder;
}
.tags-close-box {
position: absolute;
right: 0;
top: 0;
box-sizing: border-box;
padding-top: 1px;
text-align: center;
width: 110px;
height: 30px;
background: #ffffff;
box-shadow: -3px 0 15px 3px rgba(255, 16, 16, 0.1);
z-index: 10;
}
</style>