1
0
mirror of https://github.com/zclzone/vue-naive-admin.git synced 2026-01-22 23:50:22 +08:00

8 Commits

Author SHA1 Message Date
leip247
a977ec1f3a fix: #113 (#116)
* fix(slot): 优化部分slot写法,减少手动判断

* fix(slot): 优化部分slot写法,减少手动判断

* feat(table): 添加vxe-table,适配naiveui主题,并替换掉之前table,自带导出

* feat(table): 添加vxe-table,适配naiveui主题,并替换掉之前table,自带导出

* fix: 完善table总条数不显示问题
2025-03-19 09:15:41 +08:00
leip247
6d1b3a4159 feat(table): 添加vxe-table,适配naiveui主题,并替换掉之前table,自带导出 (#105)
* fix(slot): 优化部分slot写法,减少手动判断

* fix(slot): 优化部分slot写法,减少手动判断

* feat(table): 添加vxe-table,适配naiveui主题,并替换掉之前table,自带导出

* feat(table): 添加vxe-table,适配naiveui主题,并替换掉之前table,自带导出
2024-11-22 15:47:29 +08:00
leip247
6af6eb3c99 fix(slot): 优化部分slot写法,减少手动判断 (#101)
* fix(slot): 优化部分slot写法,减少手动判断

* fix(slot): 优化部分slot写法,减少手动判断
2024-11-13 11:05:03 +08:00
zclzone
69e6e9a14a fix: 替换失效图片链接 2024-10-29 15:14:04 +08:00
zclzone
d066c999cc chore: update deps 2024-10-22 15:27:46 +08:00
zclzone
97fb638ac2 chore: update deps 2024-10-08 15:44:41 +08:00
zclzone
db800f60a9 docs: update README 2024-09-26 17:25:52 +08:00
zclzone
304b74bb49 chore: 弃用sass,使用原生css替换 2024-09-25 18:19:48 +08:00
19 changed files with 1853 additions and 850 deletions

View File

@@ -20,5 +20,12 @@
"json", "json",
"jsonc" "jsonc"
], ],
"common-intellisense.ui": ["naiveUi2"] "common-intellisense.ui": [
"naiveUi2"
],
"workbench.colorCustomizations": {
"activityBar.background": "#233212",
"titleBar.activeBackground": "#314619",
"titleBar.activeForeground": "#F9FCF6"
}
} }

View File

