更新.gitignore配置,添加ContextMenu组件类型声明,构建发布dist目录

This commit is contained in:
2025-12-24 11:03:12 +08:00
parent 5cb696ac88
commit cf0275358f
22 changed files with 512 additions and 323 deletions

View File

@ -7,12 +7,15 @@
<d-modal class="!w-80" v-model="modal.visible" :title="modal.title">
{{ modal.content }}
<div class="mt-10 w-full flex justify-between">
<d-button @click="modal.handdleCancel" variant="text"
<div class="mt-4 w-full flex justify-between">
<!-- <d-button @click="modal.handdleCancel" variant="text"
class="w-[49%] hover:bg-[#8a6684] hover:!text-white">{{modal.cancelText}}</d-button>
<span class="text-[20px]"> | </span>
<d-button @click="modal.handdleSubmit" variant="text" class="w-[49%] hover:bg-[#5c866a] hover:!text-white"
color="primary">{{modal.submitText}}</d-button>
color="primary">{{modal.submitText}}</d-button> -->
<d-button class="w-[48%]" variant="solid" color="secondary" @click="modal.handdleCancel">{{modal.cancelText}}</d-button>
<d-button class="w-[48%]" variant="solid" color="primary" @click="modal.handdleSubmit">{{modal.submitText}}</d-button>
</div>
</d-modal>
</template>

View File

@ -15,3 +15,20 @@ export function addNav(data: any) {
data,
});
}
// editNav
export function editNav(id: string,data: any) {
return request({
url: `/navi/${id}`,
method: "put",
data,
});
}
// deleteNav
export function deleteNav(id: string) {
return request({
url: `/navi/${id}`,
method: "delete",
});
}

View File

@ -0,0 +1,36 @@
<template>
<Teleport to="body" v-if="show">
<div class="fixed z-[99999]" :style="menuStyle">
<slot></slot>
</div>
</Teleport>
</template>
<script setup lang="ts">
//mark import
//mark data
const props = defineProps<{
show: boolean,
options: any
}>()
let timer:any = null
const menuStyle = computed(() => {
return {
top: props.options.y + 'px',
left: props.options.x + 'px',
}
})
//mark method
//mark 周期、内置函数等
onMounted(() => {
})
</script>
<style scoped lang="less">
</style>

View File

@ -12,7 +12,7 @@ import { ThemeServiceInit, infinityTheme, sweetTheme } from "devui-theme";
import { PerfectScrollbarPlugin } from "vue3-perfect-scrollbar";
// import vue3videoPlay from "vue3-video-play";
// import "vue3-video-play/dist/style.css";
//main.js
// ThemeServiceInit({ customTheme }, "customTheme");
const themeService = ThemeServiceInit({ infinityTheme }, "infinityTheme");

View File

