This commit is contained in:
huzhushan 2021-04-19 19:47:17 +08:00
parent 77e94d2f3d
commit c5265e7fc2
43 changed files with 555 additions and 555 deletions

View File

@ -1,4 +1,4 @@
import request from '@/utils/request'; import request from '@/utils/request'
// 登录接口 // 登录接口
export const Login = data => { export const Login = data => {
@ -6,13 +6,13 @@ export const Login = data => {
url: '/api/login', url: '/api/login',
method: 'post', method: 'post',
data, data,
}); })
}; }
// 获取登录用户信息 // 获取登录用户信息
export const GetUserinfo = () => { export const GetUserinfo = () => {
return request({ return request({
url: '/api/userinfo', url: '/api/userinfo',
method: 'get', method: 'get',
}); })
}; }

View File

@ -1,9 +1,9 @@
import request from '@/utils/request'; import request from '@/utils/request'
// 获取菜单 // 获取菜单
export const GetMenus = () => { export const GetMenus = () => {
return request({ return request({
url: '/api/menus', url: '/api/menus',
method: 'get', method: 'get',
}); })
}; }

View File

@ -212,7 +212,7 @@
</div> </div>
</template> </template>
<script> <script>
import { defineComponent, reactive, toRefs, onBeforeMount } from 'vue'; import { defineComponent, reactive, toRefs, onBeforeMount } from 'vue'
const formatDate = (date, format) => { const formatDate = (date, format) => {
var obj = { var obj = {
'M+': date.getMonth() + 1, 'M+': date.getMonth() + 1,
@ -222,12 +222,12 @@ const formatDate = (date, format) => {
's+': date.getSeconds(), 's+': date.getSeconds(),
'q+': Math.floor((date.getMonth() + 3) / 3), 'q+': Math.floor((date.getMonth() + 3) / 3),
'S+': date.getMilliseconds(), 'S+': date.getMilliseconds(),
}; }
if (/(y+)/i.test(format)) { if (/(y+)/i.test(format)) {
format = format.replace( format = format.replace(
RegExp.$1, RegExp.$1,
(date.getFullYear() + '').substr(4 - RegExp.$1.length) (date.getFullYear() + '').substr(4 - RegExp.$1.length)
); )
} }
for (var k in obj) { for (var k in obj) {
if (new RegExp('(' + k + ')').test(format)) { if (new RegExp('(' + k + ')').test(format)) {
@ -236,25 +236,25 @@ const formatDate = (date, format) => {
RegExp.$1.length == 1 RegExp.$1.length == 1
? obj[k] ? obj[k]
: ('00' + obj[k]).substr(('' + obj[k]).length) : ('00' + obj[k]).substr(('' + obj[k]).length)
); )
} }
} }
return format; return format
}; }
const getSearchModel = search => { const getSearchModel = search => {
const searchModel = {}; const searchModel = {}
if (search && search.fields) { if (search && search.fields) {
search.fields.forEach(item => { search.fields.forEach(item => {
switch (item.type) { switch (item.type) {
case 'checkbox': case 'checkbox':
case 'checkbox-button': case 'checkbox-button':
searchModel[item.name] = []; searchModel[item.name] = []
break; break
default: default:
break; break
} }
if (item.defaultValue !== undefined) { if (item.defaultValue !== undefined) {
searchModel[item.name] = item.defaultValue; searchModel[item.name] = item.defaultValue
// //
if ( if (
(item.type === 'daterange' || item.type === 'datetimerange') && (item.type === 'daterange' || item.type === 'datetimerange') &&
@ -262,14 +262,14 @@ const getSearchModel = search => {
Array.isArray(item.defaultValue) Array.isArray(item.defaultValue)
) { ) {
item.defaultValue.forEach((val, index) => { item.defaultValue.forEach((val, index) => {
searchModel[item.trueNames[index]] = val; searchModel[item.trueNames[index]] = val
}); })
} }
} }
}); })
}
return searchModel
} }
return searchModel;
};
export default defineComponent({ export default defineComponent({
props: { props: {
// //
@ -316,43 +316,43 @@ export default defineComponent({
// 1transformtransform // 1transformtransform
// 2name // 2name
const optimizeFields = search => { const optimizeFields = search => {
const searchModel = JSON.parse(JSON.stringify(state.searchModel)); const searchModel = JSON.parse(JSON.stringify(state.searchModel))
if (search && search.fields) { if (search && search.fields) {
search.fields.forEach(item => { search.fields.forEach(item => {
if (!searchModel.hasOwnProperty(item.name)) { if (!searchModel.hasOwnProperty(item.name)) {
return; return
} }
if (item.transform) { if (item.transform) {
searchModel[item.name] = item.transform(searchModel[item.name]); searchModel[item.name] = item.transform(searchModel[item.name])
} }
if ( if (
(item.type === 'daterange' || item.type === 'datetimerange') && (item.type === 'daterange' || item.type === 'datetimerange') &&
!!item.trueNames !!item.trueNames
) { ) {
delete searchModel[item.name]; delete searchModel[item.name]
} }
}); })
}
return searchModel
} }
return searchModel;
};
// //
const getTableData = async () => { const getTableData = async () => {
state.loading = true; state.loading = true
const searchModel = optimizeFields(props.search); const searchModel = optimizeFields(props.search)
const { data, total } = await props.request({ const { data, total } = await props.request({
pageNum: state.pageNum, pageNum: state.pageNum,
pageSize: state.pageSize, pageSize: state.pageSize,
...searchModel, ...searchModel,
}); })
state.loading = false; state.loading = false
state.tableData = data; state.tableData = data
state.total = total; state.total = total
}; }
onBeforeMount(() => { onBeforeMount(() => {
getTableData(); getTableData()
}); })
const state = reactive({ const state = reactive({
searchModel: getSearchModel(props.search), searchModel: getSearchModel(props.search),
@ -366,80 +366,80 @@ export default defineComponent({
}, },
// //
handleSearch() { handleSearch() {
state.pageNum = 1; state.pageNum = 1
getTableData(); getTableData()
}, },
// //
handleReset() { handleReset() {
if (JSON.stringify(state.searchModel) === '{}') { if (JSON.stringify(state.searchModel) === '{}') {
return; return
} }
state.pageNum = 1; state.pageNum = 1
state.searchModel = getSearchModel(props.search); state.searchModel = getSearchModel(props.search)
getTableData(); getTableData()
}, },
// //
refresh() { refresh() {
getTableData(); getTableData()
}, },
// //
handleCurrentChange() { handleCurrentChange() {
getTableData(); getTableData()
}, },
// size // size
handleSizeChange() { handleSizeChange() {
state.pageNum = 1; state.pageNum = 1
getTableData(); getTableData()
}, },
// //
handleSelectionChange(arr) { handleSelectionChange(arr) {
emit('selectionChange', arr); emit('selectionChange', arr)
}, },
// //
filterHandler(value, row, column) { filterHandler(value, row, column) {
const property = column['property']; const property = column['property']
return row[property] === value; return row[property] === value
}, },
// //
handleDateChange(date, item, format) { handleDateChange(date, item, format) {
state.searchModel[item.name] = date ? formatDate(date, format) : ''; state.searchModel[item.name] = date ? formatDate(date, format) : ''
}, },
handleRangeChange(date, item, format) { handleRangeChange(date, item, format) {
const arr = !!date && date.map(d => formatDate(d, format)); const arr = !!date && date.map(d => formatDate(d, format))
state.searchModel[item.name] = arr ? arr : []; state.searchModel[item.name] = arr ? arr : []
if (!item.trueNames) { if (!item.trueNames) {
return; return
} }
if (arr) { if (arr) {
arr.forEach((val, index) => { arr.forEach((val, index) => {
state.searchModel[item.trueNames[index]] = val; state.searchModel[item.trueNames[index]] = val
}); })
} else { } else {
item.trueNames.forEach(key => { item.trueNames.forEach(key => {
delete state.searchModel[key]; delete state.searchModel[key]
}); })
} }
}, },
}); })
if (typeof props.pagination === 'object') { if (typeof props.pagination === 'object') {
const { layout, pageSizes, style } = props.pagination; const { layout, pageSizes, style } = props.pagination
state.paginationConfig = { state.paginationConfig = {
show: true, show: true,
layout: layout || 'total, sizes, prev, pager, next, jumper', layout: layout || 'total, sizes, prev, pager, next, jumper',
pageSizes: pageSizes || [10, 20, 30, 40, 50, 100], pageSizes: pageSizes || [10, 20, 30, 40, 50, 100],
style: style || {}, style: style || {},
}; }
} }
return { return {
...toRefs(state), ...toRefs(state),
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.page-box { .page-box {

View File

@ -5,7 +5,7 @@
</template> </template>
<script> <script>
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue'
export default defineComponent({ export default defineComponent({
name: 'SvgIcon', name: 'SvgIcon',
@ -20,10 +20,10 @@ export default defineComponent({
}, },
}, },
setup(props) { setup(props) {
const symbolId = computed(() => `#${props.prefix}-${props.name}`); const symbolId = computed(() => `#${props.prefix}-${props.name}`)
return { symbolId }; return { symbolId }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,2 +1,2 @@
export { default as SvgIcon } from '@/components/SvgIcon/index.vue'; export { default as SvgIcon } from '@/components/SvgIcon/index.vue'
export { default as ProTable } from '@/components/ProTable/index.vue'; export { default as ProTable } from '@/components/ProTable/index.vue'

View File

@ -6,21 +6,21 @@
</router-view> </router-view>
</template> </template>
<script> <script>
import { computed, defineComponent } from 'vue'; import { computed, defineComponent } from 'vue'
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
export default defineComponent({ export default defineComponent({
setup() { setup() {
const store = useStore(); const store = useStore()
const route = useRoute(); const route = useRoute()
const cacheList = computed(() => store.state.tags.cacheList); const cacheList = computed(() => store.state.tags.cacheList)
const key = computed(() => route.fullPath); const key = computed(() => route.fullPath)
return { return {
cacheList, cacheList,
key, key,
}; }
}, },
}); })
</script> </script>

View File

@ -5,18 +5,18 @@
</template> </template>
<script> <script>
import { computed, defineComponent } from 'vue'; import { computed, defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
props: ['title', 'icon'], props: ['title', 'icon'],
setup({ icon }) { setup({ icon }) {
const isElementIcon = computed(() => icon && icon.startsWith('el-icon')); const isElementIcon = computed(() => icon && icon.startsWith('el-icon'))
return { return {
isElementIcon, isElementIcon,
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.icon { .icon {

View File

@ -5,18 +5,18 @@
</div> </div>
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue'
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router'
export default defineComponent({ export default defineComponent({
setup() { setup() {
const router = useRouter(); const router = useRouter()
const goHome = () => { const goHome = () => {
router.push('/'); router.push('/')
}; }
return { goHome }; return { goHome }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.brand { .brand {

View File

@ -15,11 +15,11 @@
</el-scrollbar> </el-scrollbar>
</template> </template>
<script> <script>
import { computed, defineComponent } from 'vue'; import { computed, defineComponent } from 'vue'
import Submenu from './Submenu.vue'; import Submenu from './Submenu.vue'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router'
import config from './config/menu.module.scss'; import config from './config/menu.module.scss'
export default defineComponent({ export default defineComponent({
components: { components: {
@ -32,20 +32,20 @@ export default defineComponent({
}, },
}, },
setup() { setup() {
const route = useRoute(); const route = useRoute()
const store = useStore(); const store = useStore()
store.dispatch( store.dispatch(
'menu/generateMenus', 'menu/generateMenus',
store.state.account.userinfo && store.state.account.userinfo.role store.state.account.userinfo && store.state.account.userinfo.role
); )
return { return {
menus: computed(() => store.state.menu.menus), menus: computed(() => store.state.menu.menus),
activePath: computed(() => route.path), activePath: computed(() => route.path),
variables: computed(() => config), variables: computed(() => config),
}; }
}, },
}); })
</script> </script>
<style lang="scss"> <style lang="scss">
// menu hover // menu hover

View File

@ -15,8 +15,8 @@
</el-submenu> </el-submenu>
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue'
import Item from './Item.vue'; import Item from './Item.vue'
export default defineComponent({ export default defineComponent({
name: 'Submenu', name: 'Submenu',
components: { components: {
@ -32,5 +32,5 @@ export default defineComponent({
default: false, default: false,
}, },
}, },
}); })
</script> </script>

View File

@ -10,10 +10,10 @@
</template> </template>
<script> <script>
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue'
import Logo from './Logo.vue'; import Logo from './Logo.vue'
import Menus from './Menus.vue'; import Menus from './Menus.vue'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
export default defineComponent({ export default defineComponent({
components: { components: {
@ -21,21 +21,21 @@ export default defineComponent({
Menus, Menus,
}, },
setup() { setup() {
const store = useStore(); const store = useStore()
const collapse = computed(() => !!store.state.app.sidebar.collapse); const collapse = computed(() => !!store.state.app.sidebar.collapse)
const device = computed(() => store.state.app.device); const device = computed(() => store.state.app.device)
const closeSidebar = () => { const closeSidebar = () => {
store.commit('app/setCollapse', 1); store.commit('app/setCollapse', 1)
}; }
return { return {
collapse, collapse,
device, device,
closeSidebar, closeSidebar,
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,12 +1,12 @@
import { onMounted, onBeforeUnmount, reactive, toRefs, nextTick } from 'vue'; import { onMounted, onBeforeUnmount, reactive, toRefs, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
import { isAffix } from './useTags'; import { isAffix } from './useTags'
export const useContextMenu = tagList => { export const useContextMenu = tagList => {
const store = useStore(); const store = useStore()
const router = useRouter(); const router = useRouter()
const route = useRoute(); const route = useRoute()
const state = reactive({ const state = reactive({
visible: false, visible: false,
@ -14,89 +14,89 @@ export const useContextMenu = tagList => {
left: 0, left: 0,
selectedTag: {}, selectedTag: {},
openMenu(tag, e) { openMenu(tag, e) {
state.visible = true; state.visible = true
state.left = e.clientX; state.left = e.clientX
state.top = e.clientY; state.top = e.clientY
state.selectedTag = tag; state.selectedTag = tag
}, },
closeMenu() { closeMenu() {
state.visible = false; state.visible = false
}, },
refreshSelectedTag(tag) { refreshSelectedTag(tag) {
store.dispatch('tags/delCacheList', tag); store.dispatch('tags/delCacheList', tag)
const { fullPath } = tag; const { fullPath } = tag
nextTick(() => { nextTick(() => {
router.replace({ router.replace({
path: '/redirect' + fullPath, path: '/redirect' + fullPath,
}); })
}); })
}, },
closeTag(tag) { closeTag(tag) {
if (isAffix(tag)) return; if (isAffix(tag)) return
const closedTagIndex = tagList.value.findIndex( const closedTagIndex = tagList.value.findIndex(
item => item.fullPath === tag.fullPath item => item.fullPath === tag.fullPath
); )
store.dispatch('tags/delTag', tag); store.dispatch('tags/delTag', tag)
if (isActive(tag)) { if (isActive(tag)) {
toLastTag(closedTagIndex - 1); toLastTag(closedTagIndex - 1)
} }
}, },
closeOtherTags() { closeOtherTags() {
store.dispatch('tags/delOtherTags', state.selectedTag); store.dispatch('tags/delOtherTags', state.selectedTag)
router.push(state.selectedTag); router.push(state.selectedTag)
}, },
closeLeftTags() { closeLeftTags() {
state.closeSomeTags('left'); state.closeSomeTags('left')
}, },
closeRightTags() { closeRightTags() {
state.closeSomeTags('right'); state.closeSomeTags('right')
}, },
closeSomeTags(direction) { closeSomeTags(direction) {
const index = tagList.value.findIndex( const index = tagList.value.findIndex(
item => item.fullPath === state.selectedTag.fullPath item => item.fullPath === state.selectedTag.fullPath
); )
if ( if (
(direction === 'left' && index <= 0) || (direction === 'left' && index <= 0) ||
(direction === 'right' && index >= tagList.value.length - 1) (direction === 'right' && index >= tagList.value.length - 1)
) { ) {
return; return
} }
const needToClose = const needToClose =
direction === 'left' direction === 'left'
? tagList.value.slice(0, index) ? tagList.value.slice(0, index)
: tagList.value.slice(index + 1); : tagList.value.slice(index + 1)
store.dispatch('tags/delSomeTags', needToClose); store.dispatch('tags/delSomeTags', needToClose)
router.push(state.selectedTag); router.push(state.selectedTag)
}, },
closeAllTags() { closeAllTags() {
store.dispatch('tags/delAllTags'); store.dispatch('tags/delAllTags')
router.push('/'); router.push('/')
}, },
}); })
const isActive = tag => { const isActive = tag => {
return tag.fullPath === route.fullPath; return tag.fullPath === route.fullPath
}; }
const toLastTag = lastTagIndex => { const toLastTag = lastTagIndex => {
const lastTag = tagList.value[lastTagIndex]; const lastTag = tagList.value[lastTagIndex]
if (lastTag) { if (lastTag) {
router.push(lastTag.fullPath); router.push(lastTag.fullPath)
} else { } else {
router.push('/'); router.push('/')
}
} }
};
onMounted(() => { onMounted(() => {
document.addEventListener('click', state.closeMenu); document.addEventListener('click', state.closeMenu)
}); })
onBeforeUnmount(() => { onBeforeUnmount(() => {
document.removeEventListener('click', state.closeMenu); document.removeEventListener('click', state.closeMenu)
}); })
return toRefs(state); return toRefs(state)
}; }

View File

@ -1,41 +1,41 @@
import { ref } from 'vue'; import { ref } from 'vue'
export const useScrollbar = tagsItem => { export const useScrollbar = tagsItem => {
const scrollContainer = ref(null); const scrollContainer = ref(null)
const handleScroll = e => { const handleScroll = e => {
const eventDelta = e.wheelDelta || -e.deltaY; const eventDelta = e.wheelDelta || -e.deltaY
scrollContainer.value.wrap.scrollLeft -= eventDelta / 4; scrollContainer.value.wrap.scrollLeft -= eventDelta / 4
}; }
const moveToTarget = currentTag => { const moveToTarget = currentTag => {
const containerWidth = scrollContainer.value.scrollbar.offsetWidth; const containerWidth = scrollContainer.value.scrollbar.offsetWidth
const scrollWrapper = scrollContainer.value.wrap; const scrollWrapper = scrollContainer.value.wrap
const tagList = tagsItem.value; const tagList = tagsItem.value
let firstTag = null; let firstTag = null
let lastTag = null; let lastTag = null
if (tagList.length > 0) { if (tagList.length > 0) {
firstTag = tagList[0]; firstTag = tagList[0]
lastTag = tagList[tagList.length - 1]; lastTag = tagList[tagList.length - 1]
} }
if (firstTag === currentTag) { if (firstTag === currentTag) {
scrollWrapper.scrollLeft = 0; scrollWrapper.scrollLeft = 0
} else if (lastTag === currentTag) { } else if (lastTag === currentTag) {
scrollWrapper.scrollLeft = scrollWrapper.scrollWidth - containerWidth; scrollWrapper.scrollLeft = scrollWrapper.scrollWidth - containerWidth
} else { } else {
const el = currentTag.$el.nextElementSibling; const el = currentTag.$el.nextElementSibling
scrollWrapper.scrollLeft = scrollWrapper.scrollLeft =
el.offsetLeft + el.offsetWidth > containerWidth el.offsetLeft + el.offsetWidth > containerWidth
? el.offsetLeft - el.offsetWidth ? el.offsetLeft - el.offsetWidth
: 0; : 0
}
} }
};
return { return {
scrollContainer, scrollContainer,
handleScroll, handleScroll,
moveToTarget, moveToTarget,
}; }
}; }

View File

@ -1,94 +1,94 @@
import { useScrollbar } from './useScrollbar'; import { useScrollbar } from './useScrollbar'
import { watch, computed, ref, nextTick, onBeforeMount } from 'vue'; import { watch, computed, ref, nextTick, onBeforeMount } from 'vue'
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
export const isAffix = tag => { export const isAffix = tag => {
return !!tag.meta && !!tag.meta.affix; return !!tag.meta && !!tag.meta.affix
}; }
export const useTags = () => { export const useTags = () => {
const store = useStore(); const store = useStore()
const router = useRouter(); const router = useRouter()
const route = router.currentRoute; const route = router.currentRoute
const routes = computed(() => router.getRoutes()); const routes = computed(() => router.getRoutes())
const tagList = computed(() => store.state.tags.tagList); const tagList = computed(() => store.state.tags.tagList)
const tagsItem = ref([]); const tagsItem = ref([])
const setItemRef = (i, el) => { const setItemRef = (i, el) => {
tagsItem.value[i] = el; tagsItem.value[i] = el
}; }
const scrollbar = useScrollbar(tagsItem); const scrollbar = useScrollbar(tagsItem)
watch( watch(
() => tagList.value.length, () => tagList.value.length,
() => { () => {
tagsItem.value = []; tagsItem.value = []
} }
); )
const filterAffixTags = routes => { const filterAffixTags = routes => {
return routes.filter(route => isAffix(route)); return routes.filter(route => isAffix(route))
}; }
const initTags = () => { const initTags = () => {
const affixTags = filterAffixTags(routes.value); const affixTags = filterAffixTags(routes.value)
for (const tag of affixTags) { for (const tag of affixTags) {
if (tag.name) { if (tag.name) {
store.dispatch('tags/addTagList', tag); store.dispatch('tags/addTagList', tag)
}
} }
} }
};
const addTag = () => { const addTag = () => {
const tag = route.value; const tag = route.value
if (!!tag.name && tag.matched[0].components.default.name === 'layout') { if (!!tag.name && tag.matched[0].components.default.name === 'layout') {
store.dispatch('tags/addTag', tag); store.dispatch('tags/addTag', tag)
}
} }
};
const saveActivePosition = tag => { const saveActivePosition = tag => {
const index = tagList.value.findIndex( const index = tagList.value.findIndex(
item => item.fullPath === tag.fullPath item => item.fullPath === tag.fullPath
); )
store.dispatch('tags/saveActivePosition', Math.max(0, index)); store.dispatch('tags/saveActivePosition', Math.max(0, index))
}; }
const moveToCurrentTag = () => { const moveToCurrentTag = () => {
nextTick(() => { nextTick(() => {
for (const tag of tagsItem.value) { for (const tag of tagsItem.value) {
if (!!tag && tag.to.path === route.value.path) { if (!!tag && tag.to.path === route.value.path) {
scrollbar.moveToTarget(tag); scrollbar.moveToTarget(tag)
if (tag.to.fullPath !== route.value.fullPath) { if (tag.to.fullPath !== route.value.fullPath) {
store.dispatch('tags/updateTagList', route.value); store.dispatch('tags/updateTagList', route.value)
} }
break; break
} }
} }
}); })
}; }
onBeforeMount(() => { onBeforeMount(() => {
initTags(); initTags()
addTag(); addTag()
moveToCurrentTag(); moveToCurrentTag()
}); })
watch(route, (newRoute, oldRoute) => { watch(route, (newRoute, oldRoute) => {
saveActivePosition(oldRoute); // 保存标签的位置 saveActivePosition(oldRoute) // 保存标签的位置
addTag(); addTag()
moveToCurrentTag(); moveToCurrentTag()
}); })
return { return {
tagList, tagList,
setItemRef, setItemRef,
isAffix, isAffix,
...scrollbar, ...scrollbar,
}; }
}; }

View File

@ -46,28 +46,28 @@
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue'
import { useTags } from './hooks/useTags'; import { useTags } from './hooks/useTags'
import { useContextMenu } from './hooks/useContextMenu'; import { useContextMenu } from './hooks/useContextMenu'
export default defineComponent({ export default defineComponent({
name: 'Tagsbar', name: 'Tagsbar',
setup() { setup() {
const tags = useTags(); const tags = useTags()
const contextMenu = useContextMenu(tags.tagList); const contextMenu = useContextMenu(tags.tagList)
const onScroll = e => { const onScroll = e => {
tags.handleScroll(e); tags.handleScroll(e)
contextMenu.closeMenu.value(); contextMenu.closeMenu.value()
}; }
return { return {
onScroll, onScroll,
...tags, ...tags,
...contextMenu, ...contextMenu,
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -15,45 +15,45 @@
</el-breadcrumb> </el-breadcrumb>
</template> </template>
<script> <script>
import { defineComponent, computed, ref, onBeforeMount, watch } from 'vue'; import { defineComponent, computed, ref, onBeforeMount, watch } from 'vue'
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
export default defineComponent({ export default defineComponent({
setup() { setup() {
const store = useStore(); const store = useStore()
const device = computed(() => store.state.app.device); const device = computed(() => store.state.app.device)
const router = useRouter(); const router = useRouter()
const route = router.currentRoute; // 使useRoutewatch const route = router.currentRoute // 使useRoutewatch
const breadcrumbs = ref([]); const breadcrumbs = ref([])
const getBreadcrumbs = route => { const getBreadcrumbs = route => {
const home = [{ path: '/', meta: { title: '首页' } }]; const home = [{ path: '/', meta: { title: '首页' } }]
if (route.name === 'home') { if (route.name === 'home') {
return home; return home
} else { } else {
const matched = route.matched.filter( const matched = route.matched.filter(
item => !!item.meta && !!item.meta.title item => !!item.meta && !!item.meta.title
); )
return [...home, ...matched]; return [...home, ...matched]
}
} }
};
onBeforeMount(() => { onBeforeMount(() => {
breadcrumbs.value = getBreadcrumbs(route.value); breadcrumbs.value = getBreadcrumbs(route.value)
}); })
watch(route, newRoute => { watch(route, newRoute => {
breadcrumbs.value = getBreadcrumbs(newRoute); breadcrumbs.value = getBreadcrumbs(newRoute)
}); })
return { return {
device, device,
breadcrumbs, breadcrumbs,
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -6,22 +6,22 @@
></i> ></i>
</template> </template>
<script> <script>
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
export default defineComponent({ export default defineComponent({
setup() { setup() {
const store = useStore(); const store = useStore()
const collapse = computed(() => !!store.state.app.sidebar.collapse); const collapse = computed(() => !!store.state.app.sidebar.collapse)
const handleToggleMenu = () => { const handleToggleMenu = () => {
store.commit('app/setCollapse', +!collapse.value); store.commit('app/setCollapse', +!collapse.value)
}; }
return { return {
collapse, collapse,
handleToggleMenu, handleToggleMenu,
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.fold-btn { .fold-btn {

View File

@ -21,26 +21,26 @@
</el-dropdown> </el-dropdown>
</template> </template>
<script> <script>
import { computed, defineComponent } from 'vue'; import { computed, defineComponent } from 'vue'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router'
export default defineComponent({ export default defineComponent({
setup() { setup() {
const store = useStore(); const store = useStore()
const router = useRouter(); const router = useRouter()
const userinfo = computed(() => store.state.account.userinfo); const userinfo = computed(() => store.state.account.userinfo)
const logout = () => { const logout = () => {
store.commit('app/clearToken'); store.commit('app/clearToken')
store.commit('account/clearUserinfo'); store.commit('account/clearUserinfo')
store.dispatch('tags/delAllTags'); store.dispatch('tags/delAllTags')
router.push('/login'); router.push('/login')
}; }
return { return {
userinfo, userinfo,
logout, logout,
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -11,12 +11,12 @@
</div> </div>
</template> </template>
<script> <script>
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue'
import Logo from '@/layout/components/Sidebar/Logo.vue'; import Logo from '@/layout/components/Sidebar/Logo.vue'
import Hamburger from './Hamburger.vue'; import Hamburger from './Hamburger.vue'
import Breadcrumbs from './Breadcrumbs.vue'; import Breadcrumbs from './Breadcrumbs.vue'
import Userinfo from './Userinfo.vue'; import Userinfo from './Userinfo.vue'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
export default defineComponent({ export default defineComponent({
components: { components: {
@ -26,14 +26,14 @@ export default defineComponent({
Userinfo, Userinfo,
}, },
setup() { setup() {
const store = useStore(); const store = useStore()
const device = computed(() => store.state.app.device); const device = computed(() => store.state.app.device)
return { return {
device, device,
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.header { .header {

View File

@ -1,38 +1,38 @@
import { onBeforeMount, onBeforeUnmount /*watch*/ } from 'vue'; import { onBeforeMount, onBeforeUnmount /*watch*/ } from 'vue'
// import { useRouter } from 'vue-router'; // import { useRouter } from 'vue-router';
import { useStore } from 'vuex'; import { useStore } from 'vuex'
const WIDTH = 768; const WIDTH = 768
export const useResizeHandler = () => { export const useResizeHandler = () => {
const store = useStore(); const store = useStore()
// const router = useRouter(); // const router = useRouter();
// const route = router.currentRoute; // const route = router.currentRoute;
const isMobile = () => { const isMobile = () => {
return window.innerWidth < WIDTH; return window.innerWidth < WIDTH
}; }
const resizeHandler = () => { const resizeHandler = () => {
if (isMobile()) { if (isMobile()) {
store.commit('app/setDevice', 'mobile'); store.commit('app/setDevice', 'mobile')
store.commit('app/setCollapse', 1); store.commit('app/setCollapse', 1)
} else { } else {
store.commit('app/setDevice', 'desktop'); store.commit('app/setDevice', 'desktop')
store.commit('app/setCollapse', 0); store.commit('app/setCollapse', 0)
}
} }
};
onBeforeMount(() => { onBeforeMount(() => {
if (isMobile()) { if (isMobile()) {
store.commit('app/setDevice', 'mobile'); store.commit('app/setDevice', 'mobile')
store.commit('app/setCollapse', 1); store.commit('app/setCollapse', 1)
} }
window.addEventListener('resize', resizeHandler); window.addEventListener('resize', resizeHandler)
}); })
onBeforeUnmount(() => { onBeforeUnmount(() => {
window.removeEventListener('resize', resizeHandler); window.removeEventListener('resize', resizeHandler)
}); })
// // 监听路由的时候不能使用useRoute获取路由否则会有警告 // // 监听路由的时候不能使用useRoute获取路由否则会有警告
// watch(route, () => { // watch(route, () => {
@ -40,4 +40,4 @@ export const useResizeHandler = () => {
// store.commit('app/setCollapse', 1) // store.commit('app/setCollapse', 1)
// } // }
// }) // })
}; }

View File

@ -13,12 +13,12 @@
</div> </div>
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue'
import Sidebar from './components/Sidebar/index.vue'; import Sidebar from './components/Sidebar/index.vue'
import Topbar from './components/Topbar/index.vue'; import Topbar from './components/Topbar/index.vue'
import Tagsbar from './components/Tagsbar/index.vue'; import Tagsbar from './components/Tagsbar/index.vue'
import Content from './components/Content/index.vue'; import Content from './components/Content/index.vue'
import { useResizeHandler } from './hooks/useResizeHandler'; import { useResizeHandler } from './hooks/useResizeHandler'
export default defineComponent({ export default defineComponent({
name: 'layout', name: 'layout',
@ -29,9 +29,9 @@ export default defineComponent({
Content, Content,
}, },
setup() { setup() {
useResizeHandler(); useResizeHandler()
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,35 +1,35 @@
import { createApp } from 'vue'; import { createApp } from 'vue'
import App from './App.vue'; import App from './App.vue'
const app = createApp(App); const app = createApp(App)
// 引入element-plus // 引入element-plus
import ElementPlus from 'element-plus'; import ElementPlus from 'element-plus'
import './assets/style/element-variables.scss'; import './assets/style/element-variables.scss'
// 引入中文语言包 // 引入中文语言包
import 'dayjs/locale/zh-cn'; import 'dayjs/locale/zh-cn'
import locale from 'element-plus/lib/locale/lang/zh-cn'; import locale from 'element-plus/lib/locale/lang/zh-cn'
// 引入路由 // 引入路由
import router from './router'; import router from './router'
// 引入store // 引入store
import store from './store'; import store from './store'
// 权限控制 // 权限控制
import './permission'; import './permission'
// 引入svg图标注册脚本 // 引入svg图标注册脚本
import 'vite-plugin-svg-icons/register'; import 'vite-plugin-svg-icons/register'
// 注册全局组件 // 注册全局组件
import * as Components from './global-components'; import * as Components from './global-components'
Object.entries(Components).forEach(([key, component]) => { Object.entries(Components).forEach(([key, component]) => {
app.component(key, component); app.component(key, component)
}); })
app app
.use(ElementPlus, { locale }) .use(ElementPlus, { locale })
.use(store) .use(store)
.use(router) .use(router)
.mount('#app'); .mount('#app')

View File

@ -1,24 +1,24 @@
import router from '@/router'; import router from '@/router'
import store from '@/store'; import store from '@/store'
import { TOKEN } from '@/store/modules/app'; // TOKEN变量名 import { TOKEN } from '@/store/modules/app' // TOKEN变量名
const getPageTitle = title => { const getPageTitle = title => {
const appTitle = store.state.app.title; const appTitle = store.state.app.title
if (title) { if (title) {
return `${title} - ${appTitle}`; return `${title} - ${appTitle}`
}
return appTitle
} }
return appTitle;
};
// 白名单里面是路由对象的name // 白名单里面是路由对象的name
const WhiteList = ['login', 'forbidden', 'server-error', 'not-found']; const WhiteList = ['login', 'forbidden', 'server-error', 'not-found']
// vue-router4的路由守卫不再是通过next放行而是通过return返回true或false或者一个路由地址 // vue-router4的路由守卫不再是通过next放行而是通过return返回true或false或者一个路由地址
router.beforeEach(async to => { router.beforeEach(async to => {
document.title = getPageTitle(!!to.meta && to.meta.title); document.title = getPageTitle(!!to.meta && to.meta.title)
if (WhiteList.includes(to.name)) { if (WhiteList.includes(to.name)) {
return true; return true
} }
if (!window.localStorage[TOKEN]) { if (!window.localStorage[TOKEN]) {
return { return {
@ -27,15 +27,15 @@ router.beforeEach(async to => {
redirect: to.path, // redirect是指登录之后可以跳回到redirect指定的页面 redirect: to.path, // redirect是指登录之后可以跳回到redirect指定的页面
}, },
replace: true, replace: true,
}; }
} else { } else {
let userinfo = store.state.account.userinfo; let userinfo = store.state.account.userinfo
if (!userinfo) { if (!userinfo) {
try { try {
// 获取用户信息 // 获取用户信息
userinfo = await store.dispatch('account/getUserinfo'); userinfo = await store.dispatch('account/getUserinfo')
} catch (err) { } catch (err) {
return false; return false
} }
} }
// 如果没有权限跳转到403页面 // 如果没有权限跳转到403页面
@ -44,7 +44,7 @@ router.beforeEach(async to => {
!!to.meta.roles && !!to.meta.roles &&
!to.meta.roles.includes(userinfo.role) !to.meta.roles.includes(userinfo.role)
) { ) {
return { path: '/403', replace: true }; return { path: '/403', replace: true }
} }
} }
}); })

View File

@ -1,14 +1,14 @@
// index.js // index.js
import { createRouter, createWebHashHistory } from 'vue-router'; import { createRouter, createWebHashHistory } from 'vue-router'
import redirect from './modules/redirect'; import redirect from './modules/redirect'
import error from './modules/error'; import error from './modules/error'
import login from './modules/login'; import login from './modules/login'
import home from './modules/home'; import home from './modules/home'
import test from './modules/test'; import test from './modules/test'
// 左侧菜单 // 左侧菜单
export const allMenus = [...home, ...test]; export const allMenus = [...home, ...test]
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
@ -24,11 +24,11 @@ const router = createRouter({
], ],
scrollBehavior(to, from, savedPosition) { scrollBehavior(to, from, savedPosition) {
if (savedPosition) { if (savedPosition) {
return savedPosition; return savedPosition
} else { } else {
return { left: 0, top: 0 }; return { left: 0, top: 0 }
} }
}, },
}); })
export default router; export default router

View File

@ -1,15 +1,15 @@
import store from '@/store'; import store from '@/store'
const checkUserinfo = code => { const checkUserinfo = code => {
const userinfo = store.state.account.userinfo; const userinfo = store.state.account.userinfo
if (userinfo) { if (userinfo) {
return `/error/${code}`; return `/error/${code}`
}
return true
} }
return true;
};
const Layout = () => import('@/layout/index.vue'); const Layout = () => import('@/layout/index.vue')
const Error = () => import('@/views/error/index.vue'); const Error = () => import('@/views/error/index.vue')
export default [ export default [
{ {
@ -53,7 +53,7 @@ export default [
error: '403', error: '403',
}, },
beforeEnter() { beforeEnter() {
return checkUserinfo('403'); return checkUserinfo('403')
}, },
}, },
{ {
@ -64,7 +64,7 @@ export default [
error: '500', error: '500',
}, },
beforeEnter() { beforeEnter() {
return checkUserinfo('500'); return checkUserinfo('500')
}, },
}, },
{ {
@ -75,7 +75,7 @@ export default [
error: '404', error: '404',
}, },
beforeEnter() { beforeEnter() {
return checkUserinfo('404'); return checkUserinfo('404')
}, },
}, },
]; ]

View File

@ -1,6 +1,6 @@
// home.js // home.js
const Layout = () => import('@/layout/index.vue'); const Layout = () => import('@/layout/index.vue')
const Home = () => import('@/views/home/index.vue'); const Home = () => import('@/views/home/index.vue')
export default [ export default [
{ {
@ -23,4 +23,4 @@ export default [
}, },
], ],
}, },
]; ]

View File

@ -1,5 +1,5 @@
// login.js // login.js
const Login = () => import('@/views/login/index.vue'); const Login = () => import('@/views/login/index.vue')
export default [ export default [
{ {
@ -7,4 +7,4 @@ export default [
name: 'login', name: 'login',
component: Login, component: Login,
}, },
]; ]

View File

@ -1,5 +1,5 @@
const Layout = () => import('@/layout/index.vue'); const Layout = () => import('@/layout/index.vue')
const Redirect = () => import('@/views/redirect/index.vue'); const Redirect = () => import('@/views/redirect/index.vue')
export default [ export default [
{ {
@ -12,4 +12,4 @@ export default [
}, },
], ],
}, },
]; ]

View File

@ -1,13 +1,13 @@
const Layout = () => import('@/layout/index.vue'); const Layout = () => import('@/layout/index.vue')
const List = () => import('@/views/test/index.vue'); const List = () => import('@/views/test/index.vue')
const Add = () => import('@/views/test/Add.vue'); const Add = () => import('@/views/test/Add.vue')
const Auth = () => import('@/views/test/Auth.vue'); const Auth = () => import('@/views/test/Auth.vue')
const NoAuth = () => import('@/views/test/NoAuth.vue'); const NoAuth = () => import('@/views/test/NoAuth.vue')
const Nest = () => import('@/views/test/Nest.vue'); const Nest = () => import('@/views/test/Nest.vue')
const NestPage1 = () => import('@/views/test/nest/Page1.vue'); const NestPage1 = () => import('@/views/test/nest/Page1.vue')
const NestPage2 = () => import('@/views/test/nest/Page2.vue'); const NestPage2 = () => import('@/views/test/nest/Page2.vue')
const Iscache = () => import('@/views/test/Cache.vue'); const Iscache = () => import('@/views/test/Cache.vue')
const Nocache = () => import('@/views/test/Nocache.vue'); const Nocache = () => import('@/views/test/Nocache.vue')
export default [ export default [
{ {
@ -109,4 +109,4 @@ export default [
}, },
], ],
}, },
]; ]

View File

@ -1,9 +1,9 @@
//index.js //index.js
import { createStore } from 'vuex'; import { createStore } from 'vuex'
import app from './modules/app'; import app from './modules/app'
import account from './modules/account'; import account from './modules/account'
import menu from './modules/menu'; import menu from './modules/menu'
import tags from './modules/tags'; import tags from './modules/tags'
export default createStore({ export default createStore({
modules: { modules: {
@ -12,4 +12,4 @@ export default createStore({
menu, menu,
tags, tags,
}, },
}); })

View File

@ -1,4 +1,4 @@
import { GetUserinfo } from '@/api/login'; import { GetUserinfo } from '@/api/login'
export default { export default {
namespaced: true, namespaced: true,
@ -8,21 +8,21 @@ export default {
mutations: { mutations: {
// 保存用户信息 // 保存用户信息
setUserinfo(state, data) { setUserinfo(state, data) {
state.userinfo = data; state.userinfo = data
}, },
// 清除用户信息 // 清除用户信息
clearUserinfo(state) { clearUserinfo(state) {
state.userinfo = null; state.userinfo = null
}, },
}, },
actions: { actions: {
// 获取用户信息 // 获取用户信息
async getUserinfo({ commit }) { async getUserinfo({ commit }) {
const { code, data } = await GetUserinfo(); const { code, data } = await GetUserinfo()
if (+code === 200) { if (+code === 200) {
commit('setUserinfo', data); commit('setUserinfo', data)
return Promise.resolve(data); return Promise.resolve(data)
} }
}, },
}, },
}; }

View File

@ -1,6 +1,6 @@
import { getItem, setItem, removeItem } from '@/utils/storage'; //getItem和setItem是封装的操作localStorage的方法 import { getItem, setItem, removeItem } from '@/utils/storage' //getItem和setItem是封装的操作localStorage的方法
export const TOKEN = 'VEA-TOKEN'; export const TOKEN = 'VEA-TOKEN'
const COLLAPSE = 'VEA-COLLAPSE'; const COLLAPSE = 'VEA-COLLAPSE'
export default { export default {
namespaced: true, namespaced: true,
@ -14,28 +14,28 @@ export default {
}, },
mutations: { mutations: {
setToken(state, data) { setToken(state, data) {
state.authorization = data; state.authorization = data
// 保存到localStorage // 保存到localStorage
setItem(TOKEN, data); setItem(TOKEN, data)
}, },
clearToken(state) { clearToken(state) {
state.authorization = ''; state.authorization = ''
removeItem(TOKEN); removeItem(TOKEN)
}, },
setCollapse(state, data) { setCollapse(state, data) {
state.sidebar.collapse = data; state.sidebar.collapse = data
// 保存到localStorage // 保存到localStorage
setItem(COLLAPSE, data); setItem(COLLAPSE, data)
}, },
clearCollapse(state) { clearCollapse(state) {
state.sidebar.collapse = ''; state.sidebar.collapse = ''
removeItem(COLLAPSE); removeItem(COLLAPSE)
}, },
setDevice(state, device) { setDevice(state, device) {
state.device = device; state.device = device
}, },
}, },
actions: {}, actions: {},
}; }

View File

@ -1,23 +1,23 @@
import { allMenus } from '@/router'; import { allMenus } from '@/router'
// import { GetMenus } from '@/api/menu'; // import { GetMenus } from '@/api/menu';
const hasPermission = (role, route) => { const hasPermission = (role, route) => {
if (!!route.meta && !!route.meta.roles && !route.meta.roles.includes(role)) { if (!!route.meta && !!route.meta.roles && !route.meta.roles.includes(role)) {
return false; return false
}
return true
} }
return true;
};
const generateUrl = (path, parentPath) => { const generateUrl = (path, parentPath) => {
return path.startsWith('/') return path.startsWith('/')
? path ? path
: path : path
? `${parentPath}/${path}` ? `${parentPath}/${path}`
: parentPath; : parentPath
}; }
const getFilterMenus = (arr, role, parentPath = '') => { const getFilterMenus = (arr, role, parentPath = '') => {
const menus = []; const menus = []
arr.forEach(item => { arr.forEach(item => {
if (hasPermission(role, item) && !item.hidden) { if (hasPermission(role, item) && !item.hidden) {
@ -25,20 +25,20 @@ const getFilterMenus = (arr, role, parentPath = '') => {
url: generateUrl(item.path, parentPath), url: generateUrl(item.path, parentPath),
title: item.meta.title, title: item.meta.title,
icon: item.icon, icon: item.icon,
}; }
if (item.children) { if (item.children) {
if (item.children.length === 1) { if (item.children.length === 1) {
menu.url = generateUrl(item.children[0].path, menu.url); menu.url = generateUrl(item.children[0].path, menu.url)
} else { } else {
menu.children = getFilterMenus(item.children, role, menu.url); menu.children = getFilterMenus(item.children, role, menu.url)
} }
} }
menus.push(menu); menus.push(menu)
} }
}); })
return menus; return menus
}; }
export default { export default {
namespaced: true, namespaced: true,
@ -47,14 +47,14 @@ export default {
}, },
mutations: { mutations: {
SET_MENUS(state, data) { SET_MENUS(state, data) {
state.menus = data; state.menus = data
}, },
}, },
actions: { actions: {
async generateMenus({ commit }, role) { async generateMenus({ commit }, role) {
// 方式一:根据角色生成菜单 // 方式一:根据角色生成菜单
const menus = getFilterMenus(allMenus, role); const menus = getFilterMenus(allMenus, role)
commit('SET_MENUS', menus); commit('SET_MENUS', menus)
// // 方式二:从后台获取菜单 // // 方式二:从后台获取菜单
// const { code, data } = await GetMenus(); // const { code, data } = await GetMenus();
@ -63,4 +63,4 @@ export default {
// } // }
}, },
}, },
}; }

View File

@ -1,16 +1,16 @@
import { getItem, setItem, removeItem } from '@/utils/storage'; //getItem和setItem是封装的操作localStorage的方法 import { getItem, setItem, removeItem } from '@/utils/storage' //getItem和setItem是封装的操作localStorage的方法
const TAGLIST = 'VEA-TAGLIST'; const TAGLIST = 'VEA-TAGLIST'
const state = { const state = {
tagList: getItem(TAGLIST) || [], tagList: getItem(TAGLIST) || [],
cacheList: [], cacheList: [],
activePosition: 0, activePosition: 0,
}; }
const mutations = { const mutations = {
ADD_TAG_LIST: (state, { path, fullPath, name, meta }) => { ADD_TAG_LIST: (state, { path, fullPath, name, meta }) => {
if (state.tagList.some(v => v.path === path)) return false; if (state.tagList.some(v => v.path === path)) return false
state.tagList.splice( state.tagList.splice(
state.activePosition + 1, state.activePosition + 1,
@ -23,136 +23,136 @@ const mutations = {
fullPath: fullPath || path, fullPath: fullPath || path,
} }
) )
); )
// 保存到localStorage // 保存到localStorage
setItem(TAGLIST, state.tagList); setItem(TAGLIST, state.tagList)
}, },
ADD_CACHE_LIST: (state, tag) => { ADD_CACHE_LIST: (state, tag) => {
if (state.cacheList.includes(tag.name)) return; if (state.cacheList.includes(tag.name)) return
if (!tag.meta.noCache) { if (!tag.meta.noCache) {
state.cacheList.push(tag.name); state.cacheList.push(tag.name)
} }
}, },
DEL_TAG_LIST: (state, tag) => { DEL_TAG_LIST: (state, tag) => {
state.tagList = state.tagList.filter(v => v.path !== tag.path); state.tagList = state.tagList.filter(v => v.path !== tag.path)
// 保存到localStorage // 保存到localStorage
setItem(TAGLIST, state.tagList); setItem(TAGLIST, state.tagList)
}, },
DEL_CACHE_LIST: (state, tag) => { DEL_CACHE_LIST: (state, tag) => {
state.cacheList = state.cacheList.filter(v => v !== tag.name); state.cacheList = state.cacheList.filter(v => v !== tag.name)
}, },
DEL_OTHER_TAG_LIST: (state, tag) => { DEL_OTHER_TAG_LIST: (state, tag) => {
state.tagList = state.tagList.filter( state.tagList = state.tagList.filter(
v => !!v.meta.affix || v.path === tag.path v => !!v.meta.affix || v.path === tag.path
); )
// 保存到localStorage // 保存到localStorage
setItem(TAGLIST, state.tagList); setItem(TAGLIST, state.tagList)
}, },
DEL_OTHER_CACHE_LIST: (state, tag) => { DEL_OTHER_CACHE_LIST: (state, tag) => {
state.cacheList = state.cacheList.filter(v => v === tag.name); state.cacheList = state.cacheList.filter(v => v === tag.name)
}, },
DEL_SOME_TAG_LIST: (state, tags) => { DEL_SOME_TAG_LIST: (state, tags) => {
state.tagList = state.tagList.filter( state.tagList = state.tagList.filter(
v => !!v.meta.affix || tags.every(tag => tag.path !== v.path) v => !!v.meta.affix || tags.every(tag => tag.path !== v.path)
); )
// 保存到localStorage // 保存到localStorage
setItem(TAGLIST, state.tagList); setItem(TAGLIST, state.tagList)
}, },
DEL_SOME_CACHE_LIST: (state, tags) => { DEL_SOME_CACHE_LIST: (state, tags) => {
state.cacheList = state.cacheList.filter(v => state.cacheList = state.cacheList.filter(v =>
tags.every(tag => tag.name !== v) tags.every(tag => tag.name !== v)
); )
}, },
DEL_ALL_TAG_LIST: state => { DEL_ALL_TAG_LIST: state => {
state.tagList = state.tagList.filter(v => !!v.meta.affix); state.tagList = state.tagList.filter(v => !!v.meta.affix)
// 保存到localStorage // 保存到localStorage
removeItem(TAGLIST); removeItem(TAGLIST)
}, },
DEL_ALL_CACHE_LIST: state => { DEL_ALL_CACHE_LIST: state => {
state.cacheList = []; state.cacheList = []
}, },
UPDATE_TAG_LIST: (state, tag) => { UPDATE_TAG_LIST: (state, tag) => {
const index = state.tagList.findIndex(v => v.path === tag.path); const index = state.tagList.findIndex(v => v.path === tag.path)
if (index > -1) { if (index > -1) {
state.tagList[index] = Object.assign({}, state.tagList[index], tag); state.tagList[index] = Object.assign({}, state.tagList[index], tag)
// 保存到localStorage // 保存到localStorage
setItem(TAGLIST, state.tagList); setItem(TAGLIST, state.tagList)
} }
}, },
SAVE_ACTIVE_POSITION: (state, index) => { SAVE_ACTIVE_POSITION: (state, index) => {
state.activePosition = index; state.activePosition = index
}, },
}; }
const actions = { const actions = {
saveActivePosition({ commit }, index) { saveActivePosition({ commit }, index) {
commit('SAVE_ACTIVE_POSITION', index); commit('SAVE_ACTIVE_POSITION', index)
}, },
addTag({ dispatch }, tag) { addTag({ dispatch }, tag) {
dispatch('addTagList', tag); dispatch('addTagList', tag)
dispatch('addCacheList', tag); dispatch('addCacheList', tag)
}, },
addTagList({ commit }, tag) { addTagList({ commit }, tag) {
commit('ADD_TAG_LIST', tag); commit('ADD_TAG_LIST', tag)
}, },
addCacheList({ commit }, tag) { addCacheList({ commit }, tag) {
commit('ADD_CACHE_LIST', tag); commit('ADD_CACHE_LIST', tag)
}, },
delTag({ dispatch }, tag) { delTag({ dispatch }, tag) {
dispatch('delTagList', tag); dispatch('delTagList', tag)
dispatch('delCacheList', tag); dispatch('delCacheList', tag)
}, },
delTagList({ commit }, tag) { delTagList({ commit }, tag) {
commit('DEL_TAG_LIST', tag); commit('DEL_TAG_LIST', tag)
}, },
delCacheList({ commit }, tag) { delCacheList({ commit }, tag) {
commit('DEL_CACHE_LIST', tag); commit('DEL_CACHE_LIST', tag)
}, },
delOtherTags({ dispatch }, tag) { delOtherTags({ dispatch }, tag) {
dispatch('delOtherTagList', tag); dispatch('delOtherTagList', tag)
dispatch('delOtherCacheList', tag); dispatch('delOtherCacheList', tag)
}, },
delOtherTagList({ commit }, tag) { delOtherTagList({ commit }, tag) {
commit('DEL_OTHER_TAG_LIST', tag); commit('DEL_OTHER_TAG_LIST', tag)
}, },
delOtherCacheList({ commit }, tag) { delOtherCacheList({ commit }, tag) {
commit('DEL_OTHER_CACHE_LIST', tag); commit('DEL_OTHER_CACHE_LIST', tag)
}, },
delSomeTags({ commit }, tags) { delSomeTags({ commit }, tags) {
commit('DEL_SOME_TAG_LIST', tags); commit('DEL_SOME_TAG_LIST', tags)
commit('DEL_SOME_CACHE_LIST', tags); commit('DEL_SOME_CACHE_LIST', tags)
}, },
delAllTags({ dispatch }) { delAllTags({ dispatch }) {
dispatch('delAllTagList'); dispatch('delAllTagList')
dispatch('delAllCacheList'); dispatch('delAllCacheList')
}, },
delAllTagList({ commit }) { delAllTagList({ commit }) {
commit('DEL_ALL_TAG_LIST'); commit('DEL_ALL_TAG_LIST')
}, },
delAllCacheList({ commit }) { delAllCacheList({ commit }) {
commit('DEL_ALL_CACHE_LIST'); commit('DEL_ALL_CACHE_LIST')
}, },
updateTagList({ commit }, tag) { updateTagList({ commit }, tag) {
commit('UPDATE_TAG_LIST', tag); commit('UPDATE_TAG_LIST', tag)
}, },
}; }
export default { export default {
namespaced: true, namespaced: true,
state, state,
mutations, mutations,
actions, actions,
}; }

View File

@ -1,34 +1,34 @@
import axios from 'axios'; import axios from 'axios'
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus'
import store from '@/store'; import store from '@/store'
import router from '@/router'; import router from '@/router'
const service = axios.create({ const service = axios.create({
baseURL: '/', baseURL: '/',
timeout: 10000, timeout: 10000,
withCredentials: true, withCredentials: true,
}); })
// 拦截请求 // 拦截请求
service.interceptors.request.use( service.interceptors.request.use(
config => { config => {
const { authorization } = store.state.app; const { authorization } = store.state.app
if (authorization) { if (authorization) {
config.headers.Authorization = `Bearer ${authorization.token}`; config.headers.Authorization = `Bearer ${authorization.token}`
} }
return config; return config
}, },
error => { error => {
// console.log(error); // console.log(error);
return Promise.reject(error); return Promise.reject(error)
} }
); )
// 拦截响应 // 拦截响应
service.interceptors.response.use( service.interceptors.response.use(
// 响应成功进入第1个函数该函数的参数是响应对象 // 响应成功进入第1个函数该函数的参数是响应对象
response => { response => {
return response.data; return response.data
}, },
// 响应失败进入第2个函数该函数的参数是错误对象 // 响应失败进入第2个函数该函数的参数是错误对象
async error => { async error => {
@ -36,12 +36,12 @@ service.interceptors.response.use(
// 响应拦截器中的 error 就是那个响应的错误对象 // 响应拦截器中的 error 就是那个响应的错误对象
if (error.response && error.response.status === 401) { if (error.response && error.response.status === 401) {
// 校验是否有 refresh_token // 校验是否有 refresh_token
const { authorization } = store.state.app; const { authorization } = store.state.app
if (!authorization || !authorization.refresh_token) { if (!authorization || !authorization.refresh_token) {
router.push('/login'); router.push('/login')
// 代码不要往后执行了 // 代码不要往后执行了
return Promise.reject(error); return Promise.reject(error)
} }
// 如果有refresh_token则请求获取新的 token // 如果有refresh_token则请求获取新的 token
try { try {
@ -52,32 +52,32 @@ service.interceptors.response.use(
headers: { headers: {
Authorization: `Bearer ${authorization.refresh_token}`, Authorization: `Bearer ${authorization.refresh_token}`,
}, },
}); })
// 如果获取成功,则把新的 token 更新到容器中 // 如果获取成功,则把新的 token 更新到容器中
// console.log('刷新 token 成功', res) // console.log('刷新 token 成功', res)
store.commit('app/setToken', { store.commit('app/setToken', {
token: res.data.data.token, // 最新获取的可用 token token: res.data.data.token, // 最新获取的可用 token
refresh_token: authorization.refresh_token, // 还是原来的 refresh_token refresh_token: authorization.refresh_token, // 还是原来的 refresh_token
}); })
// 把之前失败的用户请求继续发出去 // 把之前失败的用户请求继续发出去
// config 是一个对象,其中包含本次失败请求相关的那些配置信息,例如 url、method 都有 // config 是一个对象,其中包含本次失败请求相关的那些配置信息,例如 url、method 都有
// return 把 request 的请求结果继续返回给发请求的具体位置 // return 把 request 的请求结果继续返回给发请求的具体位置
return service(error.config); return service(error.config)
} catch (err) { } catch (err) {
// 如果获取失败,直接跳转 登录页 // 如果获取失败,直接跳转 登录页
// console.log('请求刷新 token 失败', err) // console.log('请求刷新 token 失败', err)
router.push('/login'); router.push('/login')
// 清除token // 清除token
store.commit('app/clearToken'); store.commit('app/clearToken')
return Promise.reject(error); return Promise.reject(error)
} }
} }
// console.dir(error) // 可在此进行错误上报 // console.dir(error) // 可在此进行错误上报
ElMessage.error(error.message); ElMessage.error(error.message)
return Promise.reject(error); return Promise.reject(error)
} }
); )
export default service; export default service

View File

@ -1,20 +1,20 @@
export const getItem = name => { export const getItem = name => {
const data = window.localStorage.getItem(name); const data = window.localStorage.getItem(name)
try { try {
return JSON.parse(data); return JSON.parse(data)
} catch (err) { } catch (err) {
return data; return data
}
} }
};
export const setItem = (name, value) => { export const setItem = (name, value) => {
if (typeof value === 'object') { if (typeof value === 'object') {
value = JSON.stringify(value); value = JSON.stringify(value)
} }
window.localStorage.setItem(name, value); window.localStorage.setItem(name, value)
}; }
export const removeItem = name => { export const removeItem = name => {
window.localStorage.removeItem(name); window.localStorage.removeItem(name)
}; }

View File

@ -21,11 +21,11 @@
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
props: ['error'], props: ['error'],
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -3,12 +3,12 @@
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: 'home', name: 'home',
setup() {}, setup() {},
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -43,17 +43,17 @@ import {
toRefs, toRefs,
ref, ref,
computed, computed,
} from 'vue'; } from 'vue'
import { Login } from '@/api/login'; import { Login } from '@/api/login'
import { useStore } from 'vuex'; import { useStore } from 'vuex'
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router'
export default defineComponent({ export default defineComponent({
name: 'login', name: 'login',
setup() { setup() {
const { ctx } = getCurrentInstance(); // ctxvue2this const { ctx } = getCurrentInstance() // ctxvue2this
const store = useStore(); const store = useStore()
const router = useRouter(); const router = useRouter()
const route = useRoute(); const route = useRoute()
const state = reactive({ const state = reactive({
model: { model: {
userName: 'admin', userName: 'admin',
@ -78,34 +78,34 @@ export default defineComponent({
loginForm: ref(null), loginForm: ref(null),
submit: () => { submit: () => {
if (state.loading) { if (state.loading) {
return; return
} }
state.loginForm.validate(async valid => { state.loginForm.validate(async valid => {
if (valid) { if (valid) {
state.loading = true; state.loading = true
const { code, data, message } = await Login(state.model); const { code, data, message } = await Login(state.model)
if (+code === 200) { if (+code === 200) {
ctx.$message.success({ ctx.$message.success({
message: '登录成功', message: '登录成功',
duration: 1000, duration: 1000,
}); })
const targetPath = route.query.redirect; const targetPath = route.query.redirect
router.push(targetPath ? targetPath : '/'); router.push(targetPath ? targetPath : '/')
store.commit('app/setToken', data); store.commit('app/setToken', data)
} else { } else {
ctx.$message.error(message); ctx.$message.error(message)
} }
state.loading = false; state.loading = false
} }
}); })
}, },
}); })
return { return {
...toRefs(state), ...toRefs(state),
}; }
}, },
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -1,11 +1,11 @@
<script> <script>
import { h } from 'vue'; import { h } from 'vue'
export default { export default {
created() { created() {
this.$router.replace(this.$route.fullPath.replace(/^\/redirect/, '')); this.$router.replace(this.$route.fullPath.replace(/^\/redirect/, ''))
}, },
render() { render() {
return h('div'); return h('div')
}, },
}; }
</script> </script>

View File

@ -6,15 +6,15 @@
</dl> </dl>
</template> </template>
<script> <script>
import { defineComponent, onActivated } from 'vue'; import { defineComponent, onActivated } from 'vue'
export default defineComponent({ export default defineComponent({
name: 'test-cache', // namename name: 'test-cache', // namename
setup() { setup() {
console.log('cache'); console.log('cache')
onActivated(() => { onActivated(() => {
console.log('onActivated'); console.log('onActivated')
}); })
}, },
}); })
</script> </script>

View File

@ -6,12 +6,12 @@
</dl> </dl>
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue'
export default defineComponent({ export default defineComponent({
name: 'test-no-cache', // namenamename name: 'test-no-cache', // namenamename
setup() { setup() {
console.log('nocache'); console.log('nocache')
}, },
}); })
</script> </script>

View File

@ -32,7 +32,7 @@
</template> </template>
<script> <script>
import { defineComponent, reactive, ref, toRefs } from 'vue'; import { defineComponent, reactive, ref, toRefs } from 'vue'
export default defineComponent({ export default defineComponent({
name: 'testList', name: 'testList',
@ -210,15 +210,15 @@ export default defineComponent({
}, },
selectedItems: [], selectedItems: [],
batchDelete() { batchDelete() {
console.log(state.selectedItems); console.log(state.selectedItems)
}, },
// //
handleSelectionChange(arr) { handleSelectionChange(arr) {
state.selectedItems = arr; state.selectedItems = arr
}, },
// //
async getList(params) { async getList(params) {
console.log(params); console.log(params)
// params // params
const { data } = await new Promise(rs => { const { data } = await new Promise(rs => {
setTimeout(() => { setTimeout(() => {
@ -239,23 +239,23 @@ export default defineComponent({
], ],
total: 100, total: 100,
}, },
}); })
}, 3000); }, 3000)
}); })
// datatotal // datatotal
return { return {
data: data.list, data: data.list,
total: +data.total, total: +data.total,
}; }
}, },
}); })
const table = ref(null); const table = ref(null)
const refresh = () => { const refresh = () => {
table.value.refresh(); table.value.refresh()
}; }
return { ...toRefs(state), refresh, table }; return { ...toRefs(state), refresh, table }
}, },
}); })
</script> </script>