Merge branch 'cool-team-official:5.x' into 5.x

This commit is contained in:
tttclz 2022-06-09 09:57:44 +08:00 committed by GitHub
commit 15038b55f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 252 additions and 88 deletions

View File

@ -1,6 +1,6 @@
{
"name": "front-next",
"version": "5.2.4",
"version": "5.3.0",
"scripts": {
"dev": "vite --host",
"build": "vite build",
@ -9,7 +9,7 @@
"lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix"
},
"dependencies": {
"@cool-vue/crud": "^5.0.7",
"@cool-vue/crud": "^5.0.10",
"@element-plus/icons-vue": "^1.1.3",
"@vueuse/core": "^8.2.5",
"axios": "^0.27.2",

View File

@ -12,6 +12,9 @@ export const config = {
// 菜单
menu: {
// 是否分组显示
isGroup: false,
// 自定义菜单列表
list: []
},
@ -25,16 +28,6 @@ export const config = {
views: []
},
// 主题
theme: {
// 主色
color: "",
// 样式地址
url: "",
// 显示一级菜单
showAMenu: false
},
// 字体图标库
iconfont: []
},

View File

@ -2,17 +2,6 @@ import { config } from "/@/cool";
import { basename } from "/@/cool/utils";
import { createLink } from "../utils";
// 主题初始化
if (config.app.theme) {
const { url, color } = config.app.theme;
if (url) {
createLink(url, "theme-style");
}
document.getElementsByTagName("body")[0].style.setProperty("--color-primary", color);
}
// 字体图标库加载
if (config.app.iconfont) {
config.app.iconfont.forEach((e: string) => {

View File

@ -0,0 +1,114 @@
<template>
<div class="a-menu">
<el-menu
:default-active="active"
mode="horizontal"
background-color="transparent"
@select="select"
>
<el-menu-item v-for="(item, index) in menu.group" :key="index" :index="`${index}`">
<icon-svg v-if="item.icon" :name="item.icon" :size="18" />
<span class="a-menu__name">{{ item.name }}</span>
</el-menu-item>
</el-menu>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import { useBase } from "/$/base";
import { useCool } from "/@/cool";
const { router, route } = useCool();
const { menu } = useBase();
//
const active = ref<string>("0");
//
function select(index: number) {
menu.setMenu(index);
//
const url = menu.getPath(menu.group[index].children);
router.push(url);
}
onMounted(function () {
//
function deep(e: any, i: number) {
switch (e.type) {
case 0:
e.children.forEach((e: any) => {
deep(e, i);
});
break;
case 1:
if (route.path.includes(e.path)) {
active.value = String(i);
menu.setMenu(i);
}
break;
case 2:
default:
break;
}
}
menu.group.forEach((e: any, i: number) => {
deep(e, i);
});
});
</script>
<style lang="scss" scoped>
.a-menu {
margin: 5px 0 0 5px;
.el-menu {
height: 40px;
background: transparent;
border: 0;
:deep(.el-sub-menu__title) {
border: 0 !important;
}
:deep(.el-menu-item) {
display: flex;
align-items: center;
height: 40px;
padding: 0 15px;
background: transparent;
border: 0;
color: #999;
span {
font-size: 12px;
margin-left: 3px;
line-height: normal;
}
&:hover {
background: transparent;
}
&.is-active {
color: var(--color-primary);
border-radius: 5px 5px 0 0;
background: #fff;
color: #000;
}
.icon-svg {
margin-right: 5px;
}
}
}
&__name {
margin-left: 8px;
}
}
</style>

View File

@ -135,8 +135,9 @@ watch(
height: 30px;
padding: 0 10px;
border-radius: 3px;
cursor: pointer;
margin-right: 10px;
font-size: 12px;
cursor: pointer;
&:hover {
background-color: #eee;

View File

@ -64,7 +64,8 @@ export default defineComponent({
}
},
{
immediate: true
immediate: true,
deep: true
}
);

View File

@ -1,4 +1,6 @@
<template>
<a-menu v-if="app.info.menu.isGroup" />
<div class="app-topbar">
<div
class="app-topbar__collapse"
@ -51,6 +53,7 @@
import { useBase } from "/$/base";
import { useCool } from "/@/cool";
import RouteNav from "./route-nav.vue";
import AMenu from "./amenu.vue";
const { router } = useCool();
const { user, app } = useBase();
@ -74,8 +77,8 @@ function onCommand(name: string) {
align-items: center;
height: 50px;
padding: 0 10px;
margin-bottom: 10px;
background-color: #fff;
margin-bottom: 10px;
&__collapse {
display: flex;

View File

@ -78,7 +78,7 @@ export default defineComponent({
const { user, menu } = useBase();
// 1
const saving = ref<boolean>(false);
const saving = ref(false);
//
const form = reactive({
@ -88,27 +88,6 @@ export default defineComponent({
verifyCode: ""
});
//
function getPath(list: any[]) {
let path = "";
function deep(arr: any[]) {
arr.forEach((e: any) => {
if (e.type == 1) {
if (!path) {
path = e.path;
}
} else {
deep(e.children);
}
});
}
deep(list);
return path || "/";
}
//
async function toLogin() {
if (!form.username) {
@ -135,7 +114,10 @@ export default defineComponent({
await user.get();
//
const path = getPath(await menu.get());
await menu.get();
//
const path = menu.getPath();
if (path) {
router.push(path);

View File

@ -51,13 +51,13 @@ export const useMenuStore = defineStore("menu", function () {
const perms = ref<any[]>(data["menu.perms"] || []);
// 设置左侧菜单
function setMenu(i: number) {
if (isEmpty(index)) {
function setMenu(i?: number) {
if (i === undefined) {
i = index.value;
}
// 显示一级菜单
if (config.app.theme.showAMenu) {
// 显示分组显示菜单
if (config.app.menu.isGroup) {
const { children = [] } = group.value[i] || {};
index.value = i;
@ -105,12 +105,12 @@ export const useMenuStore = defineStore("menu", function () {
// 设置菜单组
function setGroup(list: Item[]) {
group.value = orderBy(list, "orderNum");
group.value = orderBy(list, "orderNum").filter((e) => e.isShow);
storage.set("menu.group", group.value);
}
// 获取菜单,权限信息
function get(): Promise<any[]> {
function get(): Promise<Item[]> {
return new Promise((resolve, reject) => {
function next(res: any) {
if (!isArray(res.menus)) {
@ -174,6 +174,29 @@ export const useMenuStore = defineStore("menu", function () {
});
}
// 获取菜单路径
function getPath(list?: Item[]) {
list = list || group.value;
let path = "";
function deep(arr: Item[]) {
arr.forEach((e: Item) => {
if (e.type == 1) {
if (!path) {
path = e.path;
}
} else {
deep(e.children || []);
}
});
}
deep(list);
return path || "/";
}
return {
routes,
group,
@ -184,6 +207,7 @@ export const useMenuStore = defineStore("menu", function () {
setPerms,
setMenu,
setRoutes,
setGroup
setGroup,
getPath
};
});

View File

@ -6,29 +6,35 @@
</div>
<el-drawer v-model="visible" title="设置主题" size="350px" append-to-body>
<el-form label-position="top">
<el-form-item label="推荐">
<ul class="cl-theme__comd">
<li @click="setComd(item)" v-for="(item, name) in themes" :key="name">
<div
class="w"
:style="{
backgroundColor: item.color
}"
>
<check v-show="item.color == form.theme.color" />
</div>
<div class="cl-theme__drawer">
<el-form label-position="top">
<el-form-item label="推荐">
<ul class="cl-theme__comd">
<li @click="setComd(item)" v-for="(item, name) in themes" :key="name">
<div
class="w"
:style="{
backgroundColor: item.color
}"
>
<check v-show="item.color == form.theme.color" />
</div>
<span>{{ item.label }}</span>
</li>
</ul>
</el-form-item>
<span>{{ item.label }}</span>
</li>
</ul>
</el-form-item>
<el-form-item label="自定义主色">
<el-color-picker v-model="form.color" @change="setColor" />
<span class="ml-10px">{{ form.color }}</span>
</el-form-item>
</el-form>
<el-form-item label="自定义主色">
<el-color-picker v-model="form.color" @change="setColor" />
<span class="ml-10px">{{ form.color }}</span>
</el-form-item>
<el-form-item label="菜单分组显示">
<el-switch v-model="form.theme.isGroup" @change="setGroup"></el-switch>
</el-form-item>
</el-form>
</div>
</el-drawer>
</template>
@ -39,6 +45,7 @@ import { module } from "/@/cool/utils";
import store from "store";
import { Check } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { useBase } from "/$/base";
export default defineComponent({
name: "cl-theme",
@ -48,9 +55,16 @@ export default defineComponent({
},
setup() {
const { app, menu } = useBase();
//
const theme = reactive<any>(store.get("theme") || module.get("theme"));
//
if (theme.isGroup === undefined) {
theme.isGroup = app.info.menu.isGroup;
}
//
const form = reactive<any>({
color: theme.color || "",
@ -60,29 +74,46 @@ export default defineComponent({
//
const visible = ref<boolean>(false);
//
function open() {
visible.value = true;
}
//
function setColor(color: string) {
setTheme({ color });
}
//
function setComd(item: any) {
form.theme = item;
Object.assign(form.theme, item);
form.color = item.color;
setTheme(item);
ElMessage.success(`切换主题:${item.label}`);
}
//
function setGroup(val: boolean) {
setTheme({ isGroup: val });
app.set({
menu: {
isGroup: val
}
});
menu.setMenu();
}
return {
app,
form,
themes,
theme,
visible,
open,
setColor,
setComd
setComd,
setTheme,
setGroup
};
}
});
@ -129,5 +160,14 @@ export default defineComponent({
}
}
}
&__drawer {
:deep(.el-form-item) {
background-color: #f7f7f7;
padding: 10px;
border-radius: 5px;
border: 1px solid #eee;
}
}
}
</style>

View File

@ -2,5 +2,5 @@ export default {
// 推荐主题:'jihei', 'guolv', 'jiangzi'
name: "default"
// 自定义主题色
// color: "#4165d7"
// color: "#4165d7",
};

View File

@ -1,6 +1,7 @@
import store from "store";
import { App } from "vue";
import { setTheme } from "./utils";
import { config } from "/@/cool/config";
import "./static/css/index.scss";
export default {
@ -8,6 +9,10 @@ export default {
const theme = store.get("theme") || options;
if (theme) {
if (theme.isGroup !== undefined) {
config.app.menu.isGroup = theme.isGroup;
}
setTheme(theme);
}
}

View File

@ -3,6 +3,12 @@
.page-layout {
background-color: rgba(47, 52, 71, 0.9);
.a-menu {
.el-menu-item {
border-radius: 5px !important;
}
}
.app-topbar {
background-color: transparent;
color: #fff;

View File

@ -43,9 +43,10 @@ export const themes = [
declare interface Options {
color?: string;
name?: string;
isGroup?: boolean;
}
export function setTheme({ color, name }: Options) {
export function setTheme({ color, name, isGroup }: Options) {
// 主题配置
const theme = store.get("theme") || {};
@ -69,6 +70,8 @@ export function setTheme({ color, name }: Options) {
color = item.color;
document.querySelector("#app")?.setAttribute("class", `theme-${name}`);
}
theme.name = name;
}
// 设置主色
@ -81,11 +84,14 @@ export function setTheme({ color, name }: Options) {
el.style.setProperty(`${pre}-light-${i}`, mix(color, mixWhite, i * 0.1));
el.style.setProperty(`${pre}-dark-${i}`, mix(color, mixBlack, i * 0.1));
}
theme.color = color;
}
// 缓存
theme.name = name;
theme.color = color;
// 菜单分组显示
if (isGroup !== undefined) {
theme.isGroup = isGroup;
}
store.set("theme", theme);
}

View File

@ -984,10 +984,10 @@
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@cool-vue/crud@^5.0.7":
version "5.0.7"
resolved "https://registry.npmjs.org/@cool-vue/crud/-/crud-5.0.7.tgz#60459f3e58b04a08c621aa41e25c03618645bd6b"
integrity sha512-/I4f6KFpPHiJE86w2pHAwu2Gn2WAd2LCFn6Bc3jzgg6RdYlAeIyRB9Ph8KasE7CCjyPdb2kyDYEQsZhOfODy9g==
"@cool-vue/crud@^5.0.10":
version "5.0.10"
resolved "https://registry.npmjs.org/@cool-vue/crud/-/crud-5.0.10.tgz#c2d70504fccdf89c907e1d32e62a93dd777fba9c"
integrity sha512-a3jZPS+Y/+7IJTA3iYjD7PK83rwtIDrnE0tcf5LfenZ7JnnlXs+QFMRybGypJfoeswsG97JmWFeSY6o/JyALDw==
dependencies:
array.prototype.flat "^1.2.4"
core-js "^3.21.1"