2002YJUN 10 months ago
parent 800c4c2a0d
commit c1ae1ffb5e

@ -0,0 +1,94 @@
<template>
<el-select
v-model="currentValue"
:multiple="multi"
:remote-method="fetchData"
filterable
remote
clearable
placeholder="选择或搜索考试"
class="filter-item"
@change="handlerChange"
>
<el-option
v-for="item in dataList"
:key="item.id"
:label="item.title"
:value="item.id"
/>
</el-select>
</template>
<script>
import { fetchList } from '@/api/exam/exam'
export default {
name: 'ExamSelect',
props: {
// /**
// *
// */
multi: Boolean,
// /**
// *
// */
value: Array,
// /**
// * valueArray
// */
default: String
},
data() {
return {
// /**
// *
// */
dataList: [],
// /**
// *
// */
currentValue: []
}
},
watch: {
// /**
// * valuevaluecurrentValue
// */
value: {
handler() {
this.currentValue = this.value
}
}
},
created() {
// /**
// * currentValuefetchData
// */
this.currentValue = this.value
this.fetchData()
},
methods: {
// /**
// *
// */
fetchData() {
fetchList().then(response => {
this.dataList = response.data.records
})
},
// /**
// *
// * @param e
// */
handlerChange(e) {
console.log(e)
this.$emit('change', e)
this.$emit('input', e)
}
}
}
</script>

@ -0,0 +1,85 @@
<template>
<div>
<file-upload-local v-model="fileUrl" :accept="accept" :tips="tips" :list-type="listType" />
</div>
</template>
<script>
import FileUploadLocal from './local'
export default {
name: 'FileUpload',
components: { FileUploadLocal },
props: {
// /**
// * URL
// */
value: String,
// /**
// *
// */
accept: {
type: String,
default: '*'
},
// /**
// *
// */
tips: String,
// /**
// *
// */
listType: {
type: String,
default: 'picture'
}
},
data() {
return {
// /**
// * URL
// */
fileUrl: ''
}
},
watch: {
// /**
// * valuevaluefillValuefileUrl
// */
value: {
handler() {
this.fillValue()
}
},
// /**
// * fileUrlfileUrlfileUrl
// */
fileUrl: {
handler() {
this.$emit('input', this.fileUrl)
}
}
},
mounted() {
//
},
created() {
// /**
// * fileUrl
// */
this.fillValue()
},
methods: {
// /**
// * valuefileUrl
// */
fillValue() {
this.fileUrl = this.value
}
}
}
</script>

@ -0,0 +1,155 @@
<template>
<div class="content">
<el-upload
v-model="fileUrl"
:action="server"
:accept="accept"
:before-remove="beforeRemove"
:on-remove="handleRemove"
:on-success="handleSuccess"
:on-exceed="handleExceed"
:drag="listType!=='picture'"
:limit="limit"
:headers="header"
:file-list="fileList"
:list-type="listType"
>
<el-button v-if="listType==='picture'" size="small" type="primary"></el-button>
<i v-if="listType!=='picture'" class="el-icon-upload" />
<div v-if="listType!=='picture'" class="el-upload__text">
将文件拖到此处
<em>点击上传</em>
</div>
<div v-if="tips" slot="tip" class="el-upload__tip">{{ tips }}</div>
</el-upload>
</div>
</template>
<script>
import { getToken } from '@/utils/auth'
export default {
name: 'FileUploadLocal',
components: { FileUploadLocal },
props: {
// /**
// * URL
// */
value: String,
// /**
// *
// */
accept: String,
// /**
// *
// */
tips: String,
// /**
// *
// */
listType: String,
// /**
// * 1
// */
limit: {
type: Number,
default: 1
}
},
data() {
return {
// /**
// *
// */
server: `${process.env.VUE_APP_BASE_API}/common/api/file/upload`,
// /**
// *
// */
fileList: [],
// /**
// * URL
// */
fileUrl: '',
// /**
// *
// */
header: {}
}
},
watch: {
// /**
// * valuevaluefillValuefileUrlfileList
// */
value: {
handler() {
this.fillValue()
}
}
},
created() {
// /**
// * fileUrlfileListtoken
// */
this.fillValue()
this.header = { token: getToken() }
},
methods: {
// /**
// * valuefileUrlfileList
// */
fillValue() {
this.fileList = []
this.fileUrl = this.value
if (this.fileUrl) {
this.fileList = [{ name: this.fileUrl, url: this.fileUrl }]
}
},
// /**
// *
// */
handleExceed() {
this.$message.warning(`每次只能上传 ${this.limit} 个文件`)
},
// /**
// *
// * @returns {Promise} Promise
// */
beforeRemove() {
return this.$confirm(`确定移除文件吗?`)
},
// /**
// *
// */
handleRemove() {
this.$emit('input', '')
this.fileList = []
},
// /**
// *
// * @param {Object} response
// */
handleSuccess(response) {
if (response.code === 1) {
this.$message({
type: 'error',
message: response.msg
})
this.fileList = []
return
}
this.$emit('input', response.data.url)
}
}
}
</script>

