184 changed files with 8 additions and 12744 deletions
@ -1,26 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { computed, unref } from 'vue' |
|
||||||
import { Tooltip } from 'ant-design-vue' |
|
||||||
import { useFullscreen } from '@vueuse/core' |
|
||||||
import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons-vue' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
|
|
||||||
defineOptions({ name: 'FullScreen' }) |
|
||||||
const { t } = useI18n() |
|
||||||
const { toggle, isFullscreen } = useFullscreen() |
|
||||||
// 重新检查全屏状态 |
|
||||||
isFullscreen.value = !!document.fullscreenElement |
|
||||||
|
|
||||||
const getTitle = computed(() => { |
|
||||||
return unref(isFullscreen) ? t('layout.header.tooltipExitFull') : t('layout.header.tooltipEntryFull') |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<Tooltip :title="getTitle" placement="bottom" :mouse-enter-delay="0.5"> |
|
||||||
<span @click="toggle"> |
|
||||||
<FullscreenOutlined v-if="!isFullscreen" /> |
|
||||||
<FullscreenExitOutlined v-else /> |
|
||||||
</span> |
|
||||||
</Tooltip> |
|
||||||
</template> |
|
@ -1,121 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { computed, ref, unref, watch } from 'vue' |
|
||||||
import { Avatar, List, Tag, Typography } from 'ant-design-vue' |
|
||||||
import type { ListItem } from './data' |
|
||||||
import { isNumber } from '@/utils/is' |
|
||||||
|
|
||||||
const props = defineProps({ |
|
||||||
list: { |
|
||||||
type: Array as PropType<ListItem[]>, |
|
||||||
default: () => [], |
|
||||||
}, |
|
||||||
pageSize: { |
|
||||||
type: [Boolean, Number] as PropType<boolean | number>, |
|
||||||
default: 5, |
|
||||||
}, |
|
||||||
currentPage: { |
|
||||||
type: Number, |
|
||||||
default: 1, |
|
||||||
}, |
|
||||||
titleRows: { |
|
||||||
type: Number, |
|
||||||
default: 1, |
|
||||||
}, |
|
||||||
descRows: { |
|
||||||
type: Number, |
|
||||||
default: 2, |
|
||||||
}, |
|
||||||
onTitleClick: { |
|
||||||
type: Function as PropType<(Recordable) => void>, |
|
||||||
}, |
|
||||||
}) |
|
||||||
const emit = defineEmits(['update:currentPage']) |
|
||||||
const current = ref(props.currentPage || 1) |
|
||||||
const getData = computed(() => { |
|
||||||
const { pageSize, list } = props |
|
||||||
if (pageSize === false) |
|
||||||
return [] |
|
||||||
const size = isNumber(pageSize) ? pageSize : 5 |
|
||||||
return list.slice(size * (unref(current) - 1), size * unref(current)) |
|
||||||
}) |
|
||||||
watch( |
|
||||||
() => props.currentPage, |
|
||||||
(v) => { |
|
||||||
current.value = v |
|
||||||
}, |
|
||||||
) |
|
||||||
const isTitleClickable = computed(() => !!props.onTitleClick) |
|
||||||
const getPagination = computed(() => { |
|
||||||
const { list, pageSize } = props |
|
||||||
// compatible line 104 |
|
||||||
// if typeof pageSize is boolean, Number(true) && 5 = 5, Number(false) && 5 = 0 |
|
||||||
const size = isNumber(pageSize) ? pageSize : Number(pageSize) && 5 |
|
||||||
if (size > 0 && list && list.length > size) { |
|
||||||
return { |
|
||||||
total: list.length, |
|
||||||
pageSize: size, |
|
||||||
// size: 'small', |
|
||||||
current: unref(current), |
|
||||||
onChange(page) { |
|
||||||
current.value = page |
|
||||||
emit('update:currentPage', page) |
|
||||||
}, |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
return false |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
function handleTitleClick(item: ListItem) { |
|
||||||
props.onTitleClick && props.onTitleClick(item) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<List class="display-none" bordered :pagination="getPagination"> |
|
||||||
<template v-for="item in getData" :key="item.id"> |
|
||||||
<List.Item class="cursor-pointer overflow-hidden p-1.5 transition-all delay-300"> |
|
||||||
<List.Item.Meta> |
|
||||||
<template #title> |
|
||||||
<div class="mb-2 font-normal"> |
|
||||||
<Typography.Paragraph |
|
||||||
style="width: 100%; margin-bottom: 0 !important" |
|
||||||
:style="{ cursor: isTitleClickable ? 'pointer' : '' }" |
|
||||||
:delete="!!item.titleDelete" |
|
||||||
:ellipsis="$props.titleRows && $props.titleRows > 0 ? { rows: $props.titleRows, tooltip: !!item.title } : false" |
|
||||||
:content="item.title" |
|
||||||
@click="handleTitleClick(item)" |
|
||||||
/> |
|
||||||
<div v-if="item.extra" class="float-right mr-0 font-normal -mt-0.375"> |
|
||||||
<Tag class="mr-0" :color="item.color"> |
|
||||||
{{ item.extra }} |
|
||||||
</Tag> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<template #avatar> |
|
||||||
<Avatar v-if="item.avatar" class="mt-1" :src="item.avatar" /> |
|
||||||
<span v-else> {{ item.avatar }}</span> |
|
||||||
</template> |
|
||||||
|
|
||||||
<template #description> |
|
||||||
<div> |
|
||||||
<div v-if="item.description" class="text-xs/18"> |
|
||||||
<Typography.Paragraph |
|
||||||
style="width: 100%; margin-bottom: 0 !important" |
|
||||||
:ellipsis="$props.descRows && $props.descRows > 0 ? { rows: $props.descRows, tooltip: !!item.description } : false" |
|
||||||
:content="item.description" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
<div class="mt-1 text-xs/18"> |
|
||||||
{{ item.datetime }} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
</List.Item.Meta> |
|
||||||
</List.Item> |
|
||||||
</template> |
|
||||||
</List> |
|
||||||
</template> |
|
@ -1,192 +0,0 @@ |
|||||||
export interface ListItem { |
|
||||||
id: string |
|
||||||
avatar: string |
|
||||||
// 通知的标题内容
|
|
||||||
title: string |
|
||||||
// 是否在标题上显示删除线
|
|
||||||
titleDelete?: boolean |
|
||||||
datetime: string |
|
||||||
type: string |
|
||||||
read?: boolean |
|
||||||
description: string |
|
||||||
clickClose?: boolean |
|
||||||
extra?: string |
|
||||||
color?: string |
|
||||||
} |
|
||||||
|
|
||||||
export interface TabItem { |
|
||||||
key: string |
|
||||||
name: string |
|
||||||
list: ListItem[] |
|
||||||
unreadlist?: ListItem[] |
|
||||||
} |
|
||||||
|
|
||||||
export const tabListData: TabItem[] = [ |
|
||||||
{ |
|
||||||
key: '1', |
|
||||||
name: '通知', |
|
||||||
list: [ |
|
||||||
{ |
|
||||||
id: '000000001', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', |
|
||||||
title: '你收到了 14 份新周报', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-09', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000002', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png', |
|
||||||
title: '你推荐的 曲妮妮 已通过第三轮面试', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-08', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000003', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png', |
|
||||||
title: '这种模板可以区分多种通知类型', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
// read: true,
|
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000004', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', |
|
||||||
title: '左侧图标用于区分不同的类型', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000005', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', |
|
||||||
title: '标题可以设置自动显示省略号,本例中标题行数已设为1行,如果内容超过1行将自动截断并支持tooltip显示完整标题。', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000006', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', |
|
||||||
title: '左侧图标用于区分不同的类型', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000007', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', |
|
||||||
title: '左侧图标用于区分不同的类型', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000008', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', |
|
||||||
title: '左侧图标用于区分不同的类型', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000009', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', |
|
||||||
title: '左侧图标用于区分不同的类型', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000010', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', |
|
||||||
title: '左侧图标用于区分不同的类型', |
|
||||||
description: '', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '1', |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
{ |
|
||||||
key: '2', |
|
||||||
name: '消息', |
|
||||||
list: [ |
|
||||||
{ |
|
||||||
id: '000000006', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', |
|
||||||
title: '曲丽丽 评论了你', |
|
||||||
description: '描述信息描述信息描述信息', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '2', |
|
||||||
clickClose: true, |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000007', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', |
|
||||||
title: '朱偏右 回复了你', |
|
||||||
description: '这种模板用于提醒谁与你发生了互动', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '2', |
|
||||||
clickClose: true, |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000008', |
|
||||||
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', |
|
||||||
title: '标题', |
|
||||||
description: |
|
||||||
'请将鼠标移动到此处,以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2,超过2行的描述内容将被省略并且可以通过tooltip查看完整内容', |
|
||||||
datetime: '2017-08-07', |
|
||||||
type: '2', |
|
||||||
clickClose: true, |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
{ |
|
||||||
key: '3', |
|
||||||
name: '待办', |
|
||||||
list: [ |
|
||||||
{ |
|
||||||
id: '000000009', |
|
||||||
avatar: '', |
|
||||||
title: '任务名称', |
|
||||||
description: '任务需要在 2017-01-12 20:00 前启动', |
|
||||||
datetime: '', |
|
||||||
extra: '未开始', |
|
||||||
color: '', |
|
||||||
type: '3', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000010', |
|
||||||
avatar: '', |
|
||||||
title: '第三方紧急代码变更', |
|
||||||
description: '冠霖 需在 2017-01-07 前完成代码变更任务', |
|
||||||
datetime: '', |
|
||||||
extra: '马上到期', |
|
||||||
color: 'red', |
|
||||||
type: '3', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000011', |
|
||||||
avatar: '', |
|
||||||
title: '信息安全考试', |
|
||||||
description: '指派竹尔于 2017-01-09 前完成更新并发布', |
|
||||||
datetime: '', |
|
||||||
extra: '已耗时 8 天', |
|
||||||
color: 'gold', |
|
||||||
type: '3', |
|
||||||
}, |
|
||||||
{ |
|
||||||
id: '000000012', |
|
||||||
avatar: '', |
|
||||||
title: 'ABCD 版本发布', |
|
||||||
description: '指派竹尔于 2017-01-09 前完成更新并发布', |
|
||||||
datetime: '', |
|
||||||
extra: '进行中', |
|
||||||
color: 'blue', |
|
||||||
type: '3', |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
] |
|
@ -1,35 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { computed, onMounted } from 'vue' |
|
||||||
import { Badge, Tooltip } from 'ant-design-vue' |
|
||||||
import { BellOutlined } from '@ant-design/icons-vue' |
|
||||||
import { storeToRefs } from 'pinia' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { PageEnum } from '@/enums/pageEnum' |
|
||||||
import { useUserMessageStore } from '@/store/modules/userMessage' |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
|
|
||||||
const store = useUserMessageStore() |
|
||||||
const { unreadCount } = storeToRefs(store) |
|
||||||
const tips = computed<string>(() => { |
|
||||||
if (unreadCount.value === 0) |
|
||||||
return '查看站内信' |
|
||||||
|
|
||||||
return `查看站内信: 未读 ${unreadCount.value} 条` |
|
||||||
}) |
|
||||||
|
|
||||||
onMounted(async () => { |
|
||||||
// 通过store进行更新 |
|
||||||
store.updateUnreadCount() |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<Tooltip :title="tips"> |
|
||||||
<Badge :count="unreadCount" :offset="[0, 15]" size="small" @click="go({ path: PageEnum.MESSAGE_PAGE })"> |
|
||||||
<BellOutlined /> |
|
||||||
</Badge> |
|
||||||
</Tooltip> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,35 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { computed, unref } from 'vue' |
|
||||||
import { Icon } from '@/components/Icon' |
|
||||||
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign' |
|
||||||
import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting' |
|
||||||
import { useMenuSetting } from '@/hooks/setting/useMenuSetting' |
|
||||||
import { triggerWindowResize } from '@/utils/event' |
|
||||||
|
|
||||||
defineOptions({ name: 'FoldButton' }) |
|
||||||
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs-content') |
|
||||||
const { getShowMenu, setMenuSetting } = useMenuSetting() |
|
||||||
const { getShowHeader, setHeaderSetting } = useHeaderSetting() |
|
||||||
|
|
||||||
const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader)) |
|
||||||
|
|
||||||
const getIcon = computed(() => (unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full')) |
|
||||||
|
|
||||||
function handleFold() { |
|
||||||
const isUnFold = unref(getIsUnFold) |
|
||||||
setMenuSetting({ |
|
||||||
show: isUnFold, |
|
||||||
hidden: !isUnFold, |
|
||||||
}) |
|
||||||
setHeaderSetting({ show: isUnFold }) |
|
||||||
triggerWindowResize() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<span :class="`${prefixCls}__extra-fold`" @click="handleFold"> |
|
||||||
<Icon :icon="getIcon" /> |
|
||||||
</span> |
|
||||||
</template> |
|
@ -1,28 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { RedoOutlined } from '@ant-design/icons-vue' |
|
||||||
import { useDesign } from '@/hooks/web/useDesign' |
|
||||||
import { useTabs } from '@/hooks/web/useTabs' |
|
||||||
|
|
||||||
defineOptions({ name: 'TabRedo' }) |
|
||||||
|
|
||||||
const loading = ref(false) |
|
||||||
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs-content') |
|
||||||
const { refreshPage } = useTabs() |
|
||||||
|
|
||||||
async function handleRedo() { |
|
||||||
loading.value = true |
|
||||||
await refreshPage() |
|
||||||
setTimeout(() => { |
|
||||||
loading.value = false |
|
||||||
// Animation execution time |
|
||||||
}, 1200) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<span :class="`${prefixCls}__extra-redo`" @click="handleRedo"> |
|
||||||
<RedoOutlined :spin="loading" /> |
|
||||||
</span> |
|
||||||
</template> |
|
@ -1,31 +0,0 @@ |
|||||||
import type { AppRouteModule } from '@/router/types' |
|
||||||
|
|
||||||
import { LAYOUT } from '@/router/constant' |
|
||||||
import { t } from '@/hooks/web/useI18n' |
|
||||||
|
|
||||||
const about: AppRouteModule = { |
|
||||||
path: '/about', |
|
||||||
name: 'About', |
|
||||||
component: LAYOUT, |
|
||||||
redirect: '/about/index', |
|
||||||
meta: { |
|
||||||
hideChildrenInMenu: true, |
|
||||||
icon: 'ant-design:pushpin-filled', |
|
||||||
title: t('routes.dashboard.about'), |
|
||||||
orderNo: 100000, |
|
||||||
}, |
|
||||||
children: [ |
|
||||||
{ |
|
||||||
path: 'index', |
|
||||||
name: 'AboutPage', |
|
||||||
component: () => import('@/views/base/about/index.vue'), |
|
||||||
meta: { |
|
||||||
title: t('routes.dashboard.about'), |
|
||||||
icon: 'ant-design:pushpin-filled', |
|
||||||
hideMenu: true, |
|
||||||
}, |
|
||||||
}, |
|
||||||
], |
|
||||||
} |
|
||||||
|
|
||||||
export default about |
|
@ -1,8 +0,0 @@ |
|||||||
// github repo url
|
|
||||||
export const GITHUB_URL = 'https://gitee.com/xingyuv/vue-vben-admin' |
|
||||||
|
|
||||||
// vue-vben-admin-next-doc
|
|
||||||
export const DOC_URL = 'http://vben-doc.x-surge.com/' |
|
||||||
|
|
||||||
// site url
|
|
||||||
export const SITE_URL = 'http://static.yudao.iocoder.cn/mp/xinyu370.jpeg' |
|
@ -1,107 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { h } from 'vue' |
|
||||||
import { Tag } from 'ant-design-vue' |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import type { DescItem } from '@/components/Description' |
|
||||||
import { Description, useDescription } from '@/components/Description' |
|
||||||
import { DOC_URL, GITHUB_URL, SITE_URL } from '@/settings/siteSetting' |
|
||||||
|
|
||||||
const { pkg, lastBuildTime } = __APP_INFO__ |
|
||||||
|
|
||||||
const { dependencies, devDependencies, name, version } = pkg |
|
||||||
|
|
||||||
const schema: DescItem[] = [] |
|
||||||
const devSchema: DescItem[] = [] |
|
||||||
|
|
||||||
const commonTagRender = (color: string) => curVal => h(Tag, { color }, () => curVal) |
|
||||||
const commonLinkRender = (text: string) => href => h('a', { href, target: '_blank' }, text) |
|
||||||
|
|
||||||
const infoSchema: DescItem[] = [ |
|
||||||
{ |
|
||||||
label: '版本', |
|
||||||
field: 'version', |
|
||||||
render: commonTagRender('blue'), |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '最后编译时间', |
|
||||||
field: 'lastBuildTime', |
|
||||||
render: commonTagRender('blue'), |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '文档地址', |
|
||||||
field: 'doc', |
|
||||||
render: commonLinkRender('文档地址'), |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '预览地址', |
|
||||||
field: 'preview', |
|
||||||
render: commonLinkRender('预览地址'), |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'Github', |
|
||||||
field: 'github', |
|
||||||
render: commonLinkRender('Github'), |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '外包服务', |
|
||||||
field: 'outsourcing', |
|
||||||
render: commonLinkRender('外包服务'), |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
const infoData = { |
|
||||||
version, |
|
||||||
lastBuildTime, |
|
||||||
doc: DOC_URL, |
|
||||||
preview: SITE_URL, |
|
||||||
github: GITHUB_URL, |
|
||||||
outsourcing: SITE_URL, |
|
||||||
} |
|
||||||
|
|
||||||
Object.keys(dependencies).forEach((key) => { |
|
||||||
schema.push({ field: key, label: key }) |
|
||||||
}) |
|
||||||
|
|
||||||
Object.keys(devDependencies).forEach((key) => { |
|
||||||
devSchema.push({ field: key, label: key }) |
|
||||||
}) |
|
||||||
|
|
||||||
const [register] = useDescription({ |
|
||||||
title: '生产环境依赖', |
|
||||||
data: dependencies, |
|
||||||
schema, |
|
||||||
column: 3, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerDev] = useDescription({ |
|
||||||
title: '开发环境依赖', |
|
||||||
data: devDependencies, |
|
||||||
schema: devSchema, |
|
||||||
column: 3, |
|
||||||
}) |
|
||||||
|
|
||||||
const [infoRegister] = useDescription({ |
|
||||||
title: '项目信息', |
|
||||||
data: infoData, |
|
||||||
schema: infoSchema, |
|
||||||
column: 2, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper title="关于"> |
|
||||||
<template #headerContent> |
|
||||||
<div class="flex items-center justify-between"> |
|
||||||
<span class="flex-1"> |
|
||||||
<a :href="GITHUB_URL" target="_blank">{{ name }}</a> |
|
||||||
基于Vue3.0、Vite、 Ant-Design-Vue 、TypeScript |
|
||||||
的后台解决方案,目标是为中大型项目开发,提供现成的开箱解决方案及丰富的示例,原则上不会限制任何代码用于商用。<br> |
|
||||||
同时,我们也提供<a :href="SITE_URL" target="_blank">外包服务</a>。 |
|
||||||
</span> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
<Description class="enter-y" @register="infoRegister" /> |
|
||||||
<Description class="enter-y my-4" @register="register" /> |
|
||||||
<Description class="enter-y" @register="registerDev" /> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,28 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { List, Switch } from 'ant-design-vue' |
|
||||||
import { msgNotifyList } from './data' |
|
||||||
import { CollapseContainer } from '@/components/Container/index' |
|
||||||
|
|
||||||
const ListItem = List.Item |
|
||||||
const ListItemMeta = List.Item.Meta |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<CollapseContainer title="新消息通知" :can-expan="false"> |
|
||||||
<List> |
|
||||||
<template v-for="item in msgNotifyList" :key="item.key"> |
|
||||||
<ListItem> |
|
||||||
<ListItemMeta> |
|
||||||
<template #title> |
|
||||||
{{ item.title }} |
|
||||||
<Switch class="float-right mr-7.5 mt-0" checked-children="开" un-checked-children="关" default-checked /> |
|
||||||
</template> |
|
||||||
<template #description> |
|
||||||
<div>{{ item.description }}</div> |
|
||||||
</template> |
|
||||||
</ListItemMeta> |
|
||||||
</ListItem> |
|
||||||
</template> |
|
||||||
</List> |
|
||||||
</CollapseContainer> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中 definition</div> |
|
||||||
</template> |
|
@ -1,43 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { VFormCreate } from '@/components/FormDesign' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { getForm } from '@/api/bpm/form' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmFormModal' }) |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const formConfig = ref({ |
|
||||||
schemas: [], |
|
||||||
rule: [], |
|
||||||
option: {}, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
const res = await getForm(data.record.id) |
|
||||||
formConfig.value.schemas = res.fields |
|
||||||
formConfig.value.option = res.conf |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" title="表单详情" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<VFormCreate :form-config="formConfig" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,9 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { VFormDesign } from '@/components/FormDesign' |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<VFormDesign /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,46 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE } from '@/utils/dict' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '表单名', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '状态', |
|
||||||
dataIndex: 'status', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.COMMON_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '备注', |
|
||||||
dataIndex: 'remark', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '表单名', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
@ -1,86 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import BpmFormModal from './FormModal.vue' |
|
||||||
import { columns, searchFormSchema } from './form.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { deleteForm, getFormPage } from '@/api/bpm/form' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmForm' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '流程表单列表', |
|
||||||
api: getFormPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
actionColumn: { |
|
||||||
width: 180, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleCreate() { |
|
||||||
// openModal(true, { isUpdate: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function openForm(record: Recordable) { |
|
||||||
if (typeof record.id === 'number') |
|
||||||
go({ name: 'BpmFormEditor', query: { id: record.id } }) |
|
||||||
} |
|
||||||
|
|
||||||
function openDetail(record: Recordable) { |
|
||||||
openModal(true, { record }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteForm(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['bpm:form:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
{{ t('action.create') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.EDIT, label: t('action.edit'), auth: 'bpm:form:update', onClick: openForm.bind(null, record) }, |
|
||||||
{ icon: IconEnum.VIEW, label: t('action.detail'), auth: 'bpm:form:query', onClick: openDetail.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'bpm:form:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<BpmFormModal @register="registerModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,58 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, unref } from 'vue' |
|
||||||
import { formSchema } from './group.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { createUserGroup, getUserGroup, updateUserGroup } from '@/api/bpm/userGroup' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmGroupModal' }) |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const isUpdate = ref(true) |
|
||||||
|
|
||||||
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showActionButtonGroup: false, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|
||||||
resetFields() |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
isUpdate.value = !!data?.isUpdate |
|
||||||
if (unref(isUpdate)) { |
|
||||||
const res = await getUserGroup(data.record.id) |
|
||||||
setFieldsValue({ ...res }) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() as any |
|
||||||
setModalProps({ confirmLoading: true }) |
|
||||||
if (unref(isUpdate)) |
|
||||||
await updateUserGroup(values) |
|
||||||
else |
|
||||||
await createUserGroup(values) |
|
||||||
|
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<BasicForm @register="registerForm" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,134 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
import { getListSimpleUsers } from '@/api/system/user' |
|
||||||
|
|
||||||
let users: any[] = [] |
|
||||||
|
|
||||||
async function getUserList() { |
|
||||||
const res = await getListSimpleUsers() |
|
||||||
users = res |
|
||||||
} |
|
||||||
|
|
||||||
await getUserList() |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '组名', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '描述', |
|
||||||
dataIndex: 'description', |
|
||||||
width: 200, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '成员', |
|
||||||
dataIndex: 'memberUserIds', |
|
||||||
width: 180, |
|
||||||
customRender: ({ record, text }) => { |
|
||||||
const names: any[] = [] |
|
||||||
if (text) { |
|
||||||
for (const userId of record.memberUserIds) { |
|
||||||
let isUser = false |
|
||||||
users.forEach((user) => { |
|
||||||
if (userId === user.id) { |
|
||||||
names.push(user.nickname) |
|
||||||
isUser = true |
|
||||||
} |
|
||||||
}) |
|
||||||
if (!isUser) |
|
||||||
names.push(`未知(${userId})`) |
|
||||||
} |
|
||||||
return useRender.renderTags(names) |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '状态', |
|
||||||
dataIndex: 'status', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.COMMON_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '组名', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '状态', |
|
||||||
field: 'status', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.COMMON_STATUS) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '创建时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '编号', |
|
||||||
field: 'id', |
|
||||||
show: false, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '组名', |
|
||||||
field: 'name', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '描述', |
|
||||||
field: 'description', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '成员', |
|
||||||
field: 'memberUserIds', |
|
||||||
required: true, |
|
||||||
component: 'ApiTransfer', |
|
||||||
componentProps: { |
|
||||||
api: () => getListSimpleUsers(), |
|
||||||
showSearch: true, |
|
||||||
labelField: 'nickname', |
|
||||||
valueField: 'id', |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '状态', |
|
||||||
field: 'status', |
|
||||||
component: 'RadioGroup', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.COMMON_STATUS), |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
@ -1,78 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import GroupModal from './GroupModal.vue' |
|
||||||
import { columns, searchFormSchema } from './group.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { deleteUserGroup, getUserGroupPage } from '@/api/bpm/userGroup' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmGroup' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '用户分组列表', |
|
||||||
api: getUserGroupPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleCreate() { |
|
||||||
openModal(true, { isUpdate: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEdit(record: Recordable) { |
|
||||||
openModal(true, { record, isUpdate: true }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteUserGroup(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['bpm:user-group:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
{{ t('action.create') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.EDIT, label: t('action.edit'), auth: 'bpm:user-group:update', onClick: handleEdit.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'bpm:user-group:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<GroupModal @register="registerModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,78 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import type { FormSchema } from '@/components/Form' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { importModel } from '@/api/bpm/model' |
|
||||||
|
|
||||||
defineOptions({ name: 'ModelImportForm' }) |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
|
|
||||||
const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '流程标识', |
|
||||||
field: 'key', |
|
||||||
component: 'Input', |
|
||||||
required: true, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程名称', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
required: true, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程描述', |
|
||||||
field: 'description', |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程文件', |
|
||||||
field: 'bpmnFile', |
|
||||||
component: 'FileUpload', |
|
||||||
componentProps: { |
|
||||||
maxCount: 1, |
|
||||||
fileType: 'file', |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
|
|
||||||
const [registerForm, { resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showActionButtonGroup: false, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => { |
|
||||||
resetFields() |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() |
|
||||||
setModalProps({ confirmLoading: true }) |
|
||||||
console.info(values) |
|
||||||
await importModel(values) |
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" title="导入流程" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<BasicForm @register="registerForm" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,58 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, unref } from 'vue' |
|
||||||
import { formSchema } from './model.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { createModel, getModel, updateModel } from '@/api/bpm/model' |
|
||||||
|
|
||||||
defineOptions({ name: 'ModelForm' }) |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const isUpdate = ref(true) |
|
||||||
|
|
||||||
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showActionButtonGroup: false, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|
||||||
resetFields() |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
isUpdate.value = !!data?.isUpdate |
|
||||||
if (unref(isUpdate)) { |
|
||||||
const res = await getModel(data.record.id) |
|
||||||
setFieldsValue({ ...res }) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() as any |
|
||||||
setModalProps({ confirmLoading: true }) |
|
||||||
if (unref(isUpdate)) |
|
||||||
await updateModel(values) |
|
||||||
else |
|
||||||
await createModel(values) |
|
||||||
|
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<BasicForm @register="registerForm" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>123</div> |
|
||||||
</template> |
|
@ -1,143 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import ModelModal from './ModelModal.vue' |
|
||||||
import ModelImportModal from './ModelImportModal.vue' |
|
||||||
import { columns, searchFormSchema } from './model.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { deleteModel, deployModel, getModelPage } from '@/api/bpm/model' |
|
||||||
|
|
||||||
// import { getAccessToken, getTenantId } from '@/utils/auth' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmModel' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
const [registerImportModal, { openModal: openImportModal }] = useModal() |
|
||||||
|
|
||||||
// const uploadParams = ref({ |
|
||||||
// 'Authorization': `Bearer ${getAccessToken()}`, |
|
||||||
// 'tenant-id': getTenantId(), |
|
||||||
// }) |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '流程模型图列表', |
|
||||||
api: getModelPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleCreate() { |
|
||||||
openModal(true, { isUpdate: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEdit(record: Recordable) { |
|
||||||
openModal(true, { record, isUpdate: true }) |
|
||||||
} |
|
||||||
|
|
||||||
/** 设计流程 */ |
|
||||||
function handleDesign(record: Recordable) { |
|
||||||
go({ name: 'BpmModelEditor', query: { modelId: record.id } }) |
|
||||||
} |
|
||||||
|
|
||||||
/** 点击任务分配按钮 */ |
|
||||||
function handleAssignRule(record: Recordable) { |
|
||||||
go({ name: 'BpmTaskAssignRuleList', query: { modelId: record.id } }) |
|
||||||
} |
|
||||||
|
|
||||||
/** 发布流程 */ |
|
||||||
async function handleDeploy(record: Recordable) { |
|
||||||
await deployModel(record.id) |
|
||||||
createMessage.success(t('common.successText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
|
|
||||||
/** 跳转到指定流程定义列表 */ |
|
||||||
function handleDefinitionList(record: Recordable) { |
|
||||||
go({ name: 'BpmProcessDefinition', query: { modelId: record.key } }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteModel(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['bpm:model:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
{{ t('action.create') }} |
|
||||||
</a-button> |
|
||||||
<a-button v-auth="['bpm:model:import']" type="primary" :pre-icon="IconEnum.UPLOAD" @click="openImportModal"> |
|
||||||
{{ t('action.import') }} |
|
||||||
</a-button> |
|
||||||
<!-- <BasicUpload |
|
||||||
:max-size="20" |
|
||||||
:max-number="1" |
|
||||||
:empty-hide-preview="true" |
|
||||||
:upload-params="uploadParams" |
|
||||||
:api="importModel" |
|
||||||
class="my-5" |
|
||||||
:accept="['.bpmn', '.xml']" |
|
||||||
@change="reload" |
|
||||||
/> --> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[{ icon: IconEnum.EDIT, label: t('action.edit'), auth: 'bpm:model:update', onClick: handleEdit.bind(null, record) }]" |
|
||||||
:drop-down-actions="[ |
|
||||||
{ icon: IconEnum.EDIT, label: '设计流程', auth: 'bpm:model:update', onClick: handleDesign.bind(null, record) }, |
|
||||||
{ icon: IconEnum.EDIT, label: '分配规则', auth: 'bpm:task-assign-rule:query', onClick: handleAssignRule.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.EDIT, |
|
||||||
label: '发布流程', |
|
||||||
auth: 'bpm:model:deploy', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDeploy.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.EDIT, |
|
||||||
label: '流程定义', |
|
||||||
auth: 'bpm:process-definition:query', |
|
||||||
onClick: handleDefinitionList.bind(null, record), |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'bpm:model:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<ModelModal @register="registerModal" @success="reload()" /> |
|
||||||
<ModelImportModal @register="registerImportModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,225 +0,0 @@ |
|||||||
import { Button, Switch } from 'ant-design-vue' |
|
||||||
import { h } from 'vue' |
|
||||||
import { getSimpleForms } from '@/api/bpm/form' |
|
||||||
import { updateModelState } from '@/api/bpm/model' |
|
||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '编号', |
|
||||||
dataIndex: 'id', |
|
||||||
defaultHidden: true, |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程标识', |
|
||||||
dataIndex: 'key', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
customRender: ({ record }) => { |
|
||||||
return h(Button, { type: 'link', onClick: handleBpmnDetail.bind(null, record) }, () => record.formName) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程分类', |
|
||||||
dataIndex: 'category', |
|
||||||
width: 120, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_MODEL_CATEGORY) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '表单信息', |
|
||||||
dataIndex: 'formType', |
|
||||||
width: 180, |
|
||||||
customRender: ({ record }) => { |
|
||||||
if (record.formId) |
|
||||||
return h(Button, { type: 'link', onClick: handleFormDetail.bind(null, record) }, () => record.formName) |
|
||||||
else if (record.formCustomCreatePath) |
|
||||||
return h(Button, { type: 'link', onClick: handleFormDetail.bind(null, record) }, () => record.formCustomCreatePath) |
|
||||||
else |
|
||||||
return useRender.renderTag('暂无表单') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '最新部署的流程定义', |
|
||||||
children: [ |
|
||||||
{ |
|
||||||
title: '流程版本', |
|
||||||
dataIndex: 'processDefinition.version', |
|
||||||
width: 160, |
|
||||||
customRender: ({ record }) => { |
|
||||||
if (record.processDefinition) |
|
||||||
return useRender.renderTag(`v${record.processDefinition.version}`) |
|
||||||
else |
|
||||||
return useRender.renderTag('未部署') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '激活状态', |
|
||||||
dataIndex: 'processDefinition.suspensionState', |
|
||||||
width: 100, |
|
||||||
customRender: ({ record }) => { |
|
||||||
if (record.processDefinition) { |
|
||||||
if (!Reflect.has(record, 'suspensionState')) |
|
||||||
record.pendingStatus = false |
|
||||||
|
|
||||||
return h(Switch, { |
|
||||||
checked: record.processDefinition.suspensionState === 1, |
|
||||||
checkedChildren: '激活', |
|
||||||
unCheckedChildren: '挂起', |
|
||||||
onChange(checked: boolean) { |
|
||||||
const newStatus = checked ? 0 : 1 |
|
||||||
const { createMessage } = useMessage() |
|
||||||
updateModelState(record.id, newStatus) |
|
||||||
.then(() => { |
|
||||||
record.status = newStatus |
|
||||||
createMessage.success('已成功修改流程状态') |
|
||||||
}) |
|
||||||
.catch(() => { |
|
||||||
createMessage.error('修改流程状态失败') |
|
||||||
}) |
|
||||||
.finally(() => { |
|
||||||
record.pendingStatus = false |
|
||||||
}) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '部署时间', |
|
||||||
dataIndex: 'processDefinition.deploymentTim', |
|
||||||
width: 180, |
|
||||||
customRender: ({ record }) => { |
|
||||||
if (record.processDefinition) |
|
||||||
return useRender.renderDate(record.processDefinition.deploymentTime) |
|
||||||
}, |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '流程标识', |
|
||||||
field: 'key', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程名称', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程分类', |
|
||||||
field: 'category', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_MODEL_CATEGORY) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '编号', |
|
||||||
field: 'id', |
|
||||||
show: false, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程标识', |
|
||||||
field: 'key', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
dynamicDisabled: ({ values }) => !!values.id, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程名称', |
|
||||||
field: 'name', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
dynamicDisabled: ({ values }) => !!values.id, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程分类', |
|
||||||
field: 'category', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_MODEL_CATEGORY) as any, |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程描述', |
|
||||||
field: 'description', |
|
||||||
component: 'InputTextArea', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表单类型', |
|
||||||
field: 'formType', |
|
||||||
component: 'Select', |
|
||||||
ifShow: ({ values }) => !!values.id, |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_MODEL_FORM_TYPE) as any, |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程表单', |
|
||||||
field: 'formId', |
|
||||||
component: 'ApiSelect', |
|
||||||
ifShow: ({ values }) => !!values.id && values.formType === 10, |
|
||||||
componentProps: { |
|
||||||
api: () => getSimpleForms(), |
|
||||||
labelField: 'name', |
|
||||||
valueField: 'id', |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表单提交路由', |
|
||||||
field: 'formCustomCreatePath', |
|
||||||
component: 'Input', |
|
||||||
helpMessage: '自定义表单的提交路径,使用 Vue 的路由地址,例如说:bpm/oa/leave/create', |
|
||||||
ifShow: ({ values }) => !!values.id && values.formType === 20, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表单查看路由', |
|
||||||
field: 'formCustomViewPath', |
|
||||||
component: 'Input', |
|
||||||
helpMessage: '自定义表单的查看路径,使用 Vue 的路由地址,例如说:bpm/oa/leave/view', |
|
||||||
ifShow: ({ values }) => !!values.id && values.formType === 20, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
function handleBpmnDetail(record: Recordable) { |
|
||||||
console.info('handleBpmnDetail', record) |
|
||||||
} |
|
||||||
|
|
||||||
function handleFormDetail(record: Recordable) { |
|
||||||
if (record.formType === 10) { |
|
||||||
console.info('handleFormDetail') |
|
||||||
} |
|
||||||
else { |
|
||||||
const go = useGo() |
|
||||||
go({ path: record.formCustomCreatePath }) |
|
||||||
} |
|
||||||
} |
|
@ -1,42 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { onMounted } from 'vue' |
|
||||||
import { formSchema } from './leave.data' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import { createLeave } from '@/api/bpm/leave' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
|
|
||||||
defineOptions({ name: 'LeaveCreate' }) |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
|
|
||||||
const [registerForm, { resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 140, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showResetButton: false, |
|
||||||
submitButtonOptions: { text: t('common.saveText') }, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() as any |
|
||||||
await createLeave(values) |
|
||||||
} |
|
||||||
finally { |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
onMounted(() => { |
|
||||||
resetFields() |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper> |
|
||||||
<BasicForm class="mt-10 h-120 w-200" @register="registerForm" @submit="handleSubmit" /> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,40 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { onMounted, ref } from 'vue' |
|
||||||
import { useRoute } from 'vue-router' |
|
||||||
import { descSchema } from './leave.data' |
|
||||||
import { Description, useDescription } from '@/components/Description' |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import { getLeave } from '@/api/bpm/leave' |
|
||||||
import { propTypes } from '@/utils/propTypes' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraJobModal' }) |
|
||||||
|
|
||||||
const props = defineProps({ |
|
||||||
id: propTypes.number.def(undefined), |
|
||||||
}) |
|
||||||
|
|
||||||
const { query } = useRoute() |
|
||||||
const datas = ref() |
|
||||||
|
|
||||||
const [registerDesc] = useDescription({ |
|
||||||
schema: descSchema, |
|
||||||
data: datas, |
|
||||||
}) |
|
||||||
|
|
||||||
async function getInfo() { |
|
||||||
const queryId = query.id as unknown as number // 从 URL 传递过来的 id 编号 |
|
||||||
const res = await getLeave(props.id || queryId) |
|
||||||
datas.value = res |
|
||||||
} |
|
||||||
|
|
||||||
/** 初始化 */ |
|
||||||
onMounted(async () => { |
|
||||||
await getInfo() |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper> |
|
||||||
<Description :column="1" @register="registerDesc" /> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,104 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { columns, searchFormSchema } from './leave.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { getLeavePage } from '@/api/bpm/leave' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { cancelProcessInstance } from '@/api/bpm/processInstance' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmLeave' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const go = useGo() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '请假列表', |
|
||||||
api: getLeavePage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
actionColumn: { |
|
||||||
width: 160, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
/** 添加操作 */ |
|
||||||
function handleCreate() { |
|
||||||
go({ name: 'OALeaveCreate' }) |
|
||||||
} |
|
||||||
|
|
||||||
/** 详情操作 */ |
|
||||||
function handleDetail(row) { |
|
||||||
go({ |
|
||||||
name: 'OALeaveDetail', |
|
||||||
query: { |
|
||||||
id: row.id, |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
/** 取消请假操作 */ |
|
||||||
async function cancelLeave(row) { |
|
||||||
// // 二次确认 |
|
||||||
// const { value } = await ElMessageBox.prompt('请输入取消原因', '取消流程', { |
|
||||||
// confirmButtonText: t('common.ok'), |
|
||||||
// cancelButtonText: t('common.cancel'), |
|
||||||
// inputPattern: /^[\s\S]*.*\S[\s\S]*$/, // 判断非空,且非空格 |
|
||||||
// inputErrorMessage: '取消原因不能为空', |
|
||||||
// }) |
|
||||||
const value = '' |
|
||||||
// 发起取消 |
|
||||||
await cancelProcessInstance(row.id, value) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
|
|
||||||
/** 审批进度 */ |
|
||||||
function handleProcessDetail(row) { |
|
||||||
go({ |
|
||||||
name: 'BpmProcessInstanceDetail', |
|
||||||
query: { |
|
||||||
id: row.processInstanceId, |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
发起请假 |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.SEARCH, label: t('action.detail'), auth: 'bpm:oa-leave:query', onClick: handleDetail.bind(null, record) }, |
|
||||||
{ icon: IconEnum.LOG, label: '进度', auth: 'bpm:oa-leave:query', onClick: handleProcessDetail.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.cancel'), |
|
||||||
auth: 'bpm:oa-leave:create', |
|
||||||
ifShow: () => { |
|
||||||
return record.result === 1 |
|
||||||
}, |
|
||||||
onClick: cancelLeave.bind(null, record), |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,158 +0,0 @@ |
|||||||
import type { DescItem } from '@/components/Description' |
|
||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '申请编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '状态', |
|
||||||
dataIndex: 'result', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '开始时间', |
|
||||||
dataIndex: 'startTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '结束时间', |
|
||||||
dataIndex: 'endTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '请假类型', |
|
||||||
dataIndex: 'type', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_OA_LEAVE_TYPE) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '原因', |
|
||||||
dataIndex: 'reason', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '申请时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '请假类型', |
|
||||||
field: 'type', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '申请时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '结果', |
|
||||||
field: 'result', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT), |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '原因', |
|
||||||
field: 'reason', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '请假类型', |
|
||||||
field: 'type', |
|
||||||
required: true, |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE) as any, |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '开始时间', |
|
||||||
field: 'startTime', |
|
||||||
required: true, |
|
||||||
component: 'DatePicker', |
|
||||||
componentProps: { |
|
||||||
showTime: true, |
|
||||||
format: 'YYYY-MM-DD HH:mm:ss', |
|
||||||
valueFormat: 'x', |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '结束时间', |
|
||||||
field: 'endTime', |
|
||||||
required: true, |
|
||||||
component: 'DatePicker', |
|
||||||
componentProps: { |
|
||||||
showTime: true, |
|
||||||
format: 'YYYY-MM-DD HH:mm:ss', |
|
||||||
valueFormat: 'x', |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '原因', |
|
||||||
field: 'reason', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const descSchema: DescItem[] = [ |
|
||||||
{ |
|
||||||
label: '请假类型', |
|
||||||
field: 'merchantOrderId', |
|
||||||
render: (curVal) => { |
|
||||||
return useRender.renderTag(curVal) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '开始时间', |
|
||||||
field: 'startTime', |
|
||||||
render: (curVal) => { |
|
||||||
return useRender.renderDate(curVal, 'YYYY-MM-DD') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '结束时间', |
|
||||||
field: 'endTime', |
|
||||||
render: (curVal) => { |
|
||||||
return useRender.renderDate(curVal, 'YYYY-MM-DD') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '原因', |
|
||||||
field: 'reason', |
|
||||||
}, |
|
||||||
] |
|
@ -1,32 +0,0 @@ |
|||||||
import type { BasicColumn } from '@/components/Table' |
|
||||||
import { DICT_TYPE } from '@/utils/dict' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '流程名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程分类', |
|
||||||
dataIndex: 'category', |
|
||||||
width: 120, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_MODEL_CATEGORY) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程版本', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 120, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderTag(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程描述', |
|
||||||
dataIndex: 'description', |
|
||||||
width: 200, |
|
||||||
}, |
|
||||||
] |
|
@ -1,115 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { Card, Steps } from 'ant-design-vue' |
|
||||||
import { ref } from 'vue' |
|
||||||
import { columns } from './create.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import Icon from '@/components/Icon' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { getProcessDefinitionBpmnXML, getProcessDefinitionList } from '@/api/bpm/definition' |
|
||||||
import { createProcessInstance } from '@/api/bpm/processInstance' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmProcessInstanceCreate' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const current = ref(0) |
|
||||||
|
|
||||||
const bpmnXML = ref(null) // BPMN 数据 |
|
||||||
const selectProcessInstance = ref() // 选择的流程实例 |
|
||||||
|
|
||||||
const [registerTable] = useTable({ |
|
||||||
api: getProcessDefinitionList, |
|
||||||
columns, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
/** 处理选择流程的按钮操作 */ |
|
||||||
async function handleSelect(row) { |
|
||||||
// 设置选择的流程 |
|
||||||
selectProcessInstance.value = row |
|
||||||
|
|
||||||
// 情况一:流程表单 |
|
||||||
if (row.formType === 10) { |
|
||||||
// 设置表单 |
|
||||||
// setConfAndFields2(detailForm, row.formConf, row.formFields) |
|
||||||
// 加载流程图 |
|
||||||
bpmnXML.value = await getProcessDefinitionBpmnXML(row.id) |
|
||||||
// 情况二:业务表单 |
|
||||||
} |
|
||||||
else if (row.formCustomCreatePath) { |
|
||||||
await go({ |
|
||||||
path: row.formCustomCreatePath, |
|
||||||
}) |
|
||||||
// 这里暂时无需加载流程图,因为跳出到另外个 Tab; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** 提交按钮 */ |
|
||||||
async function submitForm(formData) { |
|
||||||
// if (!fApi.value || !selectProcessInstance.value) |
|
||||||
// return |
|
||||||
|
|
||||||
// // 提交请求 |
|
||||||
// fApi.value.btn.loading(true) |
|
||||||
try { |
|
||||||
await createProcessInstance({ |
|
||||||
processDefinitionId: selectProcessInstance.value.id, |
|
||||||
variables: formData, |
|
||||||
}) |
|
||||||
// 提示 |
|
||||||
createMessage.success('发起流程成功') |
|
||||||
go() |
|
||||||
} |
|
||||||
finally { |
|
||||||
// fApi.value.btn.loading(false) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper> |
|
||||||
<div class="mx-auto my-0 mt-2.5 w-200"> |
|
||||||
<Steps :current="current"> |
|
||||||
<Steps.Step title="选择流程" /> |
|
||||||
<Steps.Step title="流程提交" /> |
|
||||||
</Steps> |
|
||||||
</div> |
|
||||||
<div class="m-5"> |
|
||||||
<BasicTable v-if="!selectProcessInstance" @register="registerTable"> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.SEND, label: '选择', onClick: handleSelect.bind(null, record) }, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<div v-if="selectProcessInstance"> |
|
||||||
<Card :title="`申请信息——【${selectProcessInstance.name}】`"> |
|
||||||
<template #extra> |
|
||||||
<a-button type="primary" @click="selectProcessInstance = undefined"> |
|
||||||
<Icon icon="ep:delete" /> 选择其它流程 |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<p>表单</p> |
|
||||||
<a-button type="primary" @click="submitForm"> |
|
||||||
提交 |
|
||||||
</a-button> |
|
||||||
<p>流程图</p> |
|
||||||
</Card> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>123</div> |
|
||||||
</template> |
|
@ -1,84 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { columns, searchFormSchema } from './processInstance.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { cancelProcessInstance, getMyProcessInstancePage } from '@/api/bpm/processInstance' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraApiErrorLog' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '我的流程列表', |
|
||||||
api: getMyProcessInstancePage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
/** 发起流程操作 */ |
|
||||||
function handleCreate() { |
|
||||||
go({ name: 'BpmProcessInstanceCreate' }) |
|
||||||
} |
|
||||||
|
|
||||||
/** 查看详情 */ |
|
||||||
function handleDetail(record: Recordable) { |
|
||||||
go({ name: 'BpmProcessInstanceDetail', query: { id: record.id } }) |
|
||||||
} |
|
||||||
|
|
||||||
/** 取消按钮操作 */ |
|
||||||
async function handleCancel(record: Recordable) { |
|
||||||
await cancelProcessInstance(record.id, 'TODO') |
|
||||||
createMessage.success('取消成功') |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['bpm:process-instance:query']" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
发起流程 |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ |
|
||||||
icon: IconEnum.VIEW, |
|
||||||
label: t('action.detail'), |
|
||||||
auth: 'bpm:process-instance:query', |
|
||||||
onClick: handleDetail.bind(null, record), |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.cancel'), |
|
||||||
ifShow: record.result === 1, |
|
||||||
auth: 'bpm:process-instance:cancel', |
|
||||||
popConfirm: { |
|
||||||
title: t('action.cancel'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleCancel.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,118 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '流程编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 260, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程分类', |
|
||||||
dataIndex: 'category', |
|
||||||
width: 120, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_MODEL_CATEGORY) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '当前审批任务', |
|
||||||
dataIndex: 'tasks', |
|
||||||
width: 120, |
|
||||||
customRender: ({ record }) => { |
|
||||||
if (record.tasks && record.tasks.length > 0) { |
|
||||||
const texts: any[] = [] |
|
||||||
record.tasks.forEach((val) => { |
|
||||||
texts.push(val.name) |
|
||||||
}) |
|
||||||
return useRender.renderTags(texts) |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '状态', |
|
||||||
dataIndex: 'status', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '结果', |
|
||||||
dataIndex: 'result', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '提交时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '结束时间', |
|
||||||
dataIndex: 'endTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '流程名称', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '所属流程', |
|
||||||
field: 'processDefinitionId', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '流程分类', |
|
||||||
field: 'category', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_MODEL_CATEGORY) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '状态', |
|
||||||
field: 'status', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS), |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '结果', |
|
||||||
field: 'result', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT), |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '提交时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
@ -1,79 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { getDate } from '@/utils/dateUtil' |
|
||||||
import { DICT_TYPE } from '@/utils/dict' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '任务编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '任务名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '所属流程', |
|
||||||
dataIndex: 'processInstance.name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程发起人', |
|
||||||
dataIndex: 'processInstance.startUserNickname', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '结果', |
|
||||||
dataIndex: 'result', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '审批意见', |
|
||||||
dataIndex: 'reason', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '审批时间', |
|
||||||
dataIndex: 'endTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '耗时', |
|
||||||
dataIndex: 'durationInMillis', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return getDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '流程名', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '创建时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
@ -1,53 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { columns, searchFormSchema } from './done.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { getDoneTaskPage } from '@/api/bpm/task' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmDoneTask' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
|
|
||||||
const [registerTable] = useTable({ |
|
||||||
title: '审批列表', |
|
||||||
api: getDoneTaskPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function openDetail(record: Recordable) { |
|
||||||
console.info(record) |
|
||||||
} |
|
||||||
|
|
||||||
function handleAudit(record: Recordable) { |
|
||||||
go({ name: 'BpmProcessInstanceDetail', query: { id: record.id } }) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.VIEW, label: t('action.detail'), onClick: openDetail.bind(null, record) }, |
|
||||||
{ icon: IconEnum.VIEW, label: '流程', onClick: handleAudit.bind(null, record) }, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,44 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { columns, searchFormSchema } from './todo.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { getTodoTaskPage } from '@/api/bpm/task' |
|
||||||
|
|
||||||
defineOptions({ name: 'BpmTodoTask' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
|
|
||||||
const [registerTable] = useTable({ |
|
||||||
title: '审批列表', |
|
||||||
api: getTodoTaskPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleAudit(record: Recordable) { |
|
||||||
go({ name: 'BpmProcessInstanceDetail', query: { id: record.id } }) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction :actions="[{ icon: IconEnum.VIEW, label: '审批进度', onClick: handleAudit.bind(null, record) }]" /> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,59 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '任务编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '任务名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '所属流程', |
|
||||||
dataIndex: 'processInstance.name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '流程发起人', |
|
||||||
dataIndex: 'processInstance.startUserNickname', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '状态', |
|
||||||
dataIndex: 'suspensionState', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
if (text === 1) |
|
||||||
return useRender.renderTag('激活', 'success') |
|
||||||
else if (text === 2) |
|
||||||
return useRender.renderTag('挂起', 'warning') |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '流程名', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '创建时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中 taskAssignRule</div> |
|
||||||
</template> |
|
@ -1,25 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { infoSchema } from './apiAccessLog.data' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { Description, useDescription } from '@/components/Description/index' |
|
||||||
|
|
||||||
defineOptions({ name: 'AcessLogModal' }) |
|
||||||
|
|
||||||
const logData = ref() |
|
||||||
const [registerModalInner, { closeModal }] = useModalInner((record: Recordable) => { |
|
||||||
logData.value = record |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerDescription] = useDescription({ |
|
||||||
column: 1, |
|
||||||
schema: infoSchema, |
|
||||||
data: logData, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" title="访问日志详情" width="800px" @register="registerModalInner" @ok="closeModal"> |
|
||||||
<Description @register="registerDescription" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,222 +0,0 @@ |
|||||||
import { h } from 'vue' |
|
||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
import type { DescItem } from '@/components/Description/index' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '日志编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '用户编号', |
|
||||||
dataIndex: 'userId', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '用户类型', |
|
||||||
dataIndex: 'userType', |
|
||||||
width: 120, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.USER_TYPE) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '应用名', |
|
||||||
dataIndex: 'applicationName', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '请求方法名', |
|
||||||
dataIndex: 'requestMethod', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '请求地址', |
|
||||||
dataIndex: 'requestUrl', |
|
||||||
width: 250, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '请求时间', |
|
||||||
dataIndex: 'beginTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '执行时长', |
|
||||||
dataIndex: 'duration', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderText(text.toString(), 'ms') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '操作结果', |
|
||||||
dataIndex: 'status', |
|
||||||
width: 180, |
|
||||||
ellipsis: true, |
|
||||||
customRender: ({ record }) => { |
|
||||||
const success = record.resultCode === 0 |
|
||||||
return useRender.renderTag(success ? '成功' : '失败', success ? '#87d068' : '#f50') |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '用户编号', |
|
||||||
field: 'userId', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '用户类型', |
|
||||||
field: 'userType', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.USER_TYPE) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '应用名', |
|
||||||
field: 'applicationName', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '请求地址', |
|
||||||
field: 'requestUrl', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '请求时间', |
|
||||||
field: 'beginTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '执行时长', |
|
||||||
field: 'duration', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '结果码', |
|
||||||
field: 'resultCode', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
const httpMethods = [ |
|
||||||
{ value: 'GET', color: '#108ee9' }, |
|
||||||
{ value: 'POST', color: '#2db7f5' }, |
|
||||||
{ value: 'PUT', color: 'warning' }, |
|
||||||
{ value: 'DELETE', color: '#f50' }, |
|
||||||
] |
|
||||||
|
|
||||||
export const infoSchema: DescItem[] = [ |
|
||||||
{ |
|
||||||
label: '日志id', |
|
||||||
field: 'id', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '链路id', |
|
||||||
field: 'traceId', |
|
||||||
show: data => data && data.traceId && data.traceId !== '', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '应用名称', |
|
||||||
field: 'applicationName', |
|
||||||
labelMinWidth: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'userId', |
|
||||||
label: '用户id', |
|
||||||
render(value, data) { |
|
||||||
const tag = useRender.renderDict(data.userType, DICT_TYPE.USER_TYPE) |
|
||||||
const uidTag = useRender.renderTag(`uid: ${value}`) |
|
||||||
return h('span', {}, [tag, uidTag]) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'resultCode', |
|
||||||
label: '请求结果', |
|
||||||
render(value) { |
|
||||||
return useRender.renderTag(value === 0 ? '成功' : '失败', value === 0 ? '#87d068' : '#f50') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'resultMsg', |
|
||||||
label: '响应信息', |
|
||||||
show(data) { |
|
||||||
return data && data.resultMsg && data.resultMsg !== '' |
|
||||||
}, |
|
||||||
render(value) { |
|
||||||
return h('span', { style: { color: 'red', fontWeight: 'bold' } }, value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'userIp', |
|
||||||
label: '请求ip', |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'userAgent', |
|
||||||
label: 'userAgent', |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'beginTime', |
|
||||||
label: '请求时间', |
|
||||||
render(value) { |
|
||||||
return useRender.renderDate(value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'requestUrl', |
|
||||||
label: '请求路径', |
|
||||||
render(_, data) { |
|
||||||
if (!data) |
|
||||||
return '' |
|
||||||
|
|
||||||
const { requestMethod, requestUrl } = data |
|
||||||
const current = httpMethods.find(item => item.value === requestMethod.toUpperCase()) |
|
||||||
const methodTag = current ? useRender.renderTag(requestMethod, current.color) : requestMethod |
|
||||||
return h('span', {}, [methodTag, requestUrl]) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'requestParams', |
|
||||||
label: '请求参数', |
|
||||||
render(value) { |
|
||||||
return useRender.renderJsonPreview(value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'beginTime', |
|
||||||
label: '请求开始时间', |
|
||||||
render(value) { |
|
||||||
return useRender.renderDate(value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'endTime', |
|
||||||
label: '请求结束时间', |
|
||||||
render(value) { |
|
||||||
return useRender.renderDate(value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'duration', |
|
||||||
label: '请求耗时', |
|
||||||
render(value) { |
|
||||||
// 为0的话需要转为string 否则不会显示
|
|
||||||
return useRender.renderText(String(value), 'ms') |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
@ -1,74 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { columns, searchFormSchema } from './apiAccessLog.data' |
|
||||||
import AccessLogModal from './AccessLogModal.vue' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import type { ApiAccessLogExportReqVO } from '@/api/infra/apiAccessLog' |
|
||||||
import { exportApiAccessLog, getApiAccessLogPage } from '@/api/infra/apiAccessLog' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraApiErrorLog' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createConfirm, createMessage } = useMessage() |
|
||||||
const [registerTable, { getForm }] = useTable({ |
|
||||||
title: '访问日志列表', |
|
||||||
api: getApiAccessLogPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 120, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
function handleShowInfo(record: Recordable) { |
|
||||||
openModal(true, record) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleExport() { |
|
||||||
createConfirm({ |
|
||||||
title: t('common.exportTitle'), |
|
||||||
iconType: 'warning', |
|
||||||
content: t('common.exportMessage'), |
|
||||||
async onOk() { |
|
||||||
await exportApiAccessLog(getForm().getFieldsValue() as ApiAccessLogExportReqVO) |
|
||||||
createMessage.success(t('common.exportSuccessText')) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:api-access-log:export']" :pre-icon="IconEnum.EXPORT" @click="handleExport"> |
|
||||||
{{ t('action.export') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ |
|
||||||
icon: IconEnum.VIEW, |
|
||||||
label: t('action.detail'), |
|
||||||
onClick: handleShowInfo.bind(null, record), |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<AccessLogModal @register="registerModal" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,25 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { infoSchema } from './apiErrorLog.data' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { Description, useDescription } from '@/components/Description/index' |
|
||||||
|
|
||||||
defineOptions({ name: 'ErrorLogModal' }) |
|
||||||
|
|
||||||
const logData = ref() |
|
||||||
const [registerModalInner, { closeModal }] = useModalInner((record: Recordable) => { |
|
||||||
logData.value = record |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerDescription] = useDescription({ |
|
||||||
column: 1, |
|
||||||
schema: infoSchema, |
|
||||||
data: logData, |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" title="错误日志详情" width="800px" @register="registerModalInner" @ok="closeModal"> |
|
||||||
<Description @register="registerDescription" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,248 +0,0 @@ |
|||||||
import { Textarea } from 'ant-design-vue' |
|
||||||
import { h } from 'vue' |
|
||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
import type { DescItem } from '@/components/Description/index' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '日志编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '用户编号', |
|
||||||
dataIndex: 'userId', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '用户类型', |
|
||||||
dataIndex: 'userType', |
|
||||||
width: 120, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.USER_TYPE) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '应用名', |
|
||||||
dataIndex: 'applicationName', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '请求方法名', |
|
||||||
dataIndex: 'requestMethod', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '请求地址', |
|
||||||
dataIndex: 'requestUrl', |
|
||||||
width: 250, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '异常发生时间', |
|
||||||
dataIndex: 'exceptionTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '异常名', |
|
||||||
dataIndex: 'exceptionName', |
|
||||||
width: 250, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '处理状态', |
|
||||||
dataIndex: 'processStatus', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '用户编号', |
|
||||||
field: 'userId', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '用户名称', |
|
||||||
field: 'username', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '用户类型', |
|
||||||
field: 'userType', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.USER_TYPE) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '应用名', |
|
||||||
field: 'applicationName', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '请求地址', |
|
||||||
field: 'requestUrl', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '异常时间', |
|
||||||
field: 'exceptionTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理状态', |
|
||||||
field: 'processStatus', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS), |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
function renderText(value: string, color: string, bold = true) { |
|
||||||
return h('span', { style: { color, fontWeight: bold ? 'bold' : 'normal' } }, value) |
|
||||||
} |
|
||||||
|
|
||||||
const httpMethods = [ |
|
||||||
{ value: 'GET', color: '#108ee9' }, |
|
||||||
{ value: 'POST', color: '#2db7f5' }, |
|
||||||
{ value: 'PUT', color: 'warning' }, |
|
||||||
{ value: 'DELETE', color: '#f50' }, |
|
||||||
] |
|
||||||
|
|
||||||
export const infoSchema: DescItem[] = [ |
|
||||||
{ |
|
||||||
field: 'id', |
|
||||||
label: '异常id', |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'traceId', |
|
||||||
label: '链路ID', |
|
||||||
show(data) { |
|
||||||
return data && data.traceId && data.traceId !== '' |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'applicationName', |
|
||||||
label: '应用名称', |
|
||||||
labelMinWidth: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'processStatus', |
|
||||||
label: '处理状态', |
|
||||||
render(_, data) { |
|
||||||
const { processStatus, processUserId } = data |
|
||||||
const tag = useRender.renderDict(processStatus, DICT_TYPE.INFRA_API_ERROR_LOG_PROCESS_STATUS) |
|
||||||
if (!processUserId) |
|
||||||
return tag |
|
||||||
|
|
||||||
const uidTag = useRender.renderTag(`uid: ${processUserId}`) |
|
||||||
return h('span', {}, [tag, uidTag]) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'processTime', |
|
||||||
label: '处理时间', |
|
||||||
show(data) { |
|
||||||
return data && data.processTime && data.processTime !== '' |
|
||||||
}, |
|
||||||
render(value) { |
|
||||||
return useRender.renderDate(value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'userId', |
|
||||||
label: '用户id', |
|
||||||
render(value, data) { |
|
||||||
const tag = useRender.renderDict(data.userType, DICT_TYPE.USER_TYPE) |
|
||||||
const uidTag = useRender.renderTag(`uid: ${value}`) |
|
||||||
return h('span', {}, [tag, uidTag]) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'userIp', |
|
||||||
label: 'ip地址', |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'requestUrl', |
|
||||||
label: '请求地址', |
|
||||||
render(_, data) { |
|
||||||
if (data) { |
|
||||||
const { requestMethod } = data |
|
||||||
const current = httpMethods.find(item => item.value === requestMethod) |
|
||||||
const tag = current ? useRender.renderTag(requestMethod, current.color) : requestMethod |
|
||||||
return h('span', {}, [tag, data.requestUrl]) |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'requestParams', |
|
||||||
label: '请求参数', |
|
||||||
render(value) { |
|
||||||
return useRender.renderJsonPreview(value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'userAgent', |
|
||||||
label: 'userAgent', |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'exceptionTime', |
|
||||||
label: '异常时间', |
|
||||||
render(value) { |
|
||||||
return useRender.renderDate(value) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'exceptionClassName', |
|
||||||
label: '异常类名/方法', |
|
||||||
render(_, data) { |
|
||||||
if (data) |
|
||||||
return renderText(`${data.exceptionClassName} / ${data.exceptionMethodName}`, 'red') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'exceptionMessage', |
|
||||||
label: '异常信息', |
|
||||||
render(value) { |
|
||||||
return renderText(value, 'red') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'exceptionFileName', |
|
||||||
label: '异常文件名', |
|
||||||
render(_, data) { |
|
||||||
if (data) |
|
||||||
return useRender.renderText(data.exceptionFileName, `Line: ${data.exceptionLineNumber}`) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'exceptionName', |
|
||||||
label: '异常名称', |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'exceptionRootCauseMessage', |
|
||||||
label: '异常信息', |
|
||||||
}, |
|
||||||
{ |
|
||||||
field: 'exceptionStackTrace', |
|
||||||
label: '异常堆栈', |
|
||||||
render(value) { |
|
||||||
return h(Textarea, { value, readonly: true, style: { minHeight: '300px' } }) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
@ -1,101 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { columns, searchFormSchema } from './apiErrorLog.data' |
|
||||||
import ErrorLogModal from './ErrorLogModal.vue' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { InfraApiErrorLogProcessStatusEnum } from '@/enums/systemEnum' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import type { ApiErrorLogExportReqVO } from '@/api/infra/apiErrorLog' |
|
||||||
import { exportApiErrorLog, getApiErrorLogPage, updateApiErrorLogProcess } from '@/api/infra/apiErrorLog' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraApiErrorLog' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createConfirm, createMessage } = useMessage() |
|
||||||
const [registerTable, { getForm, reload }] = useTable({ |
|
||||||
title: '异常日志列表', |
|
||||||
api: getApiErrorLogPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 220, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
function handleShowInfo(record: Recordable) { |
|
||||||
openModal(true, record) |
|
||||||
} |
|
||||||
|
|
||||||
function handleProcessClick(record, processStatus: number, type: string) { |
|
||||||
createConfirm({ |
|
||||||
iconType: 'warning', |
|
||||||
content: `确认标记为${type}?`, |
|
||||||
async onOk() { |
|
||||||
await updateApiErrorLogProcess(record.id, processStatus) |
|
||||||
createMessage.success(t('common.successText')) |
|
||||||
reload() |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleExport() { |
|
||||||
createConfirm({ |
|
||||||
title: t('common.exportTitle'), |
|
||||||
iconType: 'warning', |
|
||||||
content: t('common.exportMessage'), |
|
||||||
async onOk() { |
|
||||||
await exportApiErrorLog(getForm().getFieldsValue() as ApiErrorLogExportReqVO) |
|
||||||
createMessage.success(t('common.exportSuccessText')) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:api-error-log:export']" :pre-icon="IconEnum.EXPORT" @click="handleExport"> |
|
||||||
{{ t('action.export') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ |
|
||||||
icon: IconEnum.VIEW, |
|
||||||
label: t('action.detail'), |
|
||||||
onClick: handleShowInfo.bind(null, record), |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.EDIT, |
|
||||||
label: '已处理', |
|
||||||
auth: 'infra:api-error-log:update-status', |
|
||||||
ifShow: () => record.processStatus === InfraApiErrorLogProcessStatusEnum.INIT, |
|
||||||
onClick: handleProcessClick.bind(null, record, InfraApiErrorLogProcessStatusEnum.DONE, '已处理'), |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.EDIT, |
|
||||||
label: '已忽略', |
|
||||||
auth: 'infra:api-error-log:update-status', |
|
||||||
ifShow: () => record.processStatus === InfraApiErrorLogProcessStatusEnum.INIT, |
|
||||||
onClick: handleProcessClick.bind(null, record, InfraApiErrorLogProcessStatusEnum.IGNORE, '已忽略'), |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<ErrorLogModal @register="registerModal" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,10 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import { VFormDesign } from '@/components/FormDesign' |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper dense fixed-height content-full-height> |
|
||||||
<VFormDesign /> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,96 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { onMounted, reactive, ref } from 'vue' |
|
||||||
import { Steps } from 'ant-design-vue' |
|
||||||
import { useRoute } from 'vue-router' |
|
||||||
import BasicInfoForm from './components/BasicInfoForm.vue' |
|
||||||
import CloumInfoForm from './components/CloumInfoForm.vue' |
|
||||||
import FinishForm from './components/FinishForm.vue' |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import { getCodegenTable, updateCodegenTable } from '@/api/infra/codegen' |
|
||||||
|
|
||||||
const Step = Steps.Step |
|
||||||
|
|
||||||
const { query } = useRoute() |
|
||||||
|
|
||||||
// 表详细信息 |
|
||||||
const basicInfo = ref<any>() |
|
||||||
// 表列信息 |
|
||||||
const columnsInfo = ref<any[]>([]) |
|
||||||
|
|
||||||
const basicInfoValue = ref() |
|
||||||
|
|
||||||
const columnsInfoValue = ref() |
|
||||||
|
|
||||||
const current = ref(0) |
|
||||||
const state = reactive({ |
|
||||||
initSetp2: false, |
|
||||||
initSetp3: false, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleStep1Next(step1Values: any) { |
|
||||||
current.value++ |
|
||||||
basicInfoValue.value = step1Values |
|
||||||
state.initSetp2 = true |
|
||||||
} |
|
||||||
|
|
||||||
function handleStepPrev() { |
|
||||||
current.value-- |
|
||||||
} |
|
||||||
|
|
||||||
async function handleStep2Next(step2Values: any) { |
|
||||||
current.value++ |
|
||||||
columnsInfoValue.value = step2Values |
|
||||||
await handleSubmit() |
|
||||||
state.initSetp3 = true |
|
||||||
} |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
basicInfoValue.value.id = query.id as unknown as number |
|
||||||
const genTable = { |
|
||||||
table: basicInfoValue.value, |
|
||||||
columns: columnsInfoValue.value, |
|
||||||
} |
|
||||||
await updateCodegenTable(genTable) |
|
||||||
} |
|
||||||
|
|
||||||
function handleRedo() { |
|
||||||
current.value = 0 |
|
||||||
state.initSetp2 = false |
|
||||||
state.initSetp3 = false |
|
||||||
} |
|
||||||
|
|
||||||
async function getList() { |
|
||||||
const tableId = query.id as unknown as number |
|
||||||
const res = await getCodegenTable(tableId) |
|
||||||
basicInfo.value = res.table |
|
||||||
columnsInfo.value = res.columns |
|
||||||
} |
|
||||||
|
|
||||||
onMounted(async () => { |
|
||||||
await getList() |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper> |
|
||||||
<div class="mx-auto my-0 mt-2.5 w-200"> |
|
||||||
<Steps :current="current"> |
|
||||||
<Step title="生成信息" /> |
|
||||||
<Step title="字段信息" /> |
|
||||||
<Step title="完成" /> |
|
||||||
</Steps> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div class="m-5"> |
|
||||||
<BasicInfoForm v-show="current === 0" :basic-info="basicInfo" @next="handleStep1Next" /> |
|
||||||
<CloumInfoForm |
|
||||||
v-show="current === 1" |
|
||||||
v-if="state.initSetp2" |
|
||||||
:columns-info="columnsInfo" |
|
||||||
@prev="handleStepPrev" |
|
||||||
@next="handleStep2Next" |
|
||||||
/> |
|
||||||
<FinishForm v-show="current === 2" v-if="state.initSetp3" @redo="handleRedo" /> |
|
||||||
</div> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,157 +0,0 @@ |
|||||||
import { getDataSourceConfigList } from '@/api/infra/dataSourceConfig' |
|
||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
|
|
||||||
const dataSourceConfigs = await getDataSourceConfigList() |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '数据源', |
|
||||||
dataIndex: 'dataSourceConfigId', |
|
||||||
width: 100, |
|
||||||
customRender: ({ text }) => { |
|
||||||
for (const config of dataSourceConfigs) { |
|
||||||
if (text === config.id) |
|
||||||
return config.name |
|
||||||
} |
|
||||||
return `未知【${text}】` |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '表名称', |
|
||||||
dataIndex: 'tableName', |
|
||||||
width: 200, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '表描述', |
|
||||||
dataIndex: 'tableComment', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '实体', |
|
||||||
dataIndex: 'className', |
|
||||||
width: 200, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '更新时间', |
|
||||||
dataIndex: 'updateTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '表名称', |
|
||||||
field: 'tableName', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表描述', |
|
||||||
field: 'tableComment', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '创建时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '编号', |
|
||||||
field: 'id', |
|
||||||
show: false, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '岗位名称', |
|
||||||
field: 'name', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '岗位编码', |
|
||||||
field: 'code', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '岗位顺序', |
|
||||||
field: 'sort', |
|
||||||
required: true, |
|
||||||
defaultValue: 0, |
|
||||||
component: 'InputNumber', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '状态', |
|
||||||
field: 'status', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.COMMON_STATUS) as any, |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '备注', |
|
||||||
field: 'remark', |
|
||||||
component: 'InputTextArea', |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const importTableColumns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '表名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 200, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '表描述', |
|
||||||
dataIndex: 'comment', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const importTableSearchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '数据源', |
|
||||||
field: 'dataSourceConfigId', |
|
||||||
component: 'Select', |
|
||||||
required: true, |
|
||||||
defaultValue: dataSourceConfigs[0].id, |
|
||||||
componentProps: { |
|
||||||
options: dataSourceConfigs, |
|
||||||
fieldNames: { |
|
||||||
label: 'name', |
|
||||||
value: 'id', |
|
||||||
}, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表名称', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表描述', |
|
||||||
field: 'comment', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
@ -1,70 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { Divider } from 'ant-design-vue' |
|
||||||
import { watch } from 'vue' |
|
||||||
import { basicInfoSchemas } from './data' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import type { CodegenTableVO } from '@/api/infra/codegen/types' |
|
||||||
|
|
||||||
const props = defineProps({ |
|
||||||
basicInfo: { |
|
||||||
type: Object as PropType<Nullable<CodegenTableVO>>, |
|
||||||
default: () => null, |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
const emit = defineEmits(['next']) |
|
||||||
|
|
||||||
const [register, { setFieldsValue, resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
schemas: basicInfoSchemas, |
|
||||||
actionColOptions: { |
|
||||||
span: 14, |
|
||||||
}, |
|
||||||
showResetButton: false, |
|
||||||
submitButtonOptions: { |
|
||||||
text: '保存', |
|
||||||
}, |
|
||||||
submitFunc: customSubmitFunc, |
|
||||||
}) |
|
||||||
|
|
||||||
async function customSubmitFunc() { |
|
||||||
try { |
|
||||||
const values = await validate() |
|
||||||
emit('next', values) |
|
||||||
} |
|
||||||
catch (error) {} |
|
||||||
} |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.basicInfo, |
|
||||||
(basicInfo) => { |
|
||||||
if (!basicInfo) |
|
||||||
return |
|
||||||
resetFields() |
|
||||||
setFieldsValue({ ...basicInfo }) |
|
||||||
}, |
|
||||||
{ |
|
||||||
deep: true, |
|
||||||
immediate: true, |
|
||||||
}, |
|
||||||
) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<div class="mx-auto my-0 w-80%"> |
|
||||||
<BasicForm @register="register" /> |
|
||||||
</div> |
|
||||||
<Divider /> |
|
||||||
<h3 class="mb-3 text-base"> |
|
||||||
说明 |
|
||||||
</h3> |
|
||||||
<h4 class="mb-1 text-sm"> |
|
||||||
基本信息 |
|
||||||
</h4> |
|
||||||
<p> 配置生成的基本信息 </p> |
|
||||||
|
|
||||||
<h4>生成信息</h4> |
|
||||||
<p> 配置生成生成的详细信息。 </p> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,62 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { Divider } from 'ant-design-vue' |
|
||||||
import { columns } from './data' |
|
||||||
import type { EditRecordRow } from '@/components/Table' |
|
||||||
import { BasicTable, useTable } from '@/components/Table' |
|
||||||
import type { CodegenColumnVO } from '@/api/infra/codegen/types' |
|
||||||
|
|
||||||
defineProps({ |
|
||||||
columnsInfo: { |
|
||||||
type: Array as PropType<CodegenColumnVO[]>, |
|
||||||
default: () => null, |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
const emit = defineEmits(['next', 'prev']) |
|
||||||
|
|
||||||
const [registerTable, { getDataSource }] = useTable({ |
|
||||||
columns, |
|
||||||
maxHeight: 700, |
|
||||||
pagination: false, |
|
||||||
useSearchForm: false, |
|
||||||
showTableSetting: false, |
|
||||||
showIndexColumn: false, |
|
||||||
}) |
|
||||||
|
|
||||||
async function customResetFunc() { |
|
||||||
emit('prev') |
|
||||||
} |
|
||||||
|
|
||||||
async function customSubmitFunc() { |
|
||||||
const tableValue = getDataSource() |
|
||||||
emit('next', tableValue) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEdit(record: EditRecordRow) { |
|
||||||
record.onEdit?.(true) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div class="step2"> |
|
||||||
<div class="mx-auto my-0 w-full"> |
|
||||||
<BasicTable :data-source="columnsInfo" @register="registerTable" @row-click="handleEdit" /> |
|
||||||
</div> |
|
||||||
<Divider /> |
|
||||||
<div class="flex justify-center"> |
|
||||||
<a-button @click="customResetFunc"> |
|
||||||
上一步 |
|
||||||
</a-button> |
|
||||||
<a-button type="primary" @click="customSubmitFunc"> |
|
||||||
提交 |
|
||||||
</a-button> |
|
||||||
</div> |
|
||||||
<h3 class="mb-3 text-base"> |
|
||||||
说明 |
|
||||||
</h3> |
|
||||||
<h4 class="mb-1 text-sm"> |
|
||||||
配置字段 |
|
||||||
</h4> |
|
||||||
<p> 配置表的字段类型,增删改查,字典等 </p> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,55 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { Result } from 'ant-design-vue' |
|
||||||
import { useRoute } from 'vue-router' |
|
||||||
import PreviewModal from './PreviewModal.vue' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useTabs } from '@/hooks/web/useTabs' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { downloadCodegen, getCodegenTable } from '@/api/infra/codegen' |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { closeCurrent } = useTabs() |
|
||||||
const { query } = useRoute() |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal() |
|
||||||
|
|
||||||
function handlePreview() { |
|
||||||
const tableId = query.id as unknown as number |
|
||||||
const record = { id: tableId } |
|
||||||
openPreviewModal(true, { record }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleGenTable() { |
|
||||||
const tableId = query.id as unknown as number |
|
||||||
const res = await getCodegenTable(tableId) |
|
||||||
await downloadCodegen(res.table) |
|
||||||
createMessage.success(t('common.successText')) |
|
||||||
} |
|
||||||
|
|
||||||
function handleGoList() { |
|
||||||
closeCurrent() |
|
||||||
go('/infra/codegen') |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div class="m-5 bg-white px-8 py-12 dark:bg-dark"> |
|
||||||
<Result status="success" title="代码生成成功" sub-title="可点击下方按钮预览、下载,或返回列表页。"> |
|
||||||
<template #extra> |
|
||||||
<a-button key="console" type="primary" @click="handleGoList"> |
|
||||||
返回列表 |
|
||||||
</a-button> |
|
||||||
<a-button key="preview" @click="handlePreview"> |
|
||||||
预览 |
|
||||||
</a-button> |
|
||||||
<a-button key="download" @click="handleGenTable"> |
|
||||||
生成 |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
</Result> |
|
||||||
<PreviewModal @register="registerPreviewModal" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,43 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { importTableColumns, importTableSearchFormSchema } from '../codegen.data' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { BasicTable, useTable } from '@/components/Table' |
|
||||||
import { createCodegenList, getSchemaTableList } from '@/api/infra/codegen' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraImportTableModal' }) |
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
|
|
||||||
const [registerTable, { getSelectRowKeys, getForm }] = useTable({ |
|
||||||
api: getSchemaTableList, |
|
||||||
columns: importTableColumns, |
|
||||||
formConfig: { |
|
||||||
labelWidth: 80, |
|
||||||
schemas: importTableSearchFormSchema, |
|
||||||
}, |
|
||||||
rowSelection: { type: 'checkbox' }, |
|
||||||
rowKey: 'name', |
|
||||||
useSearchForm: true, |
|
||||||
pagination: false, |
|
||||||
showTableSetting: false, |
|
||||||
showIndexColumn: false, |
|
||||||
immediate: false, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
const datas = await getSelectRowKeys() |
|
||||||
const form = await getForm() |
|
||||||
await createCodegenList({ dataSourceConfigId: form.getFieldsValue().dataSourceConfigId, tableNames: datas }) |
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" :width="800" title="导入" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<BasicTable @register="registerTable" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,144 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, unref } from 'vue' |
|
||||||
import { Card, Tabs } from 'ant-design-vue' |
|
||||||
import { useClipboard } from '@vueuse/core' |
|
||||||
import { BasicTree } from '@/components/Tree' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { CodeEditor, MODE } from '@/components/CodeEditor' |
|
||||||
import { previewCodegen } from '@/api/infra/codegen' |
|
||||||
import type { CodegenPreviewVO } from '@/api/infra/codegen/types' |
|
||||||
import { handleTree2 } from '@/utils/tree' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraPreviewModal' }) |
|
||||||
|
|
||||||
const { createMessage } = useMessage() |
|
||||||
|
|
||||||
const fileTree = ref([]) |
|
||||||
const activeKey = ref('') |
|
||||||
const modeValue = ref(MODE.JS) |
|
||||||
const previewCodes = ref<CodegenPreviewVO[]>() |
|
||||||
|
|
||||||
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
|
|
||||||
const res = await previewCodegen(data.record.id) |
|
||||||
const file = handleFiles(res) |
|
||||||
previewCodes.value = res |
|
||||||
activeKey.value = res[0].filePath |
|
||||||
fileTree.value = handleTree2(file, 'id', 'parentId', 'children', '/') |
|
||||||
}) |
|
||||||
|
|
||||||
function handleSelect(keys) { |
|
||||||
activeKey.value = keys[0] |
|
||||||
} |
|
||||||
|
|
||||||
/** 生成 files 目录 */ |
|
||||||
interface filesType { |
|
||||||
id: string |
|
||||||
label: string |
|
||||||
parentId: string |
|
||||||
} |
|
||||||
|
|
||||||
function handleFiles(datas) { |
|
||||||
const exists = {} // key:file 的 id;value:true |
|
||||||
const files: filesType[] = [] |
|
||||||
// 遍历每个元素 |
|
||||||
for (const data of datas) { |
|
||||||
let paths = data.filePath.split('/') |
|
||||||
let fullPath = '' // 从头开始的路径,用于生成 id |
|
||||||
// 特殊处理 java 文件 |
|
||||||
if (paths[paths.length - 1].includes('.java')) { |
|
||||||
const newPaths: string[] = [] |
|
||||||
for (let i = 0; i < paths.length; i++) { |
|
||||||
let path = paths[i] |
|
||||||
if (path !== 'java') { |
|
||||||
newPaths.push(path) |
|
||||||
continue |
|
||||||
} |
|
||||||
newPaths.push(path) |
|
||||||
// 特殊处理中间的 package,进行合并 |
|
||||||
let tmp = '' |
|
||||||
while (i < paths.length) { |
|
||||||
path = paths[i + 1] |
|
||||||
if ( |
|
||||||
path === 'controller' |
|
||||||
|| path === 'convert' |
|
||||||
|| path === 'dal' |
|
||||||
|| path === 'enums' |
|
||||||
|| path === 'service' |
|
||||||
|| path === 'vo' // 下面三个,主要是兜底。可能考虑到有人改了包结构 |
|
||||||
|| path === 'mysql' |
|
||||||
|| path === 'dataobject' |
|
||||||
) |
|
||||||
break |
|
||||||
|
|
||||||
tmp = tmp ? `${tmp}.${path}` : path |
|
||||||
i++ |
|
||||||
} |
|
||||||
if (tmp) |
|
||||||
newPaths.push(tmp) |
|
||||||
} |
|
||||||
paths = newPaths |
|
||||||
} |
|
||||||
// 遍历每个 path, 拼接成树 |
|
||||||
for (let i = 0; i < paths.length; i++) { |
|
||||||
// 已经添加到 files 中,则跳过 |
|
||||||
const oldFullPath = fullPath |
|
||||||
// 下面的 replaceAll 的原因,是因为上面包处理了,导致和 tabs 不匹配,所以 replaceAll 下 |
|
||||||
fullPath = fullPath.length === 0 ? paths[i] : `${fullPath.replaceAll('.', '/')}/${paths[i]}` |
|
||||||
if (exists[fullPath]) |
|
||||||
continue |
|
||||||
|
|
||||||
// 添加到 files 中 |
|
||||||
exists[fullPath] = true |
|
||||||
files.push({ |
|
||||||
id: fullPath, |
|
||||||
label: paths[i], |
|
||||||
parentId: oldFullPath || '/', // "/" 为根节点 |
|
||||||
}) |
|
||||||
} |
|
||||||
} |
|
||||||
return files |
|
||||||
} |
|
||||||
|
|
||||||
/** 复制 */ |
|
||||||
async function copy(text: string) { |
|
||||||
const { copy, copied, isSupported } = useClipboard({ source: text }) |
|
||||||
if (!isSupported) { |
|
||||||
createMessage.error('复制失败') |
|
||||||
} |
|
||||||
else { |
|
||||||
await copy() |
|
||||||
if (unref(copied)) |
|
||||||
createMessage.success('复制成功') |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" :default-fullscreen="true" title="预览代码" @register="registerModal"> |
|
||||||
<div class="flex"> |
|
||||||
<Card class="min-w-130 w-1/4"> |
|
||||||
<BasicTree |
|
||||||
title="文件夹列表" toolbar :default-expand-all="true" tree-wrapper-class-name="h-[800px] overflow-auto" |
|
||||||
:click-row-to-expand="false" :tree-data="fileTree" :field-names="{ key: 'id', title: 'label' }" |
|
||||||
@select="handleSelect" |
|
||||||
/> |
|
||||||
</Card> |
|
||||||
<Card class="w-3/4"> |
|
||||||
<Tabs v-model:activeKey="activeKey"> |
|
||||||
<Tabs.TabPane |
|
||||||
v-for="item in previewCodes" :key="item.filePath" |
|
||||||
:tab="item.filePath.substring(item.filePath.lastIndexOf('/') + 1)" |
|
||||||
> |
|
||||||
<a-button type="link" style="float: right; padding: 4px 60px;" @click="copy(item.code)"> |
|
||||||
复制 |
|
||||||
</a-button> |
|
||||||
<CodeEditor class="max-h-200" :value="item.code" :mode="modeValue" :readonly="true" /> |
|
||||||
</Tabs.TabPane> |
|
||||||
</Tabs> |
|
||||||
</Card> |
|
||||||
</div> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,328 +0,0 @@ |
|||||||
import { listSimpleDictType } from '@/api/system/dict/type' |
|
||||||
import { listSimpleMenus } from '@/api/system/menu' |
|
||||||
import type { FormSchema } from '@/components/Form' |
|
||||||
import type { BasicColumn } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
|
|
||||||
async function getDictTypeOptions() { |
|
||||||
const dictTypeOptions: any[] = [] |
|
||||||
const res = await listSimpleDictType() |
|
||||||
dictTypeOptions.push(...res) |
|
||||||
return dictTypeOptions |
|
||||||
} |
|
||||||
|
|
||||||
export const basicInfoSchemas: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '基本信息', |
|
||||||
field: 'basicInfo', |
|
||||||
component: 'Divider', |
|
||||||
colProps: { span: 24 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表名称', |
|
||||||
field: 'tableName', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '表描述', |
|
||||||
field: 'tableComment', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '实体类名称', |
|
||||||
field: 'className', |
|
||||||
required: true, |
|
||||||
helpMessage: '默认去除表名的前缀。如果存在重复,则需要手动添加前缀,避免 MyBatis 报 Alias 重复的问题。', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '作者', |
|
||||||
field: 'author', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '生成信息', |
|
||||||
field: 'genInfo', |
|
||||||
component: 'Divider', |
|
||||||
colProps: { span: 24 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '生成模板', |
|
||||||
field: 'templateType', |
|
||||||
required: true, |
|
||||||
component: 'Select', |
|
||||||
defaultValue: '30', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '前端类型', |
|
||||||
field: 'frontType', |
|
||||||
required: true, |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_FRONT_TYPE) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '生成场景', |
|
||||||
field: 'scene', |
|
||||||
required: true, |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_SCENE), |
|
||||||
}, |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '模块名', |
|
||||||
field: 'moduleName', |
|
||||||
required: true, |
|
||||||
helpMessage: '模块名,即一级目录,例如 system、infra、tool 等等', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '业务名', |
|
||||||
field: 'businessName', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
helpMessage: '业务名,即二级目录,例如 user、permission、dict 等等', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '类名称', |
|
||||||
field: 'className', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
helpMessage: '类名称(首字母大写),例如SysUser、SysMenu、SysDictData 等等', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '类描述', |
|
||||||
field: 'classComment', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
helpMessage: '用作类描述,例如 用户', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '上级菜单', |
|
||||||
field: 'parentMenuId', |
|
||||||
required: true, |
|
||||||
component: 'ApiTreeSelect', |
|
||||||
componentProps: { |
|
||||||
api: () => listSimpleMenus(), |
|
||||||
handleTree: 'id', |
|
||||||
}, |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '自定义路径', |
|
||||||
field: 'genPath', |
|
||||||
component: 'Input', |
|
||||||
helpMessage: '填写磁盘绝对路径,若不填写,则生成到当前Web项目下', |
|
||||||
defaultValue: '/', |
|
||||||
ifShow: ({ values }) => values.genType === '1', |
|
||||||
colProps: { span: 12 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '备注', |
|
||||||
field: 'remark', |
|
||||||
component: 'InputTextArea', |
|
||||||
colProps: { span: 24 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '字段列名', |
|
||||||
dataIndex: 'columnName', |
|
||||||
width: 60, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '基础属性', |
|
||||||
children: [ |
|
||||||
{ |
|
||||||
title: '物理类型', |
|
||||||
dataIndex: 'dataType', |
|
||||||
editComponent: 'Select', |
|
||||||
width: 50, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '字段描述', |
|
||||||
dataIndex: 'columnComment', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Input', |
|
||||||
width: 50, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'Java类型', |
|
||||||
dataIndex: 'javaType', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Select', |
|
||||||
editComponentProps: { |
|
||||||
options: [ |
|
||||||
{ |
|
||||||
label: 'Long', |
|
||||||
value: 'Long', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'String', |
|
||||||
value: 'String', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'Integer', |
|
||||||
value: 'Integer', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'Double', |
|
||||||
value: 'Double', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'BigDecimal', |
|
||||||
value: 'BigDecimal', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'LocalDateTime', |
|
||||||
value: 'LocalDateTime', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'Boolean', |
|
||||||
value: 'Boolean', |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
width: 50, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'java属性', |
|
||||||
dataIndex: 'javaField', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Input', |
|
||||||
width: 50, |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '增删改查', |
|
||||||
children: [ |
|
||||||
{ |
|
||||||
title: '插入', |
|
||||||
dataIndex: 'createOperation', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Checkbox', |
|
||||||
editValueMap: (value) => { |
|
||||||
return value ? '是' : '否' |
|
||||||
}, |
|
||||||
width: 40, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '编辑', |
|
||||||
dataIndex: 'updateOperation', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Checkbox', |
|
||||||
editValueMap: (value) => { |
|
||||||
return value ? '是' : '否' |
|
||||||
}, |
|
||||||
width: 40, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '列表', |
|
||||||
dataIndex: 'listOperationResult', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Checkbox', |
|
||||||
editValueMap: (value) => { |
|
||||||
return value ? '是' : '否' |
|
||||||
}, |
|
||||||
width: 40, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '查询', |
|
||||||
dataIndex: 'listOperation', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Checkbox', |
|
||||||
editValueMap: (value) => { |
|
||||||
return value ? '是' : '否' |
|
||||||
}, |
|
||||||
width: 40, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '查询方式', |
|
||||||
dataIndex: 'listOperationCondition', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Select', |
|
||||||
editComponentProps: { |
|
||||||
options: [ |
|
||||||
{ label: '=', value: '=' }, |
|
||||||
{ label: '!=', value: '!=' }, |
|
||||||
{ label: '>', value: '>' }, |
|
||||||
{ label: '>=', value: '>=' }, |
|
||||||
{ label: '<', value: '<' }, |
|
||||||
{ label: '<=', value: '<=' }, |
|
||||||
{ label: 'LIKE', value: 'LIKE' }, |
|
||||||
{ label: 'BETWEEN', value: 'BETWEEN' }, |
|
||||||
], |
|
||||||
}, |
|
||||||
width: 80, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '允许空', |
|
||||||
dataIndex: 'nullable', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Checkbox', |
|
||||||
editValueMap: (value) => { |
|
||||||
return value ? '是' : '否' |
|
||||||
}, |
|
||||||
width: 40, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '显示类型', |
|
||||||
dataIndex: 'htmlType', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Select', |
|
||||||
editComponentProps: { |
|
||||||
options: [ |
|
||||||
{ label: '文本框', value: 'input' }, |
|
||||||
{ label: '文本域', value: 'textarea' }, |
|
||||||
{ label: '下拉框', value: 'select' }, |
|
||||||
{ label: '单选框', value: 'radio' }, |
|
||||||
{ label: '复选框', value: 'checkbox' }, |
|
||||||
{ label: '日期控件', value: 'datetime' }, |
|
||||||
{ label: '图片上传', value: 'imageUpload' }, |
|
||||||
{ label: '文件上传', value: 'fileUpload' }, |
|
||||||
{ label: '富文本控件', value: 'editor' }, |
|
||||||
], |
|
||||||
}, |
|
||||||
width: 60, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '字典类型', |
|
||||||
dataIndex: 'dictType', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Select', |
|
||||||
editComponentProps: { |
|
||||||
options: (await getDictTypeOptions()).map(item => ({ value: item.type, label: item.name })), |
|
||||||
}, |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '示例', |
|
||||||
dataIndex: 'example', |
|
||||||
editRow: true, |
|
||||||
editComponent: 'Input', |
|
||||||
width: 60, |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
] |
|
@ -1,109 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import PreviewModal from './components/PreviewModal.vue' |
|
||||||
import ImportTableModal from './components/ImportTableModal.vue' |
|
||||||
import { columns, searchFormSchema } from './codegen.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { deleteCodegenTable, downloadCodegen, getCodegenTablePage, syncCodegenFromDB } from '@/api/infra/codegen' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraCodegen' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal() |
|
||||||
const [registerImportTableModal, { openModal: openImportTableModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '代码生成列表', |
|
||||||
api: getCodegenTablePage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 360, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handlePreview(record: Recordable) { |
|
||||||
openPreviewModal(true, { |
|
||||||
record, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEditTable(record: Recordable) { |
|
||||||
go(`/codegen/editTable?id=${record.id}`) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleGenTable(record: Recordable) { |
|
||||||
await downloadCodegen(record) |
|
||||||
createMessage.success(t('common.successText')) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleSynchDb(record: Recordable) { |
|
||||||
await syncCodegenFromDB(record.id) |
|
||||||
createMessage.success(t('common.successText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteCodegenTable(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:codegen:create']" type="primary" :pre-icon="IconEnum.IMPORT" @click="openImportTableModal(true)"> |
|
||||||
{{ t('action.import') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.PREVIEW, label: '预览', auth: 'infra:codegen:preview', onClick: handlePreview.bind(null, record) }, |
|
||||||
{ icon: IconEnum.EDIT, label: t('action.edit'), auth: 'infra:codegen:update', onClick: handleEditTable.bind(null, record) }, |
|
||||||
{ icon: IconEnum.DOWNLOAD, label: '生成', auth: 'infra:codegen:download', onClick: handleGenTable.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.RESET, |
|
||||||
label: t('action.sync'), |
|
||||||
auth: 'infra:codegen:update', |
|
||||||
popConfirm: { |
|
||||||
title: `确认要强制同步${record.tableName}表结构吗?`, |
|
||||||
placement: 'left', |
|
||||||
confirm: handleSynchDb.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'infra:codegen:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<PreviewModal @register="registerPreviewModal" /> |
|
||||||
<ImportTableModal @register="registerImportTableModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,58 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, unref } from 'vue' |
|
||||||
import { formSchema } from './config.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { createConfig, getConfig, updateConfig } from '@/api/infra/config' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraConfigModal' }) |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const isUpdate = ref(true) |
|
||||||
|
|
||||||
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showActionButtonGroup: false, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|
||||||
resetFields() |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
isUpdate.value = !!data?.isUpdate |
|
||||||
if (unref(isUpdate)) { |
|
||||||
const res = await getConfig(data.record.id) |
|
||||||
setFieldsValue({ ...res }) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() as any |
|
||||||
setModalProps({ confirmLoading: true }) |
|
||||||
if (unref(isUpdate)) |
|
||||||
await updateConfig(values) |
|
||||||
else |
|
||||||
await createConfig(values) |
|
||||||
|
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<BasicForm @register="registerForm" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,139 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '参数主键', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '参数分类', |
|
||||||
dataIndex: 'category', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '参数名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '参数键名', |
|
||||||
dataIndex: 'key', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '参数键值', |
|
||||||
dataIndex: 'value', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '系统内置', |
|
||||||
dataIndex: 'type', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.INFRA_CONFIG_TYPE) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '是否可见', |
|
||||||
dataIndex: 'visible', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderTag(text ? '是' : '否') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '备注', |
|
||||||
dataIndex: 'remark', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '参数名称', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '参数键名', |
|
||||||
field: 'key', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '系统内置', |
|
||||||
field: 'type', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_CONFIG_TYPE) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '创建时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '编号', |
|
||||||
field: 'id', |
|
||||||
show: false, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '参数分类', |
|
||||||
field: 'category', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '参数名称', |
|
||||||
field: 'name', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '参数键名', |
|
||||||
field: 'key', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '参数键值', |
|
||||||
field: 'value', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '是否可见', |
|
||||||
field: 'visible', |
|
||||||
component: 'RadioGroup', |
|
||||||
componentProps: { |
|
||||||
options: [ |
|
||||||
{ label: '是', value: true }, |
|
||||||
{ label: '否', value: false }, |
|
||||||
], |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '备注', |
|
||||||
field: 'remark', |
|
||||||
component: 'InputTextArea', |
|
||||||
}, |
|
||||||
] |
|
@ -1,95 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import ConfigModal from './ConfigModal.vue' |
|
||||||
import { columns, searchFormSchema } from './config.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import type { ConfigExportReqVO } from '@/api/infra/config' |
|
||||||
import { deleteConfig, exportConfig, getConfigPage } from '@/api/infra/config' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraConfig' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createConfirm, createMessage } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { getForm, reload }] = useTable({ |
|
||||||
title: '配置中心列表', |
|
||||||
api: getConfigPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleCreate() { |
|
||||||
openModal(true, { isUpdate: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEdit(record: Recordable) { |
|
||||||
openModal(true, { record, isUpdate: true }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleExport() { |
|
||||||
createConfirm({ |
|
||||||
title: t('common.exportTitle'), |
|
||||||
iconType: 'warning', |
|
||||||
content: t('common.exportMessage'), |
|
||||||
async onOk() { |
|
||||||
await exportConfig(getForm().getFieldsValue() as ConfigExportReqVO) |
|
||||||
createMessage.success(t('common.exportSuccessText')) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteConfig(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:config:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
{{ t('action.create') }} |
|
||||||
</a-button> |
|
||||||
<a-button v-auth="['infra:config:export']" :pre-icon="IconEnum.EXPORT" @click="handleExport"> |
|
||||||
{{ t('action.export') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.EDIT, label: t('action.edit'), auth: 'infra:config:update', onClick: handleEdit.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'infra:config:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<ConfigModal @register="registerModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,56 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, unref } from 'vue' |
|
||||||
import { formSchema } from './dataSourceConfig.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { createDataSourceConfig, getDataSourceConfig, updateDataSourceConfig } from '@/api/infra/dataSourceConfig' |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const isUpdate = ref(true) |
|
||||||
|
|
||||||
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showActionButtonGroup: false, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|
||||||
resetFields() |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
isUpdate.value = !!data?.isUpdate |
|
||||||
if (unref(isUpdate)) { |
|
||||||
const res = await getDataSourceConfig(data.record.id) |
|
||||||
setFieldsValue({ ...res }) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() as any |
|
||||||
setModalProps({ confirmLoading: true }) |
|
||||||
if (unref(isUpdate)) |
|
||||||
await updateDataSourceConfig(values) |
|
||||||
else |
|
||||||
await createDataSourceConfig(values) |
|
||||||
|
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<BasicForm @register="registerForm" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,66 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '主键编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '数据源名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '数据源连接', |
|
||||||
dataIndex: 'url', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '用户名', |
|
||||||
dataIndex: 'username', |
|
||||||
width: 120, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '编号', |
|
||||||
field: 'id', |
|
||||||
show: false, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '数据源名称', |
|
||||||
field: 'name', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '数据源连接', |
|
||||||
field: 'url', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '用户名', |
|
||||||
field: 'username', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '密码', |
|
||||||
field: 'password', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
] |
|
@ -1,86 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import DataSourceConfigModal from './DataSourceConfigModal.vue' |
|
||||||
import { columns } from './dataSourceConfig.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { deleteDataSourceConfig, getDataSourceConfigList } from '@/api/infra/dataSourceConfig' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraDataSourceConfig' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '数据源列表', |
|
||||||
api: getDataSourceConfigList, |
|
||||||
columns, |
|
||||||
pagination: false, |
|
||||||
useSearchForm: false, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleCreate() { |
|
||||||
openModal(true, { isUpdate: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEdit(record: Recordable) { |
|
||||||
openModal(true, { record, isUpdate: true }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteDataSourceConfig(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:data-source-config:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
{{ t('action.create') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ |
|
||||||
icon: IconEnum.EDIT, |
|
||||||
label: t('action.edit'), |
|
||||||
ifShow: record.id !== 0, |
|
||||||
auth: 'infra:data-source-config:update', |
|
||||||
onClick: handleEdit.bind(null, record), |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
ifShow: record.id !== 0, |
|
||||||
auth: 'infra:data-source-config:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<DataSourceConfigModal @register="registerModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,53 +0,0 @@ |
|||||||
<script setup lang="ts" name="InfraDbDoc"> |
|
||||||
import { onMounted, ref } from 'vue' |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { IFrame } from '@/components/IFrame' |
|
||||||
import * as DbDocApi from '@/api/infra/dbDoc' |
|
||||||
import { downloadByData } from '@/utils/file/download' |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const src = ref('') |
|
||||||
/** 页面加载 */ |
|
||||||
async function init() { |
|
||||||
const res = await DbDocApi.exportHtml() |
|
||||||
const blob = new Blob([res], { type: 'text/html' }) |
|
||||||
const blobUrl = window.URL.createObjectURL(blob) |
|
||||||
src.value = blobUrl |
|
||||||
} |
|
||||||
/** 处理导出 */ |
|
||||||
async function handleExport(type: string) { |
|
||||||
if (type === 'HTML') { |
|
||||||
const res = await DbDocApi.exportHtml() |
|
||||||
downloadByData(res, '数据库文档.html') |
|
||||||
} |
|
||||||
if (type === 'Word') { |
|
||||||
const res = await DbDocApi.exportWord() |
|
||||||
downloadByData(res, '数据库文档.doc') |
|
||||||
} |
|
||||||
if (type === 'Markdown') { |
|
||||||
const res = await DbDocApi.exportMarkdown() |
|
||||||
downloadByData(res, '数据库文档.md') |
|
||||||
} |
|
||||||
} |
|
||||||
onMounted(async () => { |
|
||||||
await init() |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper> |
|
||||||
<div class="mb-3"> |
|
||||||
<a-button type="primary" size="small" class="mr-1" @click="handleExport('HTML')"> |
|
||||||
{{ `${t('action.export')}Html` }} |
|
||||||
</a-button> |
|
||||||
<a-button type="primary" size="small" class="mr-1" @click="handleExport('Word')"> |
|
||||||
{{ `${t('action.export')}Word` }} |
|
||||||
</a-button> |
|
||||||
<a-button type="primary" size="small" @click="handleExport('Markdown')"> |
|
||||||
{{ `${t('action.export')}Markdown` }} |
|
||||||
</a-button> |
|
||||||
</div> |
|
||||||
<IFrame :src="src" /> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,12 +0,0 @@ |
|||||||
<script setup lang="ts" name="InfraDruid"> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { IFrame } from '@/components/IFrame' |
|
||||||
|
|
||||||
const src = ref(`${import.meta.env.VITE_GLOB_BASE_URL}/druid/index.html`) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<IFrame :src="src" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,79 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '文件名', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 200, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '文件 URL', |
|
||||||
dataIndex: 'url', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderImg(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '文件路径', |
|
||||||
dataIndex: 'path', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '文件大小', |
|
||||||
dataIndex: 'size', |
|
||||||
width: 120, |
|
||||||
customRender: ({ text }) => { |
|
||||||
const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] |
|
||||||
const srcSize = Number.parseFloat(text) |
|
||||||
const index = Math.floor(Math.log(srcSize) / Math.log(1024)) |
|
||||||
const size = srcSize / 1024 ** index |
|
||||||
return `${size.toFixed(2)} ${unitArr[index]}` |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '文件类型', |
|
||||||
dataIndex: 'type', |
|
||||||
width: 100, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderTag(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '文件内容', |
|
||||||
dataIndex: 'content', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderImg(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '上传时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '文件路径', |
|
||||||
field: 'path', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '创建时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
@ -1,92 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { columns, searchFormSchema } from './file.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicUpload } from '@/components/Upload' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { deleteFile, getFilePage } from '@/api/infra/file' |
|
||||||
import { getAccessToken, getTenantId } from '@/utils/auth' |
|
||||||
import { copyText } from '@/utils/copyTextToClipboard' |
|
||||||
import { uploadApi } from '@/api/base/upload' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraFile' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
|
|
||||||
const uploadParams = ref({ |
|
||||||
'Authorization': `Bearer ${getAccessToken()}`, |
|
||||||
'tenant-id': getTenantId(), |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '文件列表', |
|
||||||
api: getFilePage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 160, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleChange() { |
|
||||||
reload() |
|
||||||
} |
|
||||||
|
|
||||||
function handleCopy(record: Recordable) { |
|
||||||
copyText(record.url) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteFile(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<BasicUpload |
|
||||||
:max-size="20" |
|
||||||
:max-number="10" |
|
||||||
:empty-hide-preview="true" |
|
||||||
:upload-params="uploadParams" |
|
||||||
:api="uploadApi" |
|
||||||
class="my-5" |
|
||||||
:accept="['image/*']" |
|
||||||
@change="handleChange" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.VIEW, label: '复制链接', onClick: handleCopy.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'infra:file:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,58 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, unref } from 'vue' |
|
||||||
import { formSchema } from './ficleConfig.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { createFileConfig, getFileConfig, updateFileConfig } from '@/api/infra/fileConfig' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraFileConfigModal' }) |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const isUpdate = ref(true) |
|
||||||
|
|
||||||
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showActionButtonGroup: false, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|
||||||
resetFields() |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
isUpdate.value = !!data?.isUpdate |
|
||||||
if (unref(isUpdate)) { |
|
||||||
const res = await getFileConfig(data.record.id) |
|
||||||
setFieldsValue({ ...res }) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() |
|
||||||
setModalProps({ confirmLoading: true }) |
|
||||||
if (unref(isUpdate)) |
|
||||||
await updateFileConfig(values) |
|
||||||
else |
|
||||||
await createFileConfig(values) |
|
||||||
|
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" :title="isUpdate ? t('action.edit') : t('action.create')" @register="registerModal" @ok="handleSubmit"> |
|
||||||
<BasicForm @register="registerForm" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,179 +0,0 @@ |
|||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '配置名', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '存储器', |
|
||||||
dataIndex: 'storage', |
|
||||||
width: 100, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.INFRA_FILE_STORAGE) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '主配置', |
|
||||||
dataIndex: 'master', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.INFRA_BOOLEAN_STRING) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '备注', |
|
||||||
dataIndex: 'remark', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '创建时间', |
|
||||||
dataIndex: 'createTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDate(text) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '配置名', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '存储器', |
|
||||||
field: 'storage', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_FILE_STORAGE) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '创建时间', |
|
||||||
field: 'createTime', |
|
||||||
component: 'RangePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '编号', |
|
||||||
field: 'id', |
|
||||||
show: false, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '配置名', |
|
||||||
field: 'name', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '存储器', |
|
||||||
field: 'storage', |
|
||||||
component: 'Select', |
|
||||||
required: true, |
|
||||||
dynamicDisabled: ({ values }) => !!values.id, |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_FILE_STORAGE) as any, |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '基础路径', |
|
||||||
field: 'config.basePath', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage >= 10 && values.storage <= 12, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '主机地址', |
|
||||||
field: 'config.host', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage >= 11 && values.storage <= 12, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '主机端口', |
|
||||||
field: 'config.port', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage >= 11 && values.storage <= 12, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '用户名', |
|
||||||
field: 'config.username', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage >= 11 && values.storage <= 12, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '密码', |
|
||||||
field: 'config.password', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage >= 11 && values.storage <= 12, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '连接模式', |
|
||||||
field: 'config.basePath', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage === 11, |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: [ |
|
||||||
{ lable: '主动模式', key: 'Active', value: 'Active' }, |
|
||||||
{ lable: '被动模式', key: 'Passive', value: 'Passive' }, |
|
||||||
], |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '节点地址', |
|
||||||
field: 'config.endpoint', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage === 20, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '存储 bucket', |
|
||||||
field: 'config.bucket', |
|
||||||
required: true, |
|
||||||
ifShow: ({ values }) => values.storage === 20, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'accessKey', |
|
||||||
field: 'config.accessKey', |
|
||||||
ifShow: ({ values }) => values.storage === 20, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'accessSecret', |
|
||||||
field: 'config.accessSecret', |
|
||||||
ifShow: ({ values }) => values.storage === 20, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '自定义域名', |
|
||||||
field: 'config.domain', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '备注', |
|
||||||
field: 'remark', |
|
||||||
component: 'InputTextArea', |
|
||||||
}, |
|
||||||
] |
|
@ -1,107 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import FileConfigModal from './FileConfigModal.vue' |
|
||||||
import { columns, searchFormSchema } from './ficleConfig.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import { deleteFileConfig, getFileConfigPage, testFileConfig, updateFileConfigMaster } from '@/api/infra/fileConfig' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraFileConfig' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createConfirm, createMessage, createSuccessModal } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { reload }] = useTable({ |
|
||||||
title: '文件配置列表', |
|
||||||
api: getFileConfigPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 280, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleCreate() { |
|
||||||
openModal(true, { isUpdate: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEdit(record: Recordable) { |
|
||||||
openModal(true, { record, isUpdate: true }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleTest(record: Recordable) { |
|
||||||
const res = await testFileConfig(record.id) |
|
||||||
createSuccessModal({ content: res }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleMaster(record: Recordable) { |
|
||||||
createConfirm({ |
|
||||||
title: '主配置', |
|
||||||
iconType: 'warning', |
|
||||||
content: `是否确认修改配置编号为"${record.id}"的数据项为主配置?`, |
|
||||||
async onOk() { |
|
||||||
await updateFileConfigMaster(record.id) |
|
||||||
createMessage.success('配置成功') |
|
||||||
reload() |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteFileConfig(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:file-config:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
{{ t('action.create') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[ |
|
||||||
{ icon: IconEnum.EDIT, label: t('action.edit'), auth: 'infra:file-config:update', onClick: handleEdit.bind(null, record) }, |
|
||||||
{ icon: IconEnum.TEST, label: t('action.test'), auth: 'infra:file-config:update', onClick: handleTest.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.AUTH, |
|
||||||
label: '主配置', |
|
||||||
auth: 'infra:file-config:update', |
|
||||||
ifShow: () => { |
|
||||||
return !record.master |
|
||||||
}, |
|
||||||
onClick: handleMaster.bind(null, record), |
|
||||||
}, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'infra:file-config:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<FileConfigModal @register="registerModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,92 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref, unref } from 'vue' |
|
||||||
import { Steps } from 'ant-design-vue' |
|
||||||
import { descSchema, formSchema } from './job.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { BasicForm, useForm } from '@/components/Form' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { Description, useDescription } from '@/components/Description' |
|
||||||
import { createJob, getJob, getJobNextTimes, updateJob } from '@/api/infra/job' |
|
||||||
import { formatToDateTime } from '@/utils/dateUtil' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraJobModal' }) |
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'register']) |
|
||||||
|
|
||||||
const Step = Steps.Step |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { createMessage } = useMessage() |
|
||||||
const isUpdate = ref(true) |
|
||||||
const isEdit = ref(true) |
|
||||||
|
|
||||||
const datas = ref() |
|
||||||
const nextTimes = ref() |
|
||||||
|
|
||||||
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|
||||||
labelWidth: 120, |
|
||||||
baseColProps: { span: 24 }, |
|
||||||
schemas: formSchema, |
|
||||||
showActionButtonGroup: false, |
|
||||||
actionColOptions: { span: 23 }, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerDesc] = useDescription({ |
|
||||||
schema: descSchema, |
|
||||||
data: datas, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => { |
|
||||||
isEdit.value = !!data?.isEdit |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
if (data?.isEdit) { |
|
||||||
resetFields() |
|
||||||
|
|
||||||
isUpdate.value = !!data?.isUpdate |
|
||||||
if (unref(isUpdate)) { |
|
||||||
const res = await getJob(data.record.id) |
|
||||||
setFieldsValue({ ...res }) |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
datas.value = await getJob(data.record.id) |
|
||||||
nextTimes.value = await getJobNextTimes(data.record.id) |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
async function handleSubmit() { |
|
||||||
try { |
|
||||||
const values = await validate() as any |
|
||||||
setModalProps({ confirmLoading: true }) |
|
||||||
if (unref(isUpdate)) |
|
||||||
await updateJob(values) |
|
||||||
else |
|
||||||
await createJob(values) |
|
||||||
|
|
||||||
closeModal() |
|
||||||
emit('success') |
|
||||||
createMessage.success(t('common.saveSuccessText')) |
|
||||||
} |
|
||||||
finally { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal |
|
||||||
v-bind="$attrs" |
|
||||||
:title="isEdit ? (isUpdate ? t('action.edit') : t('action.create')) : t('action.detail')" |
|
||||||
@register="registerModal" |
|
||||||
@ok="handleSubmit" |
|
||||||
> |
|
||||||
<BasicForm v-if="isEdit" @register="registerForm" /> |
|
||||||
<Description v-if="!isEdit" :column="2" @register="registerDesc" /> |
|
||||||
<Steps v-if="!isEdit" progress-dot :current="nextTimes && nextTimes.length" direction="vertical"> |
|
||||||
<template v-for="(nextTime, index) in nextTimes" :key="index"> |
|
||||||
<Step :title="formatToDateTime(nextTime)" :description="'第' + `${index + 1}` + '次'" /> |
|
||||||
</template> |
|
||||||
</Steps> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,141 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import JobModal from './JobModal.vue' |
|
||||||
import { columns, searchFormSchema } from './job.data' |
|
||||||
import { useGo } from '@/hooks/web/usePage' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import type { JobExportReqVO } from '@/api/infra/job' |
|
||||||
import { deleteJob, exportJob, getJobPage, runJob, updateJobStatus } from '@/api/infra/job' |
|
||||||
import { InfraJobStatusEnum } from '@/enums/systemEnum' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraJob' }) |
|
||||||
|
|
||||||
const go = useGo() |
|
||||||
const { t } = useI18n() |
|
||||||
const { createConfirm, createMessage } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { getForm, reload }] = useTable({ |
|
||||||
title: '定时任务列表', |
|
||||||
api: getJobPage, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleCreate() { |
|
||||||
openModal(true, { isEdit: true, isUpdate: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleEdit(record: Recordable) { |
|
||||||
openModal(true, { record, isEdit: true, isUpdate: true }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleChangeStatus(record: Recordable, open: boolean) { |
|
||||||
const status = open ? InfraJobStatusEnum.NORMAL : InfraJobStatusEnum.STOP |
|
||||||
const statusStr = open ? '开启' : '关闭' |
|
||||||
createConfirm({ |
|
||||||
title: '调整状态', |
|
||||||
iconType: 'warning', |
|
||||||
content: `是否确认${statusStr}定时任务编号为"${record.id}"的数据项?`, |
|
||||||
async onOk() { |
|
||||||
await updateJobStatus(record.id, status) |
|
||||||
createMessage.success(t('common.successText')) |
|
||||||
reload() |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
function handleRun(record: Recordable) { |
|
||||||
createConfirm({ |
|
||||||
title: '执行', |
|
||||||
iconType: 'warning', |
|
||||||
content: `确认要立即执行一次"${record.name}"任务吗?`, |
|
||||||
async onOk() { |
|
||||||
await runJob(record.id) |
|
||||||
createMessage.success(t('common.successText')) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
function handleView(record: Recordable) { |
|
||||||
openModal(true, { record, isEdit: false }) |
|
||||||
} |
|
||||||
|
|
||||||
function handleJobLog(record: Recordable) { |
|
||||||
if (record.id > 0) |
|
||||||
go(`/job/job-log?id=${record.id}`) |
|
||||||
else |
|
||||||
go('/job/job-log') |
|
||||||
} |
|
||||||
|
|
||||||
async function handleExport() { |
|
||||||
createConfirm({ |
|
||||||
title: t('common.exportTitle'), |
|
||||||
iconType: 'warning', |
|
||||||
content: t('common.exportMessage'), |
|
||||||
async onOk() { |
|
||||||
await exportJob(getForm().getFieldsValue() as JobExportReqVO) |
|
||||||
createMessage.success(t('common.exportSuccessText')) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleDelete(record: Recordable) { |
|
||||||
await deleteJob(record.id) |
|
||||||
createMessage.success(t('common.delSuccessText')) |
|
||||||
reload() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:job:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate"> |
|
||||||
{{ t('action.create') }} |
|
||||||
</a-button> |
|
||||||
<a-button v-auth="['infra:job:export']" :pre-icon="IconEnum.EXPORT" @click="handleExport"> |
|
||||||
{{ t('action.export') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction |
|
||||||
:actions="[{ icon: IconEnum.EDIT, label: t('action.edit'), onClick: handleEdit.bind(null, record) }]" |
|
||||||
:drop-down-actions="[ |
|
||||||
{ icon: IconEnum.AUTH, label: '开启', auth: 'infra:job:update', onClick: handleChangeStatus.bind(null, record, true) }, |
|
||||||
{ icon: IconEnum.EDIT, label: '暂停', auth: 'infra:job:update', onClick: handleChangeStatus.bind(null, record, false) }, |
|
||||||
{ icon: IconEnum.TEST, label: '执行一次', auth: 'infra:job:trigger', onClick: handleRun.bind(null, record) }, |
|
||||||
{ icon: IconEnum.PREVIEW, label: '任务详细', auth: 'infra:job:query', onClick: handleView.bind(null, record) }, |
|
||||||
{ icon: IconEnum.LOG, label: '调度日志', auth: 'infra:job:query', onClick: handleJobLog.bind(null, record) }, |
|
||||||
{ |
|
||||||
icon: IconEnum.DELETE, |
|
||||||
danger: true, |
|
||||||
label: t('action.delete'), |
|
||||||
auth: 'infra:job:delete', |
|
||||||
popConfirm: { |
|
||||||
title: t('common.delMessage'), |
|
||||||
placement: 'left', |
|
||||||
confirm: handleDelete.bind(null, record), |
|
||||||
}, |
|
||||||
}, |
|
||||||
]" |
|
||||||
/> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<JobModal @register="registerModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,172 +0,0 @@ |
|||||||
import type { DescItem } from '@/components/Description' |
|
||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
import { useComponentRegister } from '@/components/Form' |
|
||||||
import { CronTab } from '@/components/CronTab' |
|
||||||
|
|
||||||
useComponentRegister('CronTab', CronTab) |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '任务编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '任务名称', |
|
||||||
dataIndex: 'name', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '处理器的名字', |
|
||||||
dataIndex: 'handlerName', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '处理器的参数', |
|
||||||
dataIndex: 'handlerParam', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: 'CRON 表达式', |
|
||||||
dataIndex: 'cronExpression', |
|
||||||
width: 200, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '任务状态', |
|
||||||
dataIndex: 'status', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderDict(text, DICT_TYPE.INFRA_JOB_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '任务名称', |
|
||||||
field: 'name', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '任务状态', |
|
||||||
field: 'status', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_JOB_STATUS) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的名字', |
|
||||||
field: 'handlerName', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const formSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '任务编号', |
|
||||||
field: 'id', |
|
||||||
show: false, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '任务名称', |
|
||||||
field: 'name', |
|
||||||
required: true, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的名字', |
|
||||||
field: 'handlerName', |
|
||||||
required: true, |
|
||||||
dynamicDisabled: ({ values }) => !!values.id, |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的参数', |
|
||||||
field: 'handlerParam', |
|
||||||
component: 'Input', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'CRON 表达式', |
|
||||||
field: 'cronExpression', |
|
||||||
required: true, |
|
||||||
component: 'CronTab', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '重试次数', |
|
||||||
field: 'retryCount', |
|
||||||
required: true, |
|
||||||
helpMessage: '设置为 0 时,不进行重试', |
|
||||||
defaultValue: 0, |
|
||||||
component: 'InputNumber', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '重试间隔', |
|
||||||
field: 'retryInterval', |
|
||||||
required: true, |
|
||||||
helpMessage: '单位:毫秒。设置为 0 时,无需间隔', |
|
||||||
defaultValue: 0, |
|
||||||
component: 'InputNumber', |
|
||||||
suffix: '毫秒', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '监控超时时间', |
|
||||||
field: 'monitorTimeout', |
|
||||||
component: 'Input', |
|
||||||
suffix: '毫秒', |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const descSchema: DescItem[] = [ |
|
||||||
{ |
|
||||||
label: '任务编号', |
|
||||||
field: 'id', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '任务名称', |
|
||||||
field: 'name', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '任务状态', |
|
||||||
field: 'status', |
|
||||||
render: (curVal) => { |
|
||||||
return useRender.renderDict(curVal, DICT_TYPE.INFRA_JOB_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的名字', |
|
||||||
field: 'handlerName', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的参数', |
|
||||||
field: 'handlerParam', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'Cron 表达式', |
|
||||||
field: 'cronExpression', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '重试次数', |
|
||||||
field: 'retryCount', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '重试间隔', |
|
||||||
field: 'cronExpression', |
|
||||||
render: (curVal) => { |
|
||||||
return useRender.renderText(curVal, ' 毫秒') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '监控超时时间', |
|
||||||
field: 'monitorTimeout', |
|
||||||
render: (curVal) => { |
|
||||||
return curVal > 0 ? `${curVal} 毫秒` : '未开启' |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
@ -1,28 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { descSchema } from './jobLog.data' |
|
||||||
import { Description, useDescription } from '@/components/Description' |
|
||||||
import { BasicModal, useModalInner } from '@/components/Modal' |
|
||||||
import { getJobLog } from '@/api/infra/jobLog' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraJobLogModal' }) |
|
||||||
|
|
||||||
const datas = ref() |
|
||||||
|
|
||||||
const [registerDesc] = useDescription({ |
|
||||||
schema: descSchema, |
|
||||||
data: datas, |
|
||||||
}) |
|
||||||
|
|
||||||
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
|
||||||
setModalProps({ confirmLoading: false }) |
|
||||||
const res = await getJobLog(data.record.id) |
|
||||||
datas.value = res |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<BasicModal v-bind="$attrs" title="查看详情" @register="registerModal"> |
|
||||||
<Description :column="2" @register="registerDesc" /> |
|
||||||
</BasicModal> |
|
||||||
</template> |
|
@ -1,70 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { useRoute } from 'vue-router' |
|
||||||
import JobLogModal from './JobLogModal.vue' |
|
||||||
import { columns, searchFormSchema } from './jobLog.data' |
|
||||||
import { useI18n } from '@/hooks/web/useI18n' |
|
||||||
import { useMessage } from '@/hooks/web/useMessage' |
|
||||||
import { useModal } from '@/components/Modal' |
|
||||||
import { IconEnum } from '@/enums/appEnum' |
|
||||||
import { BasicTable, TableAction, useTable } from '@/components/Table' |
|
||||||
import type { JobLogExportReqVO } from '@/api/infra/jobLog' |
|
||||||
import { exportJobLog, getJobLogPage } from '@/api/infra/jobLog' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraJobLog' }) |
|
||||||
|
|
||||||
const { t } = useI18n() |
|
||||||
const { query } = useRoute() |
|
||||||
const { createConfirm, createMessage } = useMessage() |
|
||||||
const [registerModal, { openModal }] = useModal() |
|
||||||
|
|
||||||
const [registerTable, { getForm, reload }] = useTable({ |
|
||||||
title: '定时任务日志列表', |
|
||||||
api: getJobLogPage, |
|
||||||
searchInfo: { id: query.id as unknown as number }, |
|
||||||
columns, |
|
||||||
formConfig: { labelWidth: 120, schemas: searchFormSchema }, |
|
||||||
useSearchForm: true, |
|
||||||
showTableSetting: true, |
|
||||||
showIndexColumn: false, |
|
||||||
actionColumn: { |
|
||||||
width: 140, |
|
||||||
title: t('common.action'), |
|
||||||
dataIndex: 'action', |
|
||||||
fixed: 'right', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
function handleDetail(record: Recordable) { |
|
||||||
openModal(true, { record }) |
|
||||||
} |
|
||||||
|
|
||||||
async function handleExport() { |
|
||||||
createConfirm({ |
|
||||||
title: t('common.exportTitle'), |
|
||||||
iconType: 'warning', |
|
||||||
content: t('common.exportMessage'), |
|
||||||
async onOk() { |
|
||||||
await exportJobLog(getForm().getFieldsValue() as JobLogExportReqVO) |
|
||||||
createMessage.success(t('common.exportSuccessText')) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<BasicTable @register="registerTable"> |
|
||||||
<template #toolbar> |
|
||||||
<a-button v-auth="['infra:job:export']" :pre-icon="IconEnum.EXPORT" @click="handleExport"> |
|
||||||
{{ t('action.export') }} |
|
||||||
</a-button> |
|
||||||
</template> |
|
||||||
<template #bodyCell="{ column, record }"> |
|
||||||
<template v-if="column.key === 'action'"> |
|
||||||
<TableAction :actions="[{ icon: IconEnum.EDIT, label: t('action.detail'), onClick: handleDetail.bind(null, record) }]" /> |
|
||||||
</template> |
|
||||||
</template> |
|
||||||
</BasicTable> |
|
||||||
<JobLogModal @register="registerModal" @success="reload()" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,150 +0,0 @@ |
|||||||
import { h } from 'vue' |
|
||||||
import type { DescItem } from '@/components/Description' |
|
||||||
import type { BasicColumn, FormSchema } from '@/components/Table' |
|
||||||
import { useRender } from '@/components/Table' |
|
||||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict' |
|
||||||
import { JsonPreview } from '@/components/CodeEditor' |
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [ |
|
||||||
{ |
|
||||||
title: '日志编号', |
|
||||||
dataIndex: 'id', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '任务编号', |
|
||||||
dataIndex: 'jobId', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '处理器的名字', |
|
||||||
dataIndex: 'handlerName', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '处理器的参数', |
|
||||||
dataIndex: 'handlerParam', |
|
||||||
width: 180, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '第几次执行', |
|
||||||
dataIndex: 'executeIndex', |
|
||||||
width: 100, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '执行时间', |
|
||||||
dataIndex: 'beginTime', |
|
||||||
width: 180, |
|
||||||
customRender: ({ record }) => { |
|
||||||
const startTime = useRender.renderDate(record.beginTime) |
|
||||||
const endTime = useRender.renderDate(record.endTime) |
|
||||||
return useRender.renderTags([startTime, endTime]) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '执行时长', |
|
||||||
dataIndex: 'duration', |
|
||||||
width: 180, |
|
||||||
customRender: ({ text }) => { |
|
||||||
return useRender.renderText(text, ' 毫秒') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: '任务状态', |
|
||||||
dataIndex: 'status', |
|
||||||
width: 180, |
|
||||||
customRender: ({ record }) => { |
|
||||||
return useRender.renderDict(record.status, DICT_TYPE.INFRA_JOB_LOG_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const searchFormSchema: FormSchema[] = [ |
|
||||||
{ |
|
||||||
label: '处理器的名字', |
|
||||||
field: 'handlerName', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '开始执行时间', |
|
||||||
field: 'beginTime', |
|
||||||
component: 'DatePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '结束执行时间', |
|
||||||
field: 'endTime', |
|
||||||
component: 'DatePicker', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '任务状态', |
|
||||||
field: 'status', |
|
||||||
component: 'Select', |
|
||||||
componentProps: { |
|
||||||
options: getDictOptions(DICT_TYPE.INFRA_JOB_STATUS) as any, |
|
||||||
}, |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的名字', |
|
||||||
field: 'handlerName', |
|
||||||
component: 'Input', |
|
||||||
colProps: { span: 8 }, |
|
||||||
}, |
|
||||||
] |
|
||||||
|
|
||||||
export const descSchema: DescItem[] = [ |
|
||||||
{ |
|
||||||
label: '日志编号', |
|
||||||
field: 'id', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '任务编号', |
|
||||||
field: 'jobId', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的名字', |
|
||||||
field: 'handlerName', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '处理器的参数', |
|
||||||
field: 'handlerParam', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '第几次执行', |
|
||||||
field: 'executeIndex', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '执行时间', |
|
||||||
field: 'beginTime', |
|
||||||
render: (_, data) => { |
|
||||||
const startTime = `开始: ${useRender.renderDate(data.beginTime)}` |
|
||||||
const endTime = `结束: ${useRender.renderDate(data.endTime)}` |
|
||||||
return h('span', {}, [startTime, h('br'), endTime]) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '执行时长', |
|
||||||
field: 'duration', |
|
||||||
render: (curVal) => { |
|
||||||
return useRender.renderText(curVal, ' 毫秒') |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '任务状态', |
|
||||||
field: 'status', |
|
||||||
render: (curVal) => { |
|
||||||
return useRender.renderDict(curVal, DICT_TYPE.INFRA_JOB_LOG_STATUS) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '执行结果', |
|
||||||
field: 'result', |
|
||||||
render: (curVal) => { |
|
||||||
const data = JSON.parse(curVal) |
|
||||||
return h(JsonPreview, { data }) |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
@ -1,53 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import type { Ref } from 'vue' |
|
||||||
import { ref, watch } from 'vue' |
|
||||||
import { Card } from 'ant-design-vue' |
|
||||||
import { useECharts } from '@/hooks/web/useECharts' |
|
||||||
import { propTypes } from '@/utils/propTypes' |
|
||||||
|
|
||||||
const props = defineProps({ |
|
||||||
loading: propTypes.bool.def(true), |
|
||||||
commandStats: propTypes.array.def([]), |
|
||||||
width: propTypes.string.def('100%'), |
|
||||||
height: propTypes.string.def('300px'), |
|
||||||
}) |
|
||||||
|
|
||||||
const chartRef = ref<HTMLDivElement | null>(null) |
|
||||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>) |
|
||||||
|
|
||||||
const optionsData = ref<any[]>(props.commandStats) |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.loading, |
|
||||||
() => { |
|
||||||
if (props.loading) |
|
||||||
return |
|
||||||
|
|
||||||
setOptions({ |
|
||||||
tooltip: { |
|
||||||
trigger: 'item', |
|
||||||
formatter: '{a} <br/>{b} : {c} ({d}%)', |
|
||||||
}, |
|
||||||
series: [ |
|
||||||
{ |
|
||||||
name: '命令', |
|
||||||
type: 'pie', |
|
||||||
roseType: 'radius', |
|
||||||
radius: [15, 95], |
|
||||||
center: ['50%', '38%'], |
|
||||||
data: optionsData.value, |
|
||||||
animationEasing: 'cubicInOut', |
|
||||||
animationDuration: 1000, |
|
||||||
}, |
|
||||||
], |
|
||||||
}) |
|
||||||
}, |
|
||||||
{ immediate: true }, |
|
||||||
) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<Card title="命令统计" :loading="loading"> |
|
||||||
<div ref="chartRef" :style="{ width, height }" /> |
|
||||||
</Card> |
|
||||||
</template> |
|
@ -1,55 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import type { Ref } from 'vue' |
|
||||||
import { ref, watch } from 'vue' |
|
||||||
import { Card } from 'ant-design-vue' |
|
||||||
import { useECharts } from '@/hooks/web/useECharts' |
|
||||||
import { propTypes } from '@/utils/propTypes' |
|
||||||
|
|
||||||
const props = defineProps({ |
|
||||||
loading: propTypes.bool.def(true), |
|
||||||
memoryHuman: propTypes.string.def('0'), |
|
||||||
width: propTypes.string.def('100%'), |
|
||||||
height: propTypes.string.def('300px'), |
|
||||||
}) |
|
||||||
|
|
||||||
const chartRef = ref<HTMLDivElement | null>(null) |
|
||||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>) |
|
||||||
|
|
||||||
watch( |
|
||||||
() => props.loading, |
|
||||||
() => { |
|
||||||
if (props.loading) |
|
||||||
return |
|
||||||
|
|
||||||
setOptions({ |
|
||||||
tooltip: { |
|
||||||
formatter: `{b} <br/>{a} : ${props.memoryHuman}`, |
|
||||||
}, |
|
||||||
series: [ |
|
||||||
{ |
|
||||||
name: '峰值', |
|
||||||
type: 'gauge', |
|
||||||
min: 0, |
|
||||||
max: 100, |
|
||||||
detail: { |
|
||||||
formatter: props.memoryHuman, |
|
||||||
}, |
|
||||||
data: [ |
|
||||||
{ |
|
||||||
value: Number.parseFloat(props.memoryHuman), |
|
||||||
name: '内存消耗', |
|
||||||
}, |
|
||||||
], |
|
||||||
}, |
|
||||||
], |
|
||||||
}) |
|
||||||
}, |
|
||||||
{ immediate: true }, |
|
||||||
) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<Card title="内存信息" :loading="loading"> |
|
||||||
<div ref="chartRef" :style="{ width, height }" /> |
|
||||||
</Card> |
|
||||||
</template> |
|
@ -1,46 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { onMounted, ref } from 'vue' |
|
||||||
import { baseInfoSchema } from './redis.data' |
|
||||||
import { Description } from '@/components/Description' |
|
||||||
import { getCache } from '@/api/infra/redis' |
|
||||||
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraRedis' }) |
|
||||||
const CommandStats = createAsyncComponent(() => import('./components/CommandStats.vue')) |
|
||||||
const Memory = createAsyncComponent(() => import('./components/Memory.vue')) |
|
||||||
|
|
||||||
const loading = ref(true) |
|
||||||
const cacheInfo = ref<any>() |
|
||||||
const commandStats = ref<any[]>([]) |
|
||||||
const memoryHuman = ref<any>() |
|
||||||
|
|
||||||
async function getList() { |
|
||||||
const res = await getCache() |
|
||||||
cacheInfo.value = res.info |
|
||||||
memoryHuman.value = res.info.used_memory_human |
|
||||||
await res.commandStats.forEach((val) => { |
|
||||||
commandStats.value.push({ name: val.command, value: val.calls }) |
|
||||||
}) |
|
||||||
loading.value = false |
|
||||||
} |
|
||||||
|
|
||||||
onMounted(async () => { |
|
||||||
await getList() |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div class="p-4"> |
|
||||||
<Description |
|
||||||
title="基础信息" |
|
||||||
:collapse-options="{ canExpand: true, helpMessage: 'Redis 基本信息' }" |
|
||||||
:column="6" |
|
||||||
:data="cacheInfo" |
|
||||||
:schema="baseInfoSchema" |
|
||||||
/> |
|
||||||
<div class="enter-y mt-4 md:flex"> |
|
||||||
<CommandStats class="w-full md:w-1/2" :loading="loading" :command-stats="commandStats" /> |
|
||||||
<Memory class="w-full !my-4 md:w-1/2 !md:mx-4 !md:my-0" :loading="loading" :memory-human="memoryHuman" /> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,64 +0,0 @@ |
|||||||
import type { DescItem } from '@/components/Description' |
|
||||||
|
|
||||||
export const baseInfoSchema: DescItem[] = [ |
|
||||||
{ |
|
||||||
label: 'Redis版本', |
|
||||||
field: 'redis_version', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '运行模式', |
|
||||||
field: 'redis_mode', |
|
||||||
render: (val) => { |
|
||||||
return val === 'standalone' ? '单机' : '集群' |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '端口', |
|
||||||
field: 'tcp_port', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '客户端数', |
|
||||||
field: 'connected_clients', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '运行时间(天)', |
|
||||||
field: 'uptime_in_days', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '使用内存', |
|
||||||
field: 'used_memory_human', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '使用CPU', |
|
||||||
field: 'tcp_port', |
|
||||||
render: (val) => { |
|
||||||
return Number.parseFloat(val).toFixed(2) |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '内存配置', |
|
||||||
field: 'maxmemory_human', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'AOF是否开启', |
|
||||||
field: 'maxmemory_human', |
|
||||||
render: (val) => { |
|
||||||
return val === '0' ? '否' : '是' |
|
||||||
}, |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'RDB是否成功', |
|
||||||
field: 'rdb_last_bgsave_status', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: 'Key数量', |
|
||||||
field: 'expired_keys', |
|
||||||
}, |
|
||||||
{ |
|
||||||
label: '网络入口/出口', |
|
||||||
field: 'instantaneous_input_kbps', |
|
||||||
render: (_val, data) => { |
|
||||||
return `${data.instantaneous_input_kbps}kps / ${data.instantaneous_output_kbps}kps` |
|
||||||
}, |
|
||||||
}, |
|
||||||
] |
|
@ -1,29 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { onMounted, ref } from 'vue' |
|
||||||
import { IFrame } from '@/components/IFrame' |
|
||||||
import { getConfigKey } from '@/api/infra/config' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraAdminServer' }) |
|
||||||
|
|
||||||
const src = ref(`${import.meta.env.VITE_GLOB_BASE_URL}/admin/applications`) |
|
||||||
|
|
||||||
const loading = ref(true) |
|
||||||
|
|
||||||
async function getInfo() { |
|
||||||
const res = await getConfigKey('url.spring-boot-admin') |
|
||||||
if (res && res.length !== 0) |
|
||||||
src.value = res |
|
||||||
|
|
||||||
loading.value = false |
|
||||||
} |
|
||||||
|
|
||||||
onMounted(() => { |
|
||||||
getInfo() |
|
||||||
}) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<IFrame v-if="!loading" :src="src" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,14 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { IFrame } from '@/components/IFrame' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraSkywalking' }) |
|
||||||
|
|
||||||
const src = ref('http://skywalking.shop.iocoder.cn') |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<IFrame :src="src" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,16 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
import { IFrame } from '@/components/IFrame' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraSwagger' }) |
|
||||||
|
|
||||||
// knife4j |
|
||||||
// const src = ref(import.meta.env.VITE_GLOB_BASE_URL + '/doc.html') |
|
||||||
const src = ref(`${import.meta.env.VITE_GLOB_BASE_URL}/swagger-ui`) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<div> |
|
||||||
<IFrame :src="src" /> |
|
||||||
</div> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中 testDemo</div> |
|
||||||
</template> |
|
@ -1,112 +0,0 @@ |
|||||||
<script lang="ts" setup> |
|
||||||
import { computed, reactive, ref, watchEffect } from 'vue' |
|
||||||
import { Input, Tag } from 'ant-design-vue' |
|
||||||
import { useWebSocket } from '@vueuse/core' |
|
||||||
import { PageWrapper } from '@/components/Page' |
|
||||||
import { formatToDateTime } from '@/utils/dateUtil' |
|
||||||
import { useUserStore } from '@/store/modules/user' |
|
||||||
|
|
||||||
defineOptions({ name: 'InfraWebSocket' }) |
|
||||||
|
|
||||||
const InputTextArea = Input.TextArea |
|
||||||
|
|
||||||
const userStore = useUserStore() |
|
||||||
|
|
||||||
const state = reactive({ |
|
||||||
sendValue: '', |
|
||||||
recordList: [] as { id: number, time: number, res: string }[], |
|
||||||
}) |
|
||||||
const server = ref( |
|
||||||
`${(`${import.meta.env.VITE_GLOB_BASE_URL}/websocket/message`).replace('http', 'ws')}?userId=${userStore.getUserInfo.user.id}`, |
|
||||||
) |
|
||||||
const { status, data, send, close, open } = useWebSocket(server.value, { |
|
||||||
autoReconnect: false, |
|
||||||
heartbeat: true, |
|
||||||
}) |
|
||||||
watchEffect(() => { |
|
||||||
if (data.value) { |
|
||||||
try { |
|
||||||
const res = JSON.parse(data.value) |
|
||||||
state.recordList.push(res) |
|
||||||
} |
|
||||||
catch (error) { |
|
||||||
state.recordList.push({ |
|
||||||
res: data.value, |
|
||||||
id: Math.ceil(Math.random() * 1000), |
|
||||||
time: new Date().getTime(), |
|
||||||
}) |
|
||||||
} |
|
||||||
} |
|
||||||
}) |
|
||||||
const getIsOpen = computed(() => status.value === 'OPEN') |
|
||||||
const getTagColor = computed(() => (getIsOpen.value ? 'success' : 'red')) |
|
||||||
const getList = computed(() => { |
|
||||||
return [...state.recordList].reverse() |
|
||||||
}) |
|
||||||
function handlerSend() { |
|
||||||
send(state.sendValue) |
|
||||||
state.sendValue = '' |
|
||||||
} |
|
||||||
function toggle() { |
|
||||||
if (getIsOpen.value) |
|
||||||
close() |
|
||||||
else |
|
||||||
open() |
|
||||||
} |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<PageWrapper title="WebSocket 示例"> |
|
||||||
<div class="flex"> |
|
||||||
<div class="w-1/3 p-4"> |
|
||||||
<div class="flex items-center"> |
|
||||||
<span class="mr-4 text-lg font-medium"> 连接状态: </span> |
|
||||||
<Tag :color="getTagColor"> |
|
||||||
{{ status }} |
|
||||||
</Tag> |
|
||||||
</div> |
|
||||||
<hr class="my-4"> |
|
||||||
|
|
||||||
<div class="flex"> |
|
||||||
<Input v-model:value="server" disabled> |
|
||||||
<template #addonBefore> |
|
||||||
服务地址 |
|
||||||
</template> |
|
||||||
</Input> |
|
||||||
<a-button :type="getIsOpen ? 'danger' : 'primary'" @click="toggle"> |
|
||||||
{{ getIsOpen ? '关闭连接' : '开启连接' }} |
|
||||||
</a-button> |
|
||||||
</div> |
|
||||||
<p class="mt-4 text-lg font-medium"> |
|
||||||
设置 |
|
||||||
</p> |
|
||||||
<hr class="my-4"> |
|
||||||
|
|
||||||
<InputTextArea v-model:value="state.sendValue" placeholder="需要发送到服务器的内容" :disabled="!getIsOpen" allow-clear /> |
|
||||||
|
|
||||||
<a-button type="primary" block class="mt-4" :disabled="!getIsOpen" @click="handlerSend"> |
|
||||||
发送 |
|
||||||
</a-button> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div class="ml-4 w-2/3 p-4"> |
|
||||||
<span class="mr-4 text-lg font-medium"> 消息记录: </span> |
|
||||||
<hr class="my-4"> |
|
||||||
|
|
||||||
<div class="max-h-80 overflow-auto"> |
|
||||||
<ul> |
|
||||||
<li v-for="item in getList" :key="item.time" class="mt-2"> |
|
||||||
<div class="flex items-center"> |
|
||||||
<span class="mr-2 font-medium text-primary">收到消息:</span> |
|
||||||
<span>{{ formatToDateTime(item.time) }}</span> |
|
||||||
</div> |
|
||||||
<div> |
|
||||||
{{ item.res }} |
|
||||||
</div> |
|
||||||
</li> |
|
||||||
</ul> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</PageWrapper> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中</div> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中</div> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中</div> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中</div> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中</div> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中</div> |
|
||||||
</template> |
|
@ -1,3 +0,0 @@ |
|||||||
<template> |
|
||||||
<div>开发中</div> |
|
||||||
</template> |
|
Some files were not shown because too many files have changed in this diff Show More
Reference in new issue