Compare commits

..

10 Commits

Author SHA1 Message Date
xiaoxian521
33a89834d7 release: update 5.7.0 2024-06-04 16:21:22 +08:00
xiaoxian521
649aab9c7d docs: 更新特别代码贡献名单 2024-06-04 13:49:52 +08:00
way
7a6ee58e6d feat: 添加谷歌风格的页签 (#1160) 2024-06-04 13:44:47 +08:00
xiaoxian521
b402a8924f docs: update 2024-06-01 06:33:55 +08:00
xiaoxian521
9a5523d1c7 chore: 更新依赖,建议升级vue-pdf-embed至最新版 2024-05-31 14:30:00 +08:00
xiaoxian521
1e6d0283c9 docs: update 2024-05-29 11:06:01 +08:00
xiaoxian521
a8377f8d45 fix: 修复在火狐浏览器中菜单折叠后,文字超出未隐藏的问题 2024-05-28 12:19:18 +08:00
xiaoxian521
cd653c83f0 chore: 升级依赖,相关兼容处理 2024-05-28 10:16:09 +08:00
xiaoxian521
643b36fc42 docs: update README 2024-05-28 00:04:35 +08:00
RosyCloudsLee
17ed4d640d types: update 2024-05-21 09:36:14 +08:00
20 changed files with 1118 additions and 878 deletions

View File

@@ -1,3 +1,13 @@
# 5.7.0 (2024-06-04)
### 🎫 Feat
- Add Google style tabs
### 🐞 Bug fixes
- Fixed the issue where the text exceeds and is not hidden after the menu is folded in Firefox browser
# 5.6.0 (2024-05-14)
### ✔️ Refactor

View File

@@ -1,3 +1,13 @@
# 5.7.0 (2024-06-04)
### 🎫 Feat
- Add Google style tabs
### 🐞 Bug fixes
- Fixed the issue where the text exceeds and is not hidden after the menu is folded in Firefox browser
# 5.6.0 (2024-05-14)
### ✔️ Refactor

View File

@@ -1,3 +1,13 @@
# 5.7.0 (2024-06-04)
### 🎫 Feat
- 添加谷歌风格的页签
### 🐞 Bug fixes
- 修复在火狐浏览器中菜单折叠后,文字超出未隐藏的问题
# 5.6.0 (2024-05-14)
### ✔️ Refactor

View File

@@ -10,11 +10,9 @@
`vue-pure-admin` is an open source, free and out-of-the-box middle and backend management system template. Completely adopts `ECMAScript` module (`ESM`) specifications to write and organize code, using the latest `Vue3`, `Vite`, `Element-Plus`, `TypeScript`, `Pinia`, `Tailwindcss` and other mainstream technologies develop
## Sponsors
## R&D philosophy
<a class="logo" href="https://ai-tools.cn/resume/start" target="_blank" rel="sponsored noopener">
<img src="./public/sponsors/aitools.svg" alt="aitools">
</a>
Seek innovation in stability and see the future in technology
## Thin version (offering non-internationalized and internationalized versions)
@@ -184,6 +182,7 @@ Thank you very much for your in-depth understanding of the source code and your
| [WitMiao](https://github.com/WitMiao) | [code](https://github.com/pure-admin/vue-pure-admin/commits?author=WitMiao) |
| [QFifteen](https://github.com/QFifteen) | [code](https://github.com/pure-admin/vue-pure-admin/commits?author=QFifteen) |
| [edgexie](https://github.com/edgexie) | [code](https://github.com/pure-admin/vue-pure-admin/commits?author=edgexie) |
| [way-jm](https://github.com/way-jm) | [code](https://github.com/pure-admin/vue-pure-admin/commits?author=way-jm) |
## Git Contribution submission specification

View File

@@ -11,11 +11,9 @@
`vue-pure-admin` 是一款开源免费且开箱即用的中后台管理系统模版。完全采用 `ECMAScript` 模块(`ESM`)规范来编写和组织代码,使用了最新的 `Vue3`
`Vite``Element-Plus``TypeScript``Pinia``Tailwindcss` 等主流技术开发
## 赞助商
## 研发理念
<a class="logo" href="https://ai-tools.cn/resume/start" target="_blank" rel="sponsored noopener">
<img src="./public/sponsors/aitools.svg" alt="aitools">
</a>
稳定中求创新,技术中见未来
## 精简版本(实际项目开发请用精简版本,提供 `非国际化` 、`国际化` 两个版本选择)
@@ -38,6 +36,10 @@
[点我查看详情](https://pure-admin.github.io/pure-admin-doc/pages/service/)
## `max` 版本
[点我查看 max 版本](https://github.com/pure-admin/vue-pure-admin-max)
## `Tauri` 版本
[点我查看 Tauri 版本](https://github.com/pure-admin/tauri-pure-admin)
@@ -185,6 +187,7 @@ docker run -dp 8080:80 --name pure-admin vue-pure-admin
| [WitMiao](https://github.com/WitMiao) | [代码](https://github.com/pure-admin/vue-pure-admin/commits?author=WitMiao) |
| [QFifteen](https://github.com/QFifteen) | [代码](https://github.com/pure-admin/vue-pure-admin/commits?author=QFifteen) |
| [edgexie](https://github.com/edgexie) | [代码](https://github.com/pure-admin/vue-pure-admin/commits?author=edgexie) |
| [way-jm](https://github.com/way-jm) | [代码](https://github.com/pure-admin/vue-pure-admin/commits?author=way-jm) |
## `Git` 贡献提交规范

View File

@@ -53,6 +53,8 @@ panel:
pureTagsStyleSmartTip: Smart tags add fun and brilliance
pureTagsStyleCard: Card
pureTagsStyleCardTip: Card tags for efficient browsing
pureTagsStyleChrome: Chrome
pureTagsStyleChromeTip: Chrome style is classic and elegant
pureInterfaceDisplay: Interface Display
pureGreyModel: Grey Model
pureWeakModel: Weak Model

View File

@@ -53,6 +53,8 @@ panel:
pureTagsStyleSmartTip: 灵动标签,添趣生辉
pureTagsStyleCard: 卡片
pureTagsStyleCardTip: 卡片标签,高效浏览
pureTagsStyleChrome: 谷歌
pureTagsStyleChromeTip: 谷歌风格,经典美观
pureInterfaceDisplay: 界面显示
pureGreyModel: 灰色模式
pureWeakModel: 色弱模式
@@ -119,7 +121,7 @@ menus:
pureMenu1-2-1: 菜单1-2-1
pureMenu1-2-2: 菜单1-2-2
pureMenu1-3: 菜单1-3
pureMenu2: 菜单2
pureMenu2: 菜单
purePermission: 权限管理
purePermissionPage: 页面权限
purePermissionButton: 按钮权限

View File

@@ -1,6 +1,6 @@
{
"name": "vue-pure-admin",
"version": "5.6.0",
"version": "5.7.0",
"private": true,
"type": "module",
"scripts": {
@@ -56,19 +56,19 @@
"@pureadmin/table": "^3.1.2",
"@pureadmin/utils": "^2.4.7",
"@vue-flow/background": "^1.3.0",
"@vue-flow/core": "^1.33.7",
"@vueuse/core": "^10.9.0",
"@vueuse/motion": "^2.1.0",
"@vue-flow/core": "^1.34.0",
"@vueuse/core": "^10.10.0",
"@vueuse/motion": "^2.2.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"@zxcvbn-ts/core": "^3.0.4",
"animate.css": "^4.1.1",
"axios": "^1.6.8",
"axios": "^1.7.2",
"china-area-data": "^5.0.1",
"cropperjs": "^1.6.2",
"dayjs": "^1.11.11",
"echarts": "^5.5.0",
"el-table-infinite-scroll": "^3.0.3",
"el-table-infinite-scroll": "^3.0.5",
"element-plus": "^2.7.3",
"intro.js": "^7.2.0",
"js-cookie": "^3.0.5",
@@ -80,13 +80,13 @@
"nprogress": "^0.2.0",
"path": "^0.12.7",
"pinia": "^2.1.7",
"pinyin-pro": "^3.20.4",
"plus-pro-components": "^0.1.3",
"pinyin-pro": "^3.21.1",
"plus-pro-components": "^0.1.7",
"qrcode": "^1.5.3",
"qs": "^6.12.1",
"responsive-storage": "^2.2.0",
"sortablejs": "^1.15.2",
"swiper": "^11.1.2",
"swiper": "^11.1.4",
"typeit": "^8.8.3",
"v-contextmenu": "^3.2.0",
"v3-infinite-loading": "^1.3.1",
@@ -94,7 +94,7 @@
"vue": "^3.4.27",
"vue-i18n": "^9.13.1",
"vue-json-pretty": "^2.4.0",
"vue-pdf-embed": "^2.0.3",
"vue-pdf-embed": "^2.0.4",
"vue-router": "^4.3.2",
"vue-tippy": "^6.4.1",
"vue-types": "^5.1.2",
@@ -103,16 +103,16 @@
"vue3-danmaku": "^1.6.0",
"vue3-puzzle-vcode": "^1.1.7",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.6.12",
"wavesurfer.js": "^7.7.14",
"xgplayer": "^3.0.17",
"vxe-table": "^4.6.17",
"wavesurfer.js": "^7.7.15",
"xgplayer": "^3.0.18",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@commitlint/types": "^19.0.3",
"@eslint/js": "^9.2.0",
"@eslint/js": "^9.3.0",
"@faker-js/faker": "^8.4.1",
"@iconify-icons/ep": "^1.2.12",
"@iconify-icons/ri": "^1.2.10",
@@ -123,27 +123,27 @@
"@types/gradient-string": "^1.1.6",
"@types/intro.js": "^5.1.5",
"@types/js-cookie": "^3.0.6",
"@types/node": "^20.12.11",
"@types/node": "^20.12.13",
"@types/nprogress": "^0.2.3",
"@types/qrcode": "^1.5.5",
"@types/qs": "^6.9.15",
"@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^7.9.0",
"@typescript-eslint/parser": "^7.9.0",
"@typescript-eslint/eslint-plugin": "^7.11.0",
"@typescript-eslint/parser": "^7.11.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.19",
"boxen": "^7.1.1",
"cssnano": "^7.0.1",
"dagre": "^0.8.5",
"eslint": "^9.2.0",
"eslint": "^9.3.0",
"eslint-config-prettier": "^9.1.0",
"eslint-define-config": "^2.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.26.0",
"gradient-string": "^2.0.2",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"lint-staged": "^15.2.5",
"postcss": "^8.4.38",
"postcss-html": "^1.7.0",
"postcss-import": "^16.1.0",
@@ -151,8 +151,8 @@
"prettier": "^3.2.5",
"rimraf": "^5.0.7",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.77.1",
"stylelint": "^16.5.0",
"sass": "^1.77.4",
"stylelint": "^16.6.1",
"stylelint-config-recess-order": "^5.0.1",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard-scss": "^13.1.0",
@@ -160,7 +160,7 @@
"svgo": "^3.3.2",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5",
"vite": "^5.2.11",
"vite": "^5.2.12",
"vite-plugin-cdn-import": "^1.0.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-fake-server": "^2.1.1",

1639
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{
"Version": "5.6.0",
"Version": "5.7.0",
"Title": "PureAdmin",
"FixedHeader": true,
"HiddenSideBar": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 80 KiB

View File

@@ -2,6 +2,7 @@
import { useI18n } from "vue-i18n";
import LayFrame from "../lay-frame/index.vue";
import LayFooter from "../lay-footer/index.vue";
import { useTags } from "@/layout/hooks/useTag";
import { useGlobal, isNumber } from "@pureadmin/utils";
import BackTopIcon from "@/assets/svg/back_top.svg?component";
import { h, computed, Transition, defineComponent } from "vue";
@@ -12,6 +13,7 @@ const props = defineProps({
});
const { t } = useI18n();
const { showModel } = useTags();
const { $storage, $config } = useGlobal<GlobalPropertiesApi>();
const isKeepAlive = computed(() => {
@@ -51,9 +53,17 @@ const getMainWidth = computed(() => {
const getSectionStyle = computed(() => {
return [
hideTabs.value && layout ? "padding-top: 48px;" : "",
!hideTabs.value && layout ? "padding-top: 81px;" : "",
!hideTabs.value && layout
? showModel.value == "chrome"
? "padding-top: 85px;"
: "padding-top: 81px;"
: "",
hideTabs.value && !layout.value ? "padding-top: 48px;" : "",
!hideTabs.value && !layout.value ? "padding-top: 81px;" : "",
!hideTabs.value && !layout.value
? showModel.value == "chrome"
? "padding-top: 85px;"
: "padding-top: 81px;"
: "",
props.fixedHeader
? ""
: `padding-top: 0;${

View File

@@ -232,6 +232,11 @@ const markOptions = computed<Array<OptionsType>>(() => {
label: t("panel.pureTagsStyleCard"),
tip: t("panel.pureTagsStyleCardTip"),
value: "card"
},
{
label: t("panel.pureTagsStyleChrome"),
tip: t("panel.pureTagsStyleChromeTip"),
value: "chrome"
}
];
});
@@ -442,7 +447,7 @@ onUnmounted(() => removeMatchMedia);
<Segmented
resize
class="select-none"
:modelValue="markValue === 'smart' ? 0 : 1"
:modelValue="markValue === 'smart' ? 0 : markValue === 'card' ? 1 : 2"
:options="markOptions"
@change="onChange"
/>

View File

@@ -145,7 +145,7 @@ function resolvePath(routePath) {
item?.pathList?.length === 2)
"
truncated
class="!w-full !px-4 !text-inherit"
class="!w-full !pl-4 !text-inherit"
>
{{ transformI18n(onlyOneChild.meta.title) }}
</el-text>
@@ -199,7 +199,7 @@ function resolvePath(routePath) {
:class="{
'!w-full': true,
'!text-inherit': true,
'!px-4':
'!pl-4':
layout !== 'horizontal' &&
isCollapse &&
!toRaw(item.meta.icon) &&

View File

@@ -0,0 +1,33 @@
<template>
<svg class="w-full h-full">
<defs>
<symbol id="geometry-left" viewBox="0 0 214 36">
<path d="M17 0h197v36H0v-2c4.5 0 9-3.5 9-8V8c0-4.5 3.5-8 8-8z" />
</symbol>
<symbol id="geometry-right" viewBox="0 0 214 36">
<use xlink:href="#geometry-left" />
</symbol>
<clipPath>
<rect width="100%" height="100%" x="0" />
</clipPath>
</defs>
<svg width="51%" height="100%">
<use
xlink:href="#geometry-left"
width="214"
height="36"
fill="currentColor"
/>
</svg>
<g transform="scale(-1, 1)">
<svg width="51%" height="100%" x="-100%" y="0">
<use
xlink:href="#geometry-right"
width="214"
height="36"
fill="currentColor"
/>
</svg>
</g>
</svg>
</template>

View File

@@ -41,6 +41,13 @@
padding-right: 24px;
}
&.chrome-item {
padding-right: 0;
padding-left: 0;
margin-right: -18px;
box-shadow: none;
}
.el-icon-close {
position: absolute;
top: 50%;
@@ -76,6 +83,14 @@
overflow: hidden;
white-space: nowrap;
&.chrome-scroll-container {
padding-top: 4px;
.fixed-tag {
padding: 0 !important;
}
}
.tab {
position: relative;
float: left;
@@ -89,6 +104,12 @@
&:nth-child(1) {
padding: 0 12px;
}
&.chrome-item {
&:nth-child(1) {
padding: 0;
}
}
}
.fixed-tag {
@@ -173,9 +194,29 @@
color: #fff;
box-shadow: 0 0 0.7px #888;
.chrome-tab {
z-index: 10;
}
.chrome-tab__bg {
color: var(--el-color-primary-light-9) !important;
}
.tag-title {
color: var(--el-color-primary) !important;
}
.chrome-close-btn {
color: var(--el-color-primary);
&:hover {
background-color: var(--el-color-primary);
}
}
.chrome-tab-divider {
opacity: 0;
}
}
.arrow-left,
@@ -262,3 +303,69 @@
background: var(--el-color-primary);
animation: schedule-out-width 200ms ease-in;
}
/* 谷歌风格的页签 */
.chrome-tab {
position: relative;
display: inline-flex;
gap: 16px;
align-items: center;
justify-content: center;
padding: 0 24px;
white-space: nowrap;
cursor: pointer;
.tag-title {
padding: 0;
}
.chrome-tab-divider {
position: absolute;
right: 7px;
width: 1px;
height: 14px;
background-color: #2b2d2f;
}
&:hover {
z-index: 10;
.chrome-tab__bg {
color: #dee1e6;
}
.tag-title {
color: #1f1f1f;
}
.chrome-tab-divider {
opacity: 0;
}
}
.chrome-tab__bg {
position: absolute;
top: 0;
left: 0;
z-index: -10;
width: 100%;
height: 100%;
color: transparent;
pointer-events: none;
}
.chrome-close-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
color: #666;
border-radius: 50%;
&:hover {
color: white;
background-color: #b1b3b8;
}
}
}

View File

@@ -5,6 +5,7 @@ import { RouteConfigs } from "../../types";
import { useTags } from "../../hooks/useTag";
import { routerArrays } from "@/layout/types";
import { onClickOutside } from "@vueuse/core";
import TagChrome from "./components/TagChrome.vue";
import { handleAliveRoute, getTopMenu } from "@/router/utils";
import { useSettingStoreHook } from "@/store/modules/settings";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
@@ -565,6 +566,7 @@ onBeforeUnmount(() => {
<div
ref="scrollbarDom"
class="scroll-container"
:class="showModel === 'chrome' && 'chrome-scroll-container'"
@wheel.prevent="handleWheel"
>
<div ref="tabDom" class="tab select-none" :style="getTabStyle">
@@ -575,6 +577,7 @@ onBeforeUnmount(() => {
:class="[
'scroll-item is-closable',
linkIsActive(item),
showModel === 'chrome' && 'chrome-item',
!isAllEmpty(item?.meta?.fixedTag) && 'fixed-tag'
]"
@contextmenu.prevent="openMenu(item, $event)"
@@ -582,28 +585,46 @@ onBeforeUnmount(() => {
@mouseleave.prevent="onMouseleave(index)"
@click="tagOnClick(item)"
>
<span
class="tag-title dark:!text-text_color_primary dark:hover:!text-primary"
>
{{ transformI18n(item.meta.title) }}
</span>
<span
v-if="
isAllEmpty(item?.meta?.fixedTag)
? iconIsActive(item, index) ||
(index === activeIndex && index !== 0)
: false
"
class="el-icon-close"
@click.stop="deleteMenu(item)"
>
<IconifyIconOffline :icon="Close" />
</span>
<span
v-if="showModel !== 'card'"
:ref="'schedule' + index"
:class="[scheduleIsActive(item)]"
/>
<template v-if="showModel !== 'chrome'">
<span
class="tag-title dark:!text-text_color_primary dark:hover:!text-primary"
>
{{ transformI18n(item.meta.title) }}
</span>
<span
v-if="
isAllEmpty(item?.meta?.fixedTag)
? iconIsActive(item, index) ||
(index === activeIndex && index !== 0)
: false
"
class="el-icon-close"
@click.stop="deleteMenu(item)"
>
<IconifyIconOffline :icon="Close" />
</span>
<span
v-if="showModel !== 'card'"
:ref="'schedule' + index"
:class="[scheduleIsActive(item)]"
/>
</template>
<div v-else class="chrome-tab">
<div class="chrome-tab__bg">
<TagChrome />
</div>
<span class="tag-title">
{{ transformI18n(item.meta.title) }}
</span>
<span
v-if="isAllEmpty(item?.meta?.fixedTag) ? index !== 0 : false"
class="chrome-close-btn"
@click.stop="deleteMenu(item)"
>
<IconifyIconOffline :icon="Close" />
</span>
<span class="chrome-tab-divider" />
</div>
</div>
</div>
</div>

View File

@@ -48,7 +48,7 @@ import {
} from "vxe-table";
// 全局默认参数
VXETable.config({
VXETable.setConfig({
// i18n: (key, args) => {
// return unref(i18n.global.locale) === "zh"
// ? XEUtils.toFormatString(XEUtils.get(zh, key), args)

View File

@@ -115,6 +115,22 @@ html.dark {
background-color: rgb(255 255 255 / 12%);
}
}
.chrome-tab {
.tag-title {
color: #666;
}
&:hover {
.chrome-tab__bg {
color: #333;
}
.tag-title {
color: #adadad;
}
}
}
}
}

View File

@@ -36,12 +36,12 @@ export default class PureHttp {
): Promise<T>;
post<T, P>(
url: string,
params?: T,
params?: P,
config?: PureHttpRequestConfig
): Promise<P>;
): Promise<T>;
get<T, P>(
url: string,
params?: T,
params?: P,
config?: PureHttpRequestConfig
): Promise<P>;
): Promise<T>;
}