feat:菜单管理-添加web端/app端tab栏

main^2
黄伟杰 24 hours ago
parent 13133c28be
commit f66c4afd29

@ -8,7 +8,7 @@ VITE_DEV=true
# 线上环境 # 线上环境
# VITE_BASE_URL='https://besure.ngsk.tech:7001' # VITE_BASE_URL='https://besure.ngsk.tech:7001'
# 本地联调 # 本地联调
VITE_BASE_URL='http://192.168.5.167:48081' VITE_BASE_URL='http://192.168.5.106:48081'
# VITE_BASE_URL='http://192.168.5.164:48081' # VITE_BASE_URL='http://192.168.5.164:48081'
# VITE_BASE_URL='http://192.168.5.5:48081' # VITE_BASE_URL='http://192.168.5.5:48081'

@ -16,12 +16,13 @@ export interface MenuVO {
visible: boolean visible: boolean
keepAlive: boolean keepAlive: boolean
alwaysShow?: boolean alwaysShow?: boolean
clientType?: number
createTime: Date createTime: Date
} }
// 查询菜单(精简)列表 // 查询菜单(精简)列表
export const getSimpleMenusList = () => { export const getSimpleMenusList = (clientType?: number) => {
return request.get({ url: '/system/menu/simple-list' }) return request.get({ url: '/system/menu/simple-list', params: { clientType } })
} }
// 查询菜单列表 // 查询菜单列表

Binary file not shown.

Binary file not shown.

@ -1,4 +1,5 @@
import Icon from './src/Icon.vue' import Icon from './src/Icon.vue'
import IconSelect from './src/IconSelect.vue' import IconSelect from './src/IconSelect.vue'
import AppIconSelect from './src/AppIconSelect.vue'
export { Icon, IconSelect } export { Icon, IconSelect, AppIconSelect }

