feat: add vue3(element-plus)

This commit is contained in:
xingyu
2022-07-18 19:06:37 +08:00
parent c6b58dca52
commit 80a3ae8d74
423 changed files with 41039 additions and 0 deletions

View File

@ -0,0 +1,67 @@
<script setup lang="ts">
import { ref, unref, onMounted } from 'vue'
import { ContentDetailWrap } from '@/components/ContentDetailWrap'
import BasicInfoForm from './components/BasicInfoForm.vue'
import CloumInfoFormVue from './components/CloumInfoForm.vue'
import GenInfoFormVue from './components/GenInfoForm.vue'
import { ElTabs, ElTabPane, ElButton } from 'element-plus'
import { getCodegenTableApi } from '@/api/infra/codegen'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from '@/hooks/web/useI18n'
import { CodegenColumnVO, CodegenTableVO } from '@/api/infra/codegen/types'
const { t } = useI18n()
const { push } = useRouter()
const { query } = useRoute()
const tableCurrentRow = ref<Nullable<CodegenTableVO>>(null)
const cloumCurrentRow = ref<CodegenColumnVO[]>()
const getList = async () => {
const id = query.id as unknown as number
if (id) {
// 获取表详细信息
const res = await getCodegenTableApi(id)
tableCurrentRow.value = res.table
cloumCurrentRow.value = res.columns
}
}
const loading = ref(false)
const activeName = ref('cloum')
const basicInfoRef = ref<ComponentRef<typeof BasicInfoForm>>()
const genInfoRef = ref<ComponentRef<typeof GenInfoFormVue>>()
// TODO: 提交
const submitForm = async () => {
const basicInfo = unref(basicInfoRef)
const genInfo = unref(genInfoRef)
const basicValidate = await basicInfo?.elFormRef?.validate()?.catch(() => {})
const genValidate = await genInfo?.elFormRef?.validate()?.catch(() => {})
if (basicValidate && genValidate) {
const basicInfoData = (await basicInfo?.getFormData()) as CodegenTableVO
const genInfoData = (await genInfo?.getFormData()) as CodegenTableVO
console.info(basicInfoData)
console.info(genInfoData)
}
console.info(1)
}
onMounted(() => {
getList()
})
</script>
<template>
<ContentDetailWrap title="代码生成" @back="push('/infra/codegen')">
<el-tabs v-model="activeName">
<el-tab-pane label="基本信息" name="basic">
<BasicInfoForm ref="basicInfoRef" :current-row="tableCurrentRow" />
</el-tab-pane>
<el-tab-pane label="字段信息" name="cloum">
<CloumInfoFormVue ref="cloumInfoRef" :current-row="cloumCurrentRow" />
</el-tab-pane>
<el-tab-pane label="生成信息" name="genInfo">
<GenInfoFormVue ref="basicInfoRef" :current-row="tableCurrentRow" />
</el-tab-pane>
</el-tabs>
<template #right>
<el-button type="primary" :loading="loading" @click="submitForm">
{{ t('action.save') }}
</el-button>
</template>
</ContentDetailWrap>
</template>

View File

@ -0,0 +1,74 @@
import { reactive } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { required } from '@/utils/formRules'
import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验
export const rules = reactive({
title: [required],
type: [required],
status: [required]
})
// CrudSchema
const crudSchemas = reactive<CrudSchema[]>([
{
label: t('common.index'),
field: 'id',
type: 'index',
form: {
show: false
},
detail: {
show: false
}
},
{
label: '表名称',
field: 'tableName',
search: {
show: true
}
},
{
label: '表描述',
field: 'tableComment',
search: {
show: true
}
},
{
label: '实体',
field: 'className',
search: {
show: true
}
},
{
label: t('common.createTime'),
field: 'createTime',
form: {
show: false
}
},
{
label: t('common.updateTime'),
field: 'updateTime',
form: {
show: false
}
},
{
label: t('table.action'),
field: 'action',
width: '500px',
form: {
show: false
},
detail: {
show: false
}
}
])
export const { allSchemas } = useCrudSchemas(crudSchemas)

View File

