master
parent
ebaebc926a
commit
d32b16ac11
|
|
@ -76,7 +76,7 @@ router.beforeEach((to, from) => {
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
replace: true,
|
replace: true,
|
||||||
name: 'role',
|
path: to.fullPath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -109,6 +109,7 @@ export function reloadRouter() {
|
||||||
routNames.push('menus')
|
routNames.push('menus')
|
||||||
routNames.push('user')
|
routNames.push('user')
|
||||||
routNames.push('role')
|
routNames.push('role')
|
||||||
|
routNames.push('dict')
|
||||||
|
|
||||||
if (Colls.isEmpty(routNames)) {
|
if (Colls.isEmpty(routNames)) {
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import '@/components/a-icon/iconfont.css'
|
||||||
|
import {
|
||||||
|
type IconName,
|
||||||
|
icons,
|
||||||
|
} from '@/components/a-icon/iconfont.ts'
|
||||||
|
|
||||||
|
import {
|
||||||
|
computed,
|
||||||
|
defineComponent,
|
||||||
|
} from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent(
|
||||||
|
(props, {attrs}) => {
|
||||||
|
const prefixText = icons.css_prefix_text
|
||||||
|
const fontFamily = icons.font_family
|
||||||
|
const icon = computed(() => {
|
||||||
|
return props.name == null ? [] : [ fontFamily, prefixText + props.name ]
|
||||||
|
})
|
||||||
|
return () => (<><i class={icon.value} {...attrs}></i></>)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String as PropType<IconName>,
|
||||||
|
required: false,
|
||||||
|
validator: (_: string) => true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: 'AIcon',
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: "iconfont"; /* Project id 4985351 */
|
||||||
|
src: url('@/components/a-icon/iconfont.woff2?t=1764810386158') format('woff2'),
|
||||||
|
url('@/components/a-icon/iconfont.woff?t=1764810386158') format('woff'),
|
||||||
|
url('@/components/a-icon/iconfont.ttf?t=1764810386158') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-family: "iconfont", serif !important;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-bianji:before {
|
||||||
|
content: "\e604";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-koukuanliebiao:before {
|
||||||
|
content: "\e63b";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-yuechongzhi:before {
|
||||||
|
content: "\e8f5";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shanchudingdan-mian:before {
|
||||||
|
content: "\e6d7";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-quxiaodingdan:before {
|
||||||
|
content: "\e64a";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-lishiguiji-lan:before {
|
||||||
|
content: "\e672";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-guobangdanju:before {
|
||||||
|
content: "\e66c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-dianzixiaopiao:before {
|
||||||
|
content: "\e64d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xiangqing:before {
|
||||||
|
content: "\e611";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-guanliandanju:before {
|
||||||
|
content: "\e61d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-track:before {
|
||||||
|
content: "\e603";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-guanliandanxuan:before {
|
||||||
|
content: "\e68f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-dingdanxiangqing:before {
|
||||||
|
content: "\e6bf";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-tongzhi:before {
|
||||||
|
content: "\e86a";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-yujingguanli:before {
|
||||||
|
content: "\e61b";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shujuguanli:before {
|
||||||
|
content: "\e70c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-jiaoseguanli:before {
|
||||||
|
content: "\e62f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-yingyongyonghuguanli:before {
|
||||||
|
content: "\e6aa";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shangpinguanli:before {
|
||||||
|
content: "\fcf3";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xitongguanli:before {
|
||||||
|
content: "\e85c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-pinleiguanli:before {
|
||||||
|
content: "\e63d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-qiyezhuce:before {
|
||||||
|
content: "\e6a1";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shenheguanli:before {
|
||||||
|
content: "\e639";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
export const icons = {
|
||||||
|
'id': '4985351',
|
||||||
|
'name': '再昇云',
|
||||||
|
'font_family': 'iconfont',
|
||||||
|
'css_prefix_text': 'icon-',
|
||||||
|
'description': '',
|
||||||
|
'glyphs': [
|
||||||
|
{
|
||||||
|
'icon_id': '8582929',
|
||||||
|
'name': '编辑/修改',
|
||||||
|
'font_class': 'bianji',
|
||||||
|
'unicode': 'e604',
|
||||||
|
'unicode_decimal': 58884,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '41408341',
|
||||||
|
'name': '扣款',
|
||||||
|
'font_class': 'koukuanliebiao',
|
||||||
|
'unicode': 'e63b',
|
||||||
|
'unicode_decimal': 58939,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '33376724',
|
||||||
|
'name': '余额充值',
|
||||||
|
'font_class': 'yuechongzhi',
|
||||||
|
'unicode': 'e8f5',
|
||||||
|
'unicode_decimal': 59637,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '6949389',
|
||||||
|
'name': '删除订单;报表;清单',
|
||||||
|
'font_class': 'shanchudingdan-mian',
|
||||||
|
'unicode': 'e6d7',
|
||||||
|
'unicode_decimal': 59095,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '16695459',
|
||||||
|
'name': '取消订单',
|
||||||
|
'font_class': 'quxiaodingdan',
|
||||||
|
'unicode': 'e64a',
|
||||||
|
'unicode_decimal': 58954,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '14443392',
|
||||||
|
'name': '历史轨迹-蓝',
|
||||||
|
'font_class': 'lishiguiji-lan',
|
||||||
|
'unicode': 'e672',
|
||||||
|
'unicode_decimal': 58994,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '44180887',
|
||||||
|
'name': '过磅单据',
|
||||||
|
'font_class': 'guobangdanju',
|
||||||
|
'unicode': 'e66c',
|
||||||
|
'unicode_decimal': 58988,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '26397534',
|
||||||
|
'name': '电子小票',
|
||||||
|
'font_class': 'dianzixiaopiao',
|
||||||
|
'unicode': 'e64d',
|
||||||
|
'unicode_decimal': 58957,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '12814001',
|
||||||
|
'name': '详情',
|
||||||
|
'font_class': 'xiangqing',
|
||||||
|
'unicode': 'e611',
|
||||||
|
'unicode_decimal': 58897,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '9777840',
|
||||||
|
'name': '关联单据',
|
||||||
|
'font_class': 'guanliandanju',
|
||||||
|
'unicode': 'e61d',
|
||||||
|
'unicode_decimal': 58909,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '28095045',
|
||||||
|
'name': '准运证',
|
||||||
|
'font_class': 'track',
|
||||||
|
'unicode': 'e603',
|
||||||
|
'unicode_decimal': 58883,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '18446165',
|
||||||
|
'name': '关联单选',
|
||||||
|
'font_class': 'guanliandanxuan',
|
||||||
|
'unicode': 'e68f',
|
||||||
|
'unicode_decimal': 59023,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '8725687',
|
||||||
|
'name': '订单详情',
|
||||||
|
'font_class': 'dingdanxiangqing',
|
||||||
|
'unicode': 'e6bf',
|
||||||
|
'unicode_decimal': 59071,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '23500943',
|
||||||
|
'name': '通知',
|
||||||
|
'font_class': 'tongzhi',
|
||||||
|
'unicode': 'e86a',
|
||||||
|
'unicode_decimal': 59498,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '27250248',
|
||||||
|
'name': '预警管理',
|
||||||
|
'font_class': 'yujingguanli',
|
||||||
|
'unicode': 'e61b',
|
||||||
|
'unicode_decimal': 58907,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '25301786',
|
||||||
|
'name': '字典管理',
|
||||||
|
'font_class': 'shujuguanli',
|
||||||
|
'unicode': 'e70c',
|
||||||
|
'unicode_decimal': 59148,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '3590945',
|
||||||
|
'name': '角色管理',
|
||||||
|
'font_class': 'jiaoseguanli',
|
||||||
|
'unicode': 'e62f',
|
||||||
|
'unicode_decimal': 58927,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '20853364',
|
||||||
|
'name': '用户管理',
|
||||||
|
'font_class': 'yingyongyonghuguanli',
|
||||||
|
'unicode': 'e6aa',
|
||||||
|
'unicode_decimal': 59050,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '25007161',
|
||||||
|
'name': '品类管理',
|
||||||
|
'font_class': 'shangpinguanli',
|
||||||
|
'unicode': 'fcf3',
|
||||||
|
'unicode_decimal': 64755,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '9206620',
|
||||||
|
'name': '系统管理',
|
||||||
|
'font_class': 'xitongguanli',
|
||||||
|
'unicode': 'e85c',
|
||||||
|
'unicode_decimal': 59484,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '20136570',
|
||||||
|
'name': '菜单管理',
|
||||||
|
'font_class': 'pinleiguanli',
|
||||||
|
'unicode': 'e63d',
|
||||||
|
'unicode_decimal': 58941,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '15689628',
|
||||||
|
'name': '公司审核',
|
||||||
|
'font_class': 'qiyezhuce',
|
||||||
|
'unicode': 'e6a1',
|
||||||
|
'unicode_decimal': 59041,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon_id': '5468041',
|
||||||
|
'name': '审核管理',
|
||||||
|
'font_class': 'shenheguanli',
|
||||||
|
'unicode': 'e639',
|
||||||
|
'unicode_decimal': 58937,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export type IconName = (typeof icons.glyphs)[number]['font_class']
|
||||||
|
|
||||||
|
export interface IconGlyphs {
|
||||||
|
icon_id: string
|
||||||
|
name: string
|
||||||
|
font_class: IconName
|
||||||
|
unicode: string
|
||||||
|
unicode_decimal: number
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -14,8 +14,9 @@
|
||||||
width 100%;
|
width 100%;
|
||||||
overflow auto
|
overflow auto
|
||||||
padding 16px
|
padding 16px
|
||||||
|
|
||||||
box-sizing border-box
|
box-sizing border-box
|
||||||
box-shadow: rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
|
box-shadow: rgba(30, 35, 43, 0.16) 0px 2px 10px 0px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
display flex
|
display flex
|
||||||
flex-direction column
|
flex-direction column
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,11 @@ declare module 'vue' {
|
||||||
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||||
|
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
|
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||||
ElForm: typeof import('element-plus/es')['ElForm']
|
ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
|
|
@ -34,6 +36,7 @@ declare module 'vue' {
|
||||||
ElMain: typeof import('element-plus/es')['ElMain']
|
ElMain: typeof import('element-plus/es')['ElMain']
|
||||||
ElOption: typeof import('element-plus/es')['ElOption']
|
ElOption: typeof import('element-plus/es')['ElOption']
|
||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||||
|
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||||
ElTable: typeof import('element-plus/es')['ElTable']
|
ElTable: typeof import('element-plus/es')['ElTable']
|
||||||
|
|
@ -61,9 +64,11 @@ declare global {
|
||||||
const ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
const ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||||
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||||
const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||||
|
const ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||||
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||||
const ElContainer: typeof import('element-plus/es')['ElContainer']
|
const ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||||
const ElDialog: typeof import('element-plus/es')['ElDialog']
|
const ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
|
const ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||||
const ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
const ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||||
const ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
const ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||||
const ElForm: typeof import('element-plus/es')['ElForm']
|
const ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
|
|
@ -78,6 +83,7 @@ declare global {
|
||||||
const ElMain: typeof import('element-plus/es')['ElMain']
|
const ElMain: typeof import('element-plus/es')['ElMain']
|
||||||
const ElOption: typeof import('element-plus/es')['ElOption']
|
const ElOption: typeof import('element-plus/es')['ElOption']
|
||||||
const ElPagination: typeof import('element-plus/es')['ElPagination']
|
const ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||||
|
const ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
|
||||||
const ElSelect: typeof import('element-plus/es')['ElSelect']
|
const ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||||
const ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
const ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||||
const ElTable: typeof import('element-plus/es')['ElTable']
|
const ElTable: typeof import('element-plus/es')['ElTable']
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ import {
|
||||||
type MenuItemRegistered,
|
type MenuItemRegistered,
|
||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
import { elIcons } from '@/common/element/element.ts'
|
import { elIcons } from '@/common/element/element.ts'
|
||||||
|
import AIcon from '@/components/a-icon/AIcon.tsx'
|
||||||
|
import type { IconName } from '@/components/a-icon/iconfont.ts'
|
||||||
|
import styles from '@/pages/a-frame/aaside.module.styl'
|
||||||
|
|
||||||
export interface Menu extends G.TreeNode {
|
export interface Menu extends G.TreeNode {
|
||||||
// Id
|
// Id
|
||||||
|
|
@ -35,7 +38,7 @@ export interface Menu extends G.TreeNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent(
|
export default defineComponent(
|
||||||
({menus}, {emit}) => {
|
(props, {emit}) => {
|
||||||
const onMenuClick = (it: MenuItemRegistered) => emit('menuClick', it.index)
|
const onMenuClick = (it: MenuItemRegistered) => emit('menuClick', it.index)
|
||||||
const renderMenu = (it: Menu) => {
|
const renderMenu = (it: Menu) => {
|
||||||
let renderChildNode: (() => VNode[] | undefined) | undefined = undefined
|
let renderChildNode: (() => VNode[] | undefined) | undefined = undefined
|
||||||
|
|
@ -47,7 +50,10 @@ export default defineComponent(
|
||||||
case 'Catalog': {
|
case 'Catalog': {
|
||||||
currentNode = (<ElSubMenu index={it.id}>
|
currentNode = (<ElSubMenu index={it.id}>
|
||||||
{{
|
{{
|
||||||
title: () => <span>{it.title}</span>,
|
title: () => (<>
|
||||||
|
<AIcon class={styles.aIcon} name={it.icon as IconName}/>
|
||||||
|
<span>{it.title}</span>
|
||||||
|
</>),
|
||||||
default: renderChildNode,
|
default: renderChildNode,
|
||||||
}}
|
}}
|
||||||
</ElSubMenu>)
|
</ElSubMenu>)
|
||||||
|
|
@ -64,7 +70,8 @@ export default defineComponent(
|
||||||
case 'Page': {
|
case 'Page': {
|
||||||
currentNode = (<ElMenuItem index={it.id} onClick={onMenuClick}>
|
currentNode = (<ElMenuItem index={it.id} onClick={onMenuClick}>
|
||||||
{{
|
{{
|
||||||
default: () => <span>{it.title}</span>,
|
title: () => <span>{it.title}</span>,
|
||||||
|
default: () => <AIcon class={styles.aIcon} name={it.icon as IconName}/>,
|
||||||
}}
|
}}
|
||||||
</ElMenuItem>)
|
</ElMenuItem>)
|
||||||
break
|
break
|
||||||
|
|
@ -77,12 +84,12 @@ export default defineComponent(
|
||||||
const isCollapse = ref(false)
|
const isCollapse = ref(false)
|
||||||
|
|
||||||
return () => (<>
|
return () => (<>
|
||||||
<ElMenu collapse={isCollapse.value} style={{height: '100%', overflow: 'auto', '--el-menu-base-level-padding': '10px'}} class={'menus'}>
|
<ElMenu collapse={isCollapse.value} style={{height: '100%', overflow: 'auto', '--el-menu-base-level-padding': '10px'}} class={[ styles.aMenus, 'menus' ]}>
|
||||||
{{
|
{{
|
||||||
default: () => menus.map(renderMenu),
|
default: () => props.menus.map(renderMenu),
|
||||||
}}
|
}}
|
||||||
</ElMenu>
|
</ElMenu>
|
||||||
<ElButton style={{position: 'absolute', right: 0, bottom: 0, width: '32px', height: '32px'}} onClick={() => {
|
<ElButton style={{position: 'absolute', right: '6px', bottom: '6px', width: '32px', height: '32px'}} onClick={() => {
|
||||||
isCollapse.value = !isCollapse.value
|
isCollapse.value = !isCollapse.value
|
||||||
}}>
|
}}>
|
||||||
<ElIcon style={{cursor: 'pointer'}}>
|
<ElIcon style={{cursor: 'pointer'}}>
|
||||||
|
|
|
||||||
|
|
@ -70,13 +70,15 @@ onUnmounted(() => {
|
||||||
height 100%
|
height 100%
|
||||||
width 100%;
|
width 100%;
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
box-shadow: inset rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
|
||||||
|
background-color #F7F9FC
|
||||||
|
|
||||||
& > header {
|
& > header {
|
||||||
display flex
|
display flex
|
||||||
justify-content space-between
|
justify-content space-between
|
||||||
border-bottom 1px solid #E5E7EB;
|
border-bottom 1px solid #E5E7EB;
|
||||||
height 60px
|
height 60px
|
||||||
|
background-color white
|
||||||
& > div:first-child {
|
& > div:first-child {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -109,10 +111,10 @@ onUnmounted(() => {
|
||||||
& > main {
|
& > main {
|
||||||
height 100%
|
height 100%
|
||||||
width calc(100% - 300px)
|
width calc(100% - 300px)
|
||||||
padding 8px
|
padding 5px
|
||||||
overflow auto
|
overflow auto
|
||||||
background-color #F7F9FC
|
background-color #F7F9FC
|
||||||
box-shadow: inset rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
|
//box-shadow: inset rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
.a-menus {
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-icon {
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: var(--el-menu-icon-width);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,203 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="tool-bar">
|
||||||
|
<ElForm inline @submit.prevent="paging">
|
||||||
|
<ElFormItem>
|
||||||
|
<ElInput
|
||||||
|
v-model="searchForm.dictName"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入要搜索的文字"
|
||||||
|
@clear="reset"/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem>
|
||||||
|
<ElButton :icon="elIcons.Search" :loading="searching" native-type="submit" type="primary">搜索</ElButton>
|
||||||
|
<ElButton :icon="elIcons.Plus" type="primary" @click="addHandler">新建</ElButton>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
</div>
|
||||||
|
<ElTable v-loading="searching" :data="tableData"
|
||||||
|
cell-class-name="table-cell"
|
||||||
|
class="table-list"
|
||||||
|
empty-text="暂无数据"
|
||||||
|
header-row-class-name="table-header"
|
||||||
|
row-key="id">
|
||||||
|
<ElTableColumn label="字典标识" prop="dictKey"/>
|
||||||
|
|
||||||
|
<ElTableColumn label="字典名称" prop="dictName"/>
|
||||||
|
|
||||||
|
<ElTableColumn label="备注" prop="memo"/>
|
||||||
|
|
||||||
|
<ElTableColumn label="操作" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="action-btn">
|
||||||
|
<el-popconfirm
|
||||||
|
cancel-button-text="否"
|
||||||
|
cancel-button-type="primary"
|
||||||
|
confirm-button-text="是"
|
||||||
|
confirm-button-type="danger"
|
||||||
|
placement="top"
|
||||||
|
title="是否删除当前数据?"
|
||||||
|
width="180"
|
||||||
|
@confirm="delHandler(scope)">
|
||||||
|
<template #reference>
|
||||||
|
<ElButton :loading="deling" text type="danger">删除</ElButton>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
<ElButton text type="primary" @click="modifyHandler(scope)">修改</ElButton>
|
||||||
|
<ElButton text type="primary" @click="selectDictHandle(scope)">字典项</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</ElTable>
|
||||||
|
<ElPagination
|
||||||
|
:page-size="pagination.size"
|
||||||
|
:pager-count="pagination.pages"
|
||||||
|
:total="pagination.total"
|
||||||
|
class="pagination"
|
||||||
|
layout="prev, pager, next"
|
||||||
|
@change="pageChangeHandler"/>
|
||||||
|
<DictForm ref="dictForm" @edit-succ="paging"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import DictApi from '@/pages/sys/dict/dict-api.ts'
|
||||||
|
import { elIcons } from '@/common/element/element.ts'
|
||||||
|
import DictForm from '@/pages/sys/dict/DictForm.vue'
|
||||||
|
|
||||||
|
const tableData = ref<DictTypes.SearchDictResult[]>([])
|
||||||
|
const searchForm = reactive<DictTypes.SearchDictParam>(
|
||||||
|
{
|
||||||
|
orders: 'dict_key,id',
|
||||||
|
current: 1,
|
||||||
|
size: 20,
|
||||||
|
})
|
||||||
|
const searching = ref(false)
|
||||||
|
const deling = ref(false)
|
||||||
|
const dictFormIns = useTemplateRef<InstanceType<typeof DictForm>>('dictForm')
|
||||||
|
const pagination = reactive<G.Pagination>({
|
||||||
|
total: 0,
|
||||||
|
pages: 0,
|
||||||
|
current: 1,
|
||||||
|
size: 20,
|
||||||
|
})
|
||||||
|
|
||||||
|
function showDialog(data?: DictTypes.SearchDictResult) {
|
||||||
|
dictFormIns.value?.open(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
function delHandler({row}: { row: DictTypes.SearchDictResult }) {
|
||||||
|
deling.value = true
|
||||||
|
DictApi.del([ row.id! ])
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
paging()
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
deling.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function modifyHandler({row}: { row: DictTypes.SearchDictResult }) {
|
||||||
|
showDialog(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addHandler() {
|
||||||
|
showDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
const emits = defineEmits([ 'searchDict' ])
|
||||||
|
|
||||||
|
function selectDictHandle({row}: { row: DictTypes.SearchDictResult }) {
|
||||||
|
emits('searchDict', row)
|
||||||
|
}
|
||||||
|
|
||||||
|
function pageChangeHandler(currentPage: number, pageSize: number) {
|
||||||
|
searchForm.current = currentPage
|
||||||
|
searchForm.size = pageSize
|
||||||
|
paging()
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
Object.assign(searchForm, {})
|
||||||
|
paging()
|
||||||
|
}
|
||||||
|
|
||||||
|
function paging() {
|
||||||
|
searching.value = true
|
||||||
|
DictApi.paging(searchForm)
|
||||||
|
.then(res => {
|
||||||
|
tableData.value = res.data?.records ?? []
|
||||||
|
Object.assign(pagination, {
|
||||||
|
total: res.data?.total ?? 0,
|
||||||
|
pages: res.data?.pages ?? 0,
|
||||||
|
current: res.data?.current ?? 1,
|
||||||
|
size: res.data?.size ?? 20,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
searching.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
paging()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.table-list {
|
||||||
|
flex 1;
|
||||||
|
width 100%
|
||||||
|
|
||||||
|
:deep(.table-header) {
|
||||||
|
color #454C59
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color #EDF1F7
|
||||||
|
font-weight 500
|
||||||
|
position relative
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display flex
|
||||||
|
gap 5px
|
||||||
|
align-items center
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:first-child) > div::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 1px;
|
||||||
|
width: 1px;
|
||||||
|
background-color: #D3D7DE;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
content: "";
|
||||||
|
height 50%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.table-cell) {
|
||||||
|
color #2F3540
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
width 100%
|
||||||
|
display flex
|
||||||
|
flex-wrap wrap
|
||||||
|
|
||||||
|
& > button {
|
||||||
|
margin 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-bar {
|
||||||
|
display flex
|
||||||
|
justify-content space-between
|
||||||
|
margin 0 0 20px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
justify-content: end;
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -50,30 +50,48 @@
|
||||||
<ElInput v-model="menuForm.routePath" :min="0" placeholder="路由地址"/>
|
<ElInput v-model="menuForm.routePath" :min="0" placeholder="路由地址"/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem
|
<ElFormItem
|
||||||
|
|
||||||
label="编码">
|
label="编码">
|
||||||
<ElInput v-model="menuForm.sn"
|
<ElInput v-model="menuForm.sn"
|
||||||
:disabled="status === 'view'"
|
:disabled="status === 'view'"
|
||||||
:min="0" placeholder="编码"/>
|
:min="0" placeholder="编码"/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem
|
<ElFormItem label="图标">
|
||||||
|
|
||||||
label="图标">
|
|
||||||
<ElDropdown closable header="图标列表"
|
<ElDropdown closable header="图标列表"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
style="width: 100%" trigger="click">
|
style="width: 100%" trigger="click">
|
||||||
<ElInput v-model="menuForm.icon"
|
<ElInput v-model="menuForm.iconName"
|
||||||
|
placeholder="选择图标"
|
||||||
:disabled="status === 'view'"
|
:disabled="status === 'view'"
|
||||||
placeholder="选择图标"/>
|
readonly>
|
||||||
|
<template #suffix>
|
||||||
|
<AIcon :name="menuForm.icon!"/>
|
||||||
|
</template>
|
||||||
|
</ElInput>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<ElTable
|
<div class="dropdown-table-wrapper">
|
||||||
:data="iconTableDataSource"
|
<ElTable
|
||||||
empty-text="暂无数据"
|
ref="dropdownTable"
|
||||||
style="width: 324px;"
|
:data="iconTableDataSource"
|
||||||
>
|
empty-text="暂无数据"
|
||||||
<ElTableColumn label="图标" prop="name"/>
|
highlight-current-row
|
||||||
<ElTableColumn label="名称" prop="name"/>
|
style="width: 324px;"
|
||||||
</ElTable>
|
@current-change="currentChangeHandler"
|
||||||
|
>
|
||||||
|
<ElTableColumn label="#" type="index"/>
|
||||||
|
<ElTableColumn label="图标" prop="font_class">
|
||||||
|
<template #default="scope">
|
||||||
|
<AIcon :name="scope?.row?.font_class"/>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="名称" prop="name"/>
|
||||||
|
</ElTable>
|
||||||
|
<ElPagination
|
||||||
|
:page-size="pagination.size"
|
||||||
|
:pager-count="pagination.pages"
|
||||||
|
:total="pagination.total"
|
||||||
|
layout="prev, pager, next"
|
||||||
|
@change="pageChangeHandler"/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</ElDropdown>
|
</ElDropdown>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
|
|
@ -86,7 +104,6 @@
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
|
|
||||||
</ElForm>
|
</ElForm>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||||
|
|
@ -104,39 +121,52 @@ import {
|
||||||
import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
||||||
import Colls from '@/common/utils/colls.ts'
|
import Colls from '@/common/utils/colls.ts'
|
||||||
import Strings from '@/common/utils/strings.ts'
|
import Strings from '@/common/utils/strings.ts'
|
||||||
import { ElMessage } from 'element-plus'
|
import {
|
||||||
|
ElMessage,
|
||||||
|
type TableInstance,
|
||||||
|
} from 'element-plus'
|
||||||
|
import {
|
||||||
|
type IconGlyphs,
|
||||||
|
icons,
|
||||||
|
} from '@/components/a-icon/iconfont.ts'
|
||||||
|
import AIcon from '@/components/a-icon/AIcon.tsx'
|
||||||
|
|
||||||
interface IconData {
|
const pagination = reactive<G.Pagination>({
|
||||||
name: string
|
total: icons.glyphs.length,
|
||||||
|
pages: Math.ceil(icons.glyphs.length / 5),
|
||||||
|
current: 1,
|
||||||
|
size: 5,
|
||||||
|
})
|
||||||
|
|
||||||
|
function pageChangeHandler(currentPage: number, pageSize: number) {
|
||||||
|
pagination.current = currentPage
|
||||||
|
pagination.size = pageSize
|
||||||
|
iconTableDataSource.value = icons.glyphs.filter((_, i) => {
|
||||||
|
return i >= (currentPage - 1) * pageSize && i < currentPage * pageSize
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedRowKeys = ref<string[]>([])
|
const dropdownTableIns = useTemplateRef<TableInstance>('dropdownTable')
|
||||||
|
|
||||||
const iconTableDataSource = ref<IconData[]>([].filter((_, i) => {
|
const menuForm = reactive<MenuTypes.MenuForm>({
|
||||||
|
icon: 'dianzixiaopiao',
|
||||||
|
})
|
||||||
|
|
||||||
|
const iconTableDataSource = ref<IconGlyphs[]>(icons.glyphs.filter((_, i) => {
|
||||||
return i >= 0 && i < 5
|
return i >= 0 && i < 5
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
function currentChangeHandler(val?: IconGlyphs) {
|
||||||
|
console.log(val)
|
||||||
|
if (val == null) return
|
||||||
|
menuForm.icon = val.font_class
|
||||||
|
menuForm.iconName = val.name
|
||||||
|
}
|
||||||
|
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const submiting = ref(false)
|
const submiting = ref(false)
|
||||||
const status = ref<'add' | 'view' | 'modify'>('add')
|
const status = ref<'add' | 'view' | 'modify'>('add')
|
||||||
|
|
||||||
const pagination = reactive({
|
|
||||||
pageIndex: 1,
|
|
||||||
pageSize: 5,
|
|
||||||
total: 20,
|
|
||||||
size: 'sm',
|
|
||||||
showTotal: true,
|
|
||||||
onChange(pageIndex: number, pageSize: number) {
|
|
||||||
pagination.pageIndex = pageIndex
|
|
||||||
pagination.pageSize = pageSize
|
|
||||||
iconTableDataSource.value = [].filter((_, i) => {
|
|
||||||
return i >= (pageIndex - 1) * pageSize && i < pageIndex * pageSize
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const menuForm = reactive<MenuTypes.MenuForm>({})
|
|
||||||
|
|
||||||
const menuCategoryData = computed(() => {
|
const menuCategoryData = computed(() => {
|
||||||
const data: { key: string, label: string }[] = []
|
const data: { key: string, label: string }[] = []
|
||||||
for (const key in MenuCategoryDict) {
|
for (const key in MenuCategoryDict) {
|
||||||
|
|
@ -179,10 +209,8 @@ defineExpose({
|
||||||
}
|
}
|
||||||
Object.assign(menuForm, data)
|
Object.assign(menuForm, data)
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
if (data.icon != null) {
|
dropdownTableIns.value?.setCurrentRow(icons.glyphs.find(it => it.font_class === data.icon))
|
||||||
selectedRowKeys.value = [ data.icon ]
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
@ -199,4 +227,13 @@ onMounted(() => {
|
||||||
.menu-form {
|
.menu-form {
|
||||||
padding 20px
|
padding 20px
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-table-wrapper {
|
||||||
|
padding 10px
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
align-items end
|
||||||
|
justify-content space-between
|
||||||
|
gap 10px
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,15 @@
|
||||||
header-row-class-name="table-header"
|
header-row-class-name="table-header"
|
||||||
lazy
|
lazy
|
||||||
row-key="id">
|
row-key="id">
|
||||||
<ElTableColumn label="图标" prop="icon" width="60"/>
|
<!-- <ElTableColumn type="expand" width="60"/> -->
|
||||||
|
<ElTableColumn label="图标" prop="icon" width="60">
|
||||||
|
<template #default="scope">
|
||||||
|
<AIcon :name="scope.row.icon"/>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
<ElTableColumn label="类型" prop="menuCategoryTxt" width="140"/>
|
<ElTableColumn label="类型" prop="menuCategoryTxt" width="140"/>
|
||||||
<ElTableColumn label="菜单名称" prop="title"/>
|
<ElTableColumn label="菜单名称" prop="title"/>
|
||||||
|
<ElTableColumn label="编码" prop="sn" width="80"/>
|
||||||
<!-- <ElTableColumn label="路径" prop="breadcrumb"/> -->
|
<!-- <ElTableColumn label="路径" prop="breadcrumb"/> -->
|
||||||
<ElTableColumn label="路由名称" prop="routeName">
|
<ElTableColumn label="路由名称" prop="routeName">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|
@ -47,7 +53,19 @@
|
||||||
<!-- <ElTableColumn label="排序" prop="sort" width="60"/> -->
|
<!-- <ElTableColumn label="排序" prop="sort" width="60"/> -->
|
||||||
<ElTableColumn label="操作" width="180">
|
<ElTableColumn label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<ElButton text type="danger" @click="delHandler(scope)">删除</ElButton>
|
<el-popconfirm
|
||||||
|
cancel-button-text="否"
|
||||||
|
cancel-button-type="primary"
|
||||||
|
confirm-button-text="是"
|
||||||
|
confirm-button-type="danger"
|
||||||
|
placement="top"
|
||||||
|
title="是否删除当前数据?"
|
||||||
|
width="180"
|
||||||
|
@confirm="delHandler(scope)">
|
||||||
|
<template #reference>
|
||||||
|
<ElButton :loading="deling" text type="danger">删除</ElButton>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
<ElButton text type="primary" @click="modifyHandler(scope)">修改</ElButton>
|
<ElButton text type="primary" @click="modifyHandler(scope)">修改</ElButton>
|
||||||
</template>
|
</template>
|
||||||
</ElTableColumn>
|
</ElTableColumn>
|
||||||
|
|
@ -65,19 +83,28 @@ import { onMounted } from 'vue'
|
||||||
import { elIcons } from '@/common/element/element.ts'
|
import { elIcons } from '@/common/element/element.ts'
|
||||||
import MenuForm from '@/pages/sys/menus/MenuForm.vue'
|
import MenuForm from '@/pages/sys/menus/MenuForm.vue'
|
||||||
import Strings from '@/common/utils/strings.ts'
|
import Strings from '@/common/utils/strings.ts'
|
||||||
|
import AIcon from '@/components/a-icon/AIcon.tsx'
|
||||||
|
|
||||||
const tableData = ref<MenuTypes.SysMenu[]>([])
|
const tableData = ref<MenuTypes.SysMenu[]>([])
|
||||||
const searchForm = reactive<MenuTypes.SearchForm>({})
|
const searchForm = reactive<MenuTypes.SearchForm>({})
|
||||||
const searching = ref(false)
|
const searching = ref(false)
|
||||||
const showSearchForm = ref(true)
|
const showSearchForm = ref(true)
|
||||||
const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm')
|
const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm')
|
||||||
|
const deling = ref(false)
|
||||||
|
|
||||||
function showDialog(data?: MenuTypes.MenuForm) {
|
function showDialog(data?: MenuTypes.MenuForm) {
|
||||||
menuFormIns.value?.open(data)
|
menuFormIns.value?.open(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
function delHandler({row}: { row: MenuTypes.MenuForm, }) {
|
function delHandler({row}: { row: MenuTypes.MenuForm, }) {
|
||||||
|
deling.value = true
|
||||||
|
|
||||||
MenuApi.del([ row.id! ])
|
MenuApi.del([ row.id! ])
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
listAll()
|
||||||
|
})
|
||||||
|
.finally(() => deling.value = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function modifyHandler({row}: { row: MenuTypes.MenuForm, }) {
|
function modifyHandler({row}: { row: MenuTypes.MenuForm, }) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { MenuCategory } from '@/common/app/contants'
|
import { MenuCategory } from '@/common/app/contants'
|
||||||
|
import type { IconName } from '@/components/a-icon/iconfont.ts'
|
||||||
|
|
||||||
export {}
|
export {}
|
||||||
|
|
||||||
|
|
@ -45,7 +46,8 @@ declare global {
|
||||||
// 菜单名称
|
// 菜单名称
|
||||||
title?: string
|
title?: string
|
||||||
// 图标
|
// 图标
|
||||||
icon?: string
|
icon?: IconName
|
||||||
|
iconName?: string
|
||||||
// 排序
|
// 排序
|
||||||
sort?: number
|
sort?: number
|
||||||
// 路由名称
|
// 路由名称
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Page from '@/components/page/Page.vue'
|
||||||
|
import SnConfigApi from '@/pages/sys/sn-config/sn-config-api.ts'
|
||||||
|
import { descConfig } from '@/pages/sys/sn-config/sn-config-util.ts'
|
||||||
|
import SnConfigForm from '@/pages/sys/sn-config/SnConfigForm.vue'
|
||||||
|
import Strings from '@/common/utils/strings.ts'
|
||||||
|
import { elIcons } from '@/common/element/element.ts'
|
||||||
|
|
||||||
|
const snConfigForm = ref<InstanceType<typeof SnConfigForm> | null>(null)
|
||||||
|
|
||||||
|
function addHandler() {
|
||||||
|
snConfigForm.value?.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
Object.assign(searchForm, {})
|
||||||
|
searchHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchForm = reactive<SnConfigTypes.SearchSnConfigParam>({
|
||||||
|
snname: undefined,
|
||||||
|
sncode: undefined,
|
||||||
|
})
|
||||||
|
const pagination = reactive<G.Pagination>({
|
||||||
|
total: 0,
|
||||||
|
pages: 0,
|
||||||
|
current: 1,
|
||||||
|
size: 20,
|
||||||
|
})
|
||||||
|
const searching = ref(false)
|
||||||
|
|
||||||
|
function pageChangeHandler(currentPage: number, pageSize: number) {
|
||||||
|
searchForm.current = currentPage
|
||||||
|
searchForm.size = pageSize
|
||||||
|
searchHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const datasource = ref<SnConfigTypes.SnConfigDetail[]>([])
|
||||||
|
|
||||||
|
function searchHandler() {
|
||||||
|
searching.value = true
|
||||||
|
SnConfigApi.paging(searchForm, {...pagination})
|
||||||
|
.then((res) => {
|
||||||
|
pagination.current = res.data.current
|
||||||
|
pagination.size = res.data.size
|
||||||
|
pagination.total = res.data.total
|
||||||
|
datasource.value = res.data.records.map((it) => ({
|
||||||
|
key: it.id,
|
||||||
|
...it,
|
||||||
|
configDesc: descConfig(it.config).join('\n'),
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
searching.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function modify(record: SnConfigTypes.SnConfigDetail) {
|
||||||
|
snConfigForm.value?.open(record)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function del(record: SnConfigTypes.SnConfigDetail) {
|
||||||
|
console.log(record)
|
||||||
|
SnConfigApi.del(record.id)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
searchHandler()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
searchHandler()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Page>
|
||||||
|
<ElForm class="search-form" inline @submit.prevent="searchHandler">
|
||||||
|
<ElFormItem :gutter="[0, 10]" label="规则名称">
|
||||||
|
<ElInput clearable control="snname" placeholder="请输入规则名称"/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem :gutter="[0, 10]" label="规则代码">
|
||||||
|
<ElInput clearable control="sncode" placeholder="请输入规则代码"/>
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem>
|
||||||
|
<ElButton :icon="elIcons.Search" :loading="searching" native-type="submit" type="primary">搜索</ElButton>
|
||||||
|
<ElButton :icon="elIcons.Refresh" :loading="searching" @click="reset">重置</ElButton>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
<div class="tool-bar">
|
||||||
|
|
||||||
|
<ElButton :icon="elIcons.Plus" type="primary" @click="addHandler">新建</ElButton>
|
||||||
|
</div>
|
||||||
|
<ElTable
|
||||||
|
v-loading="searching" :data="datasource"
|
||||||
|
cell-class-name="table-cell"
|
||||||
|
class="table-list"
|
||||||
|
empty-text="暂无数据"
|
||||||
|
header-row-class-name="table-header"
|
||||||
|
row-key="id">
|
||||||
|
<ElTableColumn label="规则名称" prop="snname" width="140"/>
|
||||||
|
<ElTableColumn label="规则代码" prop="sncode" width="140"/>
|
||||||
|
<ElTableColumn label="示例" prop="example" width="140"/>
|
||||||
|
<ElTableColumn label="配置信息" prop="configDesc">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>
|
||||||
|
{{ Strings.isBlank(scope.row.configDesc) ? '' : scope.row.configDesc.split('\n') }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="备注" prop="memo" width="140"/>
|
||||||
|
<ElTableColumn label="备注" prop="memo" width="140"/>
|
||||||
|
<ElTableColumn label="" prop=""/>
|
||||||
|
|
||||||
|
<ElTableColumn label="操作" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-popconfirm
|
||||||
|
cancel-button-text="否"
|
||||||
|
cancel-button-type="primary"
|
||||||
|
confirm-button-text="是"
|
||||||
|
confirm-button-type="danger"
|
||||||
|
placement="top"
|
||||||
|
title="是否删除当前数据?"
|
||||||
|
width="180"
|
||||||
|
@confirm="del(scope)">
|
||||||
|
<template #reference>
|
||||||
|
<ElButton text type="danger">删除</ElButton>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
<ElButton text type="primary" @click="modify(scope)">修改</ElButton>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
|
||||||
|
</ElTable>
|
||||||
|
<ElPagination
|
||||||
|
:page-size="pagination.size"
|
||||||
|
:pager-count="pagination.pages"
|
||||||
|
:total="pagination.total"
|
||||||
|
class="pagination"
|
||||||
|
layout="prev, pager, next"
|
||||||
|
@change="pageChangeHandler"/>
|
||||||
|
<SnConfigForm ref="snConfigForm" @close="searchHandler"/>
|
||||||
|
</Page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.pagination {
|
||||||
|
justify-content: end;
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,447 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Utils from '@/common/utils'
|
||||||
|
import SnConfigApi from '@/pages/sys/sn-config/sn-config-api.ts'
|
||||||
|
import Strings from '@/common/utils/strings.ts'
|
||||||
|
import SnConfigUtil from '@/pages/sys/sn-config/sn-config-util.ts'
|
||||||
|
import {
|
||||||
|
PadMode,
|
||||||
|
RandomMode,
|
||||||
|
Rollback,
|
||||||
|
SectionName,
|
||||||
|
TimeUnit,
|
||||||
|
} from '@/pages/sys/sn-config/contant.ts'
|
||||||
|
import Colls from '@/common/utils/colls.ts'
|
||||||
|
|
||||||
|
defineOptions({name: 'SnConfigForm'})
|
||||||
|
const emits = defineEmits([ 'close' ])
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const modify = ref(false)
|
||||||
|
|
||||||
|
const snConfig = reactive<SnConfigTypes.SnConfigDetail>({
|
||||||
|
id: '',
|
||||||
|
snname: '',
|
||||||
|
sncode: '',
|
||||||
|
example: '',
|
||||||
|
config: [],
|
||||||
|
memo: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
function clearConfig() {
|
||||||
|
snConfig.config = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCloseHandler() {
|
||||||
|
visible.value = false
|
||||||
|
Object.assign(snConfig, {
|
||||||
|
id: '',
|
||||||
|
snname: '',
|
||||||
|
sncode: '',
|
||||||
|
example: '',
|
||||||
|
config: [],
|
||||||
|
memo: '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkConfig() {
|
||||||
|
const {id, snname, sncode, config} = snConfig
|
||||||
|
if (modify.value) {
|
||||||
|
if (Strings.isBlank(id)) {
|
||||||
|
ElMessage.error('未指定要修改的规则')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Strings.isBlank(snname)) {
|
||||||
|
ElMessage.error('请输入规则名称')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (Strings.isBlank(sncode)) {
|
||||||
|
ElMessage.error('请输入规则编码')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Colls.isEmpty(config)) {
|
||||||
|
ElMessage.error('请配置规则')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function processConfig(configs: SnConfigTypes.Section[]): SnConfigTypes.Section[] {
|
||||||
|
return configs.map(it => {
|
||||||
|
switch (it.sectionName) {
|
||||||
|
case 'ShiJian': {
|
||||||
|
const {sectionName, timestamp, pattern, unit} = it as SnConfigTypes.TimeSectionConfig
|
||||||
|
return {
|
||||||
|
sectionName,
|
||||||
|
timestamp,
|
||||||
|
pattern: timestamp ? undefined : pattern,
|
||||||
|
unit: !timestamp ? undefined : unit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'ZiZeng': {
|
||||||
|
const {sectionName, code, step, initialVal, padMode, padVal, padLen, rollback, allowOverflow} = it as SnConfigTypes.IncSectionConfig
|
||||||
|
return {
|
||||||
|
sectionName, code, step, initialVal, padMode,
|
||||||
|
padVal: padMode === 'Wu' ? '' : padVal,
|
||||||
|
padLen: padMode === 'Wu' ? 0 : padLen,
|
||||||
|
rollback, allowOverflow,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'SuiJi': {
|
||||||
|
const {sectionName, randomMode, workerId, datacenterId, nanoIdSize} = it as SnConfigTypes.RandomSectionConfig
|
||||||
|
return {
|
||||||
|
sectionName, randomMode,
|
||||||
|
workerId: randomMode !== 'Snowflake' ? undefined : workerId,
|
||||||
|
datacenterId: randomMode !== 'Snowflake' ? undefined : datacenterId,
|
||||||
|
nanoIdSize: randomMode !== 'NanoId' ? undefined : nanoIdSize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'GuDing': {
|
||||||
|
const {sectionName, code, value} = it as SnConfigTypes.FixedSectionConfig
|
||||||
|
return {
|
||||||
|
sectionName, code, value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`不支持的配置项: ${it.sectionName}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const pici = ref<string>('')
|
||||||
|
const showPici = computed(() => {
|
||||||
|
let show = false
|
||||||
|
for (let c of snConfig.config) {
|
||||||
|
if (c.sectionName === 'ZiZeng') {
|
||||||
|
if ((c as SnConfigTypes.IncSectionConfig).rollback === 'Pi') {
|
||||||
|
show = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return show
|
||||||
|
})
|
||||||
|
|
||||||
|
function testSn() {
|
||||||
|
SnConfigApi.next(snConfig.sncode, Strings.isBlank(pici.value) ? undefined : pici.value)
|
||||||
|
.then(res => {
|
||||||
|
ElMessage.success(`下一个编码: ${res.data}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
SnConfigApi.reset(snConfig.sncode)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success('重置成功')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSaveHandler() {
|
||||||
|
if (!checkConfig()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let {id, snname, sncode, config, memo} = Utils.clone(snConfig)
|
||||||
|
config = processConfig(config)
|
||||||
|
if (modify.value) {
|
||||||
|
SnConfigApi.modify({id, snname, sncode, config, memo})
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success('保存成功')
|
||||||
|
emits('close')
|
||||||
|
// onCloseHandler()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
SnConfigApi.add({
|
||||||
|
snname, sncode, config, memo,
|
||||||
|
}).then(() => {
|
||||||
|
ElMessage.success('保存成功')
|
||||||
|
emits('close')
|
||||||
|
// onCloseHandler()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSection(sectionName: SnConfigTypes.SectionType) {
|
||||||
|
const section = SnConfigUtil.createSection(sectionName)
|
||||||
|
section.sectionDesc = SnConfigUtil.descSection(section)
|
||||||
|
snConfig.config.push(section)
|
||||||
|
}
|
||||||
|
|
||||||
|
function delSection(index: number) {
|
||||||
|
snConfig.config.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveUp(index: number) {
|
||||||
|
if (index > 0) {
|
||||||
|
const section = snConfig.config[index]
|
||||||
|
snConfig.config[index] = snConfig.config[index - 1]
|
||||||
|
snConfig.config[index - 1] = section
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveDown(index: number) {
|
||||||
|
if (index < snConfig.config.length - 1) {
|
||||||
|
const section = snConfig.config[index]
|
||||||
|
snConfig.config[index] = snConfig.config[index + 1]
|
||||||
|
snConfig.config[index + 1] = section
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const expandedKeys = computed(() => snConfig.config.map((_, i) => i))
|
||||||
|
|
||||||
|
const arrowDropdownVisible = ref(false)
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open(data?: SnConfigTypes.SnConfigDetail) {
|
||||||
|
if (data == null) {
|
||||||
|
modify.value = false
|
||||||
|
} else {
|
||||||
|
modify.value = true
|
||||||
|
const source = Utils.clone(data)
|
||||||
|
Object.assign(snConfig, source)
|
||||||
|
}
|
||||||
|
visible.value = true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ElDialog v-model="visible" :title="Strings.isBlank(snConfig.id) ? '新增编码配置' : '修改编码配置'" width="950px"
|
||||||
|
@close="onCloseHandler">
|
||||||
|
<div class="config-panel">
|
||||||
|
<div class="config-title">
|
||||||
|
<div>
|
||||||
|
<ElInput v-model="snConfig.snname" clearable placeholder="规则名称"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ElInput v-model="snConfig.sncode" clearable placeholder="规则编码"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<ElInput v-model="snConfig.memo" clearable max-count="128" placeholder="备注" resize="none" showCount type="textarea"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="config-detail">
|
||||||
|
<ElCollapse v-if="!Colls.isEmpty(snConfig.config)" :expandedKeys="expandedKeys">
|
||||||
|
<ElCollapse v-for="(section, i) in snConfig.config" :key="i">
|
||||||
|
<template #header=" ">
|
||||||
|
<ElHeader :title="(i + 1 )+'、'+SnConfigUtil.descSection(section)">
|
||||||
|
<template #suffix>
|
||||||
|
<ElButtonGroup gap="20px" mode="text" @click.stop>
|
||||||
|
<ElPopconfirm :title="'是否删除配置?'" placement="top" @ok.stop="delSection(i)">
|
||||||
|
<ElButton danger icon="delete"/>
|
||||||
|
</ElPopconfirm>
|
||||||
|
<ElTooltip v-if="i > 0" placement="top" title="上移">
|
||||||
|
<ElButton icon="up" @click.stop="moveUp(i)"/>
|
||||||
|
</ElTooltip>
|
||||||
|
<ElTooltip v-if="i < snConfig.config.length - 1" placement="top" title="下移">
|
||||||
|
<ElButton icon="down" @click.stop="moveDown(i)"/>
|
||||||
|
</ElTooltip>
|
||||||
|
</ElButtonGroup>
|
||||||
|
</template>
|
||||||
|
</ElHeader>
|
||||||
|
</template>
|
||||||
|
<template v-if="section.sectionName === 'GuDing'">
|
||||||
|
<div class="config-item">
|
||||||
|
<div>
|
||||||
|
<div>固定值</div>
|
||||||
|
<ElInput v-model="(section as SnConfigTypes.FixedSectionConfig).value" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="section.sectionName === 'ShiJian'">
|
||||||
|
<div class="config-item">
|
||||||
|
<div>
|
||||||
|
<div>使用时间戳</div>
|
||||||
|
<ElSwitch v-model="(section as SnConfigTypes.TimeSectionConfig).timestamp" :labels="['是', '否']"/>
|
||||||
|
<div class="config-item-padding"></div>
|
||||||
|
</div>
|
||||||
|
<div v-if="(section as SnConfigTypes.TimeSectionConfig).timestamp">
|
||||||
|
<div>时间单位</div>
|
||||||
|
<ElSelect v-model="(section as SnConfigTypes.TimeSectionConfig).unit" clearable placeholder="请选择">
|
||||||
|
<ElOption v-for="(val, key) in TimeUnit" :key="'TimeUnit' + key" :label="val" :value="key"/>
|
||||||
|
</ElSelect>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div>时间格式</div>
|
||||||
|
<ElInput v-model="(section as SnConfigTypes.TimeSectionConfig).pattern" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="section.sectionName === 'ZiZeng'">
|
||||||
|
<div class="config-item">
|
||||||
|
<div>
|
||||||
|
<div>步长</div>
|
||||||
|
<ElInputNumber v-model="(section as SnConfigTypes.IncSectionConfig).step" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>初始值</div>
|
||||||
|
<ElInputNumber v-model="(section as SnConfigTypes.IncSectionConfig).initialVal" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>填充模式</div>
|
||||||
|
<ElSelect v-model="(section as SnConfigTypes.IncSectionConfig).padMode" placeholder="请选择">
|
||||||
|
<ElOption v-for="(val, key) in PadMode" :key="'PadMode' + key" :label="val" :value="key"/>
|
||||||
|
</ElSelect>
|
||||||
|
</div>
|
||||||
|
<div v-if="(section as SnConfigTypes.IncSectionConfig).padMode !== 'Wu'">
|
||||||
|
<div>填充字符</div>
|
||||||
|
<ElInput v-model="(section as SnConfigTypes.IncSectionConfig).padVal" clearable maxlength="1" minlength="1" placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
<div v-if="(section as SnConfigTypes.IncSectionConfig).padMode !== 'Wu'">
|
||||||
|
<div>填充长度</div>
|
||||||
|
<ElInputNumber v-model="(section as SnConfigTypes.IncSectionConfig).padLen" :max="20" :min="1" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>回卷模式</div>
|
||||||
|
<ElSelect v-model="(section as SnConfigTypes.IncSectionConfig).rollback" clearable placeholder="请选择">
|
||||||
|
<ElOption v-for="(val, key) in Rollback" :key="'rollback-' + key" :label="val" :value="key"/>
|
||||||
|
</ElSelect>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>允许溢出</div>
|
||||||
|
<ElSwitch v-model="(section as SnConfigTypes.IncSectionConfig).allowOverflow" :labels="['是', '否']"/>
|
||||||
|
<div class="config-item-padding"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-if="section.sectionName === 'SuiJi'">
|
||||||
|
<div class="config-item">
|
||||||
|
<div>
|
||||||
|
<div>随机模式</div>
|
||||||
|
<ElSelect v-model="(section as SnConfigTypes.RandomSectionConfig).randomMode" clearable placeholder="请选择">
|
||||||
|
<ElOption v-for="(val, key) in RandomMode" :key="'RandomMode' + key" :label="val" :value="key"/>
|
||||||
|
</ElSelect>
|
||||||
|
</div>
|
||||||
|
<div v-if="(section as SnConfigTypes.RandomSectionConfig).randomMode === 'Snowflake'">
|
||||||
|
<div>工作节点</div>
|
||||||
|
<ElInputNumber v-model="(section as SnConfigTypes.RandomSectionConfig).workerId" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
<div v-if="(section as SnConfigTypes.RandomSectionConfig).randomMode === 'Snowflake'">
|
||||||
|
<div>数据中心</div>
|
||||||
|
<ElInputNumber v-model="(section as SnConfigTypes.RandomSectionConfig).datacenterId" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
<div v-if="(section as SnConfigTypes.RandomSectionConfig).randomMode === 'NanoId'">
|
||||||
|
<div>长度</div>
|
||||||
|
<ElInputNumber v-model="(section as SnConfigTypes.RandomSectionConfig).nanoIdSize" clearable placeholder="请输入"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElCollapse>
|
||||||
|
</ElCollapse>
|
||||||
|
<ElEmpty v-else/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<ElButton mode="default" @click="onCloseHandler">关闭</ElButton>
|
||||||
|
<ElPopconfirm v-if="snConfig.sncode === 'CS' && showPici" placement="top" title="填写批次" @ok="testSn">
|
||||||
|
<ElButton danger mode="default">测试</ElButton>
|
||||||
|
<template #content>
|
||||||
|
<ElFormItem compact label="批次" required>
|
||||||
|
<ElInput v-model="pici"/>
|
||||||
|
</ElFormItem>
|
||||||
|
</template>
|
||||||
|
</ElPopconfirm>
|
||||||
|
<ElButton v-if="snConfig.sncode === 'CS' && !showPici" danger mode="default" @click="testSn">测试</ElButton>
|
||||||
|
<ElButton v-if="snConfig.sncode === 'CS'" danger mode="default" @click="reset">重置</ElButton>
|
||||||
|
<ElPopconfirm :title="'是否清空配置?'" placement="top" @ok.stop="clearConfig">
|
||||||
|
<ElButton danger mode="default">清空配置</ElButton>
|
||||||
|
</ElPopconfirm>
|
||||||
|
<ElButton mode="primary" @click="onSaveHandler">保存</ElButton>
|
||||||
|
<ElDropdown v-modelvisible="arrowDropdownVisible">
|
||||||
|
<ElButton mode="primary">
|
||||||
|
<div class="flex-center">
|
||||||
|
添加配置
|
||||||
|
<ElIcon :rotate="arrowDropdownVisible ? -180 : 0" name="down" size="16px" style="margin-left: 4px"></ElIcon>
|
||||||
|
</div>
|
||||||
|
</ElButton>
|
||||||
|
<template #dropdown>
|
||||||
|
<div class="dropdown-panel">
|
||||||
|
<ElButton v-for="(val, key) in SectionName" :key="'SectionName' + key" class="dropdown-item" mode="text" @click="addSection(key)">{{ val }}</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDropdown>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.config-panel {
|
||||||
|
width 100%
|
||||||
|
height 500px
|
||||||
|
display flex
|
||||||
|
justify-content space-between
|
||||||
|
|
||||||
|
.config-title {
|
||||||
|
width: 200px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
& > div:nth-child(3) {
|
||||||
|
flex 1
|
||||||
|
|
||||||
|
:deep(.ix-textarea) {
|
||||||
|
height 100%
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
height 100%
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-detail {
|
||||||
|
flex 1
|
||||||
|
height 100%
|
||||||
|
padding .5rem
|
||||||
|
display: flex
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.config-item {
|
||||||
|
display: flex
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display flex
|
||||||
|
align-items center
|
||||||
|
justify-content space-between
|
||||||
|
|
||||||
|
& > div:first-child {
|
||||||
|
width 80px
|
||||||
|
flex-shrink 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-item-padding {
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ix-collapse) {
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
overflow auto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.dropdown-panel {
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
margin .5rem
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
height 2rem
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom 1px solid #E5E5E5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
export const SectionName = {
|
||||||
|
GuDing: '固定值',
|
||||||
|
ShiJian: '时间值',
|
||||||
|
ZiZeng: '增量值',
|
||||||
|
SuiJi: '随机值',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TimeUnit = {
|
||||||
|
1: '毫秒',
|
||||||
|
1000: '秒',
|
||||||
|
60000: '分',
|
||||||
|
3600000: '时',
|
||||||
|
86400000: '天',
|
||||||
|
}
|
||||||
|
export const PadMode = {
|
||||||
|
Wu: '不填充',
|
||||||
|
Zuo: '左填充',
|
||||||
|
You: '右填充',
|
||||||
|
}
|
||||||
|
export const RandomMode = {
|
||||||
|
Snowflake: '雪花码',
|
||||||
|
NanoId: '唯一识别码(NanoId)',
|
||||||
|
UUID: '通用唯一识别码(UUID)',
|
||||||
|
}
|
||||||
|
export const Rollback = {
|
||||||
|
Wu: '不回卷',
|
||||||
|
Pi: '按批',
|
||||||
|
Ri: '按天',
|
||||||
|
Zhou: '按周',
|
||||||
|
Yue: '按月',
|
||||||
|
Nian: '按年',
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
export default {
|
||||||
|
component: () => import('@/pages/sys/sn-config/SnConfig.vue'),
|
||||||
|
} as RouterTypes.RouteConfig
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import {
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
} from '@/common/utils/http-util.ts'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
paging(data: SnConfigTypes.SearchSnConfigParam, {size, current, orders}: G.PageParam) {
|
||||||
|
return get<G.PageResult<SnConfigTypes.SnConfigDetail>>('/sys_sn_config/paging', {
|
||||||
|
size, current, orders,
|
||||||
|
...data,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
modify(data: SnConfigTypes.ModifySnConfigParam) {
|
||||||
|
return post('/sys_sn_config/modify', data)
|
||||||
|
},
|
||||||
|
add(data: SnConfigTypes.AddSnConfigParam) {
|
||||||
|
return post('/sys_sn_config/add', data)
|
||||||
|
},
|
||||||
|
reset(sncode: string) {
|
||||||
|
return get('/sys_sn_config/reset', {sncode})
|
||||||
|
},
|
||||||
|
next(sncode: string, pici?: string) {
|
||||||
|
return get<string>('/sys_sn_config/next', {sncode, pici})
|
||||||
|
},
|
||||||
|
del(...id: string[]) {
|
||||||
|
return post('/sys_sn_config/del', id)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
import {
|
||||||
|
PadMode,
|
||||||
|
RandomMode,
|
||||||
|
Rollback,
|
||||||
|
SectionName,
|
||||||
|
TimeUnit,
|
||||||
|
} from '@/pages/sys/sn-config/contant.ts'
|
||||||
|
import Colls from '@/common/utils/colls.ts'
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
|
|
||||||
|
export function descGuDingSection(section: SnConfigTypes.FixedSectionConfig) {
|
||||||
|
return `${SectionName.GuDing}:${section.value}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function descShiJianSection(section: SnConfigTypes.TimeSectionConfig) {
|
||||||
|
return `${SectionName.ShiJian}:${section.timestamp ? (section.unit != null ? TimeUnit[section.unit!] + '(时间戳)' : '(时间戳)') : section.pattern}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function descZhiZengSection(section: SnConfigTypes.IncSectionConfig) {
|
||||||
|
if (section.padMode === 'Wu') {
|
||||||
|
return `${SectionName.ZiZeng}:初始值为:${section.initialVal},步长为:${section.step},${PadMode[section.padMode]}字符,${Rollback[section.rollback] ?? Rollback.Wu},${section.allowOverflow ? '允许溢出' : '不允许溢出'}`
|
||||||
|
} else {
|
||||||
|
return `${SectionName.ZiZeng}:初始值为:${section.initialVal},步长为:${section.step},${PadMode[section.padMode]}(${section.padLen} 个字符:${section.padVal}),${Rollback[section.rollback] ?? Rollback.Wu},${section.allowOverflow ? '允许溢出' : '不允许溢出'}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function descSuiJiSection(section: SnConfigTypes.RandomSectionConfig) {
|
||||||
|
switch (section.randomMode) {
|
||||||
|
case 'Snowflake':
|
||||||
|
return `${SectionName.SuiJi}:${RandomMode[section.randomMode]}(工作节点:${section.workerId ?? ''},数据中心:${section.datacenterId ?? ''})`
|
||||||
|
case 'NanoId':
|
||||||
|
return `${SectionName.SuiJi}:${RandomMode[section.randomMode]}(长度:${section.nanoIdSize ?? ''})`
|
||||||
|
case 'UUID':
|
||||||
|
return `${SectionName.SuiJi}:${RandomMode[section.randomMode]}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function descConfig(sections: SnConfigTypes.Section[]) {
|
||||||
|
if (Colls.isEmpty(sections)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return sections.map(it => descSection(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function descSection(section: SnConfigTypes.Section) {
|
||||||
|
switch (section.sectionName) {
|
||||||
|
case 'GuDing':
|
||||||
|
return descGuDingSection(section as SnConfigTypes.FixedSectionConfig)
|
||||||
|
case 'ShiJian':
|
||||||
|
return descShiJianSection(section as SnConfigTypes.TimeSectionConfig)
|
||||||
|
case 'ZiZeng':
|
||||||
|
return descZhiZengSection(section as SnConfigTypes.IncSectionConfig)
|
||||||
|
case 'SuiJi':
|
||||||
|
return descSuiJiSection(section as SnConfigTypes.RandomSectionConfig)
|
||||||
|
default:
|
||||||
|
throw new Error(`不支持的配置项: ${section.sectionName}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSection(sectionName: SnConfigTypes.SectionType): SnConfigTypes.Section {
|
||||||
|
switch (sectionName) {
|
||||||
|
case 'GuDing':
|
||||||
|
return {
|
||||||
|
sectionName,
|
||||||
|
value: '',
|
||||||
|
}
|
||||||
|
case 'ShiJian':
|
||||||
|
return {
|
||||||
|
sectionName,
|
||||||
|
timestamp: false,
|
||||||
|
unit: null,
|
||||||
|
pattern: 'yyyyMMdd',
|
||||||
|
}
|
||||||
|
case 'ZiZeng':
|
||||||
|
return {
|
||||||
|
sectionName,
|
||||||
|
code: nanoid(),
|
||||||
|
padMode: 'Wu',
|
||||||
|
padVal: '',
|
||||||
|
padLen: null,
|
||||||
|
rollback: 'Wu',
|
||||||
|
allowOverflow: true,
|
||||||
|
initialVal: 1,
|
||||||
|
step: 1,
|
||||||
|
}
|
||||||
|
case 'SuiJi':
|
||||||
|
return {
|
||||||
|
sectionName,
|
||||||
|
randomMode: 'UUID',
|
||||||
|
workerId: null,
|
||||||
|
datacenterId: null,
|
||||||
|
nanoIdSize: null,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error(`不支持的配置项: ${sectionName}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
descGuDingSection,
|
||||||
|
descShiJianSection,
|
||||||
|
descZhiZengSection,
|
||||||
|
descSuiJiSection,
|
||||||
|
descConfig,
|
||||||
|
descSection,
|
||||||
|
createSection,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
export {}
|
||||||
|
declare global {
|
||||||
|
namespace SnConfigTypes {
|
||||||
|
type SectionType = 'GuDing' | 'ShiJian' | 'ZiZeng' | 'SuiJi'
|
||||||
|
|
||||||
|
interface Section extends Record<string, any> {
|
||||||
|
sectionName: SectionType
|
||||||
|
sectionDesc?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddSnConfigParam {
|
||||||
|
/**
|
||||||
|
* 规则名称
|
||||||
|
*/
|
||||||
|
snname: string
|
||||||
|
/**
|
||||||
|
* 规则代码
|
||||||
|
*/
|
||||||
|
sncode: string
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
memo: string
|
||||||
|
/**
|
||||||
|
* 配置参数
|
||||||
|
*/
|
||||||
|
config: Section[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ModifySnConfigParam {
|
||||||
|
id: string
|
||||||
|
/**
|
||||||
|
* 规则名称
|
||||||
|
*/
|
||||||
|
snname: string
|
||||||
|
/**
|
||||||
|
* 规则代码
|
||||||
|
*/
|
||||||
|
sncode: string
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
memo: string
|
||||||
|
/**
|
||||||
|
* 配置参数
|
||||||
|
*/
|
||||||
|
config: Section[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SnConfigDetail {
|
||||||
|
id: string
|
||||||
|
/**
|
||||||
|
* 规则名称
|
||||||
|
*/
|
||||||
|
snname: string
|
||||||
|
/**
|
||||||
|
* 规则代码
|
||||||
|
*/
|
||||||
|
sncode: string
|
||||||
|
/**
|
||||||
|
* 示例
|
||||||
|
*/
|
||||||
|
example: string
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
memo: string
|
||||||
|
/**
|
||||||
|
* 配置参数
|
||||||
|
*/
|
||||||
|
config: Section[]
|
||||||
|
configDesc?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FixedSectionConfig extends Section {
|
||||||
|
sectionName: 'GuDing'
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TimeSectionConfig extends Section {
|
||||||
|
sectionName: 'ShiJian'
|
||||||
|
timestamp: boolean
|
||||||
|
pattern?: string
|
||||||
|
/**
|
||||||
|
* 时间单位,1 --> 毫秒,1000-->秒,60000 --> 分,3600000 --> 时,86400000 --> 天
|
||||||
|
*/
|
||||||
|
unit?: 1 | 1000 | 60000 | 3600000 | 86400000
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IncSectionConfig extends Section {
|
||||||
|
sectionName: 'ZiZeng'
|
||||||
|
/**
|
||||||
|
* 编码段编号
|
||||||
|
*/
|
||||||
|
code: string
|
||||||
|
/**
|
||||||
|
* 步长
|
||||||
|
*/
|
||||||
|
step: number
|
||||||
|
/**
|
||||||
|
* 初始数值
|
||||||
|
*/
|
||||||
|
initialVal: number
|
||||||
|
/**
|
||||||
|
* 填充模式
|
||||||
|
*/
|
||||||
|
padMode: 'Wu' | 'Zuo' | 'You'
|
||||||
|
/**
|
||||||
|
* 填充值
|
||||||
|
*/
|
||||||
|
padVal: string
|
||||||
|
/**
|
||||||
|
* 填充长度
|
||||||
|
*/
|
||||||
|
padLen?: number
|
||||||
|
/**
|
||||||
|
* 回卷模式
|
||||||
|
*/
|
||||||
|
rollback: 'Wu' | 'Ri' | 'Zhou' | 'Yue' | 'Nian' | 'Pi'
|
||||||
|
/**
|
||||||
|
* 是否允许溢出
|
||||||
|
*/
|
||||||
|
allowOverflow: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RandomSectionConfig extends Section {
|
||||||
|
sectionName: 'SuiJi'
|
||||||
|
/**
|
||||||
|
* 随机模式
|
||||||
|
*/
|
||||||
|
randomMode: 'Snowflake' | 'NanoId' | 'UUID'
|
||||||
|
/**
|
||||||
|
* 雪花码-工作节点ID
|
||||||
|
*/
|
||||||
|
workerId?: number
|
||||||
|
/**
|
||||||
|
* 雪花码-数据中心ID
|
||||||
|
*/
|
||||||
|
datacenterId?: number
|
||||||
|
/**
|
||||||
|
* NanoId码-大小
|
||||||
|
*/
|
||||||
|
nanoIdSize?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface SearchSnConfigParam extends G.PageParam {
|
||||||
|
/**
|
||||||
|
* 规则名称
|
||||||
|
*/
|
||||||
|
snname?: string
|
||||||
|
/**
|
||||||
|
* 规则代码
|
||||||
|
*/
|
||||||
|
sncode?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue