Merge branch 'test' of https://newgitea.sxczgkj.cn/czg_team/cashier-web into test
This commit is contained in:
68
src/api/account/quick.ts
Normal file
68
src/api/account/quick.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import request from "@/utils/request";
|
||||
import { Account_BaseUrl } from "@/api/config";
|
||||
const baseURL = Account_BaseUrl + "/admin/quick";
|
||||
const API = {
|
||||
getList(data: any) {
|
||||
return request<any, QuickMenu[]>({
|
||||
url: `${baseURL}`,
|
||||
method: "get",
|
||||
params: data
|
||||
});
|
||||
},
|
||||
add(data: any) {
|
||||
return request({
|
||||
url: `${baseURL}`,
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
},
|
||||
delete(ids: [string | number]) {
|
||||
return request({
|
||||
url: `${baseURL}`,
|
||||
method: "delete",
|
||||
data: ids,
|
||||
});
|
||||
},
|
||||
edit(data: any) {
|
||||
return request({
|
||||
url: `${baseURL}`,
|
||||
method: "put",
|
||||
data: data,
|
||||
});
|
||||
},
|
||||
}
|
||||
export default API;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 悬浮窗配置 实体类。
|
||||
*
|
||||
* QuickMenu
|
||||
*/
|
||||
export interface QuickMenu {
|
||||
createTime?: string;
|
||||
id?: number;
|
||||
/**
|
||||
* 菜单Id
|
||||
*/
|
||||
menuId: number;
|
||||
/**
|
||||
* 店铺Id
|
||||
*/
|
||||
shopId?: number;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 状态 1-启用 0-禁用
|
||||
*/
|
||||
status?: number;
|
||||
updateTime?: string;
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
url?: string;
|
||||
[property: string]: any;
|
||||
}
|
||||
BIN
src/assets/images/close.png
Normal file
BIN
src/assets/images/close.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
BIN
src/assets/images/plus.png
Normal file
BIN
src/assets/images/plus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.0 KiB |
266
src/components/FastMenuConfig/dialog-add.vue
Normal file
266
src/components/FastMenuConfig/dialog-add.vue
Normal file
@@ -0,0 +1,266 @@
|
||||
<template>
|
||||
<el-dialog :title="form.id ? '编辑' : '添加'" width="400px" v-model="visible" @closed="resetForm">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-position="left">
|
||||
<el-form-item label="菜单" prop="menuId">
|
||||
<el-tree-select
|
||||
:check-strictly="true"
|
||||
v-model="form.menuId"
|
||||
:data="menus"
|
||||
:render-after-expand="false"
|
||||
style="width: 240px"
|
||||
node-key="menuId"
|
||||
:disabled-key="disabled"
|
||||
></el-tree-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="排序值">
|
||||
<el-input-number v-model="form.sort" :step="1" step-strictly />
|
||||
</el-form-item>
|
||||
<el-form-item label="启用状态">
|
||||
<el-switch v-model="form.status" :active-value="1" :inactive-value="0"></el-switch>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog_footer">
|
||||
<div class="btn">
|
||||
<el-button size="large" style="width: 100%" @click="visible = false">取 消</el-button>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
style="width: 100%"
|
||||
@click="submitHandle"
|
||||
>
|
||||
确 定
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 补充缺失的导入
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import { ElNotification, ElMessage } from "element-plus"; // 导入提示组件
|
||||
import { filterNumberInput } from "@/utils";
|
||||
import { roleTemplateAdd } from "@/api/account/roleTemplate";
|
||||
import MenuAPI from "@/api/account/menu";
|
||||
import quickApi from "@/api/account/quick";
|
||||
|
||||
const props = defineProps({
|
||||
isGetMenu: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false, // 补充默认值
|
||||
},
|
||||
parMenus: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => [], // 补充默认值
|
||||
},
|
||||
item: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => null,
|
||||
},
|
||||
});
|
||||
|
||||
const menus = ref([]);
|
||||
|
||||
/**
|
||||
* 格式化菜单数据:核心逻辑 - 禁用有子菜单的父节点,仅允许选叶子节点
|
||||
* @param arr 原始菜单数组
|
||||
* @returns 格式化后带禁用标记的菜单数组
|
||||
*/
|
||||
function returnMenu(arr) {
|
||||
let result = [];
|
||||
for (let menu of arr) {
|
||||
// 过滤掉"默认接口目录"
|
||||
if (menu.title === "默认接口目录") continue;
|
||||
|
||||
// 筛选有效子菜单:非隐藏 + 类型为0
|
||||
const children = menu.children ? menu.children.filter((v) => !v.hidden && v.type === 0) : [];
|
||||
// 递归处理子菜单
|
||||
const formattedChildren = returnMenu(children);
|
||||
|
||||
// 核心:判断是否为叶子节点(无有效子菜单)
|
||||
const isLeaf = formattedChildren.length === 0;
|
||||
|
||||
// 组装节点:有子菜单则禁用(disabled: true),无则允许选择
|
||||
const menuNode = {
|
||||
...menu,
|
||||
label: menu.title,
|
||||
value: menu.menuId,
|
||||
menuId: menu.menuId, // 保持node-key一致
|
||||
disabled: !isLeaf, // 有子菜单 → 禁用,无 → 启用
|
||||
children: formattedChildren,
|
||||
};
|
||||
|
||||
// 特殊处理:如果子菜单只有1个,直接扁平化(保持原有逻辑)
|
||||
if (formattedChildren.length === 1) {
|
||||
result.push({
|
||||
...formattedChildren[0],
|
||||
disabled: formattedChildren[0].children.length > 0, // 子节点仍判断是否有后代
|
||||
});
|
||||
} else {
|
||||
result.push(menuNode);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (!props.isGetMenu) return;
|
||||
try {
|
||||
const res = await MenuAPI.getRoutes();
|
||||
menus.value = returnMenu(res);
|
||||
} catch (error) {
|
||||
ElMessage.error("菜单数据加载失败");
|
||||
console.error("getRoutes error:", error);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听父组件传入的菜单变化
|
||||
watch(
|
||||
() => props.parMenus,
|
||||
(newVal) => {
|
||||
if (newVal.length) {
|
||||
menus.value = returnMenu(newVal);
|
||||
}
|
||||
},
|
||||
{ deep: true } // 监听数组内部变化
|
||||
);
|
||||
|
||||
// 对话框显隐绑定
|
||||
const visible = defineModel({
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
});
|
||||
|
||||
const formRef = ref(null);
|
||||
const loading = ref(false);
|
||||
// 表单初始化
|
||||
const form = ref({
|
||||
menuId: "",
|
||||
sort: 0,
|
||||
url: "",
|
||||
status: 1,
|
||||
});
|
||||
|
||||
/**
|
||||
* 自定义校验规则:确保选中的是叶子节点(兜底验证)
|
||||
* @param rule 校验规则
|
||||
* @param value 选中的menuId
|
||||
* @param callback 回调函数
|
||||
*/
|
||||
function validateLeafMenu(rule, value, callback) {
|
||||
if (!value) {
|
||||
return callback(new Error("请选择菜单"));
|
||||
}
|
||||
// 递归查找节点,判断是否为叶子节点
|
||||
const findNode = (nodes, menuId) => {
|
||||
for (let node of nodes) {
|
||||
if (node.menuId === menuId) return node;
|
||||
if (node.children) {
|
||||
const res = findNode(node.children, menuId);
|
||||
if (res) return res;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const selectedNode = findNode(menus.value, value);
|
||||
|
||||
if (!selectedNode) {
|
||||
callback(new Error("选择的菜单不存在"));
|
||||
} else if (selectedNode.disabled) {
|
||||
callback(new Error("有子菜单的父节点不可选,请选择子菜单"));
|
||||
} else {
|
||||
callback(); // 校验通过
|
||||
}
|
||||
}
|
||||
|
||||
// 表单校验规则:修复拼写错误 + 新增自定义叶子节点校验
|
||||
const rules = ref({
|
||||
menuId: [
|
||||
{
|
||||
required: true,
|
||||
validator: validateLeafMenu, // 替换原有规则为自定义校验
|
||||
trigger: "change", // 选择变化时校验(原triiger拼写错误)
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 重置表单
|
||||
function resetForm() {
|
||||
form.value = {
|
||||
menuId: "",
|
||||
sort: 0,
|
||||
url: "",
|
||||
status: 1,
|
||||
};
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields(); // 避免null调用
|
||||
}
|
||||
}
|
||||
|
||||
// 提交事件
|
||||
const emits = defineEmits(["success"]);
|
||||
async function submitHandle() {
|
||||
try {
|
||||
// 修复vaild拼写错误
|
||||
const valid = await formRef.value.validate();
|
||||
if (!valid) return;
|
||||
|
||||
loading.value = true;
|
||||
// 排序值兜底
|
||||
form.value.sort = form.value.sort === "" ? 0 : form.value.sort;
|
||||
|
||||
// 区分新增/编辑
|
||||
if (form.value.id) {
|
||||
await quickApi.edit(form.value);
|
||||
ElNotification({ title: "成功", message: "编辑成功", type: "success" });
|
||||
} else {
|
||||
await quickApi.add(form.value);
|
||||
ElNotification({ title: "成功", message: "添加成功", type: "success" });
|
||||
}
|
||||
|
||||
emits("success");
|
||||
visible.value = false;
|
||||
} catch (error) {
|
||||
ElMessage.error(form.value.id ? "编辑失败" : "添加失败");
|
||||
console.error("submit error:", error);
|
||||
} finally {
|
||||
loading.value = false; // 无论成败都关闭loading
|
||||
}
|
||||
}
|
||||
|
||||
// 监听props.item初始化表单
|
||||
watch(
|
||||
() => props.item,
|
||||
(newval) => {
|
||||
if (newval) {
|
||||
form.value = { ...newval }; // 深拷贝,避免修改原对象
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true } // 初始化触发
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dialog_footer {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
.btn {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
// 可选:美化禁用节点的样式
|
||||
.el-select-dropdown__item.is-disabled {
|
||||
color: var(--el-text-color-regular);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
183
src/components/FastMenuConfig/index.vue
Normal file
183
src/components/FastMenuConfig/index.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="table-box">
|
||||
<div class="row mb-sm">
|
||||
<el-button type="primary" @click="showAdd = true">添加</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:data="tableData.list"
|
||||
v-loading="tableData.loading"
|
||||
stripe
|
||||
border
|
||||
row-key="id"
|
||||
:tree-props="{ children: 'children' }"
|
||||
default-expand-all
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column label="ID" prop="id"></el-table-column>
|
||||
<el-table-column label="菜单名称" prop="isEnable">
|
||||
<template #default="scope">
|
||||
{{ returnMenuName(scope.row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="启用状态" prop="isEnable">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="isEnableChange($event, scope.row)"
|
||||
></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序值" prop="sort"></el-table-column>
|
||||
<el-table-column label="创建时间" prop="createTime"></el-table-column>
|
||||
<el-table-column label="操作" width="250">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="editMenu(scope.row)">编辑</el-button>
|
||||
<el-popconfirm title="确认要删除吗?" @confirm="deleteHandle(scope.row)">
|
||||
<template #reference>
|
||||
<el-button type="danger" link>删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<dialogAdd
|
||||
v-model="showAdd"
|
||||
:parMenus="menus"
|
||||
@success="Refresh()"
|
||||
:item="nowEditMenu"
|
||||
></dialogAdd>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useQuickStore, usePermissionStore } from "@/store";
|
||||
const quickStore = useQuickStore();
|
||||
|
||||
import { ref, reactive, onMounted, toRaw } from "vue";
|
||||
import MenuAPI from "@/api/account/menu";
|
||||
|
||||
import quickApi from "@/api/account/quick";
|
||||
|
||||
import dialogAdd from "./dialog-add.vue";
|
||||
|
||||
const showAdd = ref(false);
|
||||
|
||||
const nowEditMenu = ref(null);
|
||||
function editMenu(item) {
|
||||
nowEditMenu.value = { ...item };
|
||||
showAdd.value = true;
|
||||
}
|
||||
const tableData = reactive({
|
||||
loading: false,
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
list: [],
|
||||
});
|
||||
|
||||
function Refresh() {
|
||||
quickStore.getQuickMenus();
|
||||
getList();
|
||||
}
|
||||
function getList() {
|
||||
tableData.loading = true;
|
||||
quickApi
|
||||
.getList({
|
||||
page: tableData.page,
|
||||
size: tableData.size,
|
||||
isEdit: 1,
|
||||
})
|
||||
.then((res) => {
|
||||
tableData.list = res;
|
||||
tableData.total = res.length;
|
||||
})
|
||||
.finally(() => {
|
||||
tableData.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
const menus = ref([]);
|
||||
async function getMenus() {
|
||||
const res = await MenuAPI.getRoutes();
|
||||
menus.value = res;
|
||||
console.log("menus", res);
|
||||
}
|
||||
const menusIdMap = computed(() => {
|
||||
const map = getMenuMap();
|
||||
console.log("map", map);
|
||||
|
||||
return map;
|
||||
});
|
||||
function returnMenuName(item) {
|
||||
const menu = menusIdMap.value.get(`${item.menuId}`);
|
||||
console.log("menuId", item.menuId);
|
||||
console.log("menu", menu);
|
||||
|
||||
return menu ? menu.title : "";
|
||||
}
|
||||
function getMenuMap() {
|
||||
// 初始化Map
|
||||
const map = new Map();
|
||||
|
||||
// 定义递归函数处理菜单节点
|
||||
function processMenuNode(menuNode) {
|
||||
// 将当前节点存入Map
|
||||
map.set(menuNode.menuId, menuNode);
|
||||
|
||||
// 如果有子节点且子节点数组不为空,则递归处理每个子节点
|
||||
if (menuNode.children && Array.isArray(menuNode.children) && menuNode.children.length > 0) {
|
||||
menuNode.children.forEach((childNode) => {
|
||||
processMenuNode(childNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历根级菜单,逐个处理
|
||||
if (menus.value && Array.isArray(menus.value)) {
|
||||
menus.value.forEach((rootMenu) => {
|
||||
processMenuNode(rootMenu);
|
||||
});
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
function isEnableChange(value, item) {
|
||||
quickApi
|
||||
.edit({
|
||||
...item,
|
||||
status: value,
|
||||
})
|
||||
.then((res) => {
|
||||
ElMessage({
|
||||
message: "修改成功",
|
||||
type: "success",
|
||||
});
|
||||
Refresh();
|
||||
});
|
||||
}
|
||||
function deleteHandle(item) {
|
||||
quickApi.delete([item.id]).then(() => {
|
||||
Refresh();
|
||||
});
|
||||
}
|
||||
onMounted(async () => {
|
||||
await getMenus();
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
padding: 14px;
|
||||
width: 100%;
|
||||
.table-box {
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
padding: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
95
src/layout/components/FastMenu/index.vue
Normal file
95
src/layout/components/FastMenu/index.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div class="fast-menu">
|
||||
<el-dropdown
|
||||
trigger="click"
|
||||
@command="menuClick"
|
||||
placement="top-end"
|
||||
@visible-change="handleVisibleChange"
|
||||
append-to-body="true"
|
||||
>
|
||||
<img class="img" :src="imgsrc" alt="" />
|
||||
<!-- <el-icon color="#fff" size="24px">
|
||||
<Plus v-if="!showMenu" />
|
||||
<Close v-else />
|
||||
</el-icon> -->
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="(item, index) in quickStore.quickMenus"
|
||||
:key="index"
|
||||
:command="item.menuId"
|
||||
>
|
||||
{{ returnMenuName(item.menuId) }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item :command="-1">
|
||||
<el-icon>
|
||||
<Edit color="#4080FF" />
|
||||
</el-icon>
|
||||
<span style="color: #4080ff">编辑</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { useQuickStore, usePermissionStore, useUserStore } from "@/store";
|
||||
import router from "@/router";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const quickStore = useQuickStore();
|
||||
const permissionStore = usePermissionStore();
|
||||
console.log("permissionStore", permissionStore.menus);
|
||||
|
||||
function menuClick(menuId: number) {
|
||||
console.log("menuId", menuId);
|
||||
if (menuId == -1) {
|
||||
if (userStore.userInfo.id == 1) {
|
||||
return router.push("/system/commonlyUsedMenu");
|
||||
} else {
|
||||
return router.push("/commonlyUsedMenu");
|
||||
}
|
||||
}
|
||||
permissionStore.menuJump(menuId);
|
||||
}
|
||||
|
||||
function returnMenuName(menuId: number) {
|
||||
return permissionStore.returnMenuName(menuId);
|
||||
}
|
||||
|
||||
const imgsrc = computed(() => {
|
||||
return showMenu.value
|
||||
? new URL("/src/assets/images/close.png", import.meta.url).href
|
||||
: new URL("/src/assets/images/plus.png", import.meta.url).href;
|
||||
});
|
||||
const showMenu = ref(false);
|
||||
function handleVisibleChange(visible: boolean) {
|
||||
showMenu.value = visible;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.fast-menu {
|
||||
position: fixed;
|
||||
$size: 40px;
|
||||
right: 40px;
|
||||
bottom: 40px;
|
||||
width: $size;
|
||||
height: $size;
|
||||
.img {
|
||||
width: $size;
|
||||
height: $size;
|
||||
}
|
||||
// box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
|
||||
// background: linear-gradient(135deg, #409eff, #3a84ff);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
.svg-icon {
|
||||
margin-right: 0;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -27,10 +27,11 @@
|
||||
<TagsView v-if="showTagsView" />
|
||||
<AppMain />
|
||||
<Settings v-if="defaultSettings.showSettings" />
|
||||
|
||||
<!-- 返回顶部 -->
|
||||
<el-backtop target=".app-main">
|
||||
<!-- <el-backtop target=".app-main">
|
||||
<svg-icon icon-class="backtop" size="24px" />
|
||||
</el-backtop>
|
||||
</el-backtop> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -42,11 +43,15 @@
|
||||
</div>
|
||||
<AppMain />
|
||||
<Settings v-if="defaultSettings.showSettings" />
|
||||
|
||||
<!-- 返回顶部 -->
|
||||
<el-backtop target=".app-main">
|
||||
<!-- <el-backtop target=".app-main">
|
||||
<svg-icon icon-class="backtop" size="24px" />
|
||||
</el-backtop>
|
||||
</el-backtop> -->
|
||||
</div>
|
||||
|
||||
<!-- 悬浮球 -->
|
||||
<FastMenu></FastMenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -105,6 +110,7 @@ function handleOutsideClick() {
|
||||
function toggleSidebar() {
|
||||
appStore.toggleSidebar();
|
||||
}
|
||||
function showFastMenu() {}
|
||||
|
||||
const route = useRoute();
|
||||
watch(route, () => {
|
||||
|
||||
@@ -14,5 +14,6 @@ export * from "./modules/settings";
|
||||
export * from "./modules/tags-view";
|
||||
export * from "./modules/user";
|
||||
export * from "./modules/dict";
|
||||
export * from "./modules/quick";
|
||||
|
||||
export { store };
|
||||
|
||||
@@ -16,6 +16,7 @@ export const usePermissionStore = defineStore("permission", () => {
|
||||
// 路由是否加载完成
|
||||
const isRoutesLoaded = ref(false);
|
||||
|
||||
const menus = ref<RouteVO[]>([])
|
||||
|
||||
|
||||
/**
|
||||
@@ -31,10 +32,9 @@ export const usePermissionStore = defineStore("permission", () => {
|
||||
}
|
||||
MenuAPI.getRoutes()
|
||||
.then((data) => {
|
||||
menus.value = data
|
||||
if (!isTest) {
|
||||
const dynamicRoutes = parseDynamicRoutes(data.filter(v => v.type == 0));
|
||||
console.log('dynamicRoutes')
|
||||
console.log(dynamicRoutes)
|
||||
dynamicRoutes.forEach((route) => {
|
||||
//过滤出可见子节点
|
||||
let onlyOneChild = null
|
||||
@@ -95,8 +95,60 @@ export const usePermissionStore = defineStore("permission", () => {
|
||||
});
|
||||
isRoutesLoaded.value = false;
|
||||
};
|
||||
function getMenuMap() {
|
||||
// 初始化Map
|
||||
const map = new Map();
|
||||
|
||||
// 定义递归函数处理菜单节点
|
||||
function processMenuNode(menuNode) {
|
||||
// 将当前节点存入Map
|
||||
map.set(menuNode.menuId, menuNode);
|
||||
|
||||
// 如果有子节点且子节点数组不为空,则递归处理每个子节点
|
||||
if (menuNode.children && Array.isArray(menuNode.children) && menuNode.children.length > 0) {
|
||||
menuNode.children.forEach((childNode) => {
|
||||
processMenuNode(childNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历根级菜单,逐个处理
|
||||
if (menus.value && Array.isArray(menus.value)) {
|
||||
menus.value.forEach((rootMenu) => {
|
||||
processMenuNode(rootMenu);
|
||||
});
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
function returnMenuName(menuId: number | string) {
|
||||
const menu = menusIdMap.value.get(`${menuId}`);
|
||||
return menu ? menu.title : '';
|
||||
}
|
||||
const menusIdMap = computed(() => {
|
||||
const map = getMenuMap();
|
||||
return map;
|
||||
});
|
||||
|
||||
function menuJump(menuId: number | string) {
|
||||
const menu = menusIdMap.value.get(`${menuId}`);
|
||||
console.log('menu', menu);
|
||||
if (menu) {
|
||||
if (menu.name) {
|
||||
router.push({ name: menu.name as string })
|
||||
|
||||
} else {
|
||||
router.push({ path: menu.path as string })
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
menuJump,
|
||||
returnMenuName,
|
||||
menus,
|
||||
routes,
|
||||
mixedLayoutLeftRoutes,
|
||||
isRoutesLoaded,
|
||||
|
||||
37
src/store/modules/quick.ts
Normal file
37
src/store/modules/quick.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
import { store } from "@/store";
|
||||
import quickApi, { type QuickMenu } from "@/api/account/quick";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
|
||||
|
||||
export const useQuickStore = defineStore("quick", () => {
|
||||
const quickMenus = ref<QuickMenu[]>([]);
|
||||
|
||||
async function getQuickMenus() {
|
||||
const res = await quickApi.getList({ isEdit: 0 });
|
||||
const obj: any = {}
|
||||
let arr = []
|
||||
for (let menu of res) {
|
||||
if (obj.hasOwnProperty(menu.menuId) || menu.status != 1 || !usePermissionStoreHook().returnMenuName(menu.menuId)) {
|
||||
continue;
|
||||
} else {
|
||||
obj[menu.menuId] = true;
|
||||
arr.push(menu)
|
||||
}
|
||||
}
|
||||
quickMenus.value = arr;
|
||||
}
|
||||
getQuickMenus()
|
||||
return {
|
||||
quickMenus, getQuickMenus
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 用于在组件外部(如在Pinia Store 中)使用 Pinia 提供的 store 实例。
|
||||
* 官方文档解释了如何在组件外部使用 Pinia Store:
|
||||
* https://pinia.vuejs.org/core-concepts/outside-component-usage.html#using-a-store-outside-of-a-component
|
||||
*/
|
||||
export function useQuickStoreHook() {
|
||||
return useQuickStore(store);
|
||||
}
|
||||
5
src/views/admin/system/commonlyUsedMenu/index.vue
Normal file
5
src/views/admin/system/commonlyUsedMenu/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<FastMenuConfig></FastMenuConfig>
|
||||
</div>
|
||||
</template>
|
||||
5
src/views/shop/commonlyUsedMenu/index.vue
Normal file
5
src/views/shop/commonlyUsedMenu/index.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<FastMenuConfig></FastMenuConfig>
|
||||
</div>
|
||||
</template>
|
||||
@@ -4,22 +4,38 @@
|
||||
<template v-if="carts.list && carts.list.length >= 1">
|
||||
<!-- 当前购物车 -->
|
||||
<div v-for="(item, index) in carts.list" :key="index">
|
||||
<carts-item :item="item" :useVipPrice="carts.useVipPrice" @changeNumber="changeNumber"
|
||||
:selCart="carts.selCart" @itemClick="itemClick(item)" @editNote="editNote"></carts-item>
|
||||
<carts-item
|
||||
:item="item"
|
||||
:useVipPrice="carts.useVipPrice"
|
||||
@changeNumber="changeNumber"
|
||||
:selCart="carts.selCart"
|
||||
@itemClick="itemClick(item)"
|
||||
@editNote="editNote"
|
||||
></carts-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 赠菜 -->
|
||||
<div class="cart-title" v-if="carts.giftList.length > 0"><span>以下是优惠菜品</span></div>
|
||||
<div v-for="(item, index) in carts.giftList" :key="index">
|
||||
<carts-item :item="item" @changeNumber="changeNumber" :useVipPrice="carts.useVipPrice" :selCart="carts.selCart"
|
||||
@itemClick="itemClick(item)" @editNote="editNote"></carts-item>
|
||||
<carts-item
|
||||
:item="item"
|
||||
@changeNumber="changeNumber"
|
||||
:useVipPrice="carts.useVipPrice"
|
||||
:selCart="carts.selCart"
|
||||
@itemClick="itemClick(item)"
|
||||
@editNote="editNote"
|
||||
></carts-item>
|
||||
</div>
|
||||
<el-empty :image-size="60" v-if="carts.isEmpty" description="点餐列表为空" />
|
||||
<!-- 打包费 -->
|
||||
<template v-if="carts.packNum > 0">
|
||||
<div class="cart-title"><span>打包费</span></div>
|
||||
<extra-fee name="打包费" :number="carts.packNum" :price="carts.orderCostSummary.packFee"></extra-fee>
|
||||
<extra-fee
|
||||
name="打包费"
|
||||
:number="carts.packNum"
|
||||
:price="carts.orderCostSummary.packFee"
|
||||
></extra-fee>
|
||||
</template>
|
||||
<!-- 餐位费 -->
|
||||
<template v-if="perpole >= 1 && carts.dinnerType == 'dine-in'">
|
||||
@@ -40,9 +56,17 @@
|
||||
</div>
|
||||
|
||||
<div v-for="(detaiItem, index) in item" :key="index">
|
||||
<carts-item :useVipPrice="carts.useVipPrice" :canChangeNumber="false" isOld :dinerType="dinerType"
|
||||
:item="detaiItem" @changeNumber="changeNumber" :selCart="carts.selCart" @itemClick="itemClick(detaiItem)"
|
||||
@editNote="editNote"></carts-item>
|
||||
<carts-item
|
||||
:useVipPrice="carts.useVipPrice"
|
||||
:canChangeNumber="false"
|
||||
isOld
|
||||
:dinerType="dinerType"
|
||||
:item="detaiItem"
|
||||
@changeNumber="changeNumber"
|
||||
:selCart="carts.selCart"
|
||||
@itemClick="itemClick(detaiItem)"
|
||||
@editNote="editNote"
|
||||
></carts-item>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -50,9 +74,14 @@
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="u-flex u-row-right">
|
||||
<el-tooltip placement="top" effect="light" popper-class="youhui-tips" :popper-options="{
|
||||
'background-color': '#fff',
|
||||
}">
|
||||
<el-tooltip
|
||||
placement="top"
|
||||
effect="light"
|
||||
popper-class="youhui-tips"
|
||||
:popper-options="{
|
||||
'background-color': '#fff',
|
||||
}"
|
||||
>
|
||||
<template #content>
|
||||
<div class="u-flex color-000 u-font-14 u-row-between">
|
||||
<span class="font-bold">会员优惠</span>
|
||||
@@ -74,20 +103,36 @@
|
||||
</div>
|
||||
|
||||
<div class="u-flex u-row-between">
|
||||
<el-link type="primary">打印制作单</el-link>
|
||||
<!-- <el-link type="primary">打印制作单</el-link> -->
|
||||
<div></div>
|
||||
<div>
|
||||
<span class="totalNumber">共{{ customTruncateToTwoDecimals(carts.totalNumber) }}件</span>
|
||||
<span class="totalPrice">¥{{ customTruncateToTwoDecimals(carts.payMoney) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group" v-if="isXianFuKuan">
|
||||
<el-button type="primary" size="large" :disabled="!disabledMorePay" @click="createOrder('wx-aiplay')">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!disabledMorePay"
|
||||
@click="createOrder('wx-aiplay')"
|
||||
>
|
||||
微信/支付宝
|
||||
</el-button>
|
||||
<el-button type="primary" size="large" :disabled="!disabledMorePay" @click="createOrder('cash')">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!disabledMorePay"
|
||||
@click="createOrder('cash')"
|
||||
>
|
||||
现金
|
||||
</el-button>
|
||||
<el-button type="primary" size="large" :disabled="!disabledMorePay" @click="createOrder('more-pay')">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!disabledMorePay"
|
||||
@click="createOrder('more-pay')"
|
||||
>
|
||||
更多支付
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -100,20 +145,31 @@
|
||||
<el-button type="primary" size="large" :disabled="disabledMorePay" @click="createOrder('to-pay')">
|
||||
去结账
|
||||
</el-button> -->
|
||||
<el-button type="primary" size="large"
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="carts.list.length == 0 || carts.oldOrder.detailMap.length == 0"
|
||||
@click="createOrder('only-create')">
|
||||
@click="createOrder('only-create')"
|
||||
>
|
||||
仅下单
|
||||
</el-button>
|
||||
<el-button type="primary" size="large"
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="carts.list.length == 0 && isEmptyObject(carts.oldOrder.detailMap)"
|
||||
@click="createOrder('to-pay')">
|
||||
@click="createOrder('to-pay')"
|
||||
>
|
||||
去结账
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button type="default" size="large" @click="hideOrder()">加菜/返回</el-button>
|
||||
<el-button type="primary" size="large" :disabled="!carts.isLinkFinshed" @click="createOrder('to-pay')">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
:disabled="!carts.isLinkFinshed"
|
||||
@click="createOrder('to-pay')"
|
||||
>
|
||||
立即支付
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -131,7 +187,7 @@ import { useUserStore } from "@/store/modules/user";
|
||||
|
||||
function isEmptyObject(obj) {
|
||||
// 步骤1:排除null和非对象类型
|
||||
if (obj === null || typeof obj !== 'object') {
|
||||
if (obj === null || typeof obj !== "object") {
|
||||
return false;
|
||||
}
|
||||
// 步骤2:排除数组(数组也是对象,需单独判断)
|
||||
@@ -313,4 +369,4 @@ defineExpose({
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user