Update: 移动端适配
This commit is contained in:
parent
d6f3aba1a1
commit
7ddcb4cfa6
@ -13,12 +13,11 @@
|
|||||||
>
|
>
|
||||||
<n-space wrap :size="[35, 15]">
|
<n-space wrap :size="[35, 15]">
|
||||||
<slot />
|
<slot />
|
||||||
</n-space>
|
<div>
|
||||||
|
|
||||||
<div flex-shrink-0>
|
|
||||||
<n-button secondary type="primary" @click="emit('reset')">重置</n-button>
|
<n-button secondary type="primary" @click="emit('reset')">重置</n-button>
|
||||||
<n-button ml-20 type="primary" @click="emit('search')">搜索</n-button>
|
<n-button ml-20 type="primary" @click="emit('search')">搜索</n-button>
|
||||||
</div>
|
</div>
|
||||||
|
</n-space>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
>
|
>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</label>
|
</label>
|
||||||
<div :style="{ width: contentWidth + 'px' }" flex-shrink-0>
|
<div>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
|
:scroll-x="scrollX"
|
||||||
:row-key="(row) => row[rowKey]"
|
:row-key="(row) => row[rowKey]"
|
||||||
:pagination="isPagination ? pagination : false"
|
:pagination="isPagination ? pagination : false"
|
||||||
@update:checked-row-keys="onChecked"
|
@update:checked-row-keys="onChecked"
|
||||||
@ -16,7 +17,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
/**
|
/**
|
||||||
* @remote true: 后端分页 false: 前端分页
|
* @remote true: 后端分页 false: 前端分页
|
||||||
@ -34,7 +34,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
scrollX: {
|
scrollX: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1200,
|
default: 450,
|
||||||
},
|
},
|
||||||
rowKey: {
|
rowKey: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-icon mr20 size="18" style="cursor: pointer" @click="toggle">
|
<n-icon v-if="appStore.fullScreen" mr20 size="18" style="cursor: pointer" @click="toggle">
|
||||||
<icon-ant-design:fullscreen-exit-outlined v-if="isFullscreen" />
|
<icon-ant-design:fullscreen-exit-outlined v-if="isFullscreen" />
|
||||||
<icon-ant-design:fullscreen-outlined v-else />
|
<icon-ant-design:fullscreen-outlined v-else />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useFullscreen } from '@vueuse/core'
|
import { useFullscreen } from '@vueuse/core'
|
||||||
|
import { useAppStore } from '@/store'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
const { isFullscreen, toggle } = useFullscreen()
|
const { isFullscreen, toggle } = useFullscreen()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -37,5 +37,38 @@ import AppTags from './components/tags/index.vue'
|
|||||||
import { useAppStore } from '@/store'
|
import { useAppStore } from '@/store'
|
||||||
import { header, tags } from '~/settings'
|
import { header, tags } from '~/settings'
|
||||||
|
|
||||||
|
// 移动端适配
|
||||||
|
import { useBreakpoints } from '@vueuse/core'
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
const breakpointsEnum = {
|
||||||
|
xl: 1600,
|
||||||
|
lg: 1199,
|
||||||
|
md: 991,
|
||||||
|
sm: 666,
|
||||||
|
xs: 575,
|
||||||
|
}
|
||||||
|
const breakpoints = reactive(useBreakpoints(breakpointsEnum))
|
||||||
|
const isMobile = breakpoints.smaller('sm')
|
||||||
|
const isPad = breakpoints.between('sm', 'md')
|
||||||
|
const isPC = breakpoints.greater('md')
|
||||||
|
watchEffect(() => {
|
||||||
|
if (isMobile.value) {
|
||||||
|
// Mobile
|
||||||
|
appStore.setCollapsed(true)
|
||||||
|
appStore.setFullScreen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPad.value) {
|
||||||
|
// IPad
|
||||||
|
appStore.setCollapsed(true)
|
||||||
|
appStore.setFullScreen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPC.value) {
|
||||||
|
// PC
|
||||||
|
appStore.setCollapsed(false)
|
||||||
|
appStore.setFullScreen(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export const useAppStore = defineStore('app', {
|
|||||||
return {
|
return {
|
||||||
reloadFlag: true,
|
reloadFlag: true,
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
|
fullScreen: true,
|
||||||
/** keepAlive路由的key,重新赋值可重置keepAlive */
|
/** keepAlive路由的key,重新赋值可重置keepAlive */
|
||||||
aliveKeys: {},
|
aliveKeys: {},
|
||||||
isDark,
|
isDark,
|
||||||
@ -30,6 +31,9 @@ export const useAppStore = defineStore('app', {
|
|||||||
setCollapsed(collapsed) {
|
setCollapsed(collapsed) {
|
||||||
this.collapsed = collapsed
|
this.collapsed = collapsed
|
||||||
},
|
},
|
||||||
|
setFullScreen(fullScreen) {
|
||||||
|
this.fullScreen = fullScreen
|
||||||
|
},
|
||||||
setAliveKeys(key, val) {
|
setAliveKeys(key, val) {
|
||||||
this.aliveKeys[key] = val
|
this.aliveKeys[key] = val
|
||||||
},
|
},
|
||||||
@ -43,5 +47,3 @@ export const useAppStore = defineStore('app', {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -132,6 +132,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
|
style: 'margin-right: 8px;',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleEdit(row)
|
handleEdit(row)
|
||||||
modalForm.value.roles = row.roles.map((e) => (e = e.id))
|
modalForm.value.roles = row.roles.map((e) => (e = e.id))
|
||||||
@ -158,7 +159,6 @@ const columns = [
|
|||||||
{
|
{
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
style: 'margin-left: 8px;',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: () => '删除',
|
default: () => '删除',
|
||||||
@ -181,13 +181,18 @@ const columns = [
|
|||||||
<CommonPage show-footer title="API列表">
|
<CommonPage show-footer title="API列表">
|
||||||
<template #action>
|
<template #action>
|
||||||
<div>
|
<div>
|
||||||
<NButton v-permission="'post/api/v1/api/create'" type="primary" @click="handleAdd">
|
<NButton
|
||||||
|
v-permission="'post/api/v1/api/create'"
|
||||||
|
class="float-right mr-15"
|
||||||
|
type="primary"
|
||||||
|
@click="handleAdd"
|
||||||
|
>
|
||||||
<TheIcon icon="material-symbols:add" :size="18" class="mr-5" />新建API
|
<TheIcon icon="material-symbols:add" :size="18" class="mr-5" />新建API
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton
|
<NButton
|
||||||
v-permission="'post/api/v1/api/refresh'"
|
v-permission="'post/api/v1/api/refresh'"
|
||||||
|
class="float-right mr-15"
|
||||||
type="warning"
|
type="warning"
|
||||||
class="ml-16"
|
|
||||||
@click="handleRefreshApi"
|
@click="handleRefreshApi"
|
||||||
>
|
>
|
||||||
<TheIcon icon="material-symbols:refresh" :size="18" class="mr-5" />刷新API
|
<TheIcon icon="material-symbols:refresh" :size="18" class="mr-5" />刷新API
|
||||||
|
|||||||
@ -77,13 +77,12 @@ const columns = [
|
|||||||
},
|
},
|
||||||
{ title: '排序', key: 'order', width: 30, ellipsis: { tooltip: true } },
|
{ title: '排序', key: 'order', width: 30, ellipsis: { tooltip: true } },
|
||||||
{ title: '访问路径', key: 'path', width: 60, ellipsis: { tooltip: true } },
|
{ title: '访问路径', key: 'path', width: 60, ellipsis: { tooltip: true } },
|
||||||
{ title: '跳转路径', key: 'redirect', width: 80, ellipsis: { tooltip: true } },
|
{ title: '跳转路径', key: 'redirect', width: 60, ellipsis: { tooltip: true } },
|
||||||
{ title: '组件路径', key: 'component', width: 80, ellipsis: { tooltip: true } },
|
{ title: '组件路径', key: 'component', width: 60, ellipsis: { tooltip: true } },
|
||||||
{
|
{
|
||||||
title: 'KeepAlive',
|
title: '保活',
|
||||||
key: 'keepalive',
|
key: 'keepalive',
|
||||||
width: 30,
|
width: 40,
|
||||||
fixed: 'left',
|
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(NSwitch, {
|
return h(NSwitch, {
|
||||||
size: 'small',
|
size: 'small',
|
||||||
@ -96,8 +95,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
title: '隐藏',
|
title: '隐藏',
|
||||||
key: 'is_hidden',
|
key: 'is_hidden',
|
||||||
width: 30,
|
width: 40,
|
||||||
fixed: 'left',
|
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(NSwitch, {
|
return h(NSwitch, {
|
||||||
size: 'small',
|
size: 'small',
|
||||||
@ -118,7 +116,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
width: 115,
|
width: 80,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render(row) {
|
render(row) {
|
||||||
|
|||||||
@ -125,7 +125,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
width: 150,
|
width: 80,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render(row) {
|
render(row) {
|
||||||
@ -136,6 +136,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
|
style: 'margin-right: 8px;',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
handleEdit(row)
|
handleEdit(row)
|
||||||
},
|
},
|
||||||
@ -161,7 +162,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
style: 'margin-left: 10px;',
|
style: 'margin-right: 8px;',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: () => '删除',
|
default: () => '删除',
|
||||||
@ -179,7 +180,6 @@ const columns = [
|
|||||||
{
|
{
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
style: 'margin-left: 10px;',
|
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
active.value = true
|
active.value = true
|
||||||
role_id.value = row.id
|
role_id.value = row.id
|
||||||
|
|||||||
@ -92,7 +92,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
title: '用户角色',
|
title: '用户角色',
|
||||||
key: 'role',
|
key: 'role',
|
||||||
width: 80,
|
width: 60,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render(row) {
|
render(row) {
|
||||||
const roles = row.roles ?? []
|
const roles = row.roles ?? []
|
||||||
@ -108,7 +108,7 @@ const columns = [
|
|||||||
title: '超级用户',
|
title: '超级用户',
|
||||||
key: 'is_superuser',
|
key: 'is_superuser',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 70,
|
width: 40,
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(
|
return h(
|
||||||
NTag,
|
NTag,
|
||||||
@ -121,14 +121,15 @@ const columns = [
|
|||||||
title: '上次登录时间',
|
title: '上次登录时间',
|
||||||
key: 'last_login',
|
key: 'last_login',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 70,
|
width: 80,
|
||||||
|
ellipsis: { tooltip: true },
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(
|
return h(
|
||||||
NButton,
|
NButton,
|
||||||
{ size: 'small', type: 'text', ghost: true },
|
{ size: 'small', type: 'text', ghost: true },
|
||||||
{
|
{
|
||||||
default: () => (row.last_login !== null ? formatDate(row.last_login) : null),
|
default: () => (row.last_login !== null ? formatDate(row.last_login) : null),
|
||||||
icon: renderIcon('mdi:update', { size: 18 }),
|
icon: renderIcon('mdi:update', { size: 16 }),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -136,9 +137,8 @@ const columns = [
|
|||||||
{
|
{
|
||||||
title: '禁用',
|
title: '禁用',
|
||||||
key: 'is_active',
|
key: 'is_active',
|
||||||
width: 30,
|
width: 50,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
fixed: 'left',
|
|
||||||
render(row) {
|
render(row) {
|
||||||
return h(NSwitch, {
|
return h(NSwitch, {
|
||||||
size: 'small',
|
size: 'small',
|
||||||
@ -165,6 +165,7 @@ const columns = [
|
|||||||
{
|
{
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
|
style: 'margin-right: 8px;',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
// roles => role_ids
|
// roles => role_ids
|
||||||
handleEdit(row)
|
handleEdit(row)
|
||||||
@ -192,7 +193,6 @@ const columns = [
|
|||||||
{
|
{
|
||||||
size: 'small',
|
size: 'small',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
style: 'margin-left: 8px;',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: () => '删除',
|
default: () => '删除',
|
||||||
|
|||||||
@ -2,22 +2,17 @@
|
|||||||
<AppPage :show-footer="false">
|
<AppPage :show-footer="false">
|
||||||
<div flex-1>
|
<div flex-1>
|
||||||
<n-card rounded-10>
|
<n-card rounded-10>
|
||||||
|
<div flex items-center justify-between>
|
||||||
<div flex items-center>
|
<div flex items-center>
|
||||||
<img rounded-full width="60" :src="userStore.avatar" />
|
<img rounded-full width="60" :src="userStore.avatar" />
|
||||||
<div ml-20>
|
<div ml-10>
|
||||||
<p text-20>Hello, {{ userStore.name }}</p>
|
<p text-20 font-semibold>hello, {{ userStore.name }}</p>
|
||||||
<p mt-5 text-14 op-60>今天又是元气满满的一天!</p>
|
<p mt-5 text-14 op-60>今天又是元气满满的一天!</p>
|
||||||
</div>
|
</div>
|
||||||
<div ml-auto flex items-center>
|
|
||||||
<n-space :size="24" :wrap="false">
|
|
||||||
<n-statistic
|
|
||||||
v-for="item in statisticData"
|
|
||||||
:key="item.id"
|
|
||||||
class="whitespace-nowrap"
|
|
||||||
v-bind="item"
|
|
||||||
></n-statistic>
|
|
||||||
</n-space>
|
|
||||||
</div>
|
</div>
|
||||||
|
<n-space :size="12" :wrap="false">
|
||||||
|
<n-statistic v-for="item in statisticData" :key="item.id" v-bind="item"></n-statistic>
|
||||||
|
</n-space>
|
||||||
</div>
|
</div>
|
||||||
</n-card>
|
</n-card>
|
||||||
|
|
||||||
@ -29,7 +24,7 @@
|
|||||||
<n-card
|
<n-card
|
||||||
v-for="i in 9"
|
v-for="i in 9"
|
||||||
:key="i"
|
:key="i"
|
||||||
class="mb-10 mt-10 w-300 flex-shrink-0 cursor-pointer"
|
class="mb-10 mt-10 w-300 cursor-pointer"
|
||||||
hover:card-shadow
|
hover:card-shadow
|
||||||
title="Vue FastAPI Admin"
|
title="Vue FastAPI Admin"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user