@ -0,0 +1,280 @@
<script lang="ts" setup>
import { uniIconsList, uviewIconsList, uniIconsUnicodeMap, uviewIconsUnicodeMap } from './appIconData'
defineOptions({ name: 'AppIconSelect' })
const props = defineProps({
modelValue: {
require: false,
type: String
},
clearable: {
require: false,
type: Boolean
}
})
const emit = defineEmits<{ (e: 'update:modelValue', v: string) }>()
const visible = ref(false)
const inputValue = toRef(props, 'modelValue')
const currentActiveType = ref('uni-icons')
const filterValue = ref('')
const iconDataMap: Record<string, string[]> = {
'uni-icons': uniIconsList,
'uview-plus': uviewIconsList
}
const unicodeMapMap: Record<string, Record<string, string>> = {
'uni-icons': uniIconsUnicodeMap,
'uview-plus': uviewIconsUnicodeMap
}
const fontFamilyMap: Record<string, string> = {
'uni-icons': 'UniIconsFontFamily',
'uview-plus': 'uview-iconfont'
}
const tabsList = [
{ label: 'uni-icons', name: 'uni-icons' },
{ label: 'uview-plus', name: 'uview-plus' }
]
const pageSize = ref(96)
const currentPage = ref(1)
const currentIconList = computed(() => {
return iconDataMap[currentActiveType.value] || []
})
const currentUnicodeMap = computed(() => {
return unicodeMapMap[currentActiveType.value] || {}
})
const currentFontFamily = computed(() => {
return fontFamilyMap[currentActiveType.value] || 'UniIconsFontFamily'
})
const filteredList = computed(() => {
return currentIconList.value.filter((v) =>
v.toLowerCase().includes(filterValue.value.toLowerCase())
)
})
const pageList = computed(() => {
if (currentPage.value === 1) {
return filteredList.value.slice(0, pageSize.value)
}
return filteredList.value.slice(
pageSize.value * (currentPage.value - 1),
pageSize.value * (currentPage.value - 1) + pageSize.value
)
})
const iconCount = computed(() => filteredList.value.length)
function parseIconValue(value: string): { prefix: string; name: string } | null {
if (!value || value.indexOf(':') < 0) return null
const idx = value.indexOf(':')
return {
prefix: value.substring(0, idx),
name: value.substring(idx + 1)
}
}
function getUnicode(name: string): string {
return currentUnicodeMap.value[name] || ''
}
function getSelectedFontFamily(fullValue: string): string {
const parsed = parseIconValue(fullValue)
if (!parsed) return 'UniIconsFontFamily'
return fontFamilyMap[parsed.prefix] || 'UniIconsFontFamily'
}
function getSelectedUnicode(fullValue: string): string {
const parsed = parseIconValue(fullValue)
if (!parsed) return ''
const map = unicodeMapMap[parsed.prefix]
return map ? map[parsed.name] || '' : ''
}
function handleClick({ props }: any) {
currentPage.value = 1
currentActiveType.value = props.name
}
function onChangeIcon(item: string) {
emit('update:modelValue', currentActiveType.value + ':' + item)
visible.value = false
}
function onCurrentChange(page: number) {
currentPage.value = page
}
function clearIcon() {
emit('update:modelValue', '')
visible.value = false
}
watch(
() => props.modelValue,
(val) => {
if (val) {
const parsed = parseIconValue(val)
if (parsed && fontFamilyMap[parsed.prefix]) {
currentActiveType.value = parsed.prefix
}
}
}
)
watch(
() => filterValue.value,
() => {
currentPage.value = 1
}
)
</script>
<template>
<div class="selector">
<ElInput v-model="inputValue" @click="visible = !visible" :clearable="props.clearable" @clear="clearIcon">
<template #append>
<ElPopover
:visible="visible"
:width="355"
popper-class="pure-popper"
trigger="click"
>
<template #reference>
<div
class="h-32px w-40px flex cursor-pointer items-center justify-center"
@click="visible = !visible"
>
<span
v-if="inputValue && getSelectedUnicode(inputValue)"
class="app-icon-font"
:style="{ fontFamily: getSelectedFontFamily(inputValue), fontSize: '18px' }"
>{{ getSelectedUnicode(inputValue) }}</span>
<span v-else class="text-12px color-gray-500">选择</span>
</div>
</template>
<ElInput v-model="filterValue" class="p-2" clearable placeholder="搜索图标" />
<ElDivider border-style="dashed" />
<ElTabs v-model="currentActiveType" @tab-click="handleClick">
<ElTabPane
v-for="(pane, index) in tabsList"
:key="index"
:label="pane.label"
:name="pane.name"
>
<ElDivider border-style="dashed" class="tab-divider" />
<ElScrollbar height="220px">
<ul class="ml-2 flex flex-wrap">
<li
v-for="(item, key) in pageList"
:key="key"
:style="inputValue === currentActiveType + ':' + item ? { borderColor: 'var(--el-color-primary)', color: 'var(--el-color-primary)' } : {}"
:title="item"
class="icon-item mr-2 mt-1 w-1/10 flex cursor-pointer items-center justify-center border border-solid p-2"
@click="onChangeIcon(item)"
>
<span
class="app-icon-font"
:style="{ fontFamily: currentFontFamily }"
>{{ getUnicode(item) }}</span>
</li>
</ul>
</ElScrollbar>
</ElTabPane>
</ElTabs>
<ElDivider border-style="dashed" />
<ElPagination
:current-page="currentPage"
:page-size="pageSize"
:total="iconCount"
background
class="h-10 flex items-center justify-center"
layout="prev, pager, next"
size="small"
@current-change="onCurrentChange"
/>
</ElPopover>
</template>
</ElInput>
</div>
</template>
<style lang="scss">
@font-face {
font-family: 'UniIconsFontFamily';
src: url('@/assets/fonts/uniicons.ttf') format('truetype');
font-display: swap;
}
@font-face {
font-family: 'uview-iconfont';
src: url('@/assets/fonts/uview-icons.ttf') format('truetype');
font-display: swap;
}
</style>
<style lang="scss" scoped>
.app-icon-font {
font-style: normal;
font-size: 20px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.el-divider--horizontal {
margin: 1px auto !important;
}
.tab-divider.el-divider--horizontal {
margin: 0 !important;
}
.icon-item {
&:hover {
color: var(--el-color-primary);
border-color: var(--el-color-primary);
transform: scaleX(1.05);
transition: all 0.4s;
}
}
:deep(.el-tabs__nav-next) {
font-size: 15px;
line-height: 32px;
box-shadow: -5px 0 5px -6px #ccc;
}
:deep(.el-tabs__nav-prev) {
font-size: 15px;
line-height: 32px;
box-shadow: 5px 0 5px -6px #ccc;
}
:deep(.el-input-group__append) {
padding: 0;
}
:deep(.el-tabs__item) {
height: 30px;
font-size: 12px;
font-weight: normal;
line-height: 30px;
}
:deep(.el-tabs__header),
:deep(.el-tabs__nav-wrap) {
position: static;
margin: 0;
}
</style>

@ -0,0 +1,382 @@
const uniIconsUnicodeMap: Record<string, string> = {
'arrow-down': '\ue6be',
'arrow-left': '\ue6bc',
'arrow-right': '\ue6bb',
'arrow-up': '\ue6bd',
'auth': '\ue6ab',
'auth-filled': '\ue6cc',
'back': '\ue6b9',
'bars': '\ue627',
'calendar': '\ue6a0',
'calendar-filled': '\ue6c0',
'camera': '\ue65a',
'camera-filled': '\ue658',
'cart': '\ue631',
'cart-filled': '\ue6d0',
'chat': '\ue65d',
'chat-filled': '\ue659',
'chatboxes': '\ue696',
'chatboxes-filled': '\ue692',
'chatbubble': '\ue697',
'chatbubble-filled': '\ue694',
'checkbox': '\ue62b',
'checkbox-filled': '\ue62c',
'checkmarkempty': '\ue65c',
'circle': '\ue65b',
'circle-filled': '\ue65e',
'clear': '\ue66d',
'close': '\ue673',
'closeempty': '\ue66c',
'cloud-download': '\ue647',
'cloud-download-filled': '\ue646',
'cloud-upload': '\ue645',
'cloud-upload-filled': '\ue648',
'color': '\ue6cf',
'color-filled': '\ue6c9',
'compose': '\ue67f',
'contact': '\ue693',
'contact-filled': '\ue695',
'down': '\ue6b8',
'bottom': '\ue6b8',
'download': '\ue68d',
'download-filled': '\ue681',
'email': '\ue69e',
'email-filled': '\ue69a',
'eye': '\ue651',
'eye-filled': '\ue66a',
'eye-slash': '\ue6b3',
'eye-slash-filled': '\ue6b4',
'fire': '\ue6a1',
'fire-filled': '\ue6c5',
'flag': '\ue65f',
'flag-filled': '\ue660',
'folder-add': '\ue6a9',
'folder-add-filled': '\ue6c8',
'font': '\ue6a3',
'forward': '\ue6ba',
'gear': '\ue664',
'gear-filled': '\ue661',
'gift': '\ue6a4',
'gift-filled': '\ue6c4',
'hand-down': '\ue63d',
'hand-down-filled': '\ue63c',
'hand-up': '\ue63f',
'hand-up-filled': '\ue63e',
'headphones': '\ue630',
'heart': '\ue639',
'heart-filled': '\ue641',
'help': '\ue679',
'help-filled': '\ue674',
'home': '\ue662',
'home-filled': '\ue663',
'image': '\ue670',
'image-filled': '\ue678',
'images': '\ue650',
'images-filled': '\ue64b',
'info': '\ue669',
'info-filled': '\ue649',
'left': '\ue6b7',
'link': '\ue6a5',
'list': '\ue644',
'location': '\ue6ae',
'location-filled': '\ue6af',
'locked': '\ue66b',
'locked-filled': '\ue668',
'loop': '\ue633',
'mail-open': '\ue643',
'mail-open-filled': '\ue63a',
'map': '\ue667',
'map-filled': '\ue666',
'map-pin': '\ue6ad',
'map-pin-ellipse': '\ue6ac',
'medal': '\ue6a2',
'medal-filled': '\ue6c3',
'mic': '\ue671',
'mic-filled': '\ue677',
'micoff': '\ue67e',
'micoff-filled': '\ue6b0',
'minus': '\ue66f',
'minus-filled': '\ue67d',
'more': '\ue64d',
'more-filled': '\ue64e',
'navigate': '\ue66e',
'navigate-filled': '\ue67a',
'notification': '\ue6a6',
'notification-filled': '\ue6c1',
'paperclip': '\ue652',
'paperplane': '\ue672',
'paperplane-filled': '\ue675',
'person': '\ue699',
'person-filled': '\ue69d',
'personadd': '\ue69f',
'personadd-filled': '\ue698',
'phone': '\ue69c',
'phone-filled': '\ue69b',
'plus': '\ue676',
'plus-filled': '\ue6c7',
'plusempty': '\ue67b',
'pulldown': '\ue632',
'pyq': '\ue682',
'qq': '\ue680',
'redo': '\ue64a',
'redo-filled': '\ue655',
'refresh': '\ue657',
'refresh-filled': '\ue656',
'refreshempty': '\ue6bf',
'reload': '\ue6b2',
'right': '\ue6b5',
'scan': '\ue62a',
'search': '\ue654',
'settings': '\ue653',
'settings-filled': '\ue6ce',
'shop': '\ue62f',
'shop-filled': '\ue6cd',
'smallcircle': '\ue67c',
'smallcircle-filled': '\ue665',
'sound': '\ue684',
'sound-filled': '\ue686',
'spinner-cycle': '\ue68a',
'staff': '\ue6a7',
'staff-filled': '\ue6cb',
'star': '\ue688',
'star-filled': '\ue68f',
'starhalf': '\ue683',
'trash': '\ue687',
'trash-filled': '\ue685',
'tune': '\ue6aa',
'tune-filled': '\ue6ca',
'undo': '\ue64f',
'undo-filled': '\ue64c',
'up': '\ue6b6',
'top': '\ue6b6',
'upload': '\ue690',
'upload-filled': '\ue68e',
'videocam': '\ue68c',
'videocam-filled': '\ue689',
'vip': '\ue6a8',
'vip-filled': '\ue6c6',
'wallet': '\ue6b1',
'wallet-filled': '\ue6c2',
'weibo': '\ue68b',
'weixin': '\ue691'
}
const uviewIconsUnicodeMap: Record<string, string> = {
'level': '\ue693',
'column-line': '\ue68e',
'checkbox-mark': '\ue807',
'folder': '\ue7f5',
'movie': '\ue7f6',
'star-fill': '\ue669',
'star': '\ue65f',
'phone-fill': '\ue64f',
'phone': '\ue622',
'apple-fill': '\ue881',
'chrome-circle-fill': '\ue885',
'backspace': '\ue67b',
'attach': '\ue632',
'cut': '\ue948',
'empty-car': '\ue602',
'empty-coupon': '\ue682',
'empty-address': '\ue646',
'empty-favor': '\ue67c',
'empty-permission': '\ue686',
'empty-news': '\ue687',
'empty-search': '\ue664',
'github-circle-fill': '\ue887',
'rmb': '\ue608',
'person-delete-fill': '\ue66a',
'reload': '\ue788',
'order': '\ue68f',
'server-man': '\ue6bc',
'search': '\ue62a',
'fingerprint': '\ue955',
'more-dot-fill': '\ue630',
'scan': '\ue662',
'share-square': '\ue60b',
'map': '\ue61d',
'map-fill': '\ue64e',
'tags': '\ue629',
'tags-fill': '\ue651',
'bookmark-fill': '\ue63b',
'bookmark': '\ue60a',
'eye': '\ue613',
'eye-fill': '\ue641',
'mic': '\ue64a',
'mic-off': '\ue649',
'calendar': '\ue66e',
'calendar-fill': '\ue634',
'trash': '\ue623',
'trash-fill': '\ue658',
'play-left': '\ue66d',
'play-right': '\ue610',
'minus': '\ue618',
'plus': '\ue62d',
'info': '\ue653',
'info-circle': '\ue7d2',
'info-circle-fill': '\ue64b',
'question': '\ue715',
'error': '\ue6d3',
'close': '\ue685',
'checkmark': '\ue6a8',
'android-circle-fill': '\ue67e',
'android-fill': '\ue67d',
'ie': '\ue87b',
'IE-circle-fill': '\ue889',
'google': '\ue87a',
'google-circle-fill': '\ue88a',
'setting-fill': '\ue872',
'setting': '\ue61f',
'minus-square-fill': '\ue855',
'plus-square-fill': '\ue856',
'heart': '\ue7df',
'heart-fill': '\ue851',
'camera': '\ue7d7',
'camera-fill': '\ue870',
'more-circle': '\ue63e',
'more-circle-fill': '\ue645',
'chat': '\ue620',
'chat-fill': '\ue61e',
'bag-fill': '\ue617',
'bag': '\ue619',
'error-circle-fill': '\ue62c',
'error-circle': '\ue624',
'close-circle': '\ue63f',
'close-circle-fill': '\ue637',
'checkmark-circle': '\ue63d',
'checkmark-circle-fill': '\ue635',
'question-circle-fill': '\ue666',
'question-circle': '\ue625',
'share': '\ue631',
'share-fill': '\ue65e',
'shopping-cart': '\ue621',
'shopping-cart-fill': '\ue65d',
'bell': '\ue609',
'bell-fill': '\ue640',
'list': '\ue650',
'list-dot': '\ue616',
'zhihu': '\ue6ba',
'zhihu-circle-fill': '\ue709',
'zhifubao': '\ue6b9',
'zhifubao-circle-fill': '\ue6b8',
'weixin-circle-fill': '\ue6b1',
'weixin-fill': '\ue6b2',
'twitter-circle-fill': '\ue6ab',
'twitter': '\ue6aa',
'taobao-circle-fill': '\ue6a7',
'taobao': '\ue6a6',
'weibo-circle-fill': '\ue6a5',
'weibo': '\ue6a4',
'qq-fill': '\ue6a1',
'qq-circle-fill': '\ue6a0',
'moments-circel-fill': '\ue69a',
'moments': '\ue69b',
'qzone': '\ue695',
'qzone-circle-fill': '\ue696',
'baidu-circle-fill': '\ue680',
'baidu': '\ue681',
'facebook-circle-fill': '\ue68a',
'facebook': '\ue689',
'car': '\ue60c',
'car-fill': '\ue636',
'warning-fill': '\ue64d',
'warning': '\ue694',
'clock-fill': '\ue638',
'clock': '\ue60f',
'edit-pen': '\ue612',
'edit-pen-fill': '\ue66b',
'email': '\ue611',
'email-fill': '\ue642',
'minus-circle': '\ue61b',
'minus-circle-fill': '\ue652',
'plus-circle': '\ue62e',
'plus-circle-fill': '\ue661',
'file-text': '\ue663',
'file-text-fill': '\ue665',
'pushpin': '\ue7e3',
'pushpin-fill': '\ue86e',
'grid': '\ue673',
'grid-fill': '\ue678',
'play-circle': '\ue647',
'play-circle-fill': '\ue655',
'pause-circle-fill': '\ue654',
'pause': '\ue8fa',
'pause-circle': '\ue643',
'eye-off': '\ue648',
'eye-off-outline': '\ue62b',
'gift-fill': '\ue65c',
'gift': '\ue65b',
'rmb-circle-fill': '\ue657',
'rmb-circle': '\ue677',
'kefu-ermai': '\ue656',
'server-fill': '\ue751',
'coupon-fill': '\ue8c4',
'coupon': '\ue8ae',
'integral': '\ue704',
'integral-fill': '\ue703',
'home-fill': '\ue964',
'home': '\ue965',
'hourglass-half-fill': '\ue966',
'hourglass': '\ue967',
'account': '\ue628',
'plus-people-fill': '\ue626',
'minus-people-fill': '\ue615',
'account-fill': '\ue614',
'thumb-down-fill': '\ue726',
'thumb-down': '\ue727',
'thumb-up': '\ue733',
'thumb-up-fill': '\ue72f',
'lock-fill': '\ue979',
'lock-open': '\ue973',
'lock-opened-fill': '\ue974',
'lock': '\ue97a',
'red-packet-fill': '\ue690',
'photo-fill': '\ue98b',
'photo': '\ue98d',
'volume-off-fill': '\ue659',
'volume-off': '\ue644',
'volume-fill': '\ue670',
'volume': '\ue633',
'red-packet': '\ue691',
'download': '\ue63c',
'arrow-up-fill': '\ue6b0',
'arrow-down-fill': '\ue600',
'play-left-fill': '\ue675',
'play-right-fill': '\ue676',
'rewind-left-fill': '\ue679',
'rewind-right-fill': '\ue67a',
'arrow-downward': '\ue604',
'arrow-leftward': '\ue601',
'arrow-rightward': '\ue603',
'arrow-upward': '\ue607',
'arrow-down': '\ue60d',
'arrow-right': '\ue605',
'arrow-left': '\ue60e',
'arrow-up': '\ue606',
'skip-back-left': '\ue674',
'skip-forward-right': '\ue672',
'rewind-right': '\ue66f',
'rewind-left': '\ue671',
'arrow-right-double': '\ue68d',
'arrow-left-double': '\ue68c',
'wifi-off': '\ue668',
'wifi': '\ue667',
'empty-data': '\ue62f',
'empty-history': '\ue684',
'empty-list': '\ue68b',
'empty-page': '\ue627',
'empty-order': '\ue639',
'man': '\ue697',
'woman': '\ue69c',
'man-add': '\ue61c',
'man-add-fill': '\ue64c',
'man-delete': '\ue61a',
'man-delete-fill': '\ue66a',
'zh': '\ue70a',
'en': '\ue692'
}
const uniIconsList = Object.keys(uniIconsUnicodeMap)
const uviewIconsList = Object.keys(uviewIconsUnicodeMap)
export { uniIconsList, uviewIconsList, uniIconsUnicodeMap, uviewIconsUnicodeMap }

@ -1144,6 +1144,8 @@ export default {
refreshCache: 'Refresh Menu Cache', refreshCache: 'Refresh Menu Cache',
updateCacheConfirm: 'The cache will be updated and the browser will be refreshed!', updateCacheConfirm: 'The cache will be updated and the browser will be refreshed!',
updateCacheTitle: 'Refresh Menu Cache', updateCacheTitle: 'Refresh Menu Cache',
clientTypeWeb: 'Web Menu',
clientTypeApp: 'APP Menu',
visibleShow: 'Show', visibleShow: 'Show',
visibleHide: 'Hide', visibleHide: 'Hide',
always: 'Always', always: 'Always',
@ -2805,6 +2807,9 @@ export default {
templateName: 'Template Name', templateName: 'Template Name',
templateType: 'Template Type', templateType: 'Template Type',
templateJson: 'Template JSON', templateJson: 'Template JSON',
isConfigured: 'Configured',
configured: 'Configured',
notConfigured: 'Not Configured',
remark: 'Remark', remark: 'Remark',
isEnable: 'Enabled', isEnable: 'Enabled',
enabled: 'Enabled', enabled: 'Enabled',

@ -1145,6 +1145,8 @@ export default {
refreshCache: '刷新菜单缓存', refreshCache: '刷新菜单缓存',
updateCacheConfirm: '即将更新缓存刷新浏览器!', updateCacheConfirm: '即将更新缓存刷新浏览器!',
updateCacheTitle: '刷新菜单缓存', updateCacheTitle: '刷新菜单缓存',
clientTypeWeb: 'Web端菜单',
clientTypeApp: 'APP端菜单',
visibleShow: '显示', visibleShow: '显示',
visibleHide: '隐藏', visibleHide: '隐藏',
always: '总是', always: '总是',
@ -2307,6 +2309,9 @@ export default {
templateName: '模板名称', templateName: '模板名称',
templateType: '模板类型', templateType: '模板类型',
templateJson: '模板JSON', templateJson: '模板JSON',
isConfigured: '是否已配置',
configured: '已配置',
notConfigured: '未配置',
remark: '备注', remark: '备注',
isEnable: '是否启用', isEnable: '是否启用',
enabled: '启用', enabled: '启用',

@ -50,8 +50,13 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('TemplateManagement.PrintTemplate.templateJson')" align="center" prop="templateJson" <el-table-column :label="t('TemplateManagement.PrintTemplate.isConfigured')" align="center" min-width="120px">
min-width="200px" :show-overflow-tooltip="true" /> <template #default="scope">
<el-tag :type="scope.row.templateJson ? 'success' : 'info'">
{{ scope.row.templateJson ? t('TemplateManagement.PrintTemplate.configured') : t('TemplateManagement.PrintTemplate.notConfigured') }}
</el-tag>
</template>
</el-table-column>
<el-table-column :label="t('TemplateManagement.PrintTemplate.remark')" align="center" prop="remark" /> <el-table-column :label="t('TemplateManagement.PrintTemplate.remark')" align="center" prop="remark" />
<el-table-column :label="t('TemplateManagement.PrintTemplate.createTime')" align="center" prop="createTime" <el-table-column :label="t('TemplateManagement.PrintTemplate.createTime')" align="center" prop="createTime"
:formatter="dateFormatter" width="180px" sortable /> :formatter="dateFormatter" width="180px" sortable />

@ -36,7 +36,8 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item v-if="formData.type !== 3" :label="t('SystemManagement.Menu.icon')"> <el-form-item v-if="formData.type !== 3" :label="t('SystemManagement.Menu.icon')">
<IconSelect v-model="formData.icon" clearable /> <IconSelect v-if="clientType === 1" v-model="formData.icon" clearable />
<AppIconSelect v-else v-model="formData.icon" clearable />
</el-form-item> </el-form-item>
<el-form-item v-if="formData.type !== 3" :label="t('SystemManagement.Menu.path')" prop="path"> <el-form-item v-if="formData.type !== 3" :label="t('SystemManagement.Menu.path')" prop="path">
<template #label> <template #label>
@ -122,6 +123,7 @@ import * as MenuApi from '@/api/system/menu'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache' import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import { CommonStatusEnum, SystemMenuTypeEnum } from '@/utils/constants' import { CommonStatusEnum, SystemMenuTypeEnum } from '@/utils/constants'
import { defaultProps, handleTree } from '@/utils/tree' import { defaultProps, handleTree } from '@/utils/tree'
import AppIconSelect from '@/components/Icon/src/AppIconSelect.vue'
defineOptions({ name: 'SystemMenuForm' }) defineOptions({ name: 'SystemMenuForm' })
@ -133,6 +135,7 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // const dialogTitle = ref('') //
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formType = ref('') // create - update - const formType = ref('') // create - update -
const clientType = ref(1) // 1=Web2=APP
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
name: '', name: '',
@ -148,21 +151,23 @@ const formData = ref({
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
visible: true, visible: true,
keepAlive: true, keepAlive: true,
alwaysShow: true alwaysShow: true,
clientType: 1
}) })
const formRules = reactive({ const formRules = computed(() => ({
name: [{ required: true, message: t('SystemManagement.Menu.nameRequired'), trigger: 'blur' }], name: [{ required: true, message: t('SystemManagement.Menu.nameRequired'), trigger: 'blur' }],
sort: [{ required: true, message: t('SystemManagement.Menu.sortRequired'), trigger: 'blur' }], sort: [{ required: true, message: t('SystemManagement.Menu.sortRequired'), trigger: 'blur' }],
path: [{ required: true, message: t('SystemManagement.Menu.pathRequired'), trigger: 'blur' }], path: [{ required: clientType.value === 1, message: t('SystemManagement.Menu.pathRequired'), trigger: 'blur' }],
status: [{ required: true, message: t('SystemManagement.Menu.statusRequired'), trigger: 'blur' }] status: [{ required: true, message: t('SystemManagement.Menu.statusRequired'), trigger: 'blur' }]
}) }))
const formRef = ref() // Ref const formRef = ref() // Ref
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (type: string, id?: number, parentId?: number) => { const open = async (type: string, id?: number, parentId?: number, currentClientType?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
clientType.value = currentClientType ?? 1
resetForm() resetForm()
if (parentId) { if (parentId) {
formData.value.parentId = parentId formData.value.parentId = parentId
@ -206,6 +211,7 @@ const submitForm = async () => {
} }
} }
const data = formData.value as unknown as MenuApi.MenuVO const data = formData.value as unknown as MenuApi.MenuVO
data.clientType = clientType.value
if (formType.value === 'create') { if (formType.value === 'create') {
await MenuApi.createMenu(data) await MenuApi.createMenu(data)
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
@ -227,7 +233,7 @@ const submitForm = async () => {
const menuTree = ref<Tree[]>([]) // const menuTree = ref<Tree[]>([]) //
const getTree = async () => { const getTree = async () => {
menuTree.value = [] menuTree.value = []
const res = await MenuApi.getSimpleMenusList() const res = await MenuApi.getSimpleMenusList(clientType.value)
let menu: Tree = { id: 0, name: t('SystemManagement.Menu.parentRoot'), children: [] } let menu: Tree = { id: 0, name: t('SystemManagement.Menu.parentRoot'), children: [] }
menu.children = handleTree(res) menu.children = handleTree(res)
menuTree.value.push(menu) menuTree.value.push(menu)
@ -250,7 +256,8 @@ const resetForm = () => {
status: CommonStatusEnum.ENABLE, status: CommonStatusEnum.ENABLE,
visible: true, visible: true,
keepAlive: true, keepAlive: true,
alwaysShow: true alwaysShow: true,
clientType: 1
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }

@ -1,6 +1,11 @@
<template> <template>
<!-- Tabs 切换 Web/APP -->
<ContentWrap>
<el-tabs v-model="activeClientType" @tab-change="handleClientTypeChange">
<el-tab-pane :label="t('SystemManagement.Menu.clientTypeWeb')" :name="1" />
<el-tab-pane :label="t('SystemManagement.Menu.clientTypeApp')" :name="2" />
</el-tabs>
</ContentWrap>
<!-- 搜索工作栏 --> <!-- 搜索工作栏 -->
<ContentWrap> <ContentWrap>
@ -78,7 +83,8 @@
<el-table-column :show-overflow-tooltip="true" :label="t('SystemManagement.Menu.enName')" prop="enName" width="250" sortable /> <el-table-column :show-overflow-tooltip="true" :label="t('SystemManagement.Menu.enName')" prop="enName" width="250" sortable />
<el-table-column align="center" :label="t('SystemManagement.Menu.icon')" prop="icon" width="100"> <el-table-column align="center" :label="t('SystemManagement.Menu.icon')" prop="icon" width="100">
<template #default="scope"> <template #default="scope">
<Icon :icon="scope.row.icon" /> <Icon v-if="activeClientType === 1" :icon="scope.row.icon" />
<span v-else>{{ scope.row.icon }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('SystemManagement.Menu.sort')" prop="sort" width="60" /> <el-table-column :label="t('SystemManagement.Menu.sort')" prop="sort" width="60" />
@ -149,9 +155,11 @@ const message = useMessage() // 消息弹窗
const loading = ref(true) // const loading = ref(true) //
const list = ref<any>([]) // const list = ref<any>([]) //
const activeClientType = ref(1) // 1=Web2=APP
const queryParams = reactive({ const queryParams = reactive({
name: undefined, name: undefined,
status: undefined status: undefined,
clientType: 1
}) })
const queryFormRef = ref() // const queryFormRef = ref() //
const isExpandAll = ref(false) // const isExpandAll = ref(false) //
@ -173,6 +181,12 @@ const handleQuery = () => {
getList() getList()
} }
/** 切换客户端类型 */
const handleClientTypeChange = (val: number | string) => {
queryParams.clientType = val as number
getList()
}
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value.resetFields()
@ -182,7 +196,7 @@ const resetQuery = () => {
/** 添加/修改操作 */ /** 添加/修改操作 */
const formRef = ref() const formRef = ref()
const openForm = (type: string, id?: number, parentId?: number) => { const openForm = (type: string, id?: number, parentId?: number) => {
formRef.value.open(type, id, parentId) formRef.value.open(type, id, parentId, activeClientType.value)
} }
/** 展开/折叠操作 */ /** 展开/折叠操作 */

Loading…
Cancel
Save