更新
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -36,4 +36,5 @@ coverage
|
||||
__screenshots__/
|
||||
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
package-lock.json
|
||||
.clinerules
|
||||
508
src/components/scIconPicker/index.vue
Normal file
508
src/components/scIconPicker/index.vue
Normal file
@@ -0,0 +1,508 @@
|
||||
<template>
|
||||
<div class="sc-icon-picker">
|
||||
<a-input :value="selectedIcon ? '' : ''" :placeholder="placeholder" readonly @click="handleOpenPicker">
|
||||
<template #prefix v-if="selectedIcon">
|
||||
<component :is="selectedIcon" />
|
||||
</template>
|
||||
<template #suffix>
|
||||
<SearchOutlined v-if="!selectedIcon" />
|
||||
<CloseCircleFilled v-else @click.stop="handleClear" />
|
||||
</template>
|
||||
</a-input>
|
||||
|
||||
<a-modal v-model:open="visible" title="选择图标" :width="800" :footer="null" @cancel="handleCancel">
|
||||
<a-tabs v-model:activeKey="activeTab" @change="handleTabChange">
|
||||
<a-tab-pane key="antd" tab="Ant Design">
|
||||
<div class="icon-search">
|
||||
<a-input v-model:value="searchAntdValue" placeholder="搜索图标..." allow-clear>
|
||||
<template #prefix>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
<div class="icon-list">
|
||||
<div
|
||||
v-for="icon in filteredAntdIcons"
|
||||
:key="icon"
|
||||
:class="['icon-item', { active: tempIcon === icon }]"
|
||||
@click="handleSelectIcon(icon)"
|
||||
>
|
||||
<component :is="icon" />
|
||||
<div class="icon-name">{{ icon }}</div>
|
||||
</div>
|
||||
<a-empty v-if="filteredAntdIcons.length === 0" description="暂无图标" :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="element" tab="Element Plus">
|
||||
<div class="icon-search">
|
||||
<a-input v-model:value="searchElementValue" placeholder="搜索图标..." allow-clear>
|
||||
<template #prefix>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
<div class="icon-list">
|
||||
<div
|
||||
v-for="icon in filteredElementIcons"
|
||||
:key="icon"
|
||||
:class="['icon-item', { active: tempIcon === icon }]"
|
||||
@click="handleSelectIcon(icon)"
|
||||
>
|
||||
<component :is="icon" />
|
||||
<div class="icon-name">{{ icon.replace('El', '') }}</div>
|
||||
</div>
|
||||
<a-empty v-if="filteredElementIcons.length === 0" description="暂无图标" :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* @component scIconPicker
|
||||
*/
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { Empty } from 'ant-design-vue'
|
||||
import { SearchOutlined, CloseCircleFilled } from '@ant-design/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择图标',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const visible = ref(false)
|
||||
const activeTab = ref('antd')
|
||||
const searchAntdValue = ref('')
|
||||
const searchElementValue = ref('')
|
||||
const tempIcon = ref('')
|
||||
|
||||
// Ant Design 图标列表(常用图标)
|
||||
const antdIcons = [
|
||||
'HomeOutlined',
|
||||
'UserOutlined',
|
||||
'SettingOutlined',
|
||||
'EditOutlined',
|
||||
'DeleteOutlined',
|
||||
'PlusOutlined',
|
||||
'MinusOutlined',
|
||||
'CheckOutlined',
|
||||
'CloseOutlined',
|
||||
'SearchOutlined',
|
||||
'FilterOutlined',
|
||||
'ReloadOutlined',
|
||||
'DownloadOutlined',
|
||||
'UploadOutlined',
|
||||
'FileTextOutlined',
|
||||
'FolderOutlined',
|
||||
'PictureOutlined',
|
||||
'VideoCameraOutlined',
|
||||
'AudioOutlined',
|
||||
'FileOutlined',
|
||||
'CalendarOutlined',
|
||||
'ClockCircleOutlined',
|
||||
'HeartOutlined',
|
||||
'StarOutlined',
|
||||
'ThumbUpOutlined',
|
||||
'MessageOutlined',
|
||||
'PhoneOutlined',
|
||||
'MailOutlined',
|
||||
'EnvironmentOutlined',
|
||||
'GlobalOutlined',
|
||||
'LinkOutlined',
|
||||
'LockOutlined',
|
||||
'UnlockOutlined',
|
||||
'EyeOutlined',
|
||||
'EyeInvisibleOutlined',
|
||||
'ArrowLeftOutlined',
|
||||
'ArrowRightOutlined',
|
||||
'ArrowUpOutlined',
|
||||
'ArrowDownOutlined',
|
||||
'CaretLeftOutlined',
|
||||
'CaretRightOutlined',
|
||||
'CaretUpOutlined',
|
||||
'CaretDownOutlined',
|
||||
'LeftOutlined',
|
||||
'RightOutlined',
|
||||
'UpOutlined',
|
||||
'DownOutlined',
|
||||
'MenuFoldOutlined',
|
||||
'MenuUnfoldOutlined',
|
||||
'BarsOutlined',
|
||||
'MoreOutlined',
|
||||
'EllipsisOutlined',
|
||||
'DashboardOutlined',
|
||||
'AppstoreOutlined',
|
||||
'LaptopOutlined',
|
||||
'DesktopOutlined',
|
||||
'TabletOutlined',
|
||||
'MobileOutlined',
|
||||
'WifiOutlined',
|
||||
'BluetoothOutlined',
|
||||
'ThunderboltOutlined',
|
||||
'BulbOutlined',
|
||||
'SoundOutlined',
|
||||
'NotificationOutlined',
|
||||
'BellOutlined',
|
||||
'AlertOutlined',
|
||||
'WarningOutlined',
|
||||
'InfoCircleOutlined',
|
||||
'QuestionCircleOutlined',
|
||||
'CheckCircleOutlined',
|
||||
'CloseCircleOutlined',
|
||||
'StopOutlined',
|
||||
'ExclamationCircleOutlined',
|
||||
'SafetyOutlined',
|
||||
'ShieldCheckOutlined',
|
||||
'SecurityScanOutlined',
|
||||
'KeyOutlined',
|
||||
'IdcardOutlined',
|
||||
'ProfileOutlined',
|
||||
'SolutionOutlined',
|
||||
'ContactsOutlined',
|
||||
'TeamOutlined',
|
||||
'UsergroupAddOutlined',
|
||||
'UsergroupDeleteOutlined',
|
||||
'CrownOutlined',
|
||||
'GoldOutlined',
|
||||
'MoneyCollectOutlined',
|
||||
'BankOutlined',
|
||||
'PayCircleOutlined',
|
||||
'CreditCardOutlined',
|
||||
'WalletOutlined',
|
||||
'ShoppingCartOutlined',
|
||||
'ShoppingOutlined',
|
||||
'GiftOutlined',
|
||||
'HddOutlined',
|
||||
'DatabaseOutlined',
|
||||
'CloudOutlined',
|
||||
'CloudUploadOutlined',
|
||||
'CloudDownloadOutlined',
|
||||
'ServerOutlined',
|
||||
'AuditOutlined',
|
||||
'NodeIndexOutlined',
|
||||
'ReconciliationOutlined',
|
||||
'PartitionOutlined',
|
||||
'AccountBookOutlined',
|
||||
'ProjectOutlined',
|
||||
'ControlOutlined',
|
||||
'MonitorOutlined',
|
||||
'TagsOutlined',
|
||||
'TagOutlined',
|
||||
'BookOutlined',
|
||||
'ReadOutlined',
|
||||
'ExperimentOutlined',
|
||||
'FireOutlined',
|
||||
'RocketOutlined',
|
||||
'TrophyOutlined',
|
||||
'MedalOutlined',
|
||||
'DiamondOutlined',
|
||||
'ThunderboltTwoTone',
|
||||
]
|
||||
|
||||
// Element Plus 图标列表(常用图标)
|
||||
const elementIcons = [
|
||||
'ElIconEdit',
|
||||
'ElIconDelete',
|
||||
'ElIconSearch',
|
||||
'ElIconClose',
|
||||
'ElIconCheck',
|
||||
'ElIconPlus',
|
||||
'ElIconMinus',
|
||||
'ElIconUpload',
|
||||
'ElIconDownload',
|
||||
'ElIconSetting',
|
||||
'ElIconRefresh',
|
||||
'ElIconRefreshLeft',
|
||||
'ElIconRefreshRight',
|
||||
'ElIconMenu',
|
||||
'ElIconMore',
|
||||
'ElIconMoreFilled',
|
||||
'ElIconStar',
|
||||
'ElIconStarFilled',
|
||||
'ElIconSunny',
|
||||
'ElIconMoon',
|
||||
'ElIconBell',
|
||||
'ElIconBellFilled',
|
||||
'ElIconMessage',
|
||||
'ElIconMessageFilled',
|
||||
'ElIconChatDotRound',
|
||||
'ElIconChatLineSquare',
|
||||
'ElIconChatDotSquare',
|
||||
'ElIconPhone',
|
||||
'ElIconPhoneFilled',
|
||||
'ElIconLocation',
|
||||
'ElIconLocationFilled',
|
||||
'ElIconLocationInformation',
|
||||
'ElIconView',
|
||||
'ElIconHide',
|
||||
'ElIconLock',
|
||||
'ElIconUnlock',
|
||||
'ElIconKey',
|
||||
'ElIconTickets',
|
||||
'ElIconDocument',
|
||||
'ElIconDocumentAdd',
|
||||
'ElIconDocumentDelete',
|
||||
'ElIconDocumentCopy',
|
||||
'ElIconDocumentChecked',
|
||||
'ElIconDocumentRemove',
|
||||
'ElIconFolder',
|
||||
'ElIconFolderOpened',
|
||||
'ElIconFolderAdd',
|
||||
'ElIconFolderDelete',
|
||||
'ElIconFolderChecked',
|
||||
'ElIconFiles',
|
||||
'ElIconPicture',
|
||||
'ElIconPictureRounded',
|
||||
'ElIconPictureFilled',
|
||||
'ElIconVideoCamera',
|
||||
'ElIconVideoCameraFilled',
|
||||
'ElIconMicrophone',
|
||||
'ElIconMicrophoneFilled',
|
||||
'ElIconHeadset',
|
||||
'ElIconHeadsetFilled',
|
||||
'ElIconMuteNotification',
|
||||
'ElIconNotification',
|
||||
'ElIconWarning',
|
||||
'ElIconWarningFilled',
|
||||
'ElIconInfoFilled',
|
||||
'ElIconSuccessFilled',
|
||||
'ElIconCircleCheck',
|
||||
'ElIconCircleCheckFilled',
|
||||
'ElIconCircleClose',
|
||||
'ElIconCircleCloseFilled',
|
||||
'ElIconCirclePlus',
|
||||
'ElIconCirclePlusFilled',
|
||||
'ElIconCircleMinus',
|
||||
'ElIconCircleMinusFilled',
|
||||
'ElIconAim',
|
||||
'ElIconPosition',
|
||||
'ElIconCompass',
|
||||
'ElIconMapLocation',
|
||||
'ElIconPromotion',
|
||||
'ElIconDownload',
|
||||
'ElIconUploadFilled',
|
||||
'ElIconShare',
|
||||
'ElIconConnection',
|
||||
'ElIconLink',
|
||||
'ElIconUnlink',
|
||||
'ElIconOperation',
|
||||
'ElIconDataAnalysis',
|
||||
'ElIconDataLine',
|
||||
'ElIconDataBoard',
|
||||
'ElIconHistogram',
|
||||
'ElIconTrendCharts',
|
||||
'ElIconPieChart',
|
||||
'ElIconOdometer',
|
||||
'ElIconMonitor',
|
||||
'ElIconTimer',
|
||||
'ElIconClock',
|
||||
'ElIconAlarmClock',
|
||||
'ElIconCalendar',
|
||||
'ElIconDate',
|
||||
'ElIconSwitch',
|
||||
'ElIconSwitchButton',
|
||||
'ElIconTools',
|
||||
'ElIconScrewdriver',
|
||||
'ElIconHammer',
|
||||
'ElIconBrush',
|
||||
'ElIconEditPen',
|
||||
'ElIconBriefcase',
|
||||
'ElIconWallet',
|
||||
'ElIconGoods',
|
||||
'ElIconShoppingCart',
|
||||
'ElIconShoppingCartFull',
|
||||
'ElIconShoppingBag',
|
||||
'ElIconPresent',
|
||||
'ElIconSoldOut',
|
||||
'ElIconSell',
|
||||
'ElIconDiscount',
|
||||
'ElIconTicket',
|
||||
'ElIconCoin',
|
||||
'ElIconMoney',
|
||||
'ElIconWalletFilled',
|
||||
'ElIconCreditCard',
|
||||
'ElIconUser',
|
||||
'ElIconUserFilled',
|
||||
'ElIconAvatar',
|
||||
'ElIconSuitcase',
|
||||
'ElIconGrid',
|
||||
'ElIconMenuFilled',
|
||||
'ElIconHomeFilled',
|
||||
'ElIconHouse',
|
||||
'ElIconOfficeBuilding',
|
||||
'ElIconSchool',
|
||||
'ElIconReading',
|
||||
'ElIconReadingLamp',
|
||||
'ElIconNotebook',
|
||||
'ElIconNotebookFilled',
|
||||
'ElIconFinished',
|
||||
'ElIconCollection',
|
||||
'ElIconCollectionTag',
|
||||
'ElIconFiles',
|
||||
'ElIconPostcard',
|
||||
'ElIconMemo',
|
||||
'ElIconStamp',
|
||||
'ElIconPriceTag',
|
||||
'ElIconMedal',
|
||||
'ElIconTrophy',
|
||||
'ElIconTrophyBase',
|
||||
'ElIconFirstAidKit',
|
||||
'ElIconToiletPaper',
|
||||
'ElIconAim',
|
||||
'ElIconSFlag',
|
||||
'ElIconSOpportunity',
|
||||
'ElIconMagicStick',
|
||||
'ElIconHelp',
|
||||
'ElIconQuestionFilled',
|
||||
'ElIconWarning',
|
||||
'ElIconWarningFilled',
|
||||
]
|
||||
|
||||
// 当前选中的图标
|
||||
const selectedIcon = ref(props.modelValue)
|
||||
|
||||
// 过滤后的 Ant Design 图标
|
||||
const filteredAntdIcons = computed(() => {
|
||||
if (!searchAntdValue.value) {
|
||||
return antdIcons
|
||||
}
|
||||
return antdIcons.filter((icon) =>
|
||||
icon.toLowerCase().includes(searchAntdValue.value.toLowerCase()),
|
||||
)
|
||||
})
|
||||
|
||||
// 过滤后的 Element 图标
|
||||
const filteredElementIcons = computed(() => {
|
||||
if (!searchElementValue.value) {
|
||||
return elementIcons
|
||||
}
|
||||
return elementIcons.filter((icon) =>
|
||||
icon.toLowerCase().includes(searchElementValue.value.toLowerCase()),
|
||||
)
|
||||
})
|
||||
|
||||
// 打开选择器
|
||||
const handleOpenPicker = () => {
|
||||
tempIcon.value = props.modelValue
|
||||
// 根据当前图标设置默认标签页
|
||||
if (props.modelValue) {
|
||||
activeTab.value = props.modelValue.startsWith('El') ? 'element' : 'antd'
|
||||
}
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
// 清除选择
|
||||
const handleClear = () => {
|
||||
emit('update:modelValue', '')
|
||||
emit('change', '')
|
||||
}
|
||||
|
||||
// 切换标签页
|
||||
const handleTabChange = (key) => {
|
||||
activeTab.value = key
|
||||
}
|
||||
|
||||
// 选择图标(直接确认并关闭)
|
||||
const handleSelectIcon = (icon) => {
|
||||
emit('update:modelValue', icon)
|
||||
emit('change', icon)
|
||||
selectedIcon.value = icon
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 取消选择
|
||||
const handleCancel = () => {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 监听props变化,更新本地状态
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
selectedIcon.value = newVal
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.sc-icon-picker {
|
||||
:deep(.ant-input) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon-search {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.icon-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||
gap: 12px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #d9d9d9;
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background: #bfbfbf;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12px 8px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: #1890ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #e6f7ff;
|
||||
border-color: #1890ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
:deep(svg) {
|
||||
font-size: 24px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.icon-name {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<template v-for="item in menuItems" :key="item.path || item.name">
|
||||
<!-- 有子菜单 - 使用递归 -->
|
||||
<a-sub-menu v-if="item.children && item.children.length > 0" :key="`submenu-${item.path}`">
|
||||
<a-sub-menu v-if="item.children && item.children.length > 0" :key="`${item.path}`">
|
||||
<template #icon v-if="item.meta?.icon">
|
||||
<component :is="getIconComponent(item.meta.icon)" />
|
||||
</template>
|
||||
|
||||
@@ -20,21 +20,35 @@
|
||||
</div>
|
||||
|
||||
<div class="tags-actions">
|
||||
<a-tooltip title="刷新当前页">
|
||||
<a-button size="small" type="text" @click="refreshSelectedTag">
|
||||
<ReloadOutlined />
|
||||
<a-dropdown v-model:open="actionMenuVisible" trigger="click" placement="bottomRight">
|
||||
<a-button size="small" type="text">
|
||||
<MoreOutlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip title="关闭其他">
|
||||
<a-button size="small" type="text" @click="closeOthersTags">
|
||||
<ColumnWidthOutlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip title="关闭所有">
|
||||
<a-button size="small" type="text" @click="closeAllTags">
|
||||
<CloseCircleOutlined />
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<template #overlay>
|
||||
<a-menu @click="handleActionMenuClick">
|
||||
<a-menu-item key="refresh">
|
||||
<ReloadOutlined />
|
||||
<span>刷新当前页</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="closeOthers">
|
||||
<ColumnWidthOutlined />
|
||||
<span>关闭其他</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="closeLeft">
|
||||
<LeftOutlined />
|
||||
<span>关闭左侧</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="closeRight">
|
||||
<RightOutlined />
|
||||
<span>关闭右侧</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="closeAll">
|
||||
<CloseCircleOutlined />
|
||||
<span>关闭所有</span>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
|
||||
<!-- 右键菜单 -->
|
||||
@@ -76,13 +90,6 @@
|
||||
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useLayoutStore } from '@/stores/modules/layout'
|
||||
import {
|
||||
ReloadOutlined,
|
||||
CloseOutlined,
|
||||
ColumnWidthOutlined,
|
||||
CloseCircleOutlined,
|
||||
PushpinFilled
|
||||
} from '@ant-design/icons-vue'
|
||||
import config from '@/config'
|
||||
|
||||
defineOptions({
|
||||
@@ -102,6 +109,8 @@ const contextMenu = ref({
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
// 顶部操作菜单状态
|
||||
const actionMenuVisible = ref(false)
|
||||
|
||||
// 判断是否是当前激活的标签
|
||||
const isActive = (tag) => {
|
||||
@@ -179,6 +188,38 @@ const closeAllTags = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭左侧标签
|
||||
const closeLeftTags = () => {
|
||||
const currentTag = selectedTag.value || visitedViews.value.find((tag) => isActive(tag))
|
||||
if (!currentTag) return
|
||||
|
||||
const currentIndex = visitedViews.value.findIndex((tag) => tag.fullPath === currentTag.fullPath)
|
||||
if (currentIndex === -1) return
|
||||
|
||||
// 保留当前标签及其右侧的标签,以及所有固定标签
|
||||
const tagsToKeep = visitedViews.value.filter((tag, index) => {
|
||||
return tag.meta?.affix || index >= currentIndex
|
||||
})
|
||||
|
||||
layoutStore.viewTags = tagsToKeep
|
||||
}
|
||||
|
||||
// 关闭右侧标签
|
||||
const closeRightTags = () => {
|
||||
const currentTag = selectedTag.value || visitedViews.value.find((tag) => isActive(tag))
|
||||
if (!currentTag) return
|
||||
|
||||
const currentIndex = visitedViews.value.findIndex((tag) => tag.fullPath === currentTag.fullPath)
|
||||
if (currentIndex === -1) return
|
||||
|
||||
// 保留当前标签及其左侧的标签,以及所有固定标签
|
||||
const tagsToKeep = visitedViews.value.filter((tag, index) => {
|
||||
return tag.meta?.affix || index <= currentIndex
|
||||
})
|
||||
|
||||
layoutStore.viewTags = tagsToKeep
|
||||
}
|
||||
|
||||
// 点击标签
|
||||
const clickTag = (tag) => {
|
||||
if (!isActive(tag)) {
|
||||
@@ -248,6 +289,28 @@ const handleMenuClick = ({ key }) => {
|
||||
closeContextMenu()
|
||||
}
|
||||
|
||||
// 顶部操作菜单点击处理
|
||||
const handleActionMenuClick = ({ key }) => {
|
||||
switch (key) {
|
||||
case 'refresh':
|
||||
refreshSelectedTag()
|
||||
break
|
||||
case 'closeOthers':
|
||||
closeOthersTags()
|
||||
break
|
||||
case 'closeLeft':
|
||||
closeLeftTags()
|
||||
break
|
||||
case 'closeRight':
|
||||
closeRightTags()
|
||||
break
|
||||
case 'closeAll':
|
||||
closeAllTags()
|
||||
break
|
||||
}
|
||||
actionMenuVisible.value = false
|
||||
}
|
||||
|
||||
// 点击其他地方关闭右键菜单
|
||||
const handleClickOutside = (event) => {
|
||||
if (contextMenu.value.visible) {
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item label="菜单图标" name="icon">
|
||||
<a-input v-model:value="form.icon" placeholder="请输入图标类名" allow-clear />
|
||||
<sc-icon-picker v-model="form.icon" placeholder="请选择图标" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
@@ -169,6 +169,7 @@ import { ref, reactive, watch, onMounted } from 'vue'
|
||||
import { message, Empty } from 'ant-design-vue'
|
||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
||||
import authApi from '@/api/auth'
|
||||
import ScIconPicker from '@/components/scIconPicker/index.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'PermissionSave'
|
||||
|
||||
50
src/pages/home/iconPickerDemo.vue
Normal file
50
src/pages/home/iconPickerDemo.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="icon-picker-demo">
|
||||
<a-card title="图标选择器演示" style="max-width: 600px; margin: 20px auto;">
|
||||
<a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||
<a-form-item label="选择图标">
|
||||
<sc-icon-picker v-model="selectedIcon" @change="handleIconChange" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="选中值">
|
||||
<a-input v-model:value="selectedIcon" readonly />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="图标预览">
|
||||
<div v-if="selectedIcon" class="icon-preview">
|
||||
<component :is="selectedIcon" style="font-size: 48px;" />
|
||||
</div>
|
||||
<a-empty v-else description="未选择图标" :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Empty } from 'ant-design-vue'
|
||||
import ScIconPicker from '@/components/scIconPicker/index.vue'
|
||||
|
||||
const selectedIcon = ref('')
|
||||
|
||||
const handleIconChange = (value) => {
|
||||
console.log('图标已选择:', value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.icon-picker-demo {
|
||||
padding: 20px;
|
||||
|
||||
.icon-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
min-height: 88px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user