master
parent
ebaebc926a
commit
d32b16ac11
|
|
@ -76,7 +76,7 @@ router.beforeEach((to, from) => {
|
|||
} else {
|
||||
return {
|
||||
replace: true,
|
||||
name: 'role',
|
||||
path: to.fullPath,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -109,6 +109,7 @@ export function reloadRouter() {
|
|||
routNames.push('menus')
|
||||
routNames.push('user')
|
||||
routNames.push('role')
|
||||
routNames.push('dict')
|
||||
|
||||
if (Colls.isEmpty(routNames)) {
|
||||
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%;
|
||||
overflow auto
|
||||
padding 16px
|
||||
|
||||
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;
|
||||
display flex
|
||||
flex-direction column
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ declare module 'vue' {
|
|||
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
|
|
@ -34,6 +36,7 @@ declare module 'vue' {
|
|||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
|
|
@ -61,9 +64,11 @@ declare global {
|
|||
const ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
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 ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
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 ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
const ElForm: typeof import('element-plus/es')['ElForm']
|
||||
|
|
@ -78,6 +83,7 @@ declare global {
|
|||
const ElMain: typeof import('element-plus/es')['ElMain']
|
||||
const ElOption: typeof import('element-plus/es')['ElOption']
|
||||
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 ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
const ElTable: typeof import('element-plus/es')['ElTable']
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import {
|
|||
type MenuItemRegistered,
|
||||
} from 'element-plus'
|
||||
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 {
|
||||
// Id
|
||||
|
|
@ -35,7 +38,7 @@ export interface Menu extends G.TreeNode {
|
|||
}
|
||||
|
||||
export default defineComponent(
|
||||
({menus}, {emit}) => {
|
||||
(props, {emit}) => {
|
||||
const onMenuClick = (it: MenuItemRegistered) => emit('menuClick', it.index)
|
||||
const renderMenu = (it: Menu) => {
|
||||
let renderChildNode: (() => VNode[] | undefined) | undefined = undefined
|
||||
|
|
@ -47,7 +50,10 @@ export default defineComponent(
|
|||
case 'Catalog': {
|
||||
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,
|
||||
}}
|
||||
</ElSubMenu>)
|
||||
|
|
@ -64,7 +70,8 @@ export default defineComponent(
|
|||
case 'Page': {
|
||||
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>)
|
||||
break
|
||||
|
|
@ -77,12 +84,12 @@ export default defineComponent(
|
|||
const isCollapse = ref(false)
|
||||
|
||||
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>
|
||||
<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
|
||||
}}>
|
||||
<ElIcon style={{cursor: 'pointer'}}>
|
||||
|
|
|
|||
|
|
@ -70,13 +70,15 @@ onUnmounted(() => {
|
|||
height 100%
|
||||
width 100%;
|
||||
overflow hidden
|
||||
box-shadow: inset rgba(0, 0, 0, 0.12) 0px 0px 12px 0px;
|
||||
background-color #F7F9FC
|
||||
|
||||
& > header {
|
||||
display flex
|
||||
justify-content space-between
|
||||
border-bottom 1px solid #E5E7EB;
|
||||
height 60px
|
||||
|
||||
background-color white
|
||||
& > div:first-child {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
|
@ -109,10 +111,10 @@ onUnmounted(() => {
|
|||
& > main {
|
||||
height 100%
|
||||
width calc(100% - 300px)
|
||||
padding 8px
|
||||
padding 5px
|
||||
overflow auto
|
||||
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="路由地址"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
|
||||
label="编码">
|
||||
<ElInput v-model="menuForm.sn"
|
||||
:disabled="status === 'view'"
|
||||
:min="0" placeholder="编码"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem
|
||||
|
||||
label="图标">
|
||||
<ElFormItem label="图标">
|
||||
<ElDropdown closable header="图标列表"
|
||||
placement="bottom"
|
||||
style="width: 100%" trigger="click">
|
||||
<ElInput v-model="menuForm.icon"
|
||||
<ElInput v-model="menuForm.iconName"
|
||||
placeholder="选择图标"
|
||||
:disabled="status === 'view'"
|
||||
placeholder="选择图标"/>
|
||||
readonly>
|
||||
<template #suffix>
|
||||
<AIcon :name="menuForm.icon!"/>
|
||||
</template>
|
||||
</ElInput>
|
||||
<template #dropdown>
|
||||
<ElTable
|
||||
:data="iconTableDataSource"
|
||||
empty-text="暂无数据"
|
||||
style="width: 324px;"
|
||||
>
|
||||
<ElTableColumn label="图标" prop="name"/>
|
||||
<ElTableColumn label="名称" prop="name"/>
|
||||
</ElTable>
|
||||
<div class="dropdown-table-wrapper">
|
||||
<ElTable
|
||||
ref="dropdownTable"
|
||||
:data="iconTableDataSource"
|
||||
empty-text="暂无数据"
|
||||
highlight-current-row
|
||||
style="width: 324px;"
|
||||
@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>
|
||||
</ElDropdown>
|
||||
</ElFormItem>
|
||||
|
|
@ -86,7 +104,6 @@
|
|||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">{{ status === 'view' ? '关闭' : '取消' }}</ElButton>
|
||||
|
|
@ -104,39 +121,52 @@ import {
|
|||
import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
||||
import Colls from '@/common/utils/colls.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 {
|
||||
name: string
|
||||
const pagination = reactive<G.Pagination>({
|
||||
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
|
||||
}))
|
||||
|
||||
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 submiting = ref(false)
|
||||
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 data: { key: string, label: string }[] = []
|
||||
for (const key in MenuCategoryDict) {
|
||||
|
|
@ -179,10 +209,8 @@ defineExpose({
|
|||
}
|
||||
Object.assign(menuForm, data)
|
||||
showDialog.value = true
|
||||
if (data.icon != null) {
|
||||
selectedRowKeys.value = [ data.icon ]
|
||||
}
|
||||
}
|
||||
dropdownTableIns.value?.setCurrentRow(icons.glyphs.find(it => it.font_class === data.icon))
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
|
|
@ -199,4 +227,13 @@ onMounted(() => {
|
|||
.menu-form {
|
||||
padding 20px
|
||||
}
|
||||
|
||||
.dropdown-table-wrapper {
|
||||
padding 10px
|
||||
display flex
|
||||
flex-direction column
|
||||
align-items end
|
||||
justify-content space-between
|
||||
gap 10px
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -26,9 +26,15 @@
|
|||
header-row-class-name="table-header"
|
||||
lazy
|
||||
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="title"/>
|
||||
<ElTableColumn label="编码" prop="sn" width="80"/>
|
||||
<!-- <ElTableColumn label="路径" prop="breadcrumb"/> -->
|
||||
<ElTableColumn label="路由名称" prop="routeName">
|
||||
<template #default="scope">
|
||||
|
|
@ -47,7 +53,19 @@
|
|||
<!-- <ElTableColumn label="排序" prop="sort" width="60"/> -->
|
||||
<ElTableColumn label="操作" width="180">
|
||||
<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>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
|
|
@ -65,19 +83,28 @@ import { onMounted } from 'vue'
|
|||
import { elIcons } from '@/common/element/element.ts'
|
||||
import MenuForm from '@/pages/sys/menus/MenuForm.vue'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import AIcon from '@/components/a-icon/AIcon.tsx'
|
||||
|
||||
const tableData = ref<MenuTypes.SysMenu[]>([])
|
||||
const searchForm = reactive<MenuTypes.SearchForm>({})
|
||||
const searching = ref(false)
|
||||
const showSearchForm = ref(true)
|
||||
const menuFormIns = useTemplateRef<InstanceType<typeof MenuForm>>('menuForm')
|
||||
const deling = ref(false)
|
||||
|
||||
function showDialog(data?: MenuTypes.MenuForm) {
|
||||
menuFormIns.value?.open(data)
|
||||
}
|
||||
|
||||
function delHandler({row}: { row: MenuTypes.MenuForm, }) {
|
||||
deling.value = true
|
||||
|
||||
MenuApi.del([ row.id! ])
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
listAll()
|
||||
})
|
||||
.finally(() => deling.value = false)
|
||||
}
|
||||
|
||||
function modifyHandler({row}: { row: MenuTypes.MenuForm, }) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { MenuCategory } from '@/common/app/contants'
|
||||
import type { IconName } from '@/components/a-icon/iconfont.ts'
|
||||
|
||||
export {}
|
||||
|
||||
|
|
@ -45,7 +46,8 @@ declare global {
|
|||
// 菜单名称
|
||||
title?: string
|
||||
// 图标
|
||||
icon?: string
|
||||
icon?: IconName
|
||||
iconName?: string
|
||||
// 排序
|
||||
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