@ -0,0 +1,50 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active': isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
// /**
// * false
// */
isActive: {
type: Boolean,
default: false
}
},
methods: {
// /**
// * toggleClick
// */
toggleClick() {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

@ -0,0 +1,236 @@
<template>
<div :class="{'show': show}" class="header-search">
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="Search"
class="header-search-select"
@change="change"
>
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
</el-select>
</div>
</template>
<script>
// fuse is a lightweight fuzzy-search module
// make search results more in line with expectations
import Fuse from 'fuse.js'
import path from 'path'
export default {
name: 'HeaderSearch',
data() {
return {
// /**
// *
// */
search: '',
// /**
// *
// */
options: [],
// /**
// *
// */
searchPool: [],
// /**
// *
// */
show: false,
// /**
// * Fuse
// */
fuse: undefined
}
},
computed: {
// /**
// *
// * @returns {Array}
// */
routes() {
return this.$store.getters.permission_routes
}
},
watch: {
// /**
// *
// */
routes() {
this.searchPool = this.generateRoutes(this.routes)
},
// /**
// * Fuse
// */
searchPool(list) {
this.initFuse(list)
},
// /**
// *
// */
show(value) {
if (value) {
document.body.addEventListener('click', this.close)
} else {
document.body.removeEventListener('click', this.close)
}
}
},
mounted() {
// /**
// *
// */
this.searchPool = this.generateRoutes(this.routes)
},
methods: {
// /**
// *
// */
click() {
this.show = !this.show
if (this.show) {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
}
},
// /**
// *
// */
close() {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
this.options = []
this.show = false
},
// /**
// *
// * @param {Object} val
// */
change(val) {
this.$router.push(val.path)
this.search = ''
this.options = []
this.$nextTick(() => {
this.show = false
})
},
// /**
// * Fuse
// * @param {Array} list
// */
initFuse(list) {
this.fuse = new Fuse(list, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [{
name: 'title',
weight: 0.7
}, {
name: 'path',
weight: 0.3
}]
})
},
// /**
// *
// * @param {Array} routes
// * @param {String} basePath '/'
// * @param {Array} prefixTitle
// * @returns {Array}
// */
generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = []
for (const router of routes) {
// skip hidden router
if (router.hidden) { continue }
const data = {
path: path.resolve(basePath, router.path),
title: [...prefixTitle]
}
if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title]
if (router.redirect !== 'noRedirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data)
}
}
// recursive child routes
if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes]
}
}
}
return res
},
// /**
// *
// * @param {String} query
// */
querySearch(query) {
if (query !== '') {
this.options = this.fuse.search(query)
} else {
this.options = []
}
}
}
}
</script>
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
}
}
}
</style>

@ -0,0 +1,89 @@
<template>
<el-select
v-model="values"
:remote-method="fetchList"
style="width: 100%"
multiple
filterable
remote
reserve-keyword
clearable
automatic-dropdown
placeholder="请选择角色"
@change="handlerChange"
>
<el-option
v-for="item in list"
:key="item.id"
:label="item.title"
:value="item.id"
/>
</el-select>
</template>
<script>
import { fetchList } from '@/api/sys/role/role'
export default {
name: 'MeetRole',
props: {
/**
* 初始选中的角色ID数组
*/
value: {
type: Array,
default: () => []
}
},
data() {
return {
// /**
// *
// */
list: [],
// /**
// * ID
// */
values: []
}
},
watch: {
// /**
// * valuevalues
// */
value: {
handler(newVal) {
this.values = newVal
},
deep: true
}
},
created() {
// /**
// * values
// */
this.values = this.value
this.fetchList()
},
methods: {
// /**
// * list
// */
fetchList() {
fetchList().then(response => {
this.list = response.data
})
},
// /**
// * changeinput
// * @param {Array} e ID
// */
handlerChange(e) {
this.$emit('change', e)
this.$emit('input', e)
}
}
}
</script>

@ -0,0 +1,149 @@
<template>
<div :class="{'hidden': hidden}" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import { scrollTo } from '@/utils/scroll-to'
export default {
name: 'Pagination',
props: {
// /**
// *
// */
total: {
required: true,
type: Number
},
// /**
// * 1
// */
page: {
type: Number,
default: 1
},
// /**
// * 20
// */
limit: {
type: Number,
default: 20
},
// /**
// * [10, 20, 30, 50]
// */
pageSizes: {
type: Array,
default() {
return [10, 20, 30, 50]
}
},
// /**
// * 'total, sizes, prev, pager, next, jumper'
// */
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
// /**
// * true
// */
background: {
type: Boolean,
default: true
},
// /**
// * true
// */
autoScroll: {
type: Boolean,
default: true
},
// /**
// * false
// */
hidden: {
type: Boolean,
default: false
}
},
computed: {
// /**
// * page
// */
currentPage: {
get() {
return this.page
},
set(val) {
this.$emit('update:page', val)
}
},
// /**
// * limit
// */
pageSize: {
get() {
return this.limit
},
set(val) {
this.$emit('update:limit', val)
}
}
},
methods: {
// /**
// * pagination
// * @param {Number} val
// */
handleSizeChange(val) {
this.$emit('pagination', { page: this.currentPage, limit: val })
if (this.autoScroll) {
scrollTo(0, 800)
}
},
// /**
// * pagination
// * @param {Number} val
// */
handleCurrentChange(val) {
this.$emit('pagination', { page: val, limit: this.pageSize })
if (this.autoScroll) {
scrollTo(0, 800)
}
}
}
}
</script>
<style scoped>
.pagination-container {
background: #fff;
padding: 32px 16px;
}
.pagination-container.hidden {
display: none;
}
</style>
Loading…
Cancel
Save