@ -0,0 +1,88 @@
<script setup lang="ts">
import { PropType, reactive, watch } from 'vue'
import { required } from '@/utils/formRules'
import { CodegenTableVO } from '@/api/infra/codegen/types'
import { Form } from '@/components/Form'
import { useForm } from '@/hooks/web/useForm'
const props = defineProps({
currentRow: {
type: Object as PropType<Nullable<CodegenTableVO>>,
default: () => null
}
})
const rules = reactive({
tableName: [required],
tableComment: [required],
className: [required],
author: [required]
})
const schema = reactive<FormSchema[]>([
{
label: '表名称',
field: 'tableName',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '表描述',
field: 'tableComment',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '实体类名称',
field: 'className',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '作者',
field: 'author',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '备注',
field: 'remark',
component: 'Input',
componentProps: {
type: 'textarea',
rows: 4
},
colProps: {
span: 12
}
}
])
const { register, methods, elFormRef } = useForm({
schema
})
watch(
() => props.currentRow,
(currentRow) => {
if (!currentRow) return
const { setValues } = methods
setValues(currentRow)
},
{
deep: true,
immediate: true
}
)
defineExpose({
elFormRef,
getFormData: methods.getFormData
})
</script>
<template>
<Form :rules="rules" @register="register" />
</template>

View File

@ -0,0 +1,137 @@
<script setup lang="ts">
import { ElTable, ElTableColumn, ElInput, ElSelect, ElOption, ElCheckbox } from 'element-plus'
import { onMounted, PropType, ref } from 'vue'
import { CodegenColumnVO } from '@/api/infra/codegen/types'
import { listSimpleDictTypeApi } from '@/api/system/dict/dict.type'
import { DictTypeVO } from '@/api/system/dict/types'
defineProps({
currentRow: {
type: Array as unknown as PropType<CodegenColumnVO[]>,
default: () => null
}
})
/** 查询字典下拉列表 */
const dictOptions = ref<DictTypeVO[]>()
const getDictOptions = async () => {
const res = await listSimpleDictTypeApi()
dictOptions.value = res
}
const tableHeight = document.documentElement.scrollHeight - 245 + 'px'
onMounted(async () => {
await getDictOptions()
})
</script>
<template>
<el-table ref="dragTable" :data="currentRow" row-key="columnId" :max-height="tableHeight">
<el-table-column
label="字段列名"
prop="columnName"
min-width="10%"
:show-overflow-tooltip="true"
/>
<el-table-column label="字段描述" min-width="10%">
<template #default="scope">
<el-input v-model="scope.row.columnComment" />
</template>
</el-table-column>
<el-table-column
label="物理类型"
prop="dataType"
min-width="10%"
:show-overflow-tooltip="true"
/>
<el-table-column label="Java类型" min-width="11%">
<template #default="scope">
<el-select v-model="scope.row.javaType">
<el-option label="Long" value="Long" />
<el-option label="String" value="String" />
<el-option label="Integer" value="Integer" />
<el-option label="Double" value="Double" />
<el-option label="BigDecimal" value="BigDecimal" />
<el-option label="Date" value="Date" />
<el-option label="Boolean" value="Boolean" />
</el-select>
</template>
</el-table-column>
<el-table-column label="java属性" min-width="10%">
<template #default="scope">
<el-input v-model="scope.row.javaField" />
</template>
</el-table-column>
<el-table-column label="插入" min-width="4%">
<template #default="scope">
<el-checkbox true-label="true" false-label="false" v-model="scope.row.createOperation" />
</template>
</el-table-column>
<el-table-column label="编辑" min-width="4%">
<template #default="scope">
<el-checkbox true-label="true" false-label="false" v-model="scope.row.updateOperation" />
</template>
</el-table-column>
<el-table-column label="列表" min-width="4%">
<template #default="scope">
<el-checkbox
true-label="true"
false-label="false"
v-model="scope.row.listOperationResult"
/>
</template>
</el-table-column>
<el-table-column label="查询" min-width="4%">
<template #default="scope">
<el-checkbox true-label="true" false-label="false" v-model="scope.row.listOperation" />
</template>
</el-table-column>
<el-table-column label="查询方式" min-width="10%">
<template #default="scope">
<el-select v-model="scope.row.listOperationCondition">
<el-option label="=" value="=" />
<el-option label="!=" value="!=" />
<el-option label=">" value=">" />
<el-option label=">=" value=">=" />
<el-option label="<" value="<>" />
<el-option label="<=" value="<=" />
<el-option label="LIKE" value="LIKE" />
<el-option label="BETWEEN" value="BETWEEN" />
</el-select>
</template>
</el-table-column>
<el-table-column label="允许空" min-width="5%">
<template #default="scope">
<el-checkbox true-label="true" false-label="false" v-model="scope.row.nullable" />
</template>
</el-table-column>
<el-table-column label="显示类型" min-width="12%">
<template #default="scope">
<el-select v-model="scope.row.htmlType">
<el-option label="文本框" value="input" />
<el-option label="文本域" value="textarea" />
<el-option label="下拉框" value="select" />
<el-option label="单选框" value="radio" />
<el-option label="复选框" value="checkbox" />
<el-option label="日期控件" value="datetime" />
<el-option label="图片上传" value="imageUpload" />
<el-option label="文件上传" value="fileUpload" />
<el-option label="富文本控件" value="editor" />
</el-select>
</template>
</el-table-column>
<el-table-column label="字典类型" min-width="12%">
<template #default="scope">
<el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
<el-option
v-for="dict in dictOptions"
:key="dict.id"
:label="dict.name"
:value="dict.type"
/>
</el-select>
</template>
</el-table-column>
<el-table-column label="示例" min-width="10%">
<template #default="scope">
<el-input v-model="scope.row.example" />
</template>
</el-table-column>
</el-table>
</template>