@@ -83,8 +83,6 @@ npx degit zclzone/vue-naive-admin
- [naive-admin-go](https://github.com/ituserxxx/naive-admin-go): 一个 Go 后端服务,基于 gin、gorm、mysql、jwt和session已对接 Vue Naive Admin 2.0。 - [naive-admin-go](https://github.com/ituserxxx/naive-admin-go): 一个 Go 后端服务,基于 gin、gorm、mysql、jwt和session已对接 Vue Naive Admin 2.0。
- [isme-java](https://github.com/AllenDengMs/isme-java): 一个轻量且完成度高的Java后端服务基于Springboot 3 + JDK21层次结构严谨注释齐全避免过度封装代码可读性度高依赖最简化上手成本低已集成 账号管理、权限管理、API鉴权、消息国际化等功能。 - [isme-java](https://github.com/AllenDengMs/isme-java): 一个轻量且完成度高的Java后端服务基于Springboot 3 + JDK21层次结构严谨注释齐全避免过度封装代码可读性度高依赖最简化上手成本低已集成 账号管理、权限管理、API鉴权、消息国际化等功能。
## 入群交流 ## 联系作者 or 进交流
添加微信,拉你进群 [https://www.isme.top/contact.html](https://www.isme.top/contact.html)
![](https://static.isme.top/image/coder_wx.jpg)

View File

@@ -17,39 +17,42 @@
"axios": "^1.7.7", "axios": "^1.7.7",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"echarts": "^5.5.1", "echarts": "^5.5.1",
"exceljs": "^4.4.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"naive-ui": "^2.39.0", "naive-ui": "^2.40.1",
"pinia": "^2.2.2", "pinia": "^2.2.4",
"pinia-plugin-persistedstate": "^4.0.2", "pinia-plugin-persistedstate": "^4.1.1",
"vue": "^3.5.8", "vue": "^3.5.12",
"vue-echarts": "^7.0.3", "vue-echarts": "^7.0.3",
"vue-router": "^4.4.5", "vue-router": "^4.4.5",
"vxe-pc-ui": "4.2.5",
"vxe-table": "4.8.13",
"vxe-table-plugin-export-xlsx": "^4.0.4",
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^3.7.1", "@antfu/eslint-config": "^3.8.0",
"@iconify/json": "^2.2.252", "@iconify/json": "^2.2.262",
"@unocss/eslint-config": "^0.62.4", "@unocss/eslint-config": "^0.63.6",
"@unocss/eslint-plugin": "^0.62.4", "@unocss/eslint-plugin": "^0.63.6",
"@unocss/preset-rem-to-px": "^0.62.4", "@unocss/preset-rem-to-px": "^0.63.6",
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1", "@vitejs/plugin-vue-jsx": "^4.0.1",
"eslint": "^9.11.1", "eslint": "^9.13.0",
"eslint-plugin-format": "^0.1.2", "eslint-plugin-format": "^0.1.2",
"esno": "^4.7.0", "esno": "^4.8.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"glob": "^11.0.0", "glob": "^11.0.0",
"lint-staged": "^15.2.10", "lint-staged": "^15.2.10",
"rollup-plugin-visualizer": "^5.12.0", "rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.79.3",
"simple-git-hooks": "^2.11.1", "simple-git-hooks": "^2.11.1",
"taze": "^0.16.9", "taze": "^0.17.2",
"unocss": "^0.62.4", "unocss": "^0.63.6",
"unplugin-auto-import": "^0.18.3", "unplugin-auto-import": "^0.18.3",
"unplugin-vue-components": "^0.27.4", "unplugin-vue-components": "^0.27.4",
"vite": "^5.4.7", "vite": "^5.4.9",
"vite-plugin-router-warn": "^1.0.0", "vite-plugin-router-warn": "^1.0.0",
"vite-plugin-vue-devtools": "^7.4.6" "vite-plugin-vue-devtools": "^7.5.2"
}, },
"simple-git-hooks": { "simple-git-hooks": {
"pre-commit": "pnpm lint-staged" "pre-commit": "pnpm lint-staged"

2125
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,9 @@
<main :class="{ 'flex-1': full }" class="m-12"> <main :class="{ 'flex-1': full }" class="m-12">
<slot /> <slot />
</main> </main>
<slot v-if="$slots.footer" name="footer" /> <slot name="footer">
<TheFooter v-else-if="showFooter" class="mb-12 mt-auto" /> <TheFooter v-if="showFooter" class="mb-12 mt-auto" />
</slot>
<n-back-top :bottom="20" /> <n-back-top :bottom="20" />
</main> </main>
</template> </template>

View File

@@ -16,16 +16,18 @@
<slot v-if="$slots.header" name="header" /> <slot v-if="$slots.header" name="header" />
<template v-else> <template v-else>
<div class="flex items-center"> <div class="flex items-center">
<slot v-if="$slots['title-prefix']" name="title-prefix" /> <slot name="title-prefix">
<template v-else-if="back"> <template v-if="back">
<div <div
class="mr-16 flex cursor-pointer items-center text-16 opacity-60 transition-all-300 hover:opacity-40" class="mr-16 flex cursor-pointer items-center text-16 opacity-60 transition-all-300 hover:opacity-40"
@click="router.back()" @click="router.back()"
> >
<i class="i-material-symbols:arrow-left-alt" /> <i class="i-material-symbols:arrow-left-alt" />
<span class="ml-4">返回</span> <span class="ml-4">返回</span>
</div> </div>
</template> </template>
</slot>
<div class="mr-12 h-16 w-4 rounded-l-2 bg-primary" /> <div class="mr-12 h-16 w-4 rounded-l-2 bg-primary" />
<h2 class="font-normal"> <h2 class="font-normal">
{{ title ?? route.meta?.title }} {{ title ?? route.meta?.title }}
@@ -39,10 +41,11 @@
<slot /> <slot />
</AppCard> </AppCard>
<slot v-if="$slots.footer" name="footer" /> <slot name="footer">
<AppCard v-else-if="showFooter" class="flex-shrink-0 py-12"> <AppCard v-if="showFooter" class="flex-shrink-0 py-12">
<TheFooter /> <TheFooter />
</AppCard> </AppCard>
</slot>
</main> </main>
</template> </template>

View File

@@ -0,0 +1,240 @@
<template>
<div
:style="isComputedHeight ? `height: calc(100% - ${autoHeight}px);` : `height: ${autoHeight}px`"
>
<vxe-grid
ref="gridRef"
:columns="vxeColumns"
:loading="loading"
:data="data"
height="auto"
:stripe="true"
:border="true"
size="mini"
:auto-resize="true"
:pager-config="pagerConfig"
:export-config="exportConfig"
:toolbar-config="vxeToolbarConfig"
:proxy-config="proxyConfig"
v-on="gridEvent"
>
<template #loading>
<n-spin :show="loading" />
</template>
<template #total>
<span class="font-size-14 line-height-28px"> {{ pagerConfig.total }} 条数据</span>
</template>
<template v-for="(c, k) in slots" :key="k" #[c.key]="{ row }">
<template v-if="Array.isArray(c.render(row))">
<component :is="r" v-for="(r, k1) in c.render(row)" :key="k1" :row="row" :col="c" />
</template>
<template v-else>
<component :is="c.render(row)" :row="row" :col="c" />
</template>
</template>
</vxe-grid>
</div>
</template>
<script setup>
import { computed } from 'vue'
defineOptions({ name: 'MeVxeGrid' })
const props = defineProps({
/**
* @remote 当isComputedHeight为true时为除table外的高度 false时为table高度
*/
autoHeight: {
type: Number,
default: 300,
},
/**
* @isPagination 是否为自动计算高度
*/
isComputedHeight: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
},
/**
* @remote table的列
*/
columns: {
type: Array,
default: () => [],
},
data: {
type: Array,
default: () => [],
},
pagination: {
type: [Boolean, Object],
default: true,
},
exportConfig: {
type: Object,
default: () => ({}),
},
toolbarConfig: {
type: Object,
default: () => ({ }),
},
/**
* 是否显示复选框
*/
showCheck: {
type: Boolean,
default: false,
},
rowKey: {
type: String, // rowKey
default: 'id',
},
exportMethod: {
type: Function,
default: () => null,
},
remoteMethod: {
type: Function,
default: () => null,
},
})
const emits = defineEmits(['update:checked-row-keys', 'pageChanged'])
const isFirst = shallowRef(true)
const gridRef = ref(null)
watch(
() => props.data,
(n) => {
isFirst.value = false
gridRef.value.reloadData(n)
},
)
const vxeToolbarConfig = computed(() => {
return {
size: 'mini',
className: 'c-toolbar',
perfect: true,
refresh: true,
export: true,
zoom: true,
custom: true,
...props.toolbarConfig,
}
})
const pagerConfig = computed(() => {
if (props.pagination === false) {
return {
enabled: false,
}
}
return {
currentPage: props.pagination.pageNo,
pageSize: props.pagination.pageSize,
total: props.pagination.itemCount || 0,
background: true,
size: 'small',
layouts: [
'Home',
'PrevPage',
'JumpNumber',
'NextPage',
'End',
'Sizes',
'FullJump',
// 'Total',
],
slots: {
right: 'total',
},
}
})
/**
* 将naive 转为vxe-table可用的列
*/
const vxeColumns = computed(() => {
if (props.showCheck) {
return [{
type: 'checkbox',
resizable: false,
width: 45,
align: 'center',
fixed: 'left',
}, ...props.columns.map((item) => {
item.field = item.key
if (item.render) {
item.slots = { default: item.key }
}
return item
})]
}
return props.columns.map((item) => {
item.field = item.key
if (item.render) {
item.slots = { default: item.key }
}
return item
})
})
/**
* 将naive render函数转换为vxeTable的slots
*/
const slots = computed(() => {
return props.columns.filter(item => item.render)
})
const gridEvent = {
checkboxAll() {
const $grid = gridRef.value
if ($grid) {
emits(
'update:checked-row-keys',
$grid.getCheckboxRecords().map(item => item[props.rowKey]),
)
}
},
checkboxChange() {
const $grid = gridRef.value
if ($grid) {
emits(
'update:checked-row-keys',
$grid.getCheckboxRecords().map(item => item[props.rowKey]),
)
}
},
pageChange(e) {
emits('pageChanged', e)
},
}
const proxyConfig = {
props: {
result: 'data.pageData',
total: 'data.total',
},
ajax: {
query: async ({ page }) => {
if (isFirst.value === true) {
return Promise.reject('')
}
props.remoteMethod(page.currentPage, page.pageSize)
},
queryAll: async () => {
const res = await props.exportMethod()
return res
},
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -2,5 +2,6 @@ export { default as AppCard } from './AppCard.vue'
export { default as AppPage } from './AppPage.vue' export { default as AppPage } from './AppPage.vue'
export { default as CommonPage } from './CommonPage.vue' export { default as CommonPage } from './CommonPage.vue'
export { default as LayoutSetting } from './LayoutSetting.vue' export { default as LayoutSetting } from './LayoutSetting.vue'
export { default as MeVxeGrid } from './MeVxeGrid.vue'
export { default as TheFooter } from './TheFooter.vue' export { default as TheFooter } from './TheFooter.vue'
export { default as ToggleTheme } from './ToggleTheme.vue' export { default as ToggleTheme } from './ToggleTheme.vue'

View File

@@ -7,38 +7,59 @@
---------------------------------> --------------------------------->
<template> <template>
<AppCard v-if="$slots.default" bordered bg="#fafafc dark:black" class="mb-30 min-h-60 rounded-4"> <div :class="computedHeight === true ? 'h-100%' : ''">
<form class="flex justify-between p-16" @submit.prevent="handleSearch()"> <div id="search_main">
<n-scrollbar x-scrollable> <AppCard v-if="$slots.default" bordered bg="#fafafc dark:black" class="mb-30 min-h-60 rounded-4">
<n-space :wrap="!expand || isExpanded" :size="[32, 16]" class="p-10"> <form class="flex justify-between p-16" @submit.prevent="handleSearch()">
<slot /> <n-scrollbar x-scrollable>
</n-space> <n-space :wrap="!expand || isExpanded" :size="[32, 16]" class="p-10">
</n-scrollbar> <slot />
<div class="flex-shrink-0 p-10"> </n-space>
<n-button ghost type="primary" @click="handleReset"> </n-scrollbar>
<i class="i-fe:rotate-ccw mr-4" /> <div class="flex-shrink-0 p-10">
重置 <n-button ghost type="primary" @click="handleReset">
</n-button> <i class="i-fe:rotate-ccw mr-4" />
<n-button attr-type="submit" class="ml-20" type="primary"> 重置
<i class="i-fe:search mr-4" /> </n-button>
搜索 <n-button attr-type="submit" class="ml-20" type="primary">
</n-button> <i class="i-fe:search mr-4" />
搜索
</n-button>
<template v-if="expand"> <template v-if="expand">
<n-button v-if="!isExpanded" type="primary" text @click="toggleExpand"> <n-button v-if="!isExpanded" type="primary" text @click="toggleExpand">
<i class="i-fe:chevrons-down ml-4" /> <i class="i-fe:chevrons-down ml-4" />
展开 展开
</n-button> </n-button>
<n-button v-else text type="primary" @click="toggleExpand"> <n-button v-else text type="primary" @click="toggleExpand">
<i class="i-fe:chevrons-up ml-4" /> <i class="i-fe:chevrons-up ml-4" />
收起 收起
</n-button> </n-button>
</template> </template>
</div> </div>
</form> </form>
</AppCard> </AppCard>
</div>
<MeVxeGrid
:remote="remote"
:loading="loading"
:scroll-x="scrollX"
:columns="columns"
:export-config="{ filename: exportName, modes: ['all', 'current'] }"
:toolbar-config="toolbarConfig"
:data="tableData"
:auto-height="computedHeight === true ? autoHeight : computedHeight"
:row-key="rowKey"
:is-computed-height="computedHeight === true"
:show-check="showCheck"
:pagination="isPagination ? pagination : false"
:remote-method="remoteMethod"
:export-method="exportMethod"
@update:checked-row-keys="onChecked"
@update:page="onPageChange"
/>
<NDataTable <!-- <NDataTable
:remote="remote" :remote="remote"
:loading="loading" :loading="loading"
:scroll-x="scrollX" :scroll-x="scrollX"
@@ -48,14 +69,39 @@
:pagination="isPagination ? pagination : false" :pagination="isPagination ? pagination : false"
@update:checked-row-keys="onChecked" @update:checked-row-keys="onChecked"
@update:page="onPageChange" @update:page="onPageChange"
/> /> -->
</div>
</template> </template>
<script setup> <script setup>
import { NDataTable } from 'naive-ui'
import { utils, writeFile } from 'xlsx' import { utils, writeFile } from 'xlsx'
const props = defineProps({ const props = defineProps({
/**
* 是否自动计算高度适用只有search和table
*/
computedHeight: {
type: [Boolean, Number],
default: () => true,
},
showCheck: {
type: Boolean,
default: () => false,
},
toolbarConfig: {
type: Object,
default: () => ({
export: true,
zoom: true,
}),
},
/**
* @remote 导出数据表格名称
*/
exportName: {
type: String,
default: '导出数据',
},
/** /**
* @remote true: 后端分页 false 前端分页 * @remote true: 后端分页 false 前端分页
*/ */
@@ -69,13 +115,6 @@ const props = defineProps({
isPagination: { isPagination: {
type: Boolean, type: Boolean,
default: true, default: true,
},
/**
* @isShowSizePicker 是否显示每页条数选择
*/
isShowSizePicker: {
type: Boolean,
default: false,
}, },
scrollX: { scrollX: {
type: Number, type: Number,
@@ -112,8 +151,18 @@ const props = defineProps({
/** 是否支持展开 */ /** 是否支持展开 */
expand: Boolean, expand: Boolean,
}) })
const emit = defineEmits(['update:queryItems', 'onChecked', 'onDataChange']) const emit = defineEmits(['update:queryItems', 'onChecked', 'onDataChange'])
const autoHeight = ref(0)
window.onresize = () => {
autoHeight.value = document.getElementById('search_main').clientHeight + 24
}
onMounted(() => {
autoHeight.value = document.getElementById('search_main').clientHeight + 24
})
const loading = ref(false) const loading = ref(false)
const initQuery = { ...props.queryItems } const initQuery = { ...props.queryItems }
const tableData = ref([]) const tableData = ref([])
@@ -123,16 +172,6 @@ const pagination = reactive({
prefix({ itemCount }) { prefix({ itemCount }) {
return `${itemCount} 条数据` return `${itemCount} 条数据`
}, },
pageSizes: [10, 20, 50, 100],
showSizePicker: props.isShowSizePicker,
onChange: (page) => {
pagination.page = page
},
onUpdatePageSize: (pageSize) => {
pagination.pageSize = pageSize
pagination.page = 1
handleQuery()
},
}) })
// 是否展开 // 是否展开
@@ -142,6 +181,22 @@ function toggleExpand() {
isExpanded.value = !isExpanded.value isExpanded.value = !isExpanded.value
} }
async function exportMethod() {
const { data } = await props.getData({
pageNo: 1,
pageSize: 2000,
...props.queryItems,
})
return data
}
function remoteMethod(page, pageSize) {
pagination.page = page
pagination.pageSize = pageSize
handleQuery()
}
async function handleQuery() { async function handleQuery() {
try { try {
loading.value = true loading.value = true
@@ -160,6 +215,7 @@ async function handleQuery() {
// 如果当前页数据为空且总条数不为0则返回上一页数据 // 如果当前页数据为空且总条数不为0则返回上一页数据
onPageChange(pagination.page - 1) onPageChange(pagination.page - 1)
} }
return data
} }
catch (error) { catch (error) {
console.error(error) console.error(error)
@@ -197,9 +253,7 @@ function onPageChange(currentPage) {
} }
} }
function onChecked(rowKeys) { function onChecked(rowKeys) {
if (props.columns.some(item => item.type === 'selection')) { emit('onChecked', rowKeys)
emit('onChecked', rowKeys)
}
} }
function handleExport(columns = props.columns, data = tableData.value) { function handleExport(columns = props.columns, data = tableData.value) {
if (!data?.length) if (!data?.length)

View File

@@ -26,21 +26,22 @@
<!-- 底部按钮 --> <!-- 底部按钮 -->
<template #footer> <template #footer>
<slot v-if="$slots.footer" name="footer" /> <slot name="footer">
<footer v-else-if="modalOptions.showFooter" class="flex justify-end"> <footer v-if="modalOptions.showFooter" class="flex justify-end">
<n-button v-if="modalOptions.showCancel" @click="handleCancel()"> <n-button v-if="modalOptions.showCancel" @click="handleCancel()">
{{ modalOptions.cancelText }} {{ modalOptions.cancelText }}
</n-button> </n-button>
<n-button <n-button
v-if="modalOptions.showOk" v-if="modalOptions.showOk"
type="primary" type="primary"
:loading="modalOptions.okLoading" :loading="modalOptions.okLoading"
class="ml-20" class="ml-20"
@click="handleOk()" @click="handleOk()"
> >
{{ modalOptions.okText }} {{ modalOptions.okText }}
</n-button> </n-button>
</footer> </footer>
</slot>
</template> </template>
</n-card> </n-card>
</n-modal> </n-modal>

View File

@@ -59,7 +59,7 @@ function handleMenuSelect(key, item) {
} }
</script> </script>
<style lang="scss"> <style>
.side-menu:not(.n-menu--collapsed) { .side-menu:not(.n-menu--collapsed) {
.n-menu-item-content { .n-menu-item-content {
&::before { &::before {

View File

@@ -74,7 +74,7 @@ async function handleContextMenu(e, tagItem) {
} }
</script> </script>
<style scoped lang="scss"> <style scoped>
:deep(.n-tabs) { :deep(.n-tabs) {
.n-tabs-tab { .n-tabs-tab {
padding-left: 16px; padding-left: 16px;

View File

@@ -8,19 +8,35 @@
* Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top * Copyright © 2023 Ronnie Zhang(大脸怪) | https://isme.top
**********************************/ **********************************/
import ExcelJS from 'exceljs'
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import { setupDirectives } from './directives'
import { setupDirectives } from './directives'
/**
* 引入vxe-table 和 vxe-pc-ui excel导出
*/
import VxeUI from 'vxe-pc-ui'
import VXETable from 'vxe-table'
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx'
import { setupRouter } from './router' import { setupRouter } from './router'
import { setupStore } from './store' import { setupStore } from './store'
import { setupNaiveDiscreteApi } from './utils' import { setupNaiveDiscreteApi } from './utils'
import '@/styles/global.scss' import 'vxe-pc-ui/lib/style.css'
import 'vxe-table/lib/style.css'
import '@/styles/reset.css' import '@/styles/reset.css'
import '@/styles/global.css'
import 'uno.css' import 'uno.css'
async function bootstrap() { async function bootstrap() {
const app = createApp(App) const app = createApp(App)
VXETable.use(VXETablePluginExportXLSX, {
ExcelJS,
})
app.use(VxeUI).use(VXETable)
setupStore(app) setupStore(app)
setupDirectives(app) setupDirectives(app)
await setupRouter(app) await setupRouter(app)

View File

@@ -10,6 +10,7 @@ import { defaultLayout, defaultPrimaryColor, naiveThemeOverrides } from '@/setti
import { generate, getRgbStr } from '@arco-design/color' import { generate, getRgbStr } from '@arco-design/color'
import { useDark } from '@vueuse/core' import { useDark } from '@vueuse/core'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { VxeUI } from 'vxe-pc-ui'
export const useAppStore = defineStore('app', { export const useAppStore = defineStore('app', {
state: () => ({ state: () => ({
@@ -40,6 +41,18 @@ export const useAppStore = defineStore('app', {
list: true, list: true,
dark: isDark, dark: isDark,
}) })
VxeUI.setTheme(isDark ? 'dark' : 'light')
if (isDark) {
document.body.style.setProperty('--vxe-ui-font-color', '#fff')
}
else {
document.body.style.setProperty('--vxe-ui-font-color', '#000')
}
document.body.style.setProperty('--vxe-ui-font-primary-color', color)
document.body.style.setProperty('--vxe-ui-font-primary-lighten-color', color)
document.body.style.setProperty('--vxe-ui-font-primary-darken-color', color)
document.body.style.setProperty('--primary-color', getRgbStr(colors[5])) document.body.style.setProperty('--primary-color', getRgbStr(colors[5]))
this.naiveThemeOverrides.common = Object.assign(this.naiveThemeOverrides.common || {}, { this.naiveThemeOverrides.common = Object.assign(this.naiveThemeOverrides.common || {}, {
primaryColor: colors[5], primaryColor: colors[5],

View File

@@ -26,12 +26,12 @@ body {
.fade-slide-enter-from { .fade-slide-enter-from {
opacity: 0; opacity: 0;
transform: translateX(-30px); transform: translateX(-2%);
} }
.fade-slide-leave-to { .fade-slide-leave-to {
opacity: 0; opacity: 0;
transform: translateX(30px); transform: translateX(2%);
} }
/* 自定义滚动条样式 */ /* 自定义滚动条样式 */

View File

@@ -63,10 +63,9 @@ defineOptions({ name: 'ImgUpload' })
const { copy, copied } = useClipboard() const { copy, copied } = useClipboard()
const imgList = reactive([ const imgList = reactive([
{ url: 'https://cdn.isme.top/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' }, { url: 'https://img.isme.top/isme/67208863145ef.jpg' },
{ url: 'https://cdn.isme.top/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' }, { url: 'https://img.isme.top/isme/67208ab2a9de0.jpg' },
{ url: 'https://cdn.isme.top/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' }, { url: 'https://img.isme.top/isme/67208ab4c6596.jpg' },
{ url: 'https://cdn.isme.top/images/5c23d52f880511ebb6edd017c2d2eca2.jpg' },
]) ])
watch(copied, (val) => { watch(copied, (val) => {

View File

@@ -81,6 +81,7 @@
:columns="btnsColumns" :columns="btnsColumns"
:scroll-x="-1" :scroll-x="-1"
:get-data="api.getButtons" :get-data="api.getButtons"
:computed-height="300"
:query-items="{ parentId: currentMenu.id }" :query-items="{ parentId: currentMenu.id }"
/> />
</template> </template>

View File

@@ -37,6 +37,7 @@
:scroll-x="1200" :scroll-x="1200"
:columns="columns" :columns="columns"
:get-data="api.getAllUsers" :get-data="api.getAllUsers"
:show-check="true"
@on-checked="onChecked" @on-checked="onChecked"
> >
<MeQueryItem label="用户名" :label-width="50"> <MeQueryItem label="用户名" :label-width="50">
@@ -90,7 +91,7 @@ const genders = [
] ]
const columns = [ const columns = [
{ type: 'selection', fixed: 'left' }, // { type: 'selection', fixed: 'left' },
{ {
title: '头像', title: '头像',
key: 'avatar', key: 'avatar',
@@ -101,11 +102,10 @@ const columns = [
src: avatar, src: avatar,
}), }),
}, },
{ title: '用户名', key: 'username', width: 150, ellipsis: { tooltip: true } }, { title: '用户名', key: 'username', ellipsis: { tooltip: true } },
{ {
title: '角色', title: '角色',
key: 'roles', key: 'roles',
width: 200,
ellipsis: { tooltip: true }, ellipsis: { tooltip: true },
render: ({ roles }) => { render: ({ roles }) => {
if (roles?.length) { if (roles?.length) {
@@ -156,7 +156,7 @@ const columns = [
{ {
title: '操作', title: '操作',
key: 'actions', key: 'actions',
width: 100, width: 120,
align: 'right', align: 'right',
fixed: 'right', fixed: 'right',
hideInExcel: true, hideInExcel: true,

View File

@@ -162,11 +162,10 @@ const columns = [
src: avatar, src: avatar,
}), }),
}, },
{ title: '用户名', key: 'username', width: 150, ellipsis: { tooltip: true } }, { title: '用户名', key: 'username', ellipsis: { tooltip: true } },
{ {
title: '角色', title: '角色',
key: 'roles', key: 'roles',
width: 200,
ellipsis: { tooltip: true }, ellipsis: { tooltip: true },
render: ({ roles }) => { render: ({ roles }) => {
if (roles?.length) { if (roles?.length) {