Former-commit-id: 610f138abb633b0d1faa9fc11b5fbb3f6c5d7724
This commit is contained in:
april
2023-06-19 09:31:52 +08:00
14 changed files with 103 additions and 62 deletions

View File

@@ -1,6 +1,25 @@
# 2.4.0 (2023/6/17)
### ✨ feat
- 新增组件标签输入框author by [april-tong](https://april-tong.com/)
- 新增组件签名author by [april-tong](https://april-tong.com/)
- 新增组件表格author by [april-tong](https://april-tong.com/)
- Echarts 图表添加下载功能 author by [april-tong](https://april-tong.com/)
### 🔄 refactor
- 限制包管理器为 pnpm 和 node 版本16+
- 自定义组件自动导入配置
- 搜索框样式写法优化
### 🐛 fix
- 用户导入的部门回显成数字问题修复
### ⬆️ chore
- element-plus 版本升级 2.3.5 → 2.3.6
# 2.3.1 (2023/5/21) # 2.3.1 (2023/5/21)
### ✂️ refactor ### 🔄 refactor
- 组件示例文件名称优化 - 组件示例文件名称优化
# 2.2.2 (2023/5/11) # 2.2.2 (2023/5/11)
@@ -16,7 +35,7 @@
- vue 版本升级 3.2.45 → 3.3.1 ([CHANGELOG](https://github.com/vuejs/core/blob/main/CHANGELOG.md)) - vue 版本升级 3.2.45 → 3.3.1 ([CHANGELOG](https://github.com/vuejs/core/blob/main/CHANGELOG.md))
- vite 版本升级 4.3.1 → 4.3.5 - vite 版本升级 4.3.1 → 4.3.5
### ✂️ refactor ### 🔄 refactor
- 使用 vue 3.3 版本新特性 `defineOptions``setup` 定义组件名称,移除重复的 `script` 标签 - 使用 vue 3.3 版本新特性 `defineOptions``setup` 定义组件名称,移除重复的 `script` 标签
# 2.2.2 (2023/5/11) # 2.2.2 (2023/5/11)

View File

@@ -1,7 +1,7 @@
{ {
"name": "vue3-element-admin", "name": "vue3-element-admin",
"private": true, "private": true,
"version": "2.3.1", "version": "2.4.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",

View File

@@ -3,14 +3,14 @@
@import "./dark"; @import "./dark";
.app-container { .app-container {
margin: 20px; padding: 10px;
}
.search { .search-container {
padding: 18px 0 0 10px; padding: 18px 0 0 10px;
margin-bottom: 10px; margin-bottom: 10px;
background-color: var(--el-bg-color-overlay); background-color: var(--el-bg-color-overlay);
border: 1px solid var(--el-border-color-light); border: 1px solid var(--el-border-color-light);
border-radius: 4px; border-radius: 4px;
box-shadow: var(--el-box-shadow-light); box-shadow: var(--el-box-shadow-light);
}
} }

View File

@@ -9,6 +9,8 @@ export {};
declare module "@vue/runtime-core" { declare module "@vue/runtime-core" {
export interface GlobalComponents { export interface GlobalComponents {
AppMain: typeof import("./../layout/components/AppMain.vue")["default"];
BarChart: typeof import("./../views/dashboard/components/BarChart.vue")["default"];
Breadcrumb: typeof import("./../components/Breadcrumb/index.vue")["default"]; Breadcrumb: typeof import("./../components/Breadcrumb/index.vue")["default"];
ElAlert: typeof import("element-plus/es")["ElAlert"]; ElAlert: typeof import("element-plus/es")["ElAlert"];
ElBreadcrumb: typeof import("element-plus/es")["ElBreadcrumb"]; ElBreadcrumb: typeof import("element-plus/es")["ElBreadcrumb"];
@@ -46,9 +48,11 @@ declare module "@vue/runtime-core" {
ElTree: typeof import("element-plus/es")["ElTree"]; ElTree: typeof import("element-plus/es")["ElTree"];
ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"]; ElTreeSelect: typeof import("element-plus/es")["ElTreeSelect"];
ElUpload: typeof import("element-plus/es")["ElUpload"]; ElUpload: typeof import("element-plus/es")["ElUpload"];
FunnelChart: typeof import("./../views/dashboard/components/FunnelChart.vue")["default"];
GithubCorner: typeof import("./../components/GithubCorner/index.vue")["default"]; GithubCorner: typeof import("./../components/GithubCorner/index.vue")["default"];
Hamburger: typeof import("./../components/Hamburger/index.vue")["default"]; Hamburger: typeof import("./../components/Hamburger/index.vue")["default"];
IconSelect: typeof import("./../components/IconSelect/index.vue")["default"]; IconSelect: typeof import("./../components/IconSelect/index.vue")["default"];
IEpArrowDown: typeof import("~icons/ep/arrow-down")["default"];
IEpCaretBottom: typeof import("~icons/ep/caret-bottom")["default"]; IEpCaretBottom: typeof import("~icons/ep/caret-bottom")["default"];
IEpCaretTop: typeof import("~icons/ep/caret-top")["default"]; IEpCaretTop: typeof import("~icons/ep/caret-top")["default"];
IEpClose: typeof import("~icons/ep/close")["default"]; IEpClose: typeof import("~icons/ep/close")["default"];
@@ -62,18 +66,30 @@ declare module "@vue/runtime-core" {
IEpRefreshLeft: typeof import("~icons/ep/refresh-left")["default"]; IEpRefreshLeft: typeof import("~icons/ep/refresh-left")["default"];
IEpSearch: typeof import("~icons/ep/search")["default"]; IEpSearch: typeof import("~icons/ep/search")["default"];
IEpSetting: typeof import("~icons/ep/setting")["default"]; IEpSetting: typeof import("~icons/ep/setting")["default"];
IEpSortDown: typeof import("~icons/ep/sort-down")["default"];
IEpSortUp: typeof import("~icons/ep/sort-up")["default"];
IEpTop: typeof import("~icons/ep/top")["default"]; IEpTop: typeof import("~icons/ep/top")["default"];
IEpUploadFilled: typeof import("~icons/ep/upload-filled")["default"]; IEpUploadFilled: typeof import("~icons/ep/upload-filled")["default"];
LangSelect: typeof import("./../components/LangSelect/index.vue")["default"]; LangSelect: typeof import("./../components/LangSelect/index.vue")["default"];
Link: typeof import("./../layout/components/Sidebar/Link.vue")["default"];
Logo: typeof import("./../layout/components/Sidebar/Logo.vue")["default"];
MultiUpload: typeof import("./../components/Upload/MultiUpload.vue")["default"]; MultiUpload: typeof import("./../components/Upload/MultiUpload.vue")["default"];
Navbar: typeof import("./../layout/components/Navbar.vue")["default"];
Pagination: typeof import("./../components/Pagination/index.vue")["default"]; Pagination: typeof import("./../components/Pagination/index.vue")["default"];
PieChart: typeof import("./../views/dashboard/components/PieChart.vue")["default"];
RadarChart: typeof import("./../views/dashboard/components/RadarChart.vue")["default"];
RightPanel: typeof import("./../components/RightPanel/index.vue")["default"]; RightPanel: typeof import("./../components/RightPanel/index.vue")["default"];
RouterLink: typeof import("vue-router")["RouterLink"]; RouterLink: typeof import("vue-router")["RouterLink"];
RouterView: typeof import("vue-router")["RouterView"]; RouterView: typeof import("vue-router")["RouterView"];
ScrollPane: typeof import("./../layout/components/TagsView/ScrollPane.vue")["default"];
Settings: typeof import("./../layout/components/Settings/index.vue")["default"];
Sidebar: typeof import("./../layout/components/Sidebar/index.vue")["default"];
SidebarItem: typeof import("./../layout/components/Sidebar/SidebarItem.vue")["default"];
SingleUpload: typeof import("./../components/Upload/SingleUpload.vue")["default"]; SingleUpload: typeof import("./../components/Upload/SingleUpload.vue")["default"];
SizeSelect: typeof import("./../components/SizeSelect/index.vue")["default"]; SizeSelect: typeof import("./../components/SizeSelect/index.vue")["default"];
SvgIcon: typeof import("./../components/SvgIcon/index.vue")["default"]; SvgIcon: typeof import("./../components/SvgIcon/index.vue")["default"];
TagInput: typeof import("./../components/TagInput/index.vue")["default"]; TagInput: typeof import("./../components/TagInput/index.vue")["default"];
TagsView: typeof import("./../layout/components/TagsView/index.vue")["default"];
WangEditor: typeof import("./../components/WangEditor/index.vue")["default"]; WangEditor: typeof import("./../components/WangEditor/index.vue")["default"];
} }
export interface ComponentCustomProperties { export interface ComponentCustomProperties {

View File

@@ -8,12 +8,6 @@ defineOptions({
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";
import { useTransition, TransitionPresets } from "@vueuse/core"; import { useTransition, TransitionPresets } from "@vueuse/core";
import GithubCorner from "@/components/GithubCorner/index.vue";
import SvgIcon from "@/components/SvgIcon/index.vue";
import BarChart from "./components/BarChart.vue";
import PieChart from "./components/PieChart.vue";
import RadarChart from "./components/RadarChart.vue";
const userStore = useUserStore(); const userStore = useUserStore();
const date: Date = new Date(); const date: Date = new Date();
@@ -90,26 +84,26 @@ orderCount.value = 2000;
{{ greetings }} {{ greetings }}
</div> </div>
<div class="space-x-2 flex items-center"> <div class="space-x-2 flex items-center justify-end">
<el-link <el-link
target="_blank" target="_blank"
type="danger" type="danger"
href="https://blog.csdn.net/u013737132/article/details/130191394" href="https://blog.csdn.net/u013737132/article/details/130191394"
>官方0到1教程</el-link >💥官方从零到一文档</el-link
> >
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-link <el-link
target="_blank" target="_blank"
type="success" type="success"
href="https://gitee.com/youlaiorg/vue3-element-admin" href="https://gitee.com/youlaiorg"
>Gitee源码</el-link >Gitee</el-link
> >
<el-divider direction="vertical" /> <el-divider direction="vertical" />
<el-link <el-link
target="_blank" target="_blank"
type="primary" type="primary"
href="https://github.com/youlaitech/vue3-element-admin" href="https://github.com/youlaitech"
>GitHub源码 >GitHub
</el-link> </el-link>
</div> </div>
</div> </div>
@@ -160,7 +154,7 @@ orderCount.value = 2000;
</div> </div>
<div class="flex flex-col space-y-3"> <div class="flex flex-col space-y-3">
<div class="text-[var(--el-text-color-secondary)]">收入金额</div> <div class="text-[var(--el-text-color-secondary)]">收入金额</div>
<div class="text-lg"> <div class="text-lg text-right">
{{ Math.round(amountOutput) }} {{ Math.round(amountOutput) }}
</div> </div>
</div> </div>

View File

@@ -14,6 +14,14 @@
.app-container { .app-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: calc(100vh - 124px);
/* 84 = navbar + tags-view = 50 + 34 */
height: calc(100vh - 50px);
}
.hasTagsView {
.app-container {
height: calc(100vh - 84px);
}
} }
</style> </style>

View File

@@ -86,7 +86,7 @@ onMounted(() => {});
> >
<div> <div>
<div class="search"> <div class="search-container">
<el-form :inline="true"> <el-form :inline="true">
<el-form-item> <el-input v-model="inputVal" /></el-form-item> <el-form-item> <el-input v-model="inputVal" /></el-form-item>
<el-form-item <el-form-item

View File

@@ -181,7 +181,7 @@ onMounted(() => {
</script> </script>
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="search"> <div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关键字" prop="keywords"> <el-form-item label="关键字" prop="keywords">
<el-input <el-input

View File

@@ -196,7 +196,7 @@ onMounted(() => {
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="search"> <div class="search-container">
<!-- 搜索表单 --> <!-- 搜索表单 -->
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关键字" prop="name"> <el-form-item label="关键字" prop="name">

View File

@@ -194,7 +194,7 @@ onMounted(() => {
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="search"> <div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关键字" prop="name"> <el-form-item label="关键字" prop="name">
<el-input <el-input

View File

@@ -83,8 +83,6 @@ function resetQuery() {
/** /**
* 行点击事件 * 行点击事件
*
* @param row
*/ */
function onRowClick(row: MenuVO) { function onRowClick(row: MenuVO) {
selectedRowMenuId.value = row.id; selectedRowMenuId.value = row.id;
@@ -130,7 +128,7 @@ function onMenuTypeChange() {
} }
/** /**
* 菜单提交 * 菜单保存提交
*/ */
function submitForm() { function submitForm() {
menuFormRef.value.validate((isValid: boolean) => { menuFormRef.value.validate((isValid: boolean) => {
@@ -155,6 +153,7 @@ function submitForm() {
/** /**
* 删除菜单 * 删除菜单
* @param menuId 菜单ID
*/ */
function handleDelete(menuId: number) { function handleDelete(menuId: number) {
if (!menuId) { if (!menuId) {
@@ -198,6 +197,7 @@ function resetForm() {
formData.perm = undefined; formData.perm = undefined;
formData.component = undefined; formData.component = undefined;
formData.path = undefined; formData.path = undefined;
formData.redirect = undefined;
} }
onMounted(() => { onMounted(() => {
@@ -207,7 +207,7 @@ onMounted(() => {
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="search"> <div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关键字" prop="keywords"> <el-form-item label="关键字" prop="keywords">
<el-input <el-input

View File

@@ -243,7 +243,7 @@ onMounted(() => {
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="search"> <div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item prop="keywords" label="关键字"> <el-form-item prop="keywords" label="关键字">
<el-input <el-input

View File

@@ -73,7 +73,11 @@ const importDialog = reactive<DialogOption>({
title: "用户导入", title: "用户导入",
visible: false, visible: false,
}); });
const importDeptId = ref<number>(0);
/**
* 导入选择的部门ID
*/
const importDeptId = ref<number>();
const excelFile = ref<File>(); const excelFile = ref<File>();
const excelFilelist = ref<File[]>([]); const excelFilelist = ref<File[]>([]);
@@ -191,9 +195,7 @@ function resetPassword(row: { [key: string]: any }) {
} }
/** /**
* 打开弹窗 * 打开用户弹窗
*
* @param userId 用户ID
*/ */
async function openDialog(userId?: number) { async function openDialog(userId?: number) {
await getDeptOptions(); await getDeptOptions();
@@ -210,7 +212,7 @@ async function openDialog(userId?: number) {
} }
/** /**
* 关闭用户弹窗 * 关闭弹窗
*/ */
function closeDialog() { function closeDialog() {
dialog.visible = false; dialog.visible = false;
@@ -310,11 +312,11 @@ function downloadTemplate() {
} }
/** /**
* 导入弹窗 * 打开导入弹窗
*/ */
async function openImportDialog() { async function openImportDialog() {
await getDeptOptions(); await getDeptOptions();
await getRoleOptions(); importDeptId.value = undefined;
importDialog.visible = true; importDialog.visible = true;
} }
@@ -334,7 +336,7 @@ function handleExcelChange(file: UploadFile) {
} }
/** /**
* 导入用户 * 导入用户提交
*/ */
function handleUserImport() { function handleUserImport() {
if (importDeptId.value) { if (importDeptId.value) {
@@ -412,7 +414,7 @@ onMounted(() => {
</el-col> </el-col>
<el-col :lg="20" :xs="24"> <el-col :lg="20" :xs="24">
<div class="search"> <div class="search-container">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="关键字" prop="keywords"> <el-form-item label="关键字" prop="keywords">
<el-input <el-input

View File

@@ -53,39 +53,41 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
}, },
plugins: [ plugins: [
vue(), vue(),
UnoCSS({ UnoCSS({}),
/* options */
}),
AutoImport({ AutoImport({
// 自动导入 Vue 相关函数ref, reactive, toRef 等 // 自动导入 Vue 相关函数ref, reactive, toRef 等
imports: ["vue", "@vueuse/core"], imports: ["vue", "@vueuse/core"],
eslintrc: { eslintrc: {
enabled: false, // Default `false` enabled: false,
filepath: "./.eslintrc-auto-import.json", // Default `./.eslintrc-auto-import.json` filepath: "./.eslintrc-auto-import.json",
globalsPropValue: true, // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable') globalsPropValue: true,
}, },
resolvers: [ resolvers: [
// 自动导入 Element Plus 相关函数ElMessage, ElMessageBox... (带样式) // 自动导入 Element Plus 相关函数ElMessage, ElMessageBox... (带样式)
ElementPlusResolver(), ElementPlusResolver(),
// 自动导入图标组件
IconsResolver({}), IconsResolver({}),
], ],
vueTemplate: true, // 是否在 vue 模板中自动导入 vueTemplate: true,
dts: false, // 关闭自动生成 // 配置文件生成位置(false:关闭自动生成)
//dts: path.resolve(pathSrc, "types", "auto-imports.d.ts"), // 自动导入组件类型声明文件位置,默认根目录 dts: false,
// dts: "src/types/auto-imports.d.ts",
}), }),
Components({ Components({
resolvers: [ resolvers: [
// 自动注册图标组件
IconsResolver({
enabledCollections: ["ep"], //@iconify-json/ep 是 Element Plus 的图标库
}),
// 自动导入 Element Plus 组件 // 自动导入 Element Plus 组件
ElementPlusResolver(), ElementPlusResolver(),
// 自动导入图标组件
IconsResolver({
// @iconify-json/ep 是 Element Plus 的图标库
enabledCollections: ["ep"],
}),
], ],
dts: false, // 关闭自动生成 // 指定自定义组件位置(默认:src/components)
// dts: path.resolve(pathSrc, "types", "components.d.ts"), // 自动导入组件类型声明文件位置,默认根目录 dirs: ["src/**/components"],
// 配置文件位置(false:关闭自动生成)
dts: false,
// dts: "src/types/components.d.ts",
}), }),
Icons({ Icons({
@@ -100,7 +102,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
symbolId: "icon-[dir]-[name]", symbolId: "icon-[dir]-[name]",
}), }),
], ],
// 预加载项目必需的组件
optimizeDeps: { optimizeDeps: {
include: [ include: [
"vue", "vue",