View File

@ -0,0 +1,110 @@
<script setup lang="ts">
import { PropType, reactive, watch } from 'vue'
import { required } from '@/utils/formRules'
import { CodegenTableVO } from '@/api/infra/codegen/types'
import { Form } from '@/components/Form'
import { useForm } from '@/hooks/web/useForm'
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
const props = defineProps({
currentRow: {
type: Object as PropType<Nullable<CodegenTableVO>>,
default: () => null
}
})
const rules = reactive({
templateType: [required],
scene: [required],
moduleName: [required],
businessName: [required],
businessPackage: [required],
className: [required],
classComment: [required]
})
const schema = reactive<FormSchema[]>([
{
label: '生成模板',
field: 'templateType',
component: 'Select',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE)
},
colProps: {
span: 12
}
},
{
label: '生成场景',
field: 'scene',
component: 'Select',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_SCENE)
},
colProps: {
span: 12
}
},
{
label: '模块名',
field: 'moduleName',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '业务名',
field: 'businessName',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '类名称',
field: 'className',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '类描述',
field: 'classComment',
component: 'Input',
colProps: {
span: 12
}
},
{
label: '上级菜单',
field: 'parentMenuId',
component: 'Input',
colProps: {
span: 12
}
}
])
const { register, methods, elFormRef } = useForm({
schema
})
watch(
() => props.currentRow,
(currentRow) => {
if (!currentRow) return
const { setValues } = methods
setValues(currentRow)
},
{
deep: true,
immediate: true
}
)
defineExpose({
elFormRef,
getFormData: methods.getFormData
})
</script>
<template>
<Form :rules="rules" @register="register" />
</template>

View File