@ -21,15 +21,17 @@
<PerfectScrollbar class="" :style="navStyle">
<div class="navcard grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-6 gap-5 pt-3 pb-6 px-12">
<d-card class="bg-[#ffffff80] h-24" v-for="(item, index) in navlist" :key="index"
@click="goExtra(item.menu_link)">
@click="goExtra(item.menu_link)" @contextmenu.prevent="handdleContextMenu($event, item)">
<template #content>
<div class="mt-1 w-full flex flex-col items-center cursor-pointer hover:!text-primary">
<div :style="{ background: item.color }"
class="w-8 h-8 rounded-full text-white flex items-center justify-center" v-if="item.icon_error">
{{ item.first }}</div>
<img class="grid-image w-8 h-8 rounded-full" v-else :src="item.menu_icon" @error="imgErr(index as number)" />
<img class="grid-image w-8 h-8 rounded-full" v-else :src="item.menu_icon"
@error="imgErr(index as number)" />
<div class="mt-2 w-full text-center text-lg truncate">{{ item.menu_name || "" }}</div>
<em class="absolute rounded-md top-0 left-0 px-2 text-white text-center text-sm" :style="{ background: getItemColor(item) }">{{ item.tag }}</em>
<em class="absolute rounded-md top-0 left-0 px-2 text-white text-center text-sm"
:style="{ background: getItemColor(item) }">{{ item.tag }}</em>
</div>
</template>
</d-card>
@ -81,13 +83,45 @@
<!-- 音乐插件 -->
<aplayer></aplayer>
<!-- 右键菜单 -->
<contextMenu :show="menuShow" :options="MenuOptions">
<div class="!p-0 !m-0 bg-white cursor-pointer !rounded-md" @mouseenter="removeTimer" @mouseleave="hideMenu">
<div :class="menuS" @click="handdleMenuItem(1)">
修改名称
</div>
<div :class="menuS" @click="handdleMenuItem(2)">
修改链接
</div>
<div :class="menuS" @click="handdleMenuItem(3)">
修改标签
</div>
<div :class="menuS" @click="handdleMenuItem(4)">
删除导航
</div>
</div>
</contextMenu>
<!-- 编辑弹窗 -->
<d-modal class="!w-120" v-model="editModal" title="导航修改">
<div class="mb-2">
<span class="text-primary" v-if="currentClickedItem === 1">导航名称{{ currentItem.menu_name }}</span>
<span class="text-primary" v-if="currentClickedItem === 2">导航链接{{ currentItem.menu_link }}</span>
<span class="text-primary" v-if="currentClickedItem === 3">导航标签{{ currentItem.tag }}</span>
</div>
<d-input v-model="editInput" placeholder="请输入修改内容"></d-input>
<div class="mt-8 flex justify-between">
<d-button class="w-[48%]" variant="solid" color="secondary" @click="handdleItemCancel">取消</d-button>
<d-button class="w-[48%]" variant="solid" color="primary" @click="handdleItemSubmit">确定</d-button>
</div>
</d-modal>
</div>
</template>
<script setup lang="ts">
import { deepclone, getDictValue } from '@/util/index.ts'
import contextMenu from '@/components/contextMenu.vue';
import { deepclone, getDictValue } from '@/util/index.ts';
definePage({
name: 'home',
meta: {
@ -95,8 +129,17 @@ definePage({
}
})
// 右键菜单
const menuShow = ref(false)
const MenuOptions: any = reactive({});
const currentItem = ref<any>(null);
const menuS = '!m-0 py-3 px-6 text-sm text-gray-700 w-full flex items-center justify-center hover:bg-[#f5f0f0] hover:text-primary';
const currentClickedItem = ref<number>(0);
const editModal = ref<boolean>(false);
const editInput = ref<string>('');
// 新增导航弹窗
const visible: any = ref(false)
const visible: any = ref<boolean>(false)
const navData: any = reactive({
menu_link: '',
menu_name: '',
@ -149,6 +192,72 @@ const tagList: any = ref([
const usrLog = $store.log.useLogStore()
let timer: any = null;
// 2秒后自动隐藏菜单
const hideMenu = () => {
timer = setTimeout(() => {
menuShow.value = false
}, 2000)
}
const removeTimer = () => {
clearTimeout(timer)
}
function handdleMenuItem(type: number) {
menuShow.value = false
currentClickedItem.value = type
if (type == 4) {
// 删除导航
if (!currentItem.value) return
$modal({
title: '删除导航',
content: `确定要删除【${currentItem.value.menu_name}】吗?删除后不可恢复哦~`,
cancelText: '取消',
submitText: '删除',
handdleSubmit: async () => {
const res = await $http.nav.deleteNav(currentItem.value.nid)
console.log('>>> --> handdleMenuItem --> res:', res)
if (res.code == 200) {
$msg.success('删除成功')
getNavList()
}
}
})
return
}
editModal.value = true
}
function handdleItemCancel() {
editModal.value = false
editInput.value = ''
}
async function handdleItemSubmit() {
if (!editInput.value) {
$msg.error('请输入修改内容')
return
}
let updateData: any = {}
if (currentClickedItem.value == 1) {
updateData.menu_name = editInput.value
} else if (currentClickedItem.value == 2) {
updateData.menu_link = editInput.value
} else if (currentClickedItem.value == 3) {
updateData.tag = editInput.value.slice(0, 4)
}
const res = await $http.nav.editNav(currentItem.value.nid, updateData)
console.log('>>> --> handdleItemSubmit --> res:', res)
if (res.code == 200) {
$msg.success('修改成功')
editModal.value = false
editInput.value = ''
getNavList()
}
}
async function getNavList() {
const userinfo = $cookies.get("userinfo")
if (!userinfo) {
@ -166,7 +275,7 @@ async function getNavList() {
console.log("&&&&&&&&&&&&&&", navlist.value);
res.data.forEach((i: any) => {
if (!tagList.value.find((t: any) => t.name == i.tag))
tagList.value.push({ name: i.tag, color: getRandomDarkColor(30, 128), checked: false })
tagList.value.push({ name: i.tag.substring(0, 4), color: getRandomDarkColor(30, 128), checked: false })
})
cloneNavlist = deepclone(res.data)
}
@ -290,7 +399,24 @@ async function navSubmit() {
formNav.value.resetFields()
getNavList()
}
// 清空navData
navData.menu_link = ''
navData.menu_name = ''
navData.tag = ''
navData.menu_icon = ''
}
// 处理右键菜单
function handdleContextMenu(event: MouseEvent, item: any) {
menuShow.value = true; // 先隐藏菜单以重置位置
MenuOptions.x = event.clientX;
MenuOptions.y = event.clientY;
currentItem.value = item; // 存储当前右键点击的项
}
// 监听store的登录状态
watch(() => usrLog.isLogin, (newVal) => {
console.log('********** --> watch --> newVal:', newVal)
@ -325,14 +451,8 @@ onMounted(() => {
</script>
<style scoped lang="less">
/* 首页样式
.main-content {
background-image: url('@/assets/images/小鹿.png');
background-repeat: no-repeat;
background-position: 111% center;
background-size: auto 100%;
}
*/
/* layer: default */
.navcard {
display: grid;