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