@ -0,0 +1,128 @@
<script setup lang="ts">
import { reactive, ref } from 'vue'
import { getSchemaTableListApi, createCodegenListApi } from '@/api/infra/codegen'
import {
ElMessage,
ElTable,
ElTableColumn,
ElForm,
ElFormItem,
ElInput,
ElEmpty
} from 'element-plus'
import { useI18n } from '@/hooks/web/useI18n'
import { useEmitt } from '@/hooks/web/useEmitt'
import { getDataSourceConfigListApi } from '@/api/infra/dataSourceConfig'
import type { DataSourceConfigVO } from '@/api/infra/dataSourceConfig/types'
import type { DatabaseTableVO } from '@/api/infra/codegen/types'
const { t } = useI18n() // 国际化
const { emitter } = useEmitt()
// ======== 显示页面 ========
const visible = ref(false)
const queryParams = reactive({
tableName: undefined,
tableComment: undefined,
dataSourceConfigId: 0
})
const dataSourceConfigs = ref<DataSourceConfigVO[]>([])
const show = async () => {
const res = await getDataSourceConfigListApi()
dataSourceConfigs.value = res
queryParams.dataSourceConfigId = dataSourceConfigs.value[0].id
visible.value = true
await getList()
}
/** 查询表数据 */
const dbTableList = ref<DatabaseTableVO[]>([])
/** 查询表数据 */
const getList = async () => {
const res = await getSchemaTableListApi(queryParams)
dbTableList.value = res
}
// 查询操作
const handleQuery = async () => {
await getList()
}
// 重置操作
const resetQuery = async () => {
queryParams.tableName = undefined
queryParams.tableComment = undefined
await getList()
}
/** 多选框选中数据 */
const tables = ref<string[]>([])
const handleSelectionChange = (val: DatabaseTableVO[]) => {
tables.value = val.map((item) => item.name)
}
/** 导入按钮操作 */
const handleImportTable = () => {
if (tables.value.length === 0) {
ElMessage.error('请选择要导入的表')
return
}
createCodegenListApi({
dataSourceConfigId: queryParams.dataSourceConfigId,
tableNames: tables.value
}).then((res) => {
ElMessage.success(res.msg)
visible.value = false
emitter.emit('ok')
})
}
defineExpose({
show
})
</script>
<template>
<!-- 导入表 -->
<Dialog title="导入表" v-model="visible" maxHeight="500px" width="50%">
<el-form :model="queryParams" ref="queryRef" :inline="true">
<!-- <el-form-item label="数据源" prop="dataSourceConfigId">
<el-select v-model="queryParams.dataSourceConfigId" placeholder="请选择数据源" clearable>
<el-option
v-for="config in dataSourceConfigs"
:key="config.id"
:label="config.name"
:value="config.id"
/>
</el-select>
</el-form-item> -->
<el-form-item label="表名称" prop="tableName">
<el-input v-model="queryParams.tableName" placeholder="请输入表名称" clearable />
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input v-model="queryParams.tableComment" placeholder="请输入表描述" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh-right" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
<el-table
ref="table"
:data="dbTableList"
@selection-change="handleSelectionChange"
height="400px"
>
<template #empty>
<el-empty description="加载中" />
</template>
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="表名称" :show-overflow-tooltip="true" />
<el-table-column prop="comment" label="表描述" :show-overflow-tooltip="true" />
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleImportTable">{{ t('action.import') }}</el-button>
<el-button @click="visible = false">{{ t('dialog.close') }}</el-button>
</div>
</template>
</Dialog>
</template>

View File

@ -0,0 +1,148 @@
<script setup lang="ts">
import { reactive, ref, unref } from 'vue'
import { handleTree2 } from '@/utils/tree'
import { ElCard, ElTree, ElTabs, ElTabPane, ElMessage } from 'element-plus'
import { previewCodegenApi } from '@/api/infra/codegen'
import { CodegenTableVO, CodegenPreviewVO } from '@/api/infra/codegen/types'
import { useI18n } from '@/hooks/web/useI18n'
import { useClipboard } from '@vueuse/core'
const { t } = useI18n()
// ======== 显示页面 ========
const preview = reactive({
open: false,
titel: '代码预览',
fileTree: [],
activeName: ''
})
const previewCodegen = ref<CodegenPreviewVO[]>()
const show = async (row: CodegenTableVO) => {
const res = await previewCodegenApi(row.id)
let file = handleFiles(res)
previewCodegen.value = res
preview.fileTree = handleTree2(file, 'id', 'parentId', 'children', '/')
preview.activeName = res[0].filePath
preview.open = true
}
const handleNodeClick = async (data, node) => {
if (node && !node.isLeaf) {
return false
}
preview.activeName = data.id
}
/** 生成 files 目录 **/
interface filesType {
id: string
label: string
parentId: string
}
const handleFiles = (datas: CodegenPreviewVO[]) => {
let exists = {} // keyfile 的 idvaluetrue
let files: filesType[] = []
// 遍历每个元素
for (const data of datas) {
let paths = data.filePath.split('/')
let fullPath = '' // 从头开始的路径,用于生成 id
// 特殊处理 java 文件
if (paths[paths.length - 1].indexOf('.java') >= 0) {
let 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 中,则跳过
let 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
}
/** 复制 **/
const copy = async (text: string) => {
const { copy, copied, isSupported } = useClipboard({ source: text })
if (!isSupported) {
ElMessage.error(t('common.copyError'))
} else {
await copy()
if (unref(copied)) {
ElMessage.success(t('common.copySuccess'))
}
}
}
defineExpose({
show
})
</script>
<template>
<Dialog title="预览" v-model="preview.open" top="5vh" maxHeight="800px" width="90%">
<div class="flex">
<el-card class="w-1/4" :gutter="12" shadow="hover">
<el-tree
ref="treeRef"
node-key="id"
:data="preview.fileTree"
:expand-on-click-node="false"
default-expand-all
highlight-current
@node-click="handleNodeClick"
/>
</el-card>
<el-card class="w-3/4" style="margin-left: 10px" :gutter="12" shadow="hover">
<el-tabs v-model="preview.activeName">
<el-tab-pane
v-for="item in previewCodegen"
:label="item.filePath.substring(item.filePath.lastIndexOf('/') + 1)"
:name="item.filePath"
:key="item.filePath"
>
<el-button text style="float: right" @click="copy(item.code)">
{{ t('common.copy') }}
</el-button>
<pre>{{ item.code }}</pre>
<!-- <pre><code class="language-html" v-html="highlightedCode(item)"></code></pre> -->
</el-tab-pane>
</el-tabs>
</el-card>
</div>
</Dialog>
</template>

View File

@ -0,0 +1,142 @@
<script setup lang="ts">
import { ref } from 'vue'
import dayjs from 'dayjs'
import * as CodegenApi from '@/api/infra/codegen'
import { useTable } from '@/hooks/web/useTable'
import { CodegenTableVO } from '@/api/infra/codegen/types'
import { allSchemas } from './codegen.data'
import { useI18n } from '@/hooks/web/useI18n'
import ImportTable from './components/ImportTable.vue'
import Preview from './components/Preview.vue'
import download from '@/utils/download'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
const { t } = useI18n() // 国际化
const { push } = useRouter()
// ========== 列表相关 ==========
const { register, tableObject, methods } = useTable<PageResult<CodegenTableVO>, CodegenTableVO>({
getListApi: CodegenApi.getCodegenTablePageApi,
delListApi: CodegenApi.deleteCodegenTableApi
})
const { getList, setSearchParams, delList } = methods
// 导入操作
const importRef = ref()
const openImportTable = () => {
importRef.value.show()
}
// 预览操作
const previewRef = ref()
const handlePreview = (row: CodegenTableVO) => {
previewRef.value.show(row)
}
// 编辑操作
const handleEditTable = (row: CodegenTableVO) => {
push('/codegen/edit?id=' + row.id)
}
// 同步操作
const handleSynchDb = (row: CodegenTableVO) => {
// 基于 DB 同步
const tableName = row.tableName
ElMessageBox.confirm('确认要强制同步' + tableName + '表结构吗?', t('common.reminder'), {
confirmButtonText: t('common.ok'),
cancelButtonText: t('common.cancel'),
type: 'warning'
}).then(async () => {
await CodegenApi.syncCodegenFromDBApi(row.id)
ElMessage.success('同步成功')
})
}
// 生成代码操作
const handleGenTable = (row: CodegenTableVO) => {
const res = CodegenApi.downloadCodegenApi(row.id)
download.zip(res, 'codegen-' + row.className + '.zip')
}
// 删除操作
const handleDelete = (row: CodegenTableVO) => {
delList(row.id, false)
}
// 查询操作
const handleQuery = () => {
getList()
}
// ========== 初始化 ==========
getList()
</script>
<template>
<!-- 搜索工作区 -->
<ContentWrap>
<Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
</ContentWrap>
<ContentWrap>
<!-- 操作工具栏 -->
<div class="mb-10px">
<el-button type="primary" v-hasPermi="['infra:codegen:create']" @click="openImportTable">
<Icon icon="el:zoom-in" class="mr-5px" /> {{ t('action.import') }}
</el-button>
</div>
<!-- 列表 -->
<Table
:columns="allSchemas.tableColumns"
:selection="false"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
@register="register"
>
<template #createTime="{ row }">
<span>{{ dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template>
<template #updateTime="{ row }">
<span>{{ dayjs(row.updateTime).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template>
<template #action="{ row }">
<el-button
link
type="primary"
v-hasPermi="['infra:codegen:preview']"
@click="handlePreview(row)"
>
<Icon icon="ep:view" class="mr-5px" /> {{ t('action.preview') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['infra:codegen:update']"
@click="handleEditTable(row)"
>
<Icon icon="ep:edit" class="mr-5px" /> {{ t('action.edit') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['infra:codegen:delete']"
@click="handleDelete(row)"
>
<Icon icon="ep:delete" class="mr-5px" /> {{ t('action.del') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['infra:codegen:update']"
@click="handleSynchDb(row)"
>
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('action.sync') }}
</el-button>
<el-button
link
type="primary"
v-hasPermi="['infra:codegen:download']"
@click="handleGenTable(row)"
>
<Icon icon="ep:download" class="mr-5px" /> {{ t('action.generate') }}
</el-button>
</template>
</Table>
</ContentWrap>
<ImportTable ref="importRef" @ok="handleQuery" />
<Preview ref="previewRef" />
</template>