56 changed files with 6281 additions and 6 deletions
@ -0,0 +1,40 @@ |
|||
import { onMounted, onUnmounted } from 'vue'; |
|||
import type { Ref } from 'vue'; |
|||
|
|||
import Sortable from 'sortablejs'; |
|||
|
|||
/** |
|||
* vxe支持行拖动 |
|||
* @param tableRef |
|||
* @param handle css |
|||
* @param tableData 表格数据 |
|||
*/ |
|||
export const useVxeTableSortable = (tableRef: Ref, handle: string, tableData: Ref) => { |
|||
let sortable: any = null; |
|||
const handleRowDrop = () => { |
|||
if (sortable !== null) { |
|||
sortable.destroy(); |
|||
} |
|||
sortable = Sortable.create( |
|||
tableRef.value.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), |
|||
{ |
|||
handle: handle, |
|||
animation: 150, |
|||
ghostClass: 'blue-background-class', |
|||
onEnd: ({ newIndex, oldIndex }: any) => { |
|||
const currentRow = tableData.value.splice(oldIndex, 1)[0]; |
|||
tableData.value.splice(newIndex, 0, currentRow); |
|||
}, |
|||
}, |
|||
); |
|||
}; |
|||
onUnmounted(() => { |
|||
if (sortable !== null) { |
|||
sortable.destroy(); |
|||
} |
|||
}); |
|||
onMounted(handleRowDrop); |
|||
return { |
|||
handleRowDrop, |
|||
}; |
|||
}; |
|||
@ -0,0 +1,64 @@ |
|||
<template> |
|||
<div> |
|||
<SmartTable |
|||
@register="registerTable" |
|||
v-bind="getTableProps" |
|||
@current-change="handleCurrentChange" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import type { SmartTableProps } from '@/components/SmartTable'; |
|||
|
|||
import { computed } from 'vue'; |
|||
|
|||
import { SmartTable, useSmartTable } from '@/components/SmartTable'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
const props = defineProps({ |
|||
tableProps: Object as PropType<SmartTableProps>, |
|||
}); |
|||
|
|||
const emit = defineEmits(['current-change']); |
|||
|
|||
const handleCurrentChange = ({ row }) => { |
|||
emit('current-change', row); |
|||
}; |
|||
|
|||
const getTableProps = computed<SmartTableProps>(() => { |
|||
return { |
|||
rowConfig: { |
|||
isHover: true, |
|||
isCurrent: true, |
|||
}, |
|||
columns: [ |
|||
{ |
|||
title: '{generator.views.template.title.templateGroup}', |
|||
field: 'groupName', |
|||
}, |
|||
], |
|||
height: 'auto', |
|||
proxyConfig: { |
|||
ajax: { |
|||
query: async (params) => { |
|||
const result = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/listGroup', |
|||
data: { |
|||
...params.ajaxParameter, |
|||
sortName: 'seq', |
|||
}, |
|||
}); |
|||
return [{ groupName: 'ALL' }, ...result]; |
|||
}, |
|||
}, |
|||
}, |
|||
...props.tableProps, |
|||
}; |
|||
}); |
|||
|
|||
const [registerTable] = useSmartTable(); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,8 @@ |
|||
export const extensionLanguageMap: { [index: string]: string } = { |
|||
'text/x-java': 'java', |
|||
xml: 'xml', |
|||
javascript: 'js', |
|||
html: 'html', |
|||
'text/x-vue': 'vue', |
|||
typescript: 'ts', |
|||
}; |
|||
@ -0,0 +1,13 @@ |
|||
/** |
|||
* 模板类型 |
|||
*/ |
|||
export const TemplateType: any = { |
|||
TEMPLATE_CODE: { |
|||
value: 'TEMPLATE_CODE', |
|||
label: 'generator.views.template.label.templateType.templateCode', |
|||
}, |
|||
TEMPLATE_DB_DICT: { |
|||
value: 'TEMPLATE_DB_DICT', |
|||
label: 'generator.views.template.label.templateType.templateDbDict', |
|||
}, |
|||
}; |
|||
@ -0,0 +1,11 @@ |
|||
import { AppRouteRecordRaw } from '@/router/types'; |
|||
|
|||
export const CREATE_CODE_ROUTER: AppRouteRecordRaw = { |
|||
path: '/codeCreateView', |
|||
name: 'CodeCreateView', |
|||
meta: { |
|||
title: '生成代码', |
|||
}, |
|||
component: () => import('/@/modules/codeGenerator/views/codeCreate/CodeCreateView.vue'), |
|||
props: (route) => route.query, |
|||
}; |
|||
@ -0,0 +1,11 @@ |
|||
/** |
|||
* 扩展名类型映射 |
|||
*/ |
|||
export const extensionLanguageMap: any = { |
|||
'text/x-java': 'java', |
|||
xml: 'xml', |
|||
javascript: 'js', |
|||
html: 'html', |
|||
'text/x-vue': 'vue', |
|||
typescript: 'ts', |
|||
}; |
|||
@ -0,0 +1,63 @@ |
|||
<template> |
|||
<div class="full-height page-container"> |
|||
<div style="padding-bottom: 6px"> |
|||
<a-button type="primary" @click="handleDownloadAll">下载全部</a-button> |
|||
</div> |
|||
<a-tabs class="code-container"> |
|||
<a-tab-pane v-for="item in data" :key="item.templateId" :tab="item.templateName"> |
|||
<CodeEditor read-only :mode="item.language" :code="item.code" /> |
|||
</a-tab-pane> |
|||
</a-tabs> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { onMounted, ref, useAttrs } from 'vue'; |
|||
import { downloadByData } from '@/utils/file/download'; |
|||
import { extensionLanguageMap } from './CodeCreateSupport'; |
|||
import { CodeEditor } from '@/components/CodeEditor'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
const attrs = useAttrs(); |
|||
const data = ref<Array<any>>([]); |
|||
const dataLoading = ref(false); |
|||
/** |
|||
* 下载全部 |
|||
*/ |
|||
const handleDownloadAll = () => { |
|||
data.value.forEach((item): any => { |
|||
const filename = `${item.filename}.${extensionLanguageMap[item.language]}`; |
|||
downloadByData(item.code, filename); |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 加载数据函数 |
|||
*/ |
|||
const loadData = async () => { |
|||
dataLoading.value = true; |
|||
try { |
|||
data.value = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/main/createCode', |
|||
data: Object.assign({}, attrs, { |
|||
templateIdList: attrs.templateIdList?.split(','), |
|||
}), |
|||
}); |
|||
} finally { |
|||
dataLoading.value = false; |
|||
} |
|||
}; |
|||
onMounted(loadData); |
|||
</script> |
|||
|
|||
<style scoped lang="less"> |
|||
.code-container { |
|||
height: calc(100% - 38px); |
|||
border: 1px solid gainsboro; |
|||
|
|||
::v-deep(.ant-tabs-content) { |
|||
height: calc(100% - 60px); |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,80 @@ |
|||
<template> |
|||
<div class="full-height" style=" height: 100%;padding: 10px"> |
|||
<div style="padding-bottom: 6px"> |
|||
<a-button type="primary" @click="handleDownloadAll">下载全部</a-button> |
|||
</div> |
|||
<a-tabs class="code-container"> |
|||
<a-tab-pane v-for="item in data" :key="item.templateId" :tab="item.templateName"> |
|||
<CodeEditor read-only :mode="item.language" :code="item.code" /> |
|||
</a-tab-pane> |
|||
</a-tabs> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, onMounted, ref } from 'vue'; |
|||
|
|||
import { CodeEditor } from '@/components/CodeEditor'; |
|||
|
|||
import { downloadByData } from '@/utils/file/download'; |
|||
|
|||
import { extensionLanguageMap } from './CodeCreateSupport'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
/** |
|||
* 代码生成页面 |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'CodeCreateView', |
|||
components: { |
|||
CodeEditor, |
|||
}, |
|||
// @ts-ignore |
|||
setup(props, { attrs }: any) { |
|||
const data = ref<Array<any>>([]); |
|||
const dataLoading = ref(false); |
|||
/** |
|||
* 加载数据函数 |
|||
*/ |
|||
const loadData = async () => { |
|||
dataLoading.value = true; |
|||
try { |
|||
data.value = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/main/createCode', |
|||
data: Object.assign({}, attrs, { |
|||
templateIdList: attrs.templateIdList.split(','), |
|||
}), |
|||
}); |
|||
} finally { |
|||
dataLoading.value = false; |
|||
} |
|||
}; |
|||
/** |
|||
* 下载全部 |
|||
*/ |
|||
const handleDownloadAll = () => { |
|||
data.value.forEach((item): any => { |
|||
const filename = `${item.filename}.${extensionLanguageMap[item.language]}`; |
|||
downloadByData(item.code, filename); |
|||
}); |
|||
}; |
|||
onMounted(loadData); |
|||
return { |
|||
data, |
|||
handleDownloadAll, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.code-container { |
|||
height: calc(100% - 38px); |
|||
border: 1px solid gainsboro; |
|||
|
|||
::v-deep(.ant-tabs-content) { |
|||
height: calc(100% - 60px); |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,30 @@ |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
enum Api { |
|||
queryDbTable = 'db/connection/queryDbTable', |
|||
getConfigById = 'db/code/main/getConfigById', |
|||
saveConfig = 'db/code/main/save', |
|||
} |
|||
|
|||
/** |
|||
* 查询数据库信息 |
|||
* @param connectionId |
|||
* @param tableName |
|||
*/ |
|||
export const queryDbTableApi = (connectionId: number, tableName: number) => |
|||
defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: Api.queryDbTable, |
|||
data: { dbConnectionId: connectionId, tableName }, |
|||
}); |
|||
|
|||
export const getConfigByIdApi = (configId: number) => |
|||
defHttp.post({ service: ApiServiceEnum.SMART_CODE, url: Api.getConfigById, data: configId }); |
|||
|
|||
export const saveConfigApi = (model: Recordable) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: Api.saveConfig, |
|||
data: model, |
|||
}); |
|||
}; |
|||
@ -0,0 +1,330 @@ |
|||
import type { FormSchema } from '@/components/Form'; |
|||
|
|||
type ButtonType = |
|||
| 'SEARCH' |
|||
| 'RESET' |
|||
| 'ADD' |
|||
| 'EDIT' |
|||
| 'DELETE' |
|||
| 'EXCEL_IMPORT' |
|||
| 'EXCEL_EXPORT' |
|||
| 'COLUMN_SETTING' |
|||
| 'ZOOM' |
|||
| 'REFRESH' |
|||
| 'SHOW_SEARCH' |
|||
| 'PRINT'; |
|||
|
|||
interface Button { |
|||
key: ButtonType; |
|||
value: string; |
|||
} |
|||
|
|||
const tableTypeList = [ |
|||
{ |
|||
label: 'generator.views.code.title.tableType.single', |
|||
value: '10', |
|||
}, |
|||
{ |
|||
label: 'generator.views.code.title.tableType.main', |
|||
value: '20', |
|||
}, |
|||
{ |
|||
label: 'generator.views.code.title.tableType.addendum', |
|||
value: '30', |
|||
}, |
|||
]; |
|||
|
|||
const yesNoList = [ |
|||
{ |
|||
label: 'Yes', |
|||
value: true, |
|||
}, |
|||
{ |
|||
label: 'No', |
|||
value: false, |
|||
}, |
|||
]; |
|||
|
|||
export const formSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
label: '', |
|||
field: 'systemId', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.table.connectionName'), |
|||
field: 'connectionId', |
|||
slot: 'addEditForm-connectionId', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.table.tableName'), |
|||
field: 'tableName', |
|||
component: 'Input', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.table.configName'), |
|||
field: 'configName', |
|||
component: 'Input', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.table.type'), |
|||
field: 'type', |
|||
component: 'Select', |
|||
defaultValue: '10', |
|||
componentProps: { |
|||
options: tableTypeList.map((item) => ({ label: t(item.label), value: item.value })), |
|||
}, |
|||
}, |
|||
// ------------ 第二行 ---------------------
|
|||
{ |
|||
label: t('generator.views.code.title.showCheckBox'), |
|||
field: 'showCheckbox', |
|||
component: 'RadioGroup', |
|||
defaultValue: true, |
|||
componentProps: { |
|||
options: yesNoList, |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.isPage'), |
|||
field: 'page', |
|||
component: 'RadioGroup', |
|||
defaultValue: true, |
|||
componentProps: { |
|||
options: yesNoList, |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.invented'), |
|||
field: 'invented', |
|||
component: 'RadioGroup', |
|||
defaultValue: false, |
|||
componentProps: { |
|||
options: yesNoList, |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.columnSort'), |
|||
field: 'columnSort', |
|||
component: 'RadioGroup', |
|||
defaultValue: false, |
|||
componentProps: { |
|||
options: yesNoList, |
|||
}, |
|||
}, |
|||
// ------------ 第三行 ---------------------
|
|||
{ |
|||
label: t('generator.views.code.title.leftButton'), |
|||
field: 'leftButtonList', |
|||
component: 'Select', |
|||
defaultValue: ['ADD', 'DELETE'], |
|||
componentProps: { |
|||
mode: 'multiple', |
|||
options: letButtonList.map((item) => ({ |
|||
label: item.value, |
|||
value: item.key, |
|||
})), |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.rightButton'), |
|||
field: 'rightButtonList', |
|||
component: 'Select', |
|||
defaultValue: ['ZOOM', 'REFRESH', 'SHOW_SEARCH', 'COLUMN_SETTING'], |
|||
componentProps: { |
|||
mode: 'multiple', |
|||
options: rightButtonList.map((item) => ({ |
|||
label: item.value, |
|||
value: item.key, |
|||
})), |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.rowButtonType.title'), |
|||
field: 'rowButtonType', |
|||
component: 'Select', |
|||
defaultValue: 'NONE', |
|||
componentProps: { |
|||
options: rowButtonTypeList(t), |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.rowButtonList'), |
|||
field: 'rowButtonList', |
|||
component: 'Select', |
|||
componentProps: { |
|||
mode: 'multiple', |
|||
options: rowButtonList.map((item) => ({ |
|||
label: item.value, |
|||
value: item.key, |
|||
})), |
|||
}, |
|||
}, |
|||
// ------------ 第四行 ---------------------
|
|||
{ |
|||
label: t('generator.views.code.title.formColNum'), |
|||
field: 'formColNum', |
|||
component: 'Select', |
|||
defaultValue: 1, |
|||
componentProps: { |
|||
options: columnNumList(t, false), |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.searchColNum'), |
|||
field: 'searchColNum', |
|||
component: 'Select', |
|||
defaultValue: 0, |
|||
componentProps: { |
|||
options: columnNumList(t), |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('common.table.remark'), |
|||
field: 'remark', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.i18nPrefix'), |
|||
field: 'i18nPrefix', |
|||
component: 'Input', |
|||
}, |
|||
// ------------ 第五行 ---------------------
|
|||
{ |
|||
label: t('generator.views.code.title.relateTable'), |
|||
field: 'addendumTableList', |
|||
defaultValue: [], |
|||
slot: 'addEditForm-RelateTable', |
|||
}, |
|||
{ |
|||
label: '', |
|||
field: 'id', |
|||
slot: 'addEditForm-syncTable', |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
/** |
|||
* 左侧按钮列表 |
|||
*/ |
|||
const letButtonList: Button[] = [ |
|||
{ |
|||
key: 'SEARCH', |
|||
value: '搜索', |
|||
}, |
|||
{ |
|||
key: 'RESET', |
|||
value: '重置', |
|||
}, |
|||
{ |
|||
key: 'ADD', |
|||
value: '添加', |
|||
}, |
|||
{ |
|||
key: 'EDIT', |
|||
value: '修改', |
|||
}, |
|||
{ |
|||
key: 'DELETE', |
|||
value: '删除', |
|||
}, |
|||
]; |
|||
|
|||
const rightButtonList: Button[] = [ |
|||
{ |
|||
key: 'EXCEL_IMPORT', |
|||
value: 'Excel导入', |
|||
}, |
|||
{ |
|||
key: 'EXCEL_EXPORT', |
|||
value: 'Excel导出', |
|||
}, |
|||
{ |
|||
key: 'COLUMN_SETTING', |
|||
value: '列配置', |
|||
}, |
|||
{ |
|||
key: 'ZOOM', |
|||
value: '放大缩小', |
|||
}, |
|||
{ |
|||
key: 'REFRESH', |
|||
value: '刷新', |
|||
}, |
|||
{ |
|||
key: 'SHOW_SEARCH', |
|||
value: '显示搜索', |
|||
}, |
|||
{ |
|||
key: 'PRINT', |
|||
value: '打印', |
|||
}, |
|||
]; |
|||
|
|||
/** |
|||
* 行按钮 |
|||
*/ |
|||
const rowButtonList = [ |
|||
{ |
|||
key: 'EDIT', |
|||
value: '修改', |
|||
}, |
|||
{ |
|||
key: 'DELETE', |
|||
value: '删除', |
|||
}, |
|||
]; |
|||
|
|||
const columnNumList = (t: Function, hasZeroColumn = true) => { |
|||
const column = [ |
|||
{ |
|||
value: 1, |
|||
label: t('generator.views.code.title.colNum.one'), |
|||
}, |
|||
{ |
|||
value: 2, |
|||
label: t('generator.views.code.title.colNum.two'), |
|||
}, |
|||
{ |
|||
value: 3, |
|||
label: t('generator.views.code.title.colNum.three'), |
|||
}, |
|||
{ |
|||
value: 4, |
|||
label: t('generator.views.code.title.colNum.four'), |
|||
}, |
|||
]; |
|||
if (hasZeroColumn) { |
|||
return [ |
|||
{ |
|||
value: 0, |
|||
label: t('generator.views.design.title.colNum.zero'), |
|||
}, |
|||
].concat(column); |
|||
} |
|||
return column; |
|||
}; |
|||
|
|||
const rowButtonTypeList = (t: Function) => [ |
|||
{ |
|||
label: t('generator.views.code.title.rowButtonType.none'), |
|||
value: 'NONE', |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.rowButtonType.single'), |
|||
value: 'SINGLE', |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.rowButtonType.more'), |
|||
value: 'MORE', |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.title.rowButtonType.text'), |
|||
value: 'TEXT', |
|||
}, |
|||
]; |
|||
@ -0,0 +1,250 @@ |
|||
<template> |
|||
<div class="full-height page-container"> |
|||
<div class="spin"> |
|||
<div class="form-container"> |
|||
<a-spin :spinning="pageLoading"> |
|||
<BasicForm @register="registerForm" :size="getFormSize"> |
|||
<template #addEditForm-connectionId="{ model }"> |
|||
<DatabaseSelect |
|||
v-model:value="model.connectionId" |
|||
:parameter="getDatabaseListParameter" |
|||
/> |
|||
</template> |
|||
<template #addEditForm-RelateTable="{ model }"> |
|||
<a-tag |
|||
v-for="(table, index) in model.addendumTableList" |
|||
:key="index" |
|||
style="display: inline-block" |
|||
@close="() => handleRemoveRelateTable(model.addendumTableList, index)" |
|||
closable |
|||
> |
|||
{{ table.configName }} |
|||
</a-tag> |
|||
<Icon |
|||
icon="ant-design:plus-outlined" |
|||
:style="{ cursor: 'pointer' }" |
|||
@click="() => openPageAddendumTableChoseModal(true, {})" |
|||
/> |
|||
<PageAddendumTableChoseModal |
|||
:select-table-list="model.relatedTableList" |
|||
@ok="handleSetAddendumTable" |
|||
@register="registerPageAddendumTableChoseModal" |
|||
/> |
|||
</template> |
|||
<template #addEditForm-syncTable> |
|||
<a-button type="primary" :size="getButtonSize" @click="handleSyncTableData"> |
|||
{{ $t('generator.views.code.button.syncTableData') }} |
|||
</a-button> |
|||
</template> |
|||
</BasicForm> |
|||
<a-divider /> |
|||
<a-tabs style="min-height: 400px" animated> |
|||
<a-tab-pane key="1" :tab="$t('generator.views.code.title.dbMessage')"> |
|||
<TableFieldTable |
|||
class="full-height" |
|||
:data="computedTableData" |
|||
:loading="dbDataLoading" |
|||
/> |
|||
</a-tab-pane> |
|||
<a-tab-pane key="2" :tab="$t('generator.views.code.title.tableSetting')"> |
|||
<PageTableSetting |
|||
ref="pageTableSettingRef" |
|||
:edit-data="editConfigData.codePageConfigList" |
|||
:table-data="computedTableData" |
|||
:loading="dbDataLoading" |
|||
/> |
|||
</a-tab-pane> |
|||
<a-tab-pane key="3" :tab="$t('generator.views.code.title.formSetting')"> |
|||
<PageFormSetting |
|||
ref="pageFormSettingRef" |
|||
:edit-data="editConfigData.codeFormConfigList" |
|||
:table-data="computedTableData" |
|||
:loading="dbDataLoading" |
|||
/> |
|||
</a-tab-pane> |
|||
<a-tab-pane key="4" :tab="$t('generator.views.code.title.searchSetting')"> |
|||
<PageSearchSetting |
|||
ref="pageSearchSettingRef" |
|||
:edit-data="editConfigData.codeSearchConfigList" |
|||
:table-data="computedTableData" |
|||
:loading="dbDataLoading" |
|||
/> |
|||
</a-tab-pane> |
|||
</a-tabs> |
|||
</a-spin> |
|||
</div> |
|||
<a-divider /> |
|||
<div style="text-align: right"> |
|||
<a-button @click="loadConfigData"> |
|||
{{ $t('common.button.reload') }} |
|||
</a-button> |
|||
<a-button |
|||
style="margin-left: 5px" |
|||
:loading="saveLoading" |
|||
v-permission="'db:codeConfig:save'" |
|||
@click="handleSave" |
|||
type="primary" |
|||
> |
|||
{{ $t('common.button.save') }} |
|||
</a-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { ref, watch, onMounted } from 'vue'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { useRouter, useRoute } from 'vue-router'; |
|||
|
|||
import { BasicForm, useForm } from '@/components/Form'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { formSchemas } from './CodeDesignPage.config'; |
|||
import { getConfigByIdApi } from './CodeDesignPage.api'; |
|||
import { isString } from '@/utils/is'; |
|||
import { toNumber } from 'lodash-es'; |
|||
import { propTypes } from '@/utils/propTypes'; |
|||
import { useModal } from '@/components/Modal'; |
|||
|
|||
import { useLoadDbData, useSaveConfig } from './CodeDesignPageHook'; |
|||
|
|||
import DatabaseSelect from './componenets/DatabaseSelect/DatabaseSelect.vue'; |
|||
import TableFieldTable from './componenets/TableFieldTable/TableFieldTable.vue'; |
|||
import PageTableSetting from './componenets/PageTableSetting/PageTableSetting.vue'; |
|||
import PageFormSetting from './componenets/PageFromSetting/PageFormSetting.vue'; |
|||
import PageSearchSetting from './componenets/PageSearchSetting/PageSearchSetting.vue'; |
|||
import Icon from '@/components/Icon/src/Icon.vue'; |
|||
import PageAddendumTableChoseModal from './componenets/PageAddendumTableChoseModal.vue'; |
|||
|
|||
const props = defineProps({ |
|||
configId: propTypes.oneOfType([propTypes.string, propTypes.number]), |
|||
// 系统ID |
|||
systemId: propTypes.oneOfType([propTypes.string, propTypes.number]), |
|||
}); |
|||
const { t } = useI18n(); |
|||
const router = useRouter(); |
|||
const route = useRoute(); |
|||
const { getFormSize, getButtonSize } = useSizeSetting(); |
|||
|
|||
const pageLoading = ref(false); |
|||
|
|||
const getDatabaseListParameter = () => { |
|||
return { |
|||
parameter: { |
|||
'systemId@=': props.systemId, |
|||
}, |
|||
}; |
|||
}; |
|||
|
|||
/** |
|||
* 代码配置页面 |
|||
*/ |
|||
const [registerForm, { validate, setFieldsValue }] = useForm({ |
|||
colon: true, |
|||
schemas: formSchemas(t), |
|||
showActionButtonGroup: false, |
|||
baseColProps: { |
|||
span: 6, |
|||
}, |
|||
labelCol: { |
|||
span: 8, |
|||
}, |
|||
wrapperCol: { |
|||
span: 15, |
|||
}, |
|||
}); |
|||
|
|||
const handleSetAddendumTable = (tableData) => { |
|||
setFieldsValue({ addendumTableList: tableData }); |
|||
}; |
|||
|
|||
const loadConfigData = async () => { |
|||
try { |
|||
pageLoading.value = true; |
|||
let configId = props.configId; |
|||
if (!configId) { |
|||
return; |
|||
} |
|||
if (isString(configId)) { |
|||
configId = toNumber(configId); |
|||
} |
|||
const result = await getConfigByIdApi(configId); |
|||
await setFieldsValue(result); |
|||
// 加载表格数据 |
|||
handleSyncTableData(); |
|||
const { codePageConfigList, codeFormConfigList, codeSearchConfigList } = result; |
|||
editConfigData.value = { |
|||
codePageConfigList, |
|||
codeFormConfigList, |
|||
codeSearchConfigList, |
|||
}; |
|||
} finally { |
|||
pageLoading.value = false; |
|||
} |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
/** |
|||
* 监控configId变化,更新数据 |
|||
*/ |
|||
watch( |
|||
() => props.configId, |
|||
async (value) => { |
|||
if (value) { |
|||
loadConfigData(); |
|||
} else { |
|||
setFieldsValue({ |
|||
systemId: props.systemId, |
|||
}); |
|||
} |
|||
}, |
|||
{ |
|||
immediate: true, |
|||
}, |
|||
); |
|||
}); |
|||
|
|||
const { dbDataLoading, computedTableData, handleSyncTableData, isSyncRef, dbDataRef } = |
|||
useLoadDbData(validate); |
|||
const editConfigData = ref<any>({}); |
|||
|
|||
const handleRemoveRelateTable = (dataList: any[], index: number) => { |
|||
dataList.splice(index, 1); |
|||
}; |
|||
const [registerPageAddendumTableChoseModal, { openModal: openPageAddendumTableChoseModal }] = |
|||
useModal(); |
|||
|
|||
const { handleSave, saveLoading, pageTableSettingRef, pageSearchSettingRef, pageFormSettingRef } = |
|||
useSaveConfig(t, isSyncRef, validate, dbDataRef, (configId) => { |
|||
const { fullPath, query, path } = route; |
|||
console.log(fullPath); |
|||
router.push({ |
|||
path: path, |
|||
query: { |
|||
...query, |
|||
configId, |
|||
}, |
|||
}); |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped lang="less"> |
|||
.page-container { |
|||
padding: 10px; |
|||
|
|||
:deep(.ant-divider) { |
|||
margin: 5px 0; |
|||
} |
|||
|
|||
.spin { |
|||
height: 100%; |
|||
padding: 10px; |
|||
background: white; |
|||
} |
|||
|
|||
.form-container { |
|||
height: calc(100% - 42px); |
|||
overflow: auto; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,142 @@ |
|||
import { computed, createVNode, Ref, ref, unref } from 'vue'; |
|||
|
|||
import { queryDbTableApi, saveConfigApi } from './CodeDesignPage.api'; |
|||
import { message, Modal } from 'ant-design-vue'; |
|||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'; |
|||
|
|||
/** |
|||
* 加载数据库数据 |
|||
*/ |
|||
export const useLoadDbData = (validate: Function) => { |
|||
// 数据库数据加载状态
|
|||
const dbDataLoading = ref(false); |
|||
const dbDataRef = ref<Recordable>({}); |
|||
const isSyncRef = ref(false); |
|||
|
|||
/** |
|||
* 表格table计算属性 |
|||
*/ |
|||
const computedTableData = computed(() => { |
|||
const dbData = unref(dbDataRef); |
|||
if (!dbData.tableName) { |
|||
return []; |
|||
} |
|||
const primaryKeyList = dbData.primaryKeyList || []; |
|||
const baseColumnList = dbData.baseColumnList || []; |
|||
return [...primaryKeyList, ...baseColumnList]; |
|||
}); |
|||
|
|||
const handleSyncTableData = async () => { |
|||
const { connectionId, tableName } = await validate(); |
|||
try { |
|||
dbDataLoading.value = true; |
|||
dbDataRef.value = await queryDbTableApi(connectionId, tableName); |
|||
isSyncRef.value = true; |
|||
} finally { |
|||
dbDataLoading.value = false; |
|||
} |
|||
}; |
|||
|
|||
return { |
|||
dbDataLoading, |
|||
dbDataRef, |
|||
computedTableData, |
|||
isSyncRef, |
|||
handleSyncTableData, |
|||
}; |
|||
}; |
|||
|
|||
/** |
|||
* 保存操作hook |
|||
*/ |
|||
export const useSaveConfig = ( |
|||
t: Function, |
|||
isSync: Ref<boolean>, |
|||
validate: Function, |
|||
dbDataRef: Ref<Recordable>, |
|||
afterSave?: Function, |
|||
) => { |
|||
const pageTableSettingRef = ref(); |
|||
const pageSearchSettingRef = ref(); |
|||
const pageFormSettingRef = ref(); |
|||
|
|||
const saveLoading = ref(false); |
|||
|
|||
const handleSave = () => { |
|||
if (!unref(isSync)) { |
|||
message.warn(t('generator.views.code.validate.syncTable')); |
|||
return false; |
|||
} |
|||
if (!unref(pageTableSettingRef)) { |
|||
message.warn(t('generator.views.code.validate.tableSetting')); |
|||
return false; |
|||
} |
|||
if (!unref(pageFormSettingRef)) { |
|||
message.warn(t('generator.views.code.validate.formSetting')); |
|||
return false; |
|||
} |
|||
// 搜索配置实体
|
|||
if (!unref(pageSearchSettingRef)) { |
|||
message.warn(t('generator.views.code.validate.searchSetting')); |
|||
return false; |
|||
} |
|||
// 验证必填字段是否设置表单
|
|||
const pageFormSettingData = unref(pageFormSettingRef).getData() as Array<Recordable>; |
|||
const nonNullField: Array<string> = []; |
|||
pageFormSettingData.forEach((item) => { |
|||
if (item.nullable === 0 && (item.visible === false || item.used === false)) { |
|||
nonNullField.push(item.columnName); |
|||
} |
|||
}); |
|||
if (nonNullField.length > 0) { |
|||
Modal.confirm({ |
|||
title: t('common.notice.confirmSave'), |
|||
icon: createVNode(ExclamationCircleOutlined), |
|||
content: t('generator.views.code.message.saveConfirmContent', nonNullField.join(',')), |
|||
onCancel() { |
|||
return false; |
|||
}, |
|||
onOk() { |
|||
doSave(); |
|||
}, |
|||
}); |
|||
} else { |
|||
doSave(); |
|||
} |
|||
}; |
|||
|
|||
const doSave = async () => { |
|||
const formModel = await validate(); |
|||
const dbData = unref(dbDataRef); |
|||
const saveData = { |
|||
...formModel, |
|||
codePageConfigList: unref(pageTableSettingRef).getData(), |
|||
codeFormConfigList: unref(pageFormSettingRef).getData(), |
|||
codeSearchConfigList: unref(pageSearchSettingRef).getData(), |
|||
className: dbData.className, |
|||
remarks: dbData.remarks, |
|||
}; |
|||
try { |
|||
saveLoading.value = true; |
|||
const configId = await saveConfigApi(saveData); |
|||
afterSave && afterSave(configId); |
|||
} catch (e: any) { |
|||
if (e.code === 400) { |
|||
e.data.forEach((item: string) => { |
|||
message.error(item); |
|||
}); |
|||
} |
|||
return false; |
|||
} finally { |
|||
saveLoading.value = false; |
|||
} |
|||
}; |
|||
|
|||
return { |
|||
handleSave, |
|||
pageTableSettingRef, |
|||
pageSearchSettingRef, |
|||
pageFormSettingRef, |
|||
saveLoading, |
|||
}; |
|||
}; |
|||
@ -0,0 +1,54 @@ |
|||
<template> |
|||
<a-select :size="formSizeConfig" v-bind="$attrs"> |
|||
<a-select-option v-for="item in data" :key="item.key" :value="item.key"> |
|||
{{ item.value }} |
|||
</a-select-option> |
|||
</a-select> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, ref, onMounted } from 'vue'; |
|||
import type { PropType } from 'vue'; |
|||
|
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
/** |
|||
* 数据库连接下拉列 |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'DatabaseSelect', |
|||
props: { |
|||
parameter: { |
|||
type: Function as PropType<Function>, |
|||
}, |
|||
}, |
|||
setup(props) { |
|||
const data = ref<Array<any>>([]); |
|||
const loadData = async () => { |
|||
const result = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: '/db/connection/list', |
|||
data: Object.assign( |
|||
{ |
|||
sortName: 'seq', |
|||
}, |
|||
props.parameter && props.parameter(), |
|||
), |
|||
}); |
|||
data.value = result.map((item: any) => { |
|||
return { |
|||
key: item.id + '', |
|||
value: item.connectionName, |
|||
}; |
|||
}); |
|||
}; |
|||
onMounted(loadData); |
|||
return { |
|||
data, |
|||
...useSizeSetting(), |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,210 @@ |
|||
<template> |
|||
<BasicModal |
|||
@register="registerModal" |
|||
width="920px" |
|||
v-bind="$attrs" |
|||
:title="$t('generator.views.codeCreateForm.title.choseAddendum')" |
|||
@ok="handleOk" |
|||
> |
|||
<SmartTable class="smart-table" @register="registerTable"> |
|||
<template #table-relatedColumn="{ row }"> |
|||
<a-input v-model:value="row.relatedColumn" :size="getFormSize" /> |
|||
</template> |
|||
</SmartTable> |
|||
</BasicModal> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { BasicModal, useModalInner } from '@/components/Modal'; |
|||
import { SmartColumn, SmartTable, useSmartTable } from '@/components/SmartTable'; |
|||
import { FormSchema } from '@/components/Form'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { propTypes } from '@/utils/propTypes'; |
|||
import { computed, PropType, toRefs, unref } from 'vue'; |
|||
import { message } from 'ant-design-vue'; |
|||
import { defHttp } from '@/utils/http/axios'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
|
|||
const props = defineProps({ |
|||
multiple: propTypes.bool.def(true), |
|||
selectTableList: { |
|||
type: Array as PropType<Array<any>>, |
|||
default: () => [], |
|||
}, |
|||
}); |
|||
|
|||
const emit = defineEmits(['ok', 'register']); |
|||
|
|||
const { selectTableList: selectTableListRef } = toRefs(props); |
|||
|
|||
const { t } = useI18n(); |
|||
|
|||
const { getFormSize } = useSizeSetting(); |
|||
|
|||
const columns = [ |
|||
{ |
|||
title: '{generator.views.code.table.connectionName}', |
|||
field: 'connectionName', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.configName}', |
|||
field: 'configName', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.tableName}', |
|||
field: 'tableName', |
|||
width: 160, |
|||
}, |
|||
{ |
|||
title: '{generator.views.addendumTable.title.relatedColumn}', |
|||
field: 'relatedColumn', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-relatedColumn', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.remarks}', |
|||
field: 'remarks', |
|||
minWidth: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.remark}', |
|||
field: 'remark', |
|||
minWidth: 200, |
|||
}, |
|||
]; |
|||
|
|||
const searchSchemeList: FormSchema[] = [ |
|||
{ |
|||
label: t('generator.views.code.table.configName'), |
|||
field: 'configName', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.table.tableName'), |
|||
field: 'tableName', |
|||
component: 'Input', |
|||
}, |
|||
]; |
|||
|
|||
const computedColumns = computed<Partial<SmartColumn>[]>(() => { |
|||
const firstColumn: SmartColumn = { |
|||
type: 'checkbox', |
|||
width: 60, |
|||
}; |
|||
if (!props.multiple) { |
|||
firstColumn.type = 'radio'; |
|||
} |
|||
return [firstColumn, ...columns]; |
|||
}); |
|||
|
|||
/** |
|||
* 确认操作 |
|||
*/ |
|||
const handleOk = () => { |
|||
const data: any[] = []; |
|||
if (props.multiple) { |
|||
data.push(...getCheckboxRecords(false)); |
|||
} else { |
|||
const row = getRadioRecord(false); |
|||
if (row) { |
|||
data.push(row); |
|||
} |
|||
} |
|||
const errorDataList = data.filter( |
|||
(item) => |
|||
item.relatedColumn === undefined || |
|||
item.relatedColumn == null || |
|||
item.relatedColumn.trim() === '', |
|||
); |
|||
if (errorDataList.length > 0) { |
|||
errorDataList.forEach((item) => { |
|||
message.error( |
|||
t('generator.views.addendumTable.validate.relatedColumnWithConfig', item.configName), |
|||
); |
|||
}); |
|||
return false; |
|||
} |
|||
const dealData = data.map((item) => { |
|||
return { |
|||
addendumId: item.id, |
|||
relatedColumn: item.relatedColumn, |
|||
configName: item.configName, |
|||
}; |
|||
}); |
|||
emit('ok', dealData); |
|||
// 关闭弹窗 |
|||
closeModal(); |
|||
}; |
|||
|
|||
const [registerModal, { closeModal }] = useModalInner(() => { |
|||
query(); |
|||
}); |
|||
const [ |
|||
registerTable, |
|||
{ getCheckboxRecords, getRadioRecord, query, setRadioRow, setCheckboxRow }, |
|||
] = useSmartTable({ |
|||
columns: unref(computedColumns), |
|||
pagerConfig: false, |
|||
useSearchForm: true, |
|||
searchFormConfig: { |
|||
schemas: searchSchemeList, |
|||
layout: 'inline', |
|||
actionColOptions: { |
|||
span: undefined, |
|||
}, |
|||
colon: true, |
|||
}, |
|||
proxyConfig: { |
|||
autoLoad: false, |
|||
ajax: { |
|||
query: (params) => |
|||
defHttp.post({ |
|||
url: 'db/code/main/list', |
|||
data: { |
|||
...params.ajaxParameter, |
|||
parameter: { |
|||
'type@=': '30', |
|||
}, |
|||
}, |
|||
}), |
|||
}, |
|||
afterLoad: (result) => { |
|||
const selectTableList = unref(selectTableListRef); |
|||
if (selectTableList.length > 0) { |
|||
const selectTableMap: Map<number, any> = new Map<number, any>(); |
|||
selectTableList.forEach((item) => { |
|||
selectTableMap.set(item.addendumId, item); |
|||
}); |
|||
// 选中的行 |
|||
const selectRowsList: Array<any> = []; |
|||
result.forEach((item) => { |
|||
if (selectTableMap.has(item.id)) { |
|||
selectRowsList.push(item); |
|||
item.relatedColumn = selectTableMap.get(item.id).relatedColumn; |
|||
} |
|||
}); |
|||
if (selectRowsList.length > 0) { |
|||
if (!props.multiple) { |
|||
setRadioRow(selectRowsList[0]); |
|||
} else { |
|||
setCheckboxRow(selectRowsList, true); |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
}, |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.smart-table { |
|||
:deep(.ant-form-item) { |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,222 @@ |
|||
<!-- |
|||
设置表单验证规则 |
|||
--> |
|||
<template> |
|||
<BasicModal |
|||
width="1000px" |
|||
v-bind="$attrs" |
|||
title="配置验证规则" |
|||
@ok="handleOk" |
|||
@register="registerModal" |
|||
class="form-rule-set-modal" |
|||
> |
|||
<SmartTable @register="registerTable" :data="ruleListRef" class="form-rule-set-table"> |
|||
<template #table-options="{ row }"> |
|||
<a-button size="small" @click="() => handleDeleteRow(row)">删除</a-button> |
|||
</template> |
|||
<template #table-tools> |
|||
<a-button size="small" :disabled="autoValidateRef" type="primary" @click="insertRow"> |
|||
添加一行 |
|||
</a-button> |
|||
</template> |
|||
<template #table-buttons> |
|||
<a-form-item label="是否自动校验"> |
|||
<a-switch v-model:checked="autoValidateRef" /> |
|||
</a-form-item> |
|||
<span style="margin-left: 10px">开启后,校验参数自动生成,配置的校验内容无效</span> |
|||
</template> |
|||
</SmartTable> |
|||
</BasicModal> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import type { SizeType } from 'vxe-table'; |
|||
|
|||
import { ref, unref } from 'vue'; |
|||
import { useModalInner, BasicModal } from '@/components/Modal'; |
|||
import { SmartTable, useSmartTable } from '@/components/SmartTable'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { errorMessage } from '@/utils/message/SystemNotice'; |
|||
|
|||
import { getRuleList } from '../PageSettingSupport'; |
|||
|
|||
const { t } = useI18n(); |
|||
|
|||
const sizeRef = ref('small'); |
|||
// 是否自动配置 |
|||
const autoValidateRef = ref(false); |
|||
|
|||
const currentDataRef = ref<any>({}); |
|||
const ruleListRef = ref<any[]>([]); |
|||
|
|||
const [registerModal, { closeModal }] = useModalInner((data) => { |
|||
currentDataRef.value = data; |
|||
autoValidateRef.value = data.autoValidate; |
|||
ruleListRef.value = data.ruleList || []; |
|||
}); |
|||
|
|||
const insertRow = async () => { |
|||
const vxeGrid = getTableInstance(); |
|||
const { row: newRow } = await vxeGrid.insertAt({}, -1); |
|||
await vxeGrid.setActiveCell(newRow, 'ruleType'); |
|||
}; |
|||
|
|||
const handleDeleteRow = (row) => { |
|||
getTableInstance().remove(row); |
|||
}; |
|||
|
|||
const handleOk = async () => { |
|||
const vxeTable = getTableInstance(); |
|||
const errMap = await vxeTable.fullValidate().catch((errMap) => errMap); |
|||
if (errMap) { |
|||
console.log(errMap); |
|||
errorMessage('校验不通过!'); |
|||
return false; |
|||
} |
|||
const autoValidate = unref(autoValidateRef); |
|||
if (autoValidate) { |
|||
unref(currentDataRef).autoValidate = true; |
|||
unref(currentDataRef).ruleList = []; |
|||
closeModal(); |
|||
return; |
|||
} |
|||
const { tableData } = vxeTable.getTableData(); |
|||
const validateMessage = validateData(tableData); |
|||
if (validateMessage) { |
|||
errorMessage(validateMessage); |
|||
} |
|||
unref(currentDataRef).autoValidate = false; |
|||
unref(currentDataRef).ruleList = tableData; |
|||
closeModal(); |
|||
}; |
|||
|
|||
const [registerTable, { getTableInstance }] = useSmartTable({ |
|||
border: true, |
|||
size: unref(sizeRef) as SizeType, |
|||
editConfig: { |
|||
trigger: 'click', |
|||
mode: 'row', |
|||
}, |
|||
editRules: { |
|||
message: [{ required: true, message: '请填写校验文案' }], |
|||
ruleTrigger: [{ required: true, message: '请选择触发时机' }], |
|||
ruleType: [{ required: true, message: '校验类型必须选择' }], |
|||
}, |
|||
toolbarConfig: { |
|||
slots: { |
|||
tools: 'table-tools', |
|||
buttons: 'table-buttons', |
|||
}, |
|||
}, |
|||
columns: [ |
|||
{ |
|||
title: '校验类型', |
|||
field: 'ruleType', |
|||
width: 140, |
|||
editRender: { |
|||
name: '$select', |
|||
options: getRuleList(t), |
|||
}, |
|||
}, |
|||
{ |
|||
title: '触发时机', |
|||
field: 'ruleTrigger', |
|||
width: 150, |
|||
editRender: { |
|||
name: '$select', |
|||
options: [ |
|||
{ |
|||
value: 'BLUR', |
|||
label: 'blur', |
|||
}, |
|||
{ |
|||
value: 'CHANGE', |
|||
label: 'change', |
|||
}, |
|||
], |
|||
props: { |
|||
multiple: true, |
|||
}, |
|||
}, |
|||
}, |
|||
{ |
|||
title: '长度', |
|||
field: 'len', |
|||
width: 120, |
|||
editRender: { |
|||
name: '$input', |
|||
props: { type: 'number' }, |
|||
}, |
|||
}, |
|||
{ |
|||
title: '最大程度', |
|||
field: 'max', |
|||
width: 120, |
|||
editRender: { |
|||
name: '$input', |
|||
props: { type: 'number' }, |
|||
}, |
|||
}, |
|||
{ |
|||
title: '最小长度', |
|||
field: 'min', |
|||
width: 120, |
|||
editRender: { |
|||
name: '$input', |
|||
props: { type: 'number' }, |
|||
}, |
|||
}, |
|||
{ |
|||
title: '校验文案', |
|||
field: 'message', |
|||
minWidth: 200, |
|||
editRender: { |
|||
name: '$input', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '正则表达式', |
|||
field: 'pattern', |
|||
width: 180, |
|||
editRender: { |
|||
name: '$input', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '操作', |
|||
field: 'options', |
|||
width: 120, |
|||
fixed: 'right', |
|||
slots: { |
|||
default: 'table-options', |
|||
}, |
|||
}, |
|||
], |
|||
}); |
|||
|
|||
/** |
|||
* 校验数据 |
|||
*/ |
|||
const validateData = (dataList: Array<any>) => { |
|||
// 验证类型是否重复 |
|||
const hasType: Array<string> = []; |
|||
for (const { ruleType, pattern } of dataList) { |
|||
if (hasType.includes(ruleType)) { |
|||
return '校验类型不可重复:' + ruleType; |
|||
} |
|||
hasType.push(ruleType); |
|||
if (ruleType === 'regexp' && (pattern == null || pattern.trim() === '')) { |
|||
return '正则类型必须设置正则表达式'; |
|||
} |
|||
} |
|||
return null; |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.form-rule-set-table { |
|||
:deep(.ant-form-item) { |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,362 @@ |
|||
<template> |
|||
<div class="full-height"> |
|||
<vxe-grid |
|||
v-bind="$attrs" |
|||
ref="tableRef" |
|||
:size="tableSizeConfig" |
|||
:columns="columns" |
|||
row-key |
|||
highlight-hover-row |
|||
stripe |
|||
:data="data" |
|||
align="center" |
|||
> |
|||
<template #table-drop="{ rowIndex }"> |
|||
<div class="table-drop" :data-id="rowIndex"> |
|||
<MenuOutlined /> |
|||
</div> |
|||
</template> |
|||
<template #table-title="{ row }"> |
|||
<a-input v-model:value="row.title" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-visible="{ row }"> |
|||
<a-checkbox v-model:checked="row.visible" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-hidden="{ row }"> |
|||
<a-checkbox v-model:checked="row.hidden" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-readonly="{ row }"> |
|||
<a-checkbox v-model:checked="row.readonly" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-useTableSearch="{ row }"> |
|||
<a-checkbox v-model:checked="row.useTableSearch" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-tableName="{ row }"> |
|||
<a-input |
|||
v-model:value="row.tableName" |
|||
:disabled="!row.useTableSearch" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-keyColumnName="{ row }"> |
|||
<a-input |
|||
v-model:value="row.keyColumnName" |
|||
:disabled="!row.useTableSearch" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-valueColumnName="{ row }"> |
|||
<a-input |
|||
v-model:value="row.valueColumnName" |
|||
:disabled="!row.useTableSearch" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-tableWhere="{ row }"> |
|||
<a-input v-model:value="row.tableWhere" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-controlType="{ row }"> |
|||
<a-select v-model:value="row.controlType" :size="formSizeConfig" style="width: 100px"> |
|||
<a-select-option v-for="item in controlList" :key="item.key" :value="item.key"> |
|||
{{ $t(item.value) }} |
|||
</a-select-option> |
|||
</a-select> |
|||
<a-tooltip v-if="row.controlType === 'SELECT_TABLE'" placement="top"> |
|||
<template #title> |
|||
<span>选择表格</span> |
|||
</template> |
|||
<PlusOutlined |
|||
:style="{ cursor: 'pointer', 'margin-left': '5px' }" |
|||
@click="() => handleShowChoseSelectTable(row)" |
|||
/> |
|||
</a-tooltip> |
|||
</template> |
|||
<template #table-rules="{ row }"> |
|||
<Icon |
|||
v-if="row.autoValidate === true || (row.ruleList && row.ruleList.length > 0)" |
|||
color="red" |
|||
icon="ant-design:info-circle-outlined" |
|||
/> |
|||
<a-button :size="tableButtonSizeConfig" @click="() => openRuleSetModal(true, row)"> |
|||
设置规则 |
|||
</a-button> |
|||
</template> |
|||
<template #table-visible-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerVisibleCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-hidden-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerHiddenCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-readonly-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerReadonlyCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-used-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerUseCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-used="{ row }"> |
|||
<a-checkbox v-model:checked="row.used" :disabled="!row.visible" :size="formSizeConfig" /> |
|||
</template> |
|||
</vxe-grid> |
|||
<!-- 下拉表格设置 --> |
|||
<PageAddendumTableChoseModal |
|||
@ok="handleChoseTable" |
|||
:select-table-list="currentRow.selectTableList === null ? [] : currentRow.selectTableList" |
|||
@register="registerSelectTableModal" |
|||
/> |
|||
<!-- 验证规则 --> |
|||
<FormRuleSetModal @register="registerFormRuleSetModal" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, ref, onMounted, watch, toRefs } from 'vue'; |
|||
import type { Ref, PropType } from 'vue'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
|
|||
import { MenuOutlined, PlusOutlined } from '@ant-design/icons-vue'; |
|||
|
|||
import FormRuleSetModal from './FormRuleSetModal.vue'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import PageAddendumTableChoseModal from '../PageAddendumTableChoseModal.vue'; |
|||
|
|||
import { useVxeTableSortable } from '@/components/SmartTable'; |
|||
import { |
|||
controlList, |
|||
getRuleList, |
|||
vueTableHeaderCheckboxSupport, |
|||
vueChoseSelectTableSupport, |
|||
} from '../PageSettingSupport'; |
|||
import Icon from '@/components/Icon/src/Icon.vue'; |
|||
|
|||
const copyField = [ |
|||
'columnName', |
|||
'remarks', |
|||
'nullable', |
|||
'javaProperty', |
|||
'extType', |
|||
'javaType', |
|||
'simpleJavaType', |
|||
]; |
|||
|
|||
/** |
|||
* 创建数据 |
|||
*/ |
|||
const createDataFromTableData = (tableData: Array<any>, editData: Ref | undefined) => { |
|||
if (editData && editData.value) { |
|||
return editData.value; |
|||
} |
|||
return tableData.map((item) => { |
|||
const data: any = {}; |
|||
copyField.forEach((field) => { |
|||
data[field] = item[field]; |
|||
}); |
|||
return Object.assign(data, { |
|||
title: data.remarks, |
|||
readonly: false, |
|||
visible: true, |
|||
hidden: false, |
|||
used: true, |
|||
controlType: 'INPUT', |
|||
rules: [], |
|||
useTableSearch: false, |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
export default defineComponent({ |
|||
name: 'PageFormSetting', |
|||
components: { |
|||
Icon, |
|||
MenuOutlined, |
|||
PlusOutlined, |
|||
FormRuleSetModal, |
|||
PageAddendumTableChoseModal, |
|||
}, |
|||
props: { |
|||
tableData: { |
|||
type: Array as PropType<Array<any>>, |
|||
default: () => [], |
|||
}, |
|||
editData: { |
|||
type: Array as PropType<Array<any>>, |
|||
}, |
|||
}, |
|||
setup(props) { |
|||
const sizeConfigHoops = useSizeSetting(); |
|||
const { t } = useI18n(); |
|||
const { tableData, editData } = toRefs(props); |
|||
const tableRef = ref(); |
|||
const data = ref<Array<any>>([]); |
|||
const currentRow = ref<any>({}); |
|||
|
|||
const [registerFormRuleSetModal, { openModal: openRuleSetModal }] = useModal(); |
|||
|
|||
watch(tableData, () => { |
|||
data.value = createDataFromTableData(tableData.value, editData); |
|||
}); |
|||
onMounted(() => { |
|||
data.value = createDataFromTableData(tableData.value, editData); |
|||
}); |
|||
const getData = () => { |
|||
return data.value; |
|||
}; |
|||
|
|||
const { checked } = vueTableHeaderCheckboxSupport(data, 'visible'); |
|||
return { |
|||
data, |
|||
getData, |
|||
tableRef, |
|||
currentRow, |
|||
...sizeConfigHoops, |
|||
openRuleSetModal, |
|||
registerFormRuleSetModal, |
|||
...vueChoseSelectTableSupport(currentRow), |
|||
...useVxeTableSortable(tableRef, '.table-drop', data), |
|||
ruleList: ref(getRuleList(t)), |
|||
controlList: ref(controlList), |
|||
headerVisibleCheckboxChecked: checked, |
|||
headerHiddenCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'hidden', false).checked, |
|||
headerReadonlyCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'readonly', false) |
|||
.checked, |
|||
headerUseCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'used', true).checked, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
columns: [ |
|||
{ |
|||
title: '#', |
|||
field: 'drop', |
|||
width: 80, |
|||
slots: { |
|||
default: 'table-drop', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableField.title.columnName}', |
|||
field: 'columnName', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.title}', |
|||
field: 'title', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
slots: { |
|||
default: 'table-title', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.controlType}', |
|||
field: 'controlType', |
|||
width: 150, |
|||
slots: { |
|||
default: 'table-controlType', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.readonly}', |
|||
field: 'readonly', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-readonly', |
|||
header: 'table-readonly-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.visible}', |
|||
field: 'visible', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-visible', |
|||
header: 'table-visible-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.hidden}', |
|||
field: 'hidden', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-hidden', |
|||
header: 'table-hidden-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.used}', |
|||
field: 'used', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-used', |
|||
header: 'table-used-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.useTableSearch}', |
|||
field: 'useTableSearch', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-useTableSearch', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.design.formSetting.title.tableName}', |
|||
field: 'tableName', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-tableName', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.keyColumnName}', |
|||
field: 'keyColumnName', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-keyColumnName', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.valueColumnName}', |
|||
field: 'valueColumnName', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-valueColumnName', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.tableWhere}', |
|||
field: 'tableWhere', |
|||
minWidth: 180, |
|||
slots: { |
|||
default: 'table-tableWhere', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.rules}', |
|||
field: 'rules', |
|||
width: 180, |
|||
slots: { |
|||
default: 'table-rules', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.remarks}', |
|||
field: 'remarks', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
], |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,380 @@ |
|||
<template> |
|||
<div class="full-height"> |
|||
<vxe-grid |
|||
ref="tableRef" |
|||
row-key |
|||
:size="tableSizeConfig" |
|||
:columns="columns" |
|||
:data="data" |
|||
align="center" |
|||
highlight-hover-row |
|||
stripe |
|||
v-bind="$attrs" |
|||
> |
|||
<template #table-drop="{ rowIndex }"> |
|||
<div class="table-drop" :data-id="rowIndex"> |
|||
<MenuOutlined /> |
|||
</div> |
|||
</template> |
|||
<template #table-title="{ row }"> |
|||
<a-input v-model:value="row.title" :disabled="!row.visible" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-visible="{ row }"> |
|||
<a-checkbox v-model:checked="row.visible" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-hidden="{ row }"> |
|||
<a-checkbox v-model:checked="row.hidden" :disabled="!row.visible" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-readonly="{ row }"> |
|||
<a-checkbox |
|||
v-model:checked="row.readonly" |
|||
:disabled="!row.visible" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-used="{ row }"> |
|||
<a-checkbox v-model:checked="row.used" :disabled="!row.visible" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-searchSymbol="{ row }"> |
|||
<a-select |
|||
v-model:value="row.searchSymbol" |
|||
:disabled="!row.visible" |
|||
:size="formSizeConfig" |
|||
style="width: 100px" |
|||
> |
|||
<a-select-option v-for="item in searchSymbolList" :key="item" :value="item"> |
|||
{{ item }} |
|||
</a-select-option> |
|||
</a-select> |
|||
</template> |
|||
<template #table-useTableSearch="{ row }"> |
|||
<a-checkbox |
|||
v-model:checked="row.useTableSearch" |
|||
:disabled="!row.visible" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-tableName="{ row }"> |
|||
<a-input |
|||
v-model:value="row.tableName" |
|||
:disabled="!(row.useTableSearch && row.visible)" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-keyColumnName="{ row }"> |
|||
<a-input |
|||
v-model:value="row.keyColumnName" |
|||
:disabled="!(row.useTableSearch && row.visible)" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-valueColumnName="{ row }"> |
|||
<a-input |
|||
v-model:value="row.valueColumnName" |
|||
:disabled="!(row.useTableSearch && row.visible)" |
|||
:size="formSizeConfig" |
|||
/> |
|||
</template> |
|||
<template #table-tableWhere="{ row }"> |
|||
<a-input v-model:value="row.tableWhere" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-controlType="{ row }"> |
|||
<a-select |
|||
v-model:value="row.controlType" |
|||
:disabled="!row.visible" |
|||
style="width: 100px" |
|||
:size="formSizeConfig" |
|||
> |
|||
<a-select-option v-for="item in controlList" :key="item.key" :value="item.key"> |
|||
{{ $t(item.value) }} |
|||
</a-select-option> |
|||
</a-select> |
|||
<a-tooltip v-if="row.controlType === 'selectTable'" placement="top"> |
|||
<template #title> |
|||
<span>选择表格</span> |
|||
</template> |
|||
<PlusOutlined |
|||
:style="{ cursor: 'pointer', 'margin-left': '5px' }" |
|||
@click="() => handleShowChoseSelectTable(row)" |
|||
/> |
|||
</a-tooltip> |
|||
</template> |
|||
<template #table-rules="{ row }"> |
|||
<a-select |
|||
v-model:value="row.rules" |
|||
:disabled="!row.visible" |
|||
mode="multiple" |
|||
:size="formSizeConfig" |
|||
style="width: 160px" |
|||
> |
|||
<a-select-option v-for="item in ruleList" :key="item.key" :value="item.key"> |
|||
{{ item.value }} |
|||
</a-select-option> |
|||
</a-select> |
|||
</template> |
|||
<template #table-visible-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerVisibleCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-hidden-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerHiddenCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-readonly-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerReadonlyCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-used-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerUseCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
</vxe-grid> |
|||
<PageAddendumTableChoseModal |
|||
@ok="handleChoseTable" |
|||
:select-table-list="currentRow.selectTableList == null ? [] : currentRow.selectTableList" |
|||
@register="registerSelectTableModal" |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, onMounted, ref, toRefs, watch } from 'vue'; |
|||
import type { Ref, PropType } from 'vue'; |
|||
|
|||
import { MenuOutlined, PlusOutlined } from '@ant-design/icons-vue'; |
|||
import PageAddendumTableChoseModal from '../PageAddendumTableChoseModal.vue'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { useVxeTableSortable } from '@/components/SmartTable'; |
|||
|
|||
import { |
|||
controlList, |
|||
getRuleList, |
|||
searchSymbolList, |
|||
vueTableHeaderCheckboxSupport, |
|||
vueChoseSelectTableSupport, |
|||
} from '../PageSettingSupport'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
|
|||
const copyField = [ |
|||
'columnName', |
|||
'remarks', |
|||
'nullable', |
|||
'javaProperty', |
|||
'extType', |
|||
'javaType', |
|||
'simpleJavaType', |
|||
]; |
|||
|
|||
/** |
|||
* 创建数据 |
|||
*/ |
|||
const createDataFromTableData = (tableData: Array<any>, editData: Ref | undefined) => { |
|||
if (editData && editData.value) { |
|||
return editData.value; |
|||
} |
|||
return tableData.map((item) => { |
|||
const data: any = {}; |
|||
copyField.forEach((field) => { |
|||
data[field] = item[field]; |
|||
}); |
|||
return Object.assign(data, { |
|||
title: data.remarks, |
|||
readonly: false, |
|||
visible: true, |
|||
hidden: false, |
|||
used: true, |
|||
controlType: 'INPUT', |
|||
searchSymbol: '=', |
|||
rules: [], |
|||
useTableSearch: false, |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 搜索配置页面 |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'PageSearchSetting', |
|||
components: { |
|||
MenuOutlined, |
|||
PlusOutlined, |
|||
PageAddendumTableChoseModal, |
|||
}, |
|||
props: { |
|||
tableData: { |
|||
type: Array as PropType<Array<any>>, |
|||
default: () => [], |
|||
}, |
|||
editData: { |
|||
type: Array as PropType<Array<any>>, |
|||
}, |
|||
}, |
|||
setup(props) { |
|||
const { t } = useI18n(); |
|||
const { tableData, editData } = toRefs(props); |
|||
const sizeConfigHoops = useSizeSetting(); |
|||
const tableRef = ref(); |
|||
const data = ref<Array<any>>([]); |
|||
const currentRow = ref<any>({}); |
|||
watch(tableData, () => { |
|||
data.value = createDataFromTableData(tableData.value, editData); |
|||
}); |
|||
onMounted(() => { |
|||
data.value = createDataFromTableData(tableData.value, editData); |
|||
}); |
|||
const getData = () => { |
|||
return data.value; |
|||
}; |
|||
return { |
|||
...sizeConfigHoops, |
|||
data, |
|||
getData, |
|||
tableRef, |
|||
currentRow, |
|||
...vueChoseSelectTableSupport(currentRow), |
|||
...useVxeTableSortable(tableRef, '.table-drop', data), |
|||
ruleList: ref(getRuleList(t)), |
|||
controlList: ref(controlList), |
|||
searchSymbolList: ref(searchSymbolList), |
|||
headerVisibleCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'visible').checked, |
|||
headerHiddenCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'hidden', false).checked, |
|||
headerReadonlyCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'readonly', false) |
|||
.checked, |
|||
headerUseCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'used', true).checked, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
columns: [ |
|||
{ |
|||
title: '#', |
|||
field: 'drop', |
|||
width: 80, |
|||
slots: { |
|||
default: 'table-drop', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableField.title.columnName}', |
|||
field: 'columnName', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.title}', |
|||
field: 'title', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
slots: { |
|||
default: 'table-title', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.controlType}', |
|||
field: 'controlType', |
|||
width: 150, |
|||
slots: { |
|||
default: 'table-controlType', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.readonly}', |
|||
field: 'readonly', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-readonly', |
|||
header: 'table-readonly-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.visible}', |
|||
field: 'visible', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-visible', |
|||
header: 'table-visible-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.hidden}', |
|||
field: 'hidden', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-hidden', |
|||
header: 'table-hidden-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.used}', |
|||
field: 'used', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-used', |
|||
header: 'table-used-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.searchSetting.title.searchSymbol}', |
|||
field: 'searchSymbol', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-searchSymbol', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.useTableSearch}', |
|||
field: 'useTableSearch', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-useTableSearch', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.tableName}', |
|||
field: 'tableName', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-tableName', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.keyColumnName}', |
|||
field: 'keyColumnName', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-keyColumnName', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.valueColumnName}', |
|||
field: 'valueColumnName', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-valueColumnName', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.formSetting.title.tableWhere}', |
|||
field: 'tableWhere', |
|||
minWidth: 180, |
|||
slots: { |
|||
default: 'table-tableWhere', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.remarks}', |
|||
field: 'remarks', |
|||
minWidth: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
], |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,174 @@ |
|||
import { ref, watch } from 'vue'; |
|||
import type { Ref } from 'vue'; |
|||
import { useModal } from '@/components/Modal'; |
|||
|
|||
/** |
|||
* 空间列表 |
|||
*/ |
|||
export const controlList = [ |
|||
{ |
|||
key: 'INPUT', |
|||
value: 'generator.views.code.title.controlList.input', |
|||
}, |
|||
{ |
|||
key: 'TEXTAREA', |
|||
value: 'generator.views.code.title.controlList.textarea', |
|||
}, |
|||
{ |
|||
key: 'NUMBER', |
|||
value: 'generator.views.code.title.controlList.number', |
|||
}, |
|||
{ |
|||
key: 'PASSWORD', |
|||
value: 'generator.views.code.title.controlList.password', |
|||
}, |
|||
{ |
|||
key: 'SELECT', |
|||
value: 'generator.views.code.title.controlList.select', |
|||
}, |
|||
{ |
|||
key: 'TRANSFER', |
|||
value: 'generator.views.code.title.controlList.transfer', |
|||
}, |
|||
{ |
|||
key: 'SELECT_TABLE', |
|||
value: 'generator.views.code.title.controlList.selectTable', |
|||
}, |
|||
{ |
|||
key: 'RADIO', |
|||
value: 'generator.views.code.title.controlList.radio', |
|||
}, |
|||
{ |
|||
key: 'CHECKBOX', |
|||
value: 'generator.views.code.title.controlList.checkbox', |
|||
}, |
|||
{ |
|||
key: 'SWITCH_TYPE', |
|||
value: 'generator.views.code.title.controlList.switch_type', |
|||
}, |
|||
{ |
|||
key: 'DATE', |
|||
value: 'generator.views.code.title.controlList.date', |
|||
}, |
|||
{ |
|||
key: 'TIME', |
|||
value: 'generator.views.code.title.controlList.time', |
|||
}, |
|||
{ |
|||
key: 'DATETIME', |
|||
value: 'generator.views.code.title.controlList.datetime', |
|||
}, |
|||
{ |
|||
key: 'FILE', |
|||
value: 'generator.views.code.title.controlList.file', |
|||
}, |
|||
{ |
|||
key: 'DATA_DICT', |
|||
value: 'generator.views.design.title.controlList.dataDict', |
|||
}, |
|||
{ |
|||
key: 'CATEGORY_DICT', |
|||
value: 'generator.views.design.title.controlList.categoryDict', |
|||
}, |
|||
]; |
|||
|
|||
/** |
|||
* rule列表 |
|||
*/ |
|||
const ruleList = [ |
|||
{ |
|||
value: 'NOT_EMPTY', |
|||
label: 'generator.views.code.title.ruleList.notEmpty', |
|||
}, |
|||
{ |
|||
value: 'PHONE', |
|||
label: 'generator.views.code.title.ruleList.PHONE', |
|||
}, |
|||
{ |
|||
value: 'EMAIL', |
|||
label: 'generator.views.code.title.ruleList.EMAIL', |
|||
}, |
|||
{ |
|||
value: 'NUMBER', |
|||
label: 'generator.views.code.title.ruleList.NUMBER', |
|||
}, |
|||
{ |
|||
value: 'REGEXP', |
|||
label: 'generator.views.code.title.ruleList.REGEXP', |
|||
}, |
|||
]; |
|||
|
|||
export const getRuleList = (t: Function): Recordable[] => { |
|||
return ruleList.map((item) => { |
|||
return { |
|||
...item, |
|||
label: t(item.label), |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 查询标识列表 |
|||
*/ |
|||
export const searchSymbolList = [ |
|||
'=', |
|||
'like', |
|||
'>', |
|||
'>=', |
|||
'<', |
|||
'<=', |
|||
'in', |
|||
'notIn', |
|||
'notLike', |
|||
'likeLeft', |
|||
'likeRight', |
|||
]; |
|||
|
|||
/** |
|||
* table header checkbox |
|||
* @param tableData |
|||
* @param field |
|||
* @param defaultValue |
|||
*/ |
|||
export const vueTableHeaderCheckboxSupport = ( |
|||
tableData: Ref, |
|||
field: string, |
|||
defaultValue = true, |
|||
) => { |
|||
const checked = ref(defaultValue); |
|||
watch(checked, () => { |
|||
tableData.value.forEach((item: any) => { |
|||
item[field] = checked.value; |
|||
}); |
|||
}); |
|||
return { |
|||
checked, |
|||
}; |
|||
}; |
|||
|
|||
/** |
|||
* 下拉表格支持 |
|||
*/ |
|||
export const vueChoseSelectTableSupport = (currentRow: Ref) => { |
|||
const [registerSelectTableModal, { openModal: openSelectTableModal }] = useModal(); |
|||
/** |
|||
* 显示列选择 |
|||
* @param row |
|||
*/ |
|||
const handleShowChoseSelectTable = (row: any) => { |
|||
currentRow.value = row; |
|||
openSelectTableModal(true, {}); |
|||
}; |
|||
/** |
|||
* 选择表格后 |
|||
* @param tableList |
|||
*/ |
|||
const handleChoseTable = (tableList: Array<any>) => { |
|||
currentRow.value.selectTableList = tableList; |
|||
}; |
|||
return { |
|||
registerSelectTableModal, |
|||
handleShowChoseSelectTable, |
|||
handleChoseTable, |
|||
}; |
|||
}; |
|||
@ -0,0 +1,331 @@ |
|||
<template> |
|||
<div class="full-height"> |
|||
<vxe-grid |
|||
v-bind="$attrs" |
|||
ref="tableRef" |
|||
:size="tableSizeConfig" |
|||
:data="data" |
|||
row-key |
|||
align="center" |
|||
highlight-hover-row |
|||
stripe |
|||
:columns="columns" |
|||
> |
|||
<template #table-sortable="{ row }"> |
|||
<a-checkbox v-model:checked="row.sortable" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-fixed="{ row }"> |
|||
<a-select v-model:value="row.fixed" :size="formSizeConfig" style="width: 100px"> |
|||
<a-select-option value="left">left</a-select-option> |
|||
<a-select-option value="right">right</a-select-option> |
|||
</a-select> |
|||
</template> |
|||
<template #table-resizable="{ row }"> |
|||
<a-checkbox v-model:checked="row.resizable" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-visible="{ row }"> |
|||
<a-checkbox v-model:checked="row.visible" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-hidden="{ row }"> |
|||
<a-checkbox v-model:checked="row.hidden" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-align="{ row }"> |
|||
<a-select v-model:value="row.align" :size="formSizeConfig" style="width: 100px"> |
|||
<a-select-option value="left">left</a-select-option> |
|||
<a-select-option value="center">center</a-select-option> |
|||
<a-select-option value="right">right</a-select-option> |
|||
</a-select> |
|||
</template> |
|||
<template #table-title="{ row }"> |
|||
<a-input v-model:value="row.title" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-width="{ row }"> |
|||
<a-input v-model:value="row.width" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-format="{ row }"> |
|||
<a-input v-model:value="row.format" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-drop="{ rowIndex }"> |
|||
<div class="table-drop" :data-id="rowIndex"> |
|||
<MenuOutlined /> |
|||
</div> |
|||
</template> |
|||
<template #table-visible-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerVisibleCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-sortable-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerSortableCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-resizable-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerResizableCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<template #table-hidden-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerHiddenCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
<!-- 是否可编辑 --> |
|||
<template #table-editable="{ row }"> |
|||
<a-checkbox v-model:checked="row.editable" :size="formSizeConfig" /> |
|||
</template> |
|||
<template #table-editable-header="{ column }"> |
|||
<a-checkbox v-model:checked="headerEditableCheckboxChecked" :size="formSizeConfig" /> |
|||
{{ $t(column.title.replace('{', '').replace('}', '')) }} |
|||
</template> |
|||
</vxe-grid> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, ref, watch, toRefs, onMounted, unref } from 'vue'; |
|||
import type { Ref, PropType } from 'vue'; |
|||
|
|||
import { MenuOutlined } from '@ant-design/icons-vue'; |
|||
|
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { useVxeTableSortable } from '@/components/SmartTable'; |
|||
import { vueTableHeaderCheckboxSupport } from '../PageSettingSupport'; |
|||
|
|||
/** |
|||
* copy列 |
|||
*/ |
|||
const copyField = [ |
|||
'columnName', |
|||
'javaProperty', |
|||
'javaType', |
|||
'typeName', |
|||
'columnSize', |
|||
'decimalDigits', |
|||
'columnDef', |
|||
'nullable', |
|||
'remarks', |
|||
'primaryKey', |
|||
'indexed', |
|||
'tableName', |
|||
'extType', |
|||
'simpleJavaType', |
|||
]; |
|||
|
|||
/** |
|||
* 创建数据 |
|||
*/ |
|||
const createDataFromTableData = ( |
|||
tableData: Array<any>, |
|||
editData: Ref<Array<any> | undefined>, |
|||
) => { |
|||
if (editData && editData.value) { |
|||
const tableDataMap: Record<string, any> = {}; |
|||
tableData.forEach((item) => { |
|||
tableDataMap[item.javaProperty] = item; |
|||
}); |
|||
return unref(editData)!.map((item) => { |
|||
const itemData = { |
|||
...item, |
|||
}; |
|||
const tableDataItem = tableDataMap[item.javaProperty]; |
|||
copyField.forEach((field) => { |
|||
itemData[field] = tableDataItem[field]; |
|||
}); |
|||
return itemData; |
|||
}); |
|||
} |
|||
return tableData.map((item) => { |
|||
const data: any = {}; |
|||
copyField.forEach((field) => { |
|||
data[field] = item[field]; |
|||
}); |
|||
// 获取align |
|||
let align = 'left'; |
|||
const typeName = item.typeName; |
|||
if (['DATETIME', 'DATE', 'TIME'].includes(typeName)) { |
|||
align = 'center'; |
|||
} |
|||
if (['INT', 'NUMBER', 'NUMERIC', 'LONG', 'BIGINT'].includes(typeName)) { |
|||
align = 'right'; |
|||
} |
|||
return Object.assign(data, { |
|||
title: data.remarks && data.remarks.trim() !== '' ? data.remarks : data.javaProperty, |
|||
sortable: false, |
|||
fixed: null, |
|||
width: 120, |
|||
align: align, |
|||
resizable: false, |
|||
visible: true, |
|||
hidden: false, |
|||
format: '', |
|||
// 是否可编辑 |
|||
editable: false, |
|||
}); |
|||
}); |
|||
}; |
|||
|
|||
/** |
|||
* 页面表格配置组件 |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'PageTableSetting', |
|||
components: { |
|||
MenuOutlined, |
|||
}, |
|||
props: { |
|||
tableData: { |
|||
type: Array as PropType<Array<any>>, |
|||
default: () => [], |
|||
}, |
|||
editData: { |
|||
type: Array as PropType<Array<any> | undefined>, |
|||
}, |
|||
}, |
|||
setup(props) { |
|||
const tableRef = ref(); |
|||
const { tableData, editData } = toRefs(props); |
|||
const data = ref<Array<any>>([]); |
|||
const tableSortableVue = useVxeTableSortable(tableRef, '.table-drop', data); |
|||
watch([tableData, editData], () => { |
|||
data.value = createDataFromTableData(tableData.value, editData); |
|||
console.log(data.value); |
|||
}); |
|||
onMounted(() => { |
|||
data.value = createDataFromTableData(tableData.value, editData); |
|||
}); |
|||
const getData = () => { |
|||
return data.value; |
|||
}; |
|||
const sizeConfigHoops = useSizeSetting(); |
|||
return { |
|||
...sizeConfigHoops, |
|||
...tableSortableVue, |
|||
data, |
|||
getData, |
|||
tableRef, |
|||
headerVisibleCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'visible').checked, |
|||
headerSortableCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'sortable', false) |
|||
.checked, |
|||
headerResizableCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'resizable', false) |
|||
.checked, |
|||
headerHiddenCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'hidden', false).checked, |
|||
headerEditableCheckboxChecked: vueTableHeaderCheckboxSupport(data, 'editable', false) |
|||
.checked, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
columns: [ |
|||
{ |
|||
title: '#', |
|||
field: 'drop', |
|||
width: 80, |
|||
slots: { |
|||
default: 'table-drop', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableField.title.columnName}', |
|||
field: 'columnName', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableField.title.remarks}', |
|||
field: 'remarks', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.title}', |
|||
field: 'title', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
slots: { |
|||
default: 'table-title', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.sortable}', |
|||
field: 'sortable', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-sortable', |
|||
header: 'table-sortable-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.fixed}', |
|||
field: 'fixed', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-fixed', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.width}', |
|||
field: 'width', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-width', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.align}', |
|||
field: 'align', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-align', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.resizable}', |
|||
field: 'resizable', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-resizable', |
|||
header: 'table-resizable-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.visible}', |
|||
field: 'visible', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-visible', |
|||
header: 'table-visible-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.hidden}', |
|||
field: 'hidden', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-hidden', |
|||
header: 'table-hidden-header', |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.tableSetting.title.editable}', |
|||
field: 'editable', |
|||
width: 110, |
|||
slots: { |
|||
default: 'table-editable', |
|||
header: 'table-editable-header', |
|||
}, |
|||
}, |
|||
// { |
|||
// title: '{generator.views.tableSetting.title.format}', |
|||
// field: 'format', |
|||
// width: 120, |
|||
// slots: { |
|||
// default: 'table-format' |
|||
// } |
|||
// } |
|||
], |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,107 @@ |
|||
<template> |
|||
<div> |
|||
<vxe-grid |
|||
align="center" |
|||
stripe |
|||
v-bind="$attrs" |
|||
:size="tableSizeConfig" |
|||
border |
|||
:columns="columns" |
|||
> |
|||
<template #table-nullable="{ row }"> |
|||
<a-switch :size="formSizeConfig" disabled :checked="row.nullable === 1" /> |
|||
</template> |
|||
<template #table-primaryKey="{ row }"> |
|||
<a-switch :size="formSizeConfig" disabled :checked="row.primaryKey" /> |
|||
</template> |
|||
<template #table-indexed="{ row }"> |
|||
<a-switch :size="formSizeConfig" disabled :checked="row.indexed" /> |
|||
</template> |
|||
</vxe-grid> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent } from 'vue'; |
|||
|
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
|
|||
/** |
|||
* 数据库字段信息 |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'TableFieldTable', |
|||
setup() { |
|||
const sizeConfigHoops = useSizeSetting(); |
|||
return { |
|||
...sizeConfigHoops, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
columns: [ |
|||
{ |
|||
field: 'columnName', |
|||
title: '{generator.views.tableField.title.columnName}', |
|||
width: 160, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
field: 'typeName', |
|||
title: '{generator.views.tableField.title.typeName}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'columnSize', |
|||
title: '{generator.views.tableField.title.columnSize}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'decimalDigits', |
|||
title: '{generator.views.tableField.title.decimalDigits}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'columnDef', |
|||
title: '{generator.views.tableField.title.columnDef}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'nullable', |
|||
title: '{generator.views.tableField.title.nullable}', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-nullable', |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'remarks', |
|||
title: '{generator.views.tableField.title.remarks}', |
|||
minWidth: 120, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
field: 'primaryKey', |
|||
title: '{generator.views.tableField.title.primaryKey}', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-primaryKey', |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'indexed', |
|||
title: '{generator.views.tableField.title.indexed}', |
|||
width: 120, |
|||
slots: { |
|||
default: 'table-indexed', |
|||
}, |
|||
}, |
|||
], |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,20 @@ |
|||
export default { |
|||
trans: true, |
|||
key: 'generator.views.design', |
|||
data: { |
|||
title: { |
|||
controlList: { |
|||
dataDict: 'Data dict', |
|||
categoryDict: 'Category dict', |
|||
}, |
|||
colNum: { |
|||
zero: 'inline', |
|||
}, |
|||
}, |
|||
formSetting: { |
|||
title: { |
|||
tableName: 'Model class', |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,20 @@ |
|||
export default { |
|||
trans: true, |
|||
key: 'generator.views.design', |
|||
data: { |
|||
title: { |
|||
controlList: { |
|||
dataDict: '数据字典', |
|||
categoryDict: '分类字典', |
|||
}, |
|||
colNum: { |
|||
zero: '单行', |
|||
}, |
|||
}, |
|||
formSetting: { |
|||
title: { |
|||
tableName: '实体类名', |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,16 @@ |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
enum Api { |
|||
listBySystem = 'db/code/main/listBySystem', |
|||
delete = 'db/code/main/batchDeleteById', |
|||
} |
|||
|
|||
export const listBySystemApi = (parameter) => |
|||
defHttp.post({ service: ApiServiceEnum.SMART_CODE, url: Api.listBySystem, data: parameter }); |
|||
|
|||
export const deleteApi = (data) => |
|||
defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: Api.delete, |
|||
data: data.map((item: any) => item.id), |
|||
}); |
|||
@ -0,0 +1,136 @@ |
|||
import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable'; |
|||
|
|||
const tableTypeList = [ |
|||
{ |
|||
label: 'generator.views.code.title.tableType.single', |
|||
value: '10', |
|||
color: 'green', |
|||
}, |
|||
{ |
|||
label: 'generator.views.code.title.tableType.main', |
|||
value: '20', |
|||
color: 'blue', |
|||
}, |
|||
{ |
|||
label: 'generator.views.code.title.tableType.addendum', |
|||
value: '30', |
|||
color: 'purple', |
|||
}, |
|||
]; |
|||
|
|||
export const tableColumns = (t: Function): SmartColumn[] => { |
|||
return [ |
|||
{ |
|||
type: 'checkbox', |
|||
width: 60, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.connectionName}', |
|||
field: 'connectionName', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.configName}', |
|||
field: 'configName', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.tableName}', |
|||
field: 'tableName', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.type}', |
|||
field: 'type', |
|||
width: 120, |
|||
slots: { |
|||
default: ({ row }) => { |
|||
const value = row.type; |
|||
if (value) { |
|||
const filterList = tableTypeList.filter((item) => item.value === value); |
|||
if (filterList.length > 0) { |
|||
const data = filterList[0]; |
|||
return <a-tag color={data.color}>{t(data.label)}</a-tag>; |
|||
} |
|||
} |
|||
return ''; |
|||
}, |
|||
}, |
|||
}, |
|||
{ |
|||
title: '{generator.views.code.table.remarks}', |
|||
field: 'remarks', |
|||
minWidth: 200, |
|||
}, |
|||
{ |
|||
title: '{common.table.remark}', |
|||
field: 'remark', |
|||
minWidth: 200, |
|||
}, |
|||
{ |
|||
title: '{common.table.createTime}', |
|||
field: 'createTime', |
|||
width: 165, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
title: '{common.table.createUser}', |
|||
field: 'createBy', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.updateTime}', |
|||
field: 'updateTime', |
|||
width: 165, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
title: '{common.table.updateUser}', |
|||
field: 'updateBy', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.operation}', |
|||
field: 'operation', |
|||
width: 140, |
|||
fixed: 'right', |
|||
slots: { |
|||
default: 'table-operation', |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
export const searchFormColumns = (t: Function): SmartSearchFormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'tableName', |
|||
label: '', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.code.table.tableName'), |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'type', |
|||
label: '', |
|||
component: 'Select', |
|||
componentProps: { |
|||
style: { |
|||
width: '100px', |
|||
}, |
|||
placeholder: t('generator.views.code.table.type'), |
|||
options: tableTypeList.map((item) => { |
|||
return { |
|||
...item, |
|||
label: t(item.label), |
|||
}; |
|||
}), |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
@ -0,0 +1,175 @@ |
|||
<template> |
|||
<div class="full-height page-container"> |
|||
<LayoutSeparate first-size="240px" :show-line="false" class="full-height"> |
|||
<template #first> |
|||
<div class="full-height system-container"> |
|||
<SystemSimpleList |
|||
@current-change="handleSelectSystemChange" |
|||
:row-config="{ isHover: true, isCurrent: true }" |
|||
height="auto" |
|||
/> |
|||
</div> |
|||
</template> |
|||
<template #second> |
|||
<SmartTable @register="registerTable" :size="getTableSize"> |
|||
<template #table-operation="{ row }"> |
|||
<SmartVxeTableAction :actions="getTableAction(row)" /> |
|||
</template> |
|||
</SmartTable> |
|||
</template> |
|||
</LayoutSeparate> |
|||
<CodeCreateModal @register="registerCodeCreateModal" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import type { ActionItem } from '@/components/SmartTable'; |
|||
|
|||
import { tableColumns, searchFormColumns } from './CodeListView.config'; |
|||
import { listBySystemApi, deleteApi } from './CodeListView.api'; |
|||
import { useRouter } from 'vue-router'; |
|||
import { buildUUID } from '@/utils/uuid'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
|
|||
import { SmartVxeTableAction, SmartTable, useSmartTable } from '@/components/SmartTable'; |
|||
import CodeCreateModal from './components/CodeCreateModal.vue'; |
|||
import { LayoutSeparate } from '@/components/LayoutSeparate'; |
|||
import SystemSimpleList from '@/modules/system/components/system/SystemSimpleList.vue'; |
|||
import { errorMessage } from '@/utils/message/SystemNotice'; |
|||
|
|||
const { t } = useI18n(); |
|||
const router = useRouter(); |
|||
const { getTableSize } = useSizeSetting(); |
|||
|
|||
const toDesign = (configId?: number) => { |
|||
if (!currentSystem?.id) { |
|||
errorMessage(t('generator.views.code.message.noSelectSystem')); |
|||
return false; |
|||
} |
|||
router.push({ |
|||
path: '/code/codeDesign', |
|||
query: { |
|||
setKey: buildUUID(), |
|||
configId, |
|||
systemId: currentSystem.id, |
|||
}, |
|||
}); |
|||
}; |
|||
|
|||
let currentSystem: Recordable = {}; |
|||
const handleSelectSystemChange = (row) => { |
|||
currentSystem = row; |
|||
reload(); |
|||
}; |
|||
|
|||
const getTableAction = (row): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('common.button.edit'), |
|||
onClick: () => toDesign(row.id), |
|||
}, |
|||
{ |
|||
label: t('generator.views.code.button.createCode'), |
|||
onClick: () => openCodeCreateModal(true, row), |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
// 生成代码弹窗 |
|||
const [registerCodeCreateModal, { openModal: openCodeCreateModal }] = useModal(); |
|||
|
|||
const [registerTable, { reload }] = useSmartTable({ |
|||
searchFormConfig: { |
|||
searchWithSymbol: true, |
|||
layout: 'inline', |
|||
schemas: searchFormColumns(t), |
|||
actionColOptions: { |
|||
span: undefined, |
|||
}, |
|||
baseRowStyle: { |
|||
width: '100%', |
|||
}, |
|||
labelAlign: 'left', |
|||
}, |
|||
height: 'auto', |
|||
columns: tableColumns(t), |
|||
useSearchForm: true, |
|||
pagerConfig: true, |
|||
sortConfig: { |
|||
remote: true, |
|||
}, |
|||
columnConfig: { |
|||
resizable: true, |
|||
}, |
|||
proxyConfig: { |
|||
autoLoad: false, |
|||
ajax: { |
|||
query: (params) => { |
|||
const queryParameter = { |
|||
...params.ajaxParameter, |
|||
systemId: currentSystem.id, |
|||
}; |
|||
return listBySystemApi(queryParameter); |
|||
}, |
|||
delete: ({ body }) => deleteApi(body.removeRecords), |
|||
}, |
|||
}, |
|||
toolbarConfig: { |
|||
refresh: true, |
|||
buttons: [ |
|||
{ |
|||
code: 'ModalAdd', |
|||
props: { |
|||
onClick: () => toDesign(), |
|||
}, |
|||
}, |
|||
{ |
|||
code: 'delete', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.system-container { |
|||
margin-right: 5px; |
|||
} |
|||
|
|||
.code-container { |
|||
::v-deep(.ant-modal-content) { |
|||
height: 100%; |
|||
} |
|||
|
|||
::v-deep(.ant-modal) { |
|||
max-width: 100%; |
|||
} |
|||
|
|||
::v-deep(.ant-form-item) { |
|||
margin-bottom: 0; |
|||
} |
|||
|
|||
::v-deep(.ant-list-item) { |
|||
padding: 8px 0; |
|||
} |
|||
|
|||
::v-deep(.ant-modal-body) { |
|||
padding: 10px; |
|||
} |
|||
|
|||
::v-deep(.ant-tabs-top-content) { |
|||
height: calc(100% - 65px); |
|||
} |
|||
|
|||
::v-deep(.ant-spin-nested-loading) { |
|||
height: 100%; |
|||
} |
|||
|
|||
::v-deep(.ant-spin-container) { |
|||
height: 100%; |
|||
overflow: auto; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,187 @@ |
|||
<template> |
|||
<a-form |
|||
ref="formRef" |
|||
class="create-code-form" |
|||
:model="formModel" |
|||
:rules="rules" |
|||
:wrapper-col="wrapperCol" |
|||
:label-col="labelCol" |
|||
> |
|||
<a-form-item :label="$t('generator.views.codeCreateForm.title.description')"> |
|||
<a-input v-model:value="formModel.description" /> |
|||
</a-form-item> |
|||
<a-form-item :label="$t('generator.views.codeCreateForm.title.tableName')"> |
|||
<a-input v-model:value="formModel.tableName" disabled /> |
|||
</a-form-item> |
|||
<a-form-item name="className" :label="$t('generator.views.codeCreateForm.title.className')"> |
|||
<a-input v-model:value="formModel.className" /> |
|||
</a-form-item> |
|||
<a-form-item name="packages" :label="$t('generator.views.codeCreateForm.title.packages')"> |
|||
<a-input v-model:value="formModel.packages" /> |
|||
</a-form-item> |
|||
<a-form-item :label="$t('generator.views.codeCreateForm.title.extPackages')"> |
|||
<a-input v-model:value="formModel.extPackages" /> |
|||
</a-form-item> |
|||
<a-form-item :label="$t('generator.views.codeCreateForm.title.controllerBasePath')"> |
|||
<a-input v-model:value="formModel.controllerBasePath" /> |
|||
</a-form-item> |
|||
<div> |
|||
<a-transfer |
|||
:target-keys="targetKeysModel" |
|||
:render="(item) => item.title" |
|||
:data-source="transDataSource" |
|||
show-search |
|||
@change="handleTransChange" |
|||
/> |
|||
</div> |
|||
</a-form> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, reactive, toRefs, watch, ref, onMounted, type PropType } from 'vue'; |
|||
import { useI18n } from 'vue-i18n'; |
|||
|
|||
import { message } from 'ant-design-vue'; |
|||
|
|||
import { TemplateType } from '@/modules/codeGenerator/constants/DatabaseConstants'; |
|||
|
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
const modelData = { |
|||
description: '', |
|||
packages: '', |
|||
tableName: '', |
|||
className: '', |
|||
controllerBasePath: '', |
|||
extPackages: '', |
|||
}; |
|||
|
|||
/** |
|||
* 代码生成form |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'CodeCreateForm', |
|||
props: { |
|||
codeData: { |
|||
type: Object as PropType<any>, |
|||
default: () => ({}) as any, |
|||
}, |
|||
}, |
|||
setup(props) { |
|||
const { t } = useI18n(); |
|||
const { codeData } = toRefs(props); |
|||
const formRef = ref(); |
|||
const formModel = reactive(modelData); |
|||
const transDataSource = ref([]); |
|||
const dataLoading = ref(false); |
|||
const targetKeysModel = ref<Array<string>>([]); |
|||
watch(codeData, () => { |
|||
formModel.description = codeData.value.remarks; |
|||
formModel.tableName = codeData.value.tableName; |
|||
formModel.className = codeData.value.className; |
|||
targetKeysModel.value = []; |
|||
}); |
|||
const loadTemplateData = async () => { |
|||
dataLoading.value = true; |
|||
try { |
|||
const result = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/list', |
|||
data: { |
|||
parameter: { |
|||
'templateType@=': TemplateType.TEMPLATE_CODE.value, |
|||
}, |
|||
}, |
|||
}); |
|||
transDataSource.value = result.map((item: any) => { |
|||
return { |
|||
key: item.templateId + '', |
|||
title: item.name, |
|||
}; |
|||
}); |
|||
} finally { |
|||
dataLoading.value = false; |
|||
} |
|||
}; |
|||
const handleTransChange = (targetKeys: Array<string>) => { |
|||
targetKeysModel.value = targetKeys; |
|||
}; |
|||
onMounted(loadTemplateData); |
|||
/** |
|||
* 获取form的值 |
|||
*/ |
|||
const getFormData = () => { |
|||
return { |
|||
mainId: codeData.value.id, |
|||
...formModel, |
|||
templateIdList: targetKeysModel.value, |
|||
}; |
|||
}; |
|||
/** |
|||
* 验证表单 |
|||
*/ |
|||
const validate = (): Promise<any> => { |
|||
return formRef.value.validate().then(() => { |
|||
if (targetKeysModel.value.length === 0) { |
|||
const errorMessage = t('generator.views.codeCreateForm.message.choseTemplate'); |
|||
message.error(errorMessage); |
|||
return Promise.reject(new Error(errorMessage)); |
|||
} |
|||
}); |
|||
}; |
|||
return { |
|||
formModel, |
|||
transDataSource, |
|||
dataLoading, |
|||
handleTransChange, |
|||
targetKeysModel, |
|||
getFormData, |
|||
formRef, |
|||
validate, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
labelCol: { |
|||
span: 6, |
|||
}, |
|||
wrapperCol: { |
|||
span: 17, |
|||
}, |
|||
rules: { |
|||
packages: [ |
|||
{ |
|||
required: true, |
|||
message: this.$t('generator.views.codeCreateForm.validate.packages'), |
|||
trigger: 'blur', |
|||
}, |
|||
], |
|||
className: [ |
|||
{ |
|||
required: true, |
|||
message: this.$t('generator.views.codeCreateForm.validate.className'), |
|||
trigger: 'blur', |
|||
}, |
|||
], |
|||
controllerBasePath: [ |
|||
{ |
|||
required: true, |
|||
message: this.$t('generator.views.codeCreateForm.validate.controllerBasePath'), |
|||
trigger: 'blur', |
|||
}, |
|||
], |
|||
}, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.create-code-form { |
|||
::v-deep(.ant-transfer-list) { |
|||
flex: none; |
|||
width: 46%; |
|||
height: 450px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,147 @@ |
|||
<template> |
|||
<BasicModal |
|||
@register="registerModal" |
|||
width="800px" |
|||
@ok="handleOk" |
|||
style="top: 15px" |
|||
:title="$t('generator.views.code.button.createCode')" |
|||
> |
|||
<BasicForm @register="registerForm"> |
|||
<template #form-templateIdList="{ model }"> |
|||
<SmartTableSelect |
|||
v-model:value="model.templateIdList" |
|||
:table-props="{}" |
|||
title="选择模板" |
|||
defaultFullscreen |
|||
multiple |
|||
:list-api="listByIdApi" |
|||
label-field="name" |
|||
value-field="templateId" |
|||
> |
|||
<template #table="{ addSelectData, removeSelectData, selectData }"> |
|||
<TemplateSelectTable |
|||
:add-select-data="addSelectData" |
|||
:remove-select-data="removeSelectData" |
|||
:select-data="selectData" |
|||
/> |
|||
</template> |
|||
</SmartTableSelect> |
|||
</template> |
|||
</BasicForm> |
|||
</BasicModal> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { useRouter } from 'vue-router'; |
|||
import { message } from 'ant-design-vue'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
import { BasicModal, useModalInner } from '@/components/Modal'; |
|||
import { BasicForm, useForm, SmartTableSelect } from '@/components/Form'; |
|||
import TemplateSelectTable from './TemplateSelectTable.vue'; |
|||
|
|||
const router = useRouter(); |
|||
const { t } = useI18n(); |
|||
|
|||
const handleOk = async () => { |
|||
const model = await validate(); |
|||
const templateIdList = model.templateIdList; |
|||
if (!templateIdList || templateIdList.length === 0) { |
|||
message.warn(t('generator.views.codeCreateForm.message.choseTemplate')); |
|||
} |
|||
const url = router.resolve({ |
|||
path: '/codeCreateView', |
|||
query: { |
|||
...model, |
|||
templateIdList: templateIdList.join(','), |
|||
}, |
|||
}); |
|||
window.open(url.href, '_blank'); |
|||
}; |
|||
|
|||
const [registerModal] = useModalInner((codeConfigData: Recordable) => { |
|||
const { remarks, tableName, className, id } = codeConfigData; |
|||
setFieldsValue({ |
|||
description: remarks, |
|||
tableName, |
|||
className, |
|||
mainId: id, |
|||
}); |
|||
}); |
|||
|
|||
const listByIdApi = (ids) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/listById', |
|||
data: ids, |
|||
}); |
|||
}; |
|||
|
|||
const [registerForm, { setFieldsValue, validate }] = useForm({ |
|||
labelCol: { |
|||
span: 6, |
|||
}, |
|||
wrapperCol: { |
|||
span: 17, |
|||
}, |
|||
baseColProps: { |
|||
span: 24, |
|||
}, |
|||
showActionButtonGroup: false, |
|||
schemas: [ |
|||
{ |
|||
label: '', |
|||
field: 'mainId', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: t('generator.views.codeCreateForm.title.description'), |
|||
field: 'description', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: t('generator.views.codeCreateForm.title.tableName'), |
|||
field: 'tableName', |
|||
component: 'Input', |
|||
componentProps: { |
|||
disabled: true, |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.codeCreateForm.title.className'), |
|||
field: 'className', |
|||
component: 'Input', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.codeCreateForm.title.packages'), |
|||
field: 'packages', |
|||
component: 'Input', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.codeCreateForm.title.controllerBasePath'), |
|||
field: 'controllerBasePath', |
|||
component: 'Input', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.codeCreateForm.title.customConfig'), |
|||
field: 'customConfig', |
|||
component: 'InputTextArea', |
|||
componentProps: { |
|||
placeholder: t('generator.views.codeCreateForm.message.customConfig'), |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.codeCreateForm.title.templateList'), |
|||
field: 'templateIdList', |
|||
slot: 'form-templateIdList', |
|||
}, |
|||
], |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,9 @@ |
|||
<template> |
|||
<BasicModal /> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import BasicModal from '@/components/Modal/src/BasicModal.vue'; |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,150 @@ |
|||
<template> |
|||
<LayoutSeparate first-size="200px" :show-line="false" class="full-height"> |
|||
<template #first> |
|||
<TemplateGroup class="full-height" @current-change="handleCurrentChange" /> |
|||
</template> |
|||
<template #second> |
|||
<SmartTable |
|||
@register="registerTable" |
|||
@checkbox-change="handleCheckboxChange" |
|||
@proxy-query="resetCheckbox" |
|||
/> |
|||
</template> |
|||
</LayoutSeparate> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
import { merge } from 'lodash-es'; |
|||
|
|||
import { SmartTable, useSmartTable } from '@/components/SmartTable'; |
|||
import { LayoutSeparate } from '@/components/LayoutSeparate'; |
|||
import { TemplateType as templateTypeConstants } from '@/modules/codeGenerator/constants/DatabaseConstants'; |
|||
import TemplateGroup from '@/modules/codeGenerator/components/template/TemplateGroup.vue'; |
|||
import { watch } from 'vue'; |
|||
|
|||
const props = defineProps({ |
|||
addSelectData: { |
|||
type: Function as PropType<Function>, |
|||
required: true, |
|||
}, |
|||
removeSelectData: { |
|||
type: Function as PropType<Function>, |
|||
required: true, |
|||
}, |
|||
selectData: Array, |
|||
}); |
|||
const { t } = useI18n(); |
|||
|
|||
let currentGroup: Recordable = {}; |
|||
|
|||
const handleCurrentChange = (row) => { |
|||
currentGroup = row || {}; |
|||
query(); |
|||
}; |
|||
|
|||
const handleCheckboxChange = ({ checked, row }) => { |
|||
if (checked) { |
|||
props.addSelectData([row]); |
|||
} else { |
|||
props.removeSelectData([row]); |
|||
} |
|||
}; |
|||
|
|||
const resetCheckbox = async () => { |
|||
// 数据重新加载后,设置选中的数据 |
|||
await getTableInstance().setAllCheckboxRow(false); |
|||
await setCheckboxRow(props.selectData, true); |
|||
}; |
|||
|
|||
watch( |
|||
() => props.selectData, |
|||
() => { |
|||
resetCheckbox(); |
|||
}, |
|||
); |
|||
|
|||
const [registerTable, { query, getTableInstance, setCheckboxRow }] = useSmartTable({ |
|||
useSearchForm: true, |
|||
height: 'auto', |
|||
pagerConfig: true, |
|||
rowConfig: { |
|||
keyField: 'templateId', |
|||
}, |
|||
proxyConfig: { |
|||
ajax: { |
|||
query: (params) => { |
|||
const parameter = merge(params.ajaxParameter, { |
|||
parameter: { |
|||
'groupId@=': currentGroup.groupId, |
|||
}, |
|||
}); |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/list', |
|||
data: parameter, |
|||
}); |
|||
}, |
|||
}, |
|||
}, |
|||
searchFormConfig: { |
|||
colon: true, |
|||
layout: 'inline', |
|||
baseColProps: { |
|||
span: 12, |
|||
}, |
|||
actionColOptions: { |
|||
span: 12, |
|||
}, |
|||
schemas: [ |
|||
{ |
|||
label: t('generator.views.template.table.name'), |
|||
field: 'name', |
|||
component: 'Input', |
|||
}, |
|||
], |
|||
}, |
|||
columns: [ |
|||
{ |
|||
type: 'checkbox', |
|||
width: 60, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'name', |
|||
title: '{generator.views.template.table.name}', |
|||
width: 200, |
|||
fixed: 'left', |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
field: 'templateType', |
|||
title: '{generator.views.template.table.templateType}', |
|||
width: 140, |
|||
formatter: ({ row }: any) => { |
|||
const templateType = templateTypeConstants[row.templateType]; |
|||
if (templateType) { |
|||
return t(templateType.label); |
|||
} |
|||
return ''; |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'language', |
|||
title: '{generator.views.template.table.language}', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
field: 'remark', |
|||
title: '{generator.views.template.table.remark}', |
|||
minWidth: 200, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
], |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,55 @@ |
|||
import { computed, ref } from 'vue'; |
|||
import { isEmpty } from '@/utils/is'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
export const useLoadDbData = ({ validateAddEdit }) => { |
|||
// 数据库数据加载状态
|
|||
const dbDataLoading = ref(false); |
|||
const dbData = ref<Recordable>({}); |
|||
|
|||
/** |
|||
* 加载数据库数据 |
|||
*/ |
|||
const loadDbData = async () => { |
|||
const { connectionId, tableName } = await validateAddEdit(); |
|||
if (!isEmpty(connectionId) && !isEmpty(tableName)) { |
|||
dbDataLoading.value = true; |
|||
try { |
|||
dbData.value = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/connection/queryDbTable', |
|||
data: { |
|||
dbConnectionId: connectionId, |
|||
tableName: tableName, |
|||
}, |
|||
}); |
|||
} finally { |
|||
dbDataLoading.value = false; |
|||
} |
|||
} |
|||
}; |
|||
/** |
|||
* 表格table计算属性 |
|||
*/ |
|||
const computedTableData = computed(() => { |
|||
if (!dbData.value.tableName) { |
|||
return []; |
|||
} |
|||
const primaryKeyList = dbData.value.primaryKeyList || []; |
|||
const baseColumnList = dbData.value.baseColumnList || []; |
|||
return [...primaryKeyList, ...baseColumnList]; |
|||
}); |
|||
/** |
|||
* 同步表 |
|||
*/ |
|||
const handleSyncTableData = () => { |
|||
loadDbData(); |
|||
}; |
|||
return { |
|||
dbData, |
|||
dbDataLoading, |
|||
computedTableData, |
|||
handleSyncTableData, |
|||
loadDbData, |
|||
}; |
|||
}; |
|||
@ -0,0 +1,166 @@ |
|||
export default { |
|||
generator: { |
|||
views: { |
|||
code: { |
|||
table: { |
|||
connectionName: 'Connection name', |
|||
configName: 'Config name', |
|||
tableName: 'Table name', |
|||
type: 'Type', |
|||
remarks: 'Table remark', |
|||
}, |
|||
title: { |
|||
dbMessage: 'DB information', |
|||
tableSetting: 'Table setting', |
|||
formSetting: 'Form setting', |
|||
searchSetting: 'Search setting', |
|||
design: 'Design', |
|||
showCheckBox: 'Show check box', |
|||
isPage: 'Pagination', |
|||
invented: 'Virtual scrolling', |
|||
columnSort: 'Order adjustable', |
|||
leftButton: 'Left button', |
|||
rightButton: 'Right button', |
|||
rowButtonType: { |
|||
title: 'Row button type', |
|||
none: 'none', |
|||
single: 'unified', |
|||
more: 'more', |
|||
text: 'text', |
|||
}, |
|||
rowButtonList: 'Row button', |
|||
formColNum: 'Form col num', |
|||
searchColNum: 'Search col num', |
|||
relateTable: 'Relate addendum', |
|||
tableType: { |
|||
single: 'single', |
|||
main: 'main', |
|||
addendum: 'addendum', |
|||
}, |
|||
colNum: { |
|||
one: 'One column', |
|||
two: 'Two column', |
|||
three: 'Three column', |
|||
four: 'Four column', |
|||
}, |
|||
controlList: { |
|||
input: 'INPUT', |
|||
textarea: 'TEXTAREA', |
|||
number: 'NUMBER', |
|||
password: 'PASSWORD', |
|||
select: 'SELECT', |
|||
transfer: 'TRANSFER', |
|||
selectTable: 'SELECT_TABLE', |
|||
radio: 'RADIO', |
|||
checkbox: 'CHECKBOX', |
|||
switch_type: 'SWITCH', |
|||
date: 'DATE', |
|||
time: 'TIME', |
|||
datetime: 'DATETIME', |
|||
file: 'FILE', |
|||
}, |
|||
ruleList: { |
|||
notEmpty: 'NOT_EMPTY', |
|||
PHONE: 'PHONE', |
|||
EMAIL: 'EMAIL', |
|||
NUMBER: 'NUMBER', |
|||
REGEXP: 'REGEXP', |
|||
}, |
|||
i18nPrefix: 'I18n prefix', |
|||
}, |
|||
button: { |
|||
createCode: 'Generate code', |
|||
syncTableData: 'Sync table information', |
|||
}, |
|||
validate: { |
|||
connectionName: 'Please select a database connection', |
|||
tableName: 'Please enter a table name', |
|||
configName: 'Please enter the configuration name', |
|||
syncTable: 'Please synchronize table information first', |
|||
tableSetting: 'Please configure the table', |
|||
formSetting: 'Please configure the form', |
|||
searchSetting: 'Please configure the search', |
|||
i18nPrefix: 'Please enter the i18n prefix', |
|||
}, |
|||
message: { |
|||
saveConfirmContent: 'Non empty field: [{0}] has no form set', |
|||
noSelectSystem: 'Please select system', |
|||
}, |
|||
}, |
|||
codeCreateForm: { |
|||
title: { |
|||
description: 'Function description', |
|||
tableName: 'Table name', |
|||
className: 'Model class name', |
|||
packages: 'packages', |
|||
extPackages: 'ext packages', |
|||
controllerBasePath: 'controller path', |
|||
choseAddendum: 'Select addendum', |
|||
customConfig: 'Custom config', |
|||
}, |
|||
message: { |
|||
choseTemplate: 'Please select a template', |
|||
customConfig: 'Please enter json', |
|||
}, |
|||
validate: { |
|||
packages: 'Please enter package', |
|||
className: 'Please enter model class name', |
|||
controllerBasePath: 'Path cannot be empty', |
|||
}, |
|||
}, |
|||
tableField: { |
|||
title: { |
|||
columnName: 'Column name', |
|||
typeName: 'Column type', |
|||
columnSize: 'Column size', |
|||
decimalDigits: 'Decimal digits', |
|||
columnDef: 'Default value', |
|||
nullable: 'Nullable', |
|||
remarks: 'Table remark', |
|||
primaryKey: 'Primary key', |
|||
indexed: 'Indexed', |
|||
}, |
|||
}, |
|||
tableSetting: { |
|||
title: { |
|||
title: 'Title', |
|||
sortable: 'Sortable', |
|||
fixed: 'Fixed', |
|||
width: 'Width', |
|||
align: 'Align', |
|||
resizable: 'Resizable', |
|||
visible: 'Render', |
|||
hidden: 'Hidden', |
|||
editable: 'Editable', |
|||
format: 'Format', |
|||
}, |
|||
}, |
|||
formSetting: { |
|||
title: { |
|||
controlType: 'Control type', |
|||
readonly: 'Readonly', |
|||
used: 'Transfer background', |
|||
useTableSearch: 'Query DB', |
|||
keyColumnName: 'Key column', |
|||
valueColumnName: 'Value column', |
|||
tableWhere: 'Query criteria/Dict code', |
|||
rules: 'Rules', |
|||
}, |
|||
}, |
|||
searchSetting: { |
|||
title: { |
|||
searchSymbol: 'Search identity', |
|||
}, |
|||
}, |
|||
addendumTable: { |
|||
title: { |
|||
relatedColumn: 'Associated field', |
|||
}, |
|||
validate: { |
|||
relatedColumn: 'Please select an associated field', |
|||
relatedColumnWithConfig: 'Please set the associated field, configuration: {0}', |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,167 @@ |
|||
export default { |
|||
generator: { |
|||
views: { |
|||
code: { |
|||
table: { |
|||
connectionName: '连接名称', |
|||
configName: '配置名称', |
|||
tableName: '表名', |
|||
type: '类型', |
|||
remarks: '表备注', |
|||
}, |
|||
title: { |
|||
dbMessage: '数据库信息', |
|||
tableSetting: '表格配置', |
|||
formSetting: '表单配置', |
|||
searchSetting: '查询配置', |
|||
design: '设计', |
|||
showCheckBox: '显示复选框', |
|||
isPage: '是否分页', |
|||
invented: '虚拟滚动', |
|||
columnSort: '列顺序可调', |
|||
leftButton: '左侧按钮', |
|||
rightButton: '右侧按钮', |
|||
rowButtonType: { |
|||
title: '行按钮类型', |
|||
none: '无', |
|||
single: '统一', |
|||
more: '多个', |
|||
text: '文本', |
|||
}, |
|||
rowButtonList: '行操作按钮', |
|||
formColNum: '表单列数', |
|||
searchColNum: '搜索列数', |
|||
relateTable: '关联附表', |
|||
tableType: { |
|||
single: '单表', |
|||
main: '主表', |
|||
addendum: '附表', |
|||
}, |
|||
colNum: { |
|||
one: '一列', |
|||
two: '两列', |
|||
three: '三列', |
|||
four: '四列', |
|||
}, |
|||
controlList: { |
|||
input: '文本框', |
|||
textarea: '文本域', |
|||
number: '数字', |
|||
password: '密码', |
|||
select: '下拉框', |
|||
transfer: '穿梭框', |
|||
selectTable: '下拉表格', |
|||
radio: '单选框', |
|||
checkbox: '多选框', |
|||
switch_type: '开关', |
|||
date: '日期', |
|||
time: '时间', |
|||
datetime: '日期时间', |
|||
file: '文件', |
|||
}, |
|||
ruleList: { |
|||
notEmpty: '非空', |
|||
PHONE: '手机号码', |
|||
EMAIL: '邮箱', |
|||
NUMBER: '数字', |
|||
REGEXP: '正则', |
|||
}, |
|||
i18nPrefix: '国际化前缀', |
|||
}, |
|||
button: { |
|||
createCode: '生成代码', |
|||
syncTableData: '同步表信息', |
|||
}, |
|||
validate: { |
|||
connectionName: '请选择数据库连接', |
|||
tableName: '请输入表名', |
|||
configName: '请输入配置名', |
|||
syncTable: '请先同步表信息', |
|||
tableSetting: '请进行表格配置', |
|||
formSetting: '请进行表单配置', |
|||
searchSetting: '请进行搜索配置', |
|||
i18nPrefix: '请输入国际化前缀', |
|||
}, |
|||
message: { |
|||
saveConfirmContent: '非空字段:【{0}】未设置form', |
|||
noSelectSystem: '请选择系统', |
|||
}, |
|||
}, |
|||
codeCreateForm: { |
|||
title: { |
|||
description: '功能描述', |
|||
tableName: '表名', |
|||
className: '实体类名', |
|||
packages: '包名', |
|||
extPackages: 'ext包名', |
|||
controllerBasePath: 'controller路径', |
|||
choseAddendum: '选择附表', |
|||
customConfig: '自定义配置', |
|||
templateList: '模板', |
|||
}, |
|||
message: { |
|||
choseTemplate: '请选择模板', |
|||
customConfig: '请输入json', |
|||
}, |
|||
validate: { |
|||
packages: '请输入包名', |
|||
className: '请输入实体类名', |
|||
controllerBasePath: '路径不能为空', |
|||
}, |
|||
}, |
|||
tableField: { |
|||
title: { |
|||
columnName: '字段名称', |
|||
typeName: '字段类型', |
|||
columnSize: '字段长度', |
|||
decimalDigits: '小数位数', |
|||
columnDef: '默认值', |
|||
nullable: '允许空值', |
|||
remarks: '表备注', |
|||
primaryKey: '主键', |
|||
indexed: '索引', |
|||
}, |
|||
}, |
|||
tableSetting: { |
|||
title: { |
|||
title: '标题', |
|||
sortable: '是否排序', |
|||
fixed: '列冻结', |
|||
width: '宽度', |
|||
align: '对齐方式', |
|||
resizable: '支持拖动', |
|||
visible: '是否渲染', |
|||
hidden: '是否隐藏', |
|||
editable: '是否可编辑', |
|||
format: '格式化', |
|||
}, |
|||
}, |
|||
formSetting: { |
|||
title: { |
|||
controlType: '控件类型', |
|||
readonly: '是否只读', |
|||
used: '是否传送后台', |
|||
useTableSearch: '查询数据库', |
|||
keyColumnName: 'key字段', |
|||
valueColumnName: 'value字段', |
|||
tableWhere: '查询条件/字典code', |
|||
rules: '验证规则', |
|||
}, |
|||
}, |
|||
searchSetting: { |
|||
title: { |
|||
searchSymbol: '搜索标识', |
|||
}, |
|||
}, |
|||
addendumTable: { |
|||
title: { |
|||
relatedColumn: '关联字段', |
|||
}, |
|||
validate: { |
|||
relatedColumn: '请选择关联字段', |
|||
relatedColumnWithConfig: '请设置关联字段,配置:{0}', |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,19 @@ |
|||
import { testConnectedApi } from './DatabaseListView.api'; |
|||
import { message, Modal } from 'ant-design-vue'; |
|||
|
|||
export const handleTestConnected = async (row, t: Function, setLoading) => { |
|||
try { |
|||
setLoading(true); |
|||
const result = await testConnectedApi(row.id); |
|||
if (result.result === true) { |
|||
message.success(t('generator.views.database.message.connectSuccess')); |
|||
} else { |
|||
Modal.error({ |
|||
title: t('generator.views.database.message.connectFail'), |
|||
content: result.message, |
|||
}); |
|||
} |
|||
} finally { |
|||
setLoading(false); |
|||
} |
|||
}; |
|||
@ -0,0 +1,70 @@ |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
enum api { |
|||
saveUpdate = 'db/connection/saveUpdate', |
|||
getById = 'db/connection/getById', |
|||
listBySystem = 'db/connection/listBySystem', |
|||
batchDeleteById = 'db/connection/batchDeleteById', |
|||
testConnected = 'db/connection/testConnection', |
|||
listTemplate = 'db/code/template/list', |
|||
createDict = '/public/db/createDic', |
|||
} |
|||
|
|||
export const saveUpdateApi = (data: any) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: api.saveUpdate, |
|||
data, |
|||
}); |
|||
}; |
|||
|
|||
export const getByIdApi = (id: number) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: api.getById, |
|||
data: id, |
|||
}); |
|||
}; |
|||
|
|||
export const listApi = (data?: any) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: api.listBySystem, |
|||
data, |
|||
}); |
|||
}; |
|||
|
|||
export const deleteApi = async (rows: any[]) => { |
|||
if (rows.length === 0) { |
|||
return; |
|||
} |
|||
await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: api.batchDeleteById, |
|||
data: rows.map((item: any) => item.id), |
|||
}); |
|||
}; |
|||
|
|||
export const testConnectedApi = (id: number) => |
|||
defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: api.testConnected, |
|||
data: id, |
|||
}); |
|||
|
|||
export const listTemplate = (templateType?: string) => |
|||
defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: api.listTemplate, |
|||
data: { |
|||
parameter: { |
|||
'templateType@=': templateType, |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
export const getCreateDicUrl = ({ row, templateId, tempToken }) => { |
|||
return `${defHttp.getApiUrlByService( |
|||
ApiServiceEnum.SMART_CODE, |
|||
)}/public/db/createDic?connectionId=${row.id}&templateId=${templateId}&access-token=${tempToken}`;
|
|||
}; |
|||
@ -0,0 +1,203 @@ |
|||
import type { FormSchema } from '@/components/Form'; |
|||
import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable'; |
|||
|
|||
const dbTypeList = ['MYSQL', 'SQL_SERVER', 'ORACLE']; |
|||
|
|||
export const tableColumns: SmartColumn[] = [ |
|||
{ |
|||
type: 'checkbox', |
|||
width: 60, |
|||
align: 'center', |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '{generator.views.database.table.connectionName}', |
|||
field: 'connectionName', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '{generator.views.database.table.databaseName}', |
|||
field: 'databaseName', |
|||
width: 160, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
title: '{generator.views.database.table.type}', |
|||
field: 'type', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{generator.views.database.table.url}', |
|||
field: 'url', |
|||
minWidth: 200, |
|||
showOverflow: 'tooltip', |
|||
}, |
|||
{ |
|||
title: '{generator.views.database.table.username}', |
|||
field: 'username', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{generator.views.database.table.tableSchema}', |
|||
field: 'tableSchema', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.createTime}', |
|||
field: 'createTime', |
|||
width: 165, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
title: '{common.table.createUser}', |
|||
field: 'createBy', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.updateTime}', |
|||
field: 'updateTime', |
|||
width: 165, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
title: '{common.table.updateUser}', |
|||
field: 'updateBy', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.operation}', |
|||
field: 'operation', |
|||
width: 120, |
|||
fixed: 'right', |
|||
slots: { |
|||
default: 'table-operation', |
|||
}, |
|||
}, |
|||
]; |
|||
|
|||
export const addEditForm: (t: Function) => Array<FormSchema> = (t: Function) => { |
|||
return [ |
|||
{ |
|||
field: 'id', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
field: 'systemId', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.table.connectionName'), |
|||
field: 'connectionName', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.validate.connectionName'), |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.table.databaseName'), |
|||
field: 'databaseName', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.validate.databaseName'), |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.table.type'), |
|||
field: 'type', |
|||
component: 'Select', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.validate.type'), |
|||
options: dbTypeList.map((item) => { |
|||
return { |
|||
label: item, |
|||
value: item, |
|||
}; |
|||
}), |
|||
}, |
|||
rules: [ |
|||
{ |
|||
message: t('generator.views.database.validate.type'), |
|||
required: true, |
|||
trigger: 'change', |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.table.url'), |
|||
field: 'url', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.validate.url'), |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.table.username'), |
|||
field: 'username', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.validate.username'), |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.table.password'), |
|||
field: 'password', |
|||
component: 'InputPassword', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.validate.password'), |
|||
}, |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.table.tableSchema'), |
|||
field: 'tableSchema', |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
}, |
|||
] as FormSchema[]; |
|||
}; |
|||
|
|||
/** |
|||
* 搜索表单配置 |
|||
* @param t |
|||
*/ |
|||
export const searchForm: (t: Function) => SmartSearchFormSchema[] = (t: Function) => { |
|||
return [ |
|||
{ |
|||
field: 'connectionName', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.table.connectionName'), |
|||
}, |
|||
colProps: { span: 6 }, |
|||
searchSymbol: 'likeRight', |
|||
label: '', |
|||
}, |
|||
{ |
|||
field: 'databaseName', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.table.databaseName'), |
|||
}, |
|||
colProps: { span: 6 }, |
|||
searchSymbol: '=', |
|||
label: '', |
|||
}, |
|||
{ |
|||
field: 'project', |
|||
component: 'Input', |
|||
componentProps: { |
|||
placeholder: t('generator.views.database.table.project'), |
|||
}, |
|||
colProps: { span: 6 }, |
|||
searchSymbol: 'likeLeft', |
|||
label: '', |
|||
}, |
|||
]; |
|||
}; |
|||
@ -0,0 +1,172 @@ |
|||
<!-- |
|||
数据列表页面 |
|||
@author zhongming4762 |
|||
--> |
|||
<template> |
|||
<div class="full-height page-container"> |
|||
<LayoutSeparate first-size="240px" :show-line="false" class="full-height layout-container"> |
|||
<template #first> |
|||
<div class="full-height system-container"> |
|||
<SystemSimpleList |
|||
@current-change="handleSelectSystemChange" |
|||
:row-config="{ isHover: true, isCurrent: true }" |
|||
height="auto" |
|||
/> |
|||
</div> |
|||
</template> |
|||
<template #second> |
|||
<SmartTable :size="getTableSize" @register="registerTable"> |
|||
<template #table-operation="{ row }"> |
|||
<SmartVxeTableAction |
|||
:actions="getTableAction(row)" |
|||
:drop-down-actions="getDropDownAction(row)" |
|||
/> |
|||
</template> |
|||
</SmartTable> |
|||
</template> |
|||
</LayoutSeparate> |
|||
<TemplateSelectedModal template-type="template_db_dict" @register="registerModal" /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
|
|||
import { |
|||
ActionItem, |
|||
SmartVxeTableAction, |
|||
SmartTable, |
|||
useSmartTable, |
|||
} from '@/components/SmartTable'; |
|||
|
|||
import TemplateSelectedModal from './components/TemplateSelectedModal.vue'; |
|||
import { useModal } from '@/components/Modal'; |
|||
import { LayoutSeparate } from '@/components/LayoutSeparate'; |
|||
import SystemSimpleList from '@/modules/system/components/system/SystemSimpleList.vue'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
|
|||
import { addEditForm, searchForm, tableColumns } from './DatabaseListView.data'; |
|||
import { listApi, deleteApi, getByIdApi, saveUpdateApi } from './DatabaseListView.api'; |
|||
import { handleTestConnected } from './DatabaseListHooks'; |
|||
|
|||
const { t } = useI18n(); |
|||
const { getTableSize } = useSizeSetting(); |
|||
|
|||
const [registerModal, { openModal }] = useModal(); |
|||
let currentSystem: Recordable = {}; |
|||
|
|||
const handleSelectSystemChange = (row) => { |
|||
currentSystem = row; |
|||
query(); |
|||
}; |
|||
|
|||
const getTableAction = (row): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('common.button.edit'), |
|||
onClick: () => editByRowModal(row), |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const getDropDownAction = (row): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('generator.views.database.button.testConnected'), |
|||
onClick: () => handleTestConnected(row, t, setLoading), |
|||
}, |
|||
{ |
|||
label: t('generator.views.database.button.createDic'), |
|||
onClick: () => openModal(true, row), |
|||
auth: 'db:connection:createDic', |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const [registerTable, { editByRowModal, setLoading, query, showAddModal }] = useSmartTable({ |
|||
searchFormConfig: { |
|||
searchWithSymbol: true, |
|||
schemas: searchForm(t), |
|||
layout: 'inline', |
|||
actionColOptions: { |
|||
span: undefined, |
|||
}, |
|||
}, |
|||
addEditConfig: { |
|||
modalConfig: { |
|||
width: 600, |
|||
}, |
|||
formConfig: { |
|||
schemas: addEditForm(t), |
|||
baseColProps: { |
|||
span: 24, |
|||
}, |
|||
}, |
|||
}, |
|||
columnConfig: { |
|||
resizable: true, |
|||
}, |
|||
border: true, |
|||
height: 'auto', |
|||
columns: tableColumns, |
|||
useSearchForm: true, |
|||
pagerConfig: true, |
|||
sortConfig: { |
|||
remote: true, |
|||
}, |
|||
proxyConfig: { |
|||
autoLoad: false, |
|||
ajax: { |
|||
query: (params) => { |
|||
const queryParameter = { |
|||
...params.ajaxParameter, |
|||
systemId: currentSystem.id, |
|||
}; |
|||
return listApi(queryParameter); |
|||
}, |
|||
delete: async ({ body }) => { |
|||
await deleteApi(body.removeRecords); |
|||
}, |
|||
getById: async (row) => { |
|||
return getByIdApi(row.id); |
|||
}, |
|||
save: async ({ body }) => { |
|||
const { insertRecords, updateRecords } = body; |
|||
const data = [...insertRecords, ...updateRecords][0]; |
|||
return saveUpdateApi(data); |
|||
}, |
|||
}, |
|||
}, |
|||
rowConfig: { |
|||
keyField: 'id', |
|||
}, |
|||
toolbarConfig: { |
|||
refresh: true, |
|||
buttons: [ |
|||
{ |
|||
// name: t('common.button.add'), |
|||
code: 'ModalAdd', |
|||
props: { |
|||
onClick: () => |
|||
showAddModal({ |
|||
systemId: currentSystem.id, |
|||
}), |
|||
}, |
|||
}, |
|||
{ |
|||
code: 'ModalEdit', |
|||
}, |
|||
{ |
|||
code: 'delete', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped lang="less"> |
|||
.system-container { |
|||
margin-right: 5px; |
|||
background: white; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,77 @@ |
|||
<template> |
|||
<BasicModal |
|||
v-bind="$attrs" |
|||
:title="isAddRef ? $t('common.button.add') : $t('common.button.edit')" |
|||
:width="700" |
|||
@ok="handleSave" |
|||
@register="registerModal" |
|||
> |
|||
<BasicForm @register="registerAddEditForm" :size="getFormSize" /> |
|||
</BasicModal> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { ref } from 'vue'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
|
|||
import { BasicModal, useModalInner } from '@/components/Modal'; |
|||
import BasicForm from '@/components/Form/src/BasicForm.vue'; |
|||
import { useForm } from '@/components/Form'; |
|||
import { addEditForm } from '@/modules/codeGenerator/views/database/DatabaseListView.data'; |
|||
|
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
|
|||
import { getByIdApi, saveUpdateApi } from '../DatabaseListView.api'; |
|||
|
|||
const emit = defineEmits(['success', 'register']); |
|||
|
|||
const { t } = useI18n(); |
|||
const { getFormSize } = useSizeSetting(); |
|||
const isAddRef = ref(true); |
|||
|
|||
const [registerAddEditForm, { setFieldsValue, resetFields, validate }] = useForm({ |
|||
schemas: addEditForm(t), |
|||
baseColProps: { |
|||
span: 24, |
|||
}, |
|||
labelCol: { |
|||
span: 5, |
|||
}, |
|||
wrapperCol: { |
|||
span: 18, |
|||
}, |
|||
// @ts-ignore |
|||
showActionButtonGroup: false, |
|||
}); |
|||
|
|||
const [registerModal, { changeLoading, closeModal }] = useModalInner(async ({ isAdd, id }) => { |
|||
await resetFields(); |
|||
isAddRef.value = isAdd; |
|||
if (!isAdd) { |
|||
changeLoading(true); |
|||
try { |
|||
const result = await getByIdApi(id); |
|||
await setFieldsValue({ |
|||
...result, |
|||
}); |
|||
} finally { |
|||
changeLoading(false); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
/** |
|||
* 执行保存操作 |
|||
*/ |
|||
const handleSave = async () => { |
|||
const model = await validate(); |
|||
changeLoading(true); |
|||
try { |
|||
await saveUpdateApi(model); |
|||
closeModal(); |
|||
emit('success'); |
|||
} finally { |
|||
changeLoading(false); |
|||
} |
|||
}; |
|||
</script> |
|||
@ -0,0 +1,84 @@ |
|||
<template> |
|||
<a-transfer |
|||
class="db-template-selected" |
|||
:data-source="transDataSource" |
|||
:target-keys="targetKeysModel" |
|||
show-search |
|||
:render="(item: any) => item.title" |
|||
@change="handleTransChange" |
|||
/> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, ref, toRefs, onMounted } from 'vue'; |
|||
import type { PropType } from 'vue'; |
|||
|
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
/** |
|||
* 模板选择组件 |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'TemplateSelected', |
|||
props: { |
|||
templateType: { |
|||
type: String as PropType<string>, |
|||
}, |
|||
}, |
|||
emits: ['templateChange'], |
|||
setup(props, content) { |
|||
const { templateType } = toRefs(props); |
|||
// 所有模板数据 |
|||
const transDataSource = ref([]); |
|||
const dataLoading = ref(false); |
|||
const targetKeysModel = ref<Array<string>>([]); |
|||
/** |
|||
* 加载模板数据 |
|||
*/ |
|||
const loadData = async () => { |
|||
dataLoading.value = true; |
|||
targetKeysModel.value = []; |
|||
try { |
|||
const result = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/list', |
|||
data: { |
|||
parameter: { |
|||
'templateType@=': templateType.value, |
|||
}, |
|||
}, |
|||
}); |
|||
transDataSource.value = result.map((item: any) => { |
|||
return { |
|||
key: item.templateId + '', |
|||
title: item.name, |
|||
}; |
|||
}); |
|||
} finally { |
|||
dataLoading.value = false; |
|||
} |
|||
}; |
|||
onMounted(loadData); |
|||
const handleTransChange = (targetKeys: Array<string>) => { |
|||
content.emit('templateChange', targetKeys); |
|||
targetKeysModel.value = targetKeys; |
|||
}; |
|||
return { |
|||
transDataSource, |
|||
targetKeysModel, |
|||
handleTransChange, |
|||
loadData, |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.db-template-selected { |
|||
::v-deep(.ant-transfer-list) { |
|||
flex: none; |
|||
width: 46%; |
|||
height: 450px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,97 @@ |
|||
<template> |
|||
<BasicModal |
|||
v-bind="$attrs" |
|||
@register="registerModal" |
|||
@ok="handleCreate" |
|||
:width="600" |
|||
:title="$t('generator.views.database.common.chooseTemplate')" |
|||
> |
|||
<a-transfer |
|||
class="db-template-selected" |
|||
:data-source="transDataSource" |
|||
:target-keys="targetKeysModel" |
|||
show-search |
|||
:render="(item: any) => item.title" |
|||
@change="handleTransChange" |
|||
/> |
|||
</BasicModal> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { PropType, ref, unref } from 'vue'; |
|||
|
|||
import BasicModal from '@/components/Modal/src/BasicModal.vue'; |
|||
import { listTemplate, getCreateDicUrl } from '../DatabaseListView.api'; |
|||
import { useModalInner } from '@/components/Modal'; |
|||
import { message } from 'ant-design-vue'; |
|||
import { applyTempToken } from '@/utils/auth'; |
|||
import { useMessage } from '@/hooks/web/useMessage'; |
|||
import { Result } from '/#/axios'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
|
|||
const props = defineProps({ |
|||
templateType: String as PropType<string>, |
|||
}); |
|||
|
|||
const { t } = useI18n(); |
|||
|
|||
const currentRow = ref<any>(null); |
|||
|
|||
const [registerModal, { closeModal }] = useModalInner((data) => { |
|||
targetKeysModel.value = []; |
|||
currentRow.value = data; |
|||
loadData(); |
|||
}); |
|||
|
|||
const transDataSource = ref([]); |
|||
const targetKeysModel = ref<Array<string>>([]); |
|||
const dataLoading = ref(false); |
|||
|
|||
const loadData = async () => { |
|||
dataLoading.value = true; |
|||
targetKeysModel.value = []; |
|||
try { |
|||
const result = await listTemplate(props.templateType); |
|||
transDataSource.value = result.map((item: any) => { |
|||
return { |
|||
key: item.templateId + '', |
|||
title: item.name, |
|||
}; |
|||
}); |
|||
} finally { |
|||
dataLoading.value = false; |
|||
} |
|||
}; |
|||
const handleCreate = async () => { |
|||
const selectTemplateIdList = unref(targetKeysModel); |
|||
if (selectTemplateIdList.length === 0) { |
|||
message.error(t('generator.views.database.validate.template')); |
|||
return false; |
|||
} |
|||
try { |
|||
const tempToken = await applyTempToken('db:connection:createDic', false); |
|||
selectTemplateIdList.forEach((templateId) => { |
|||
const url = getCreateDicUrl({ row: unref(currentRow), templateId, tempToken }); |
|||
window.open(url); |
|||
}); |
|||
closeModal(); |
|||
} catch (e) { |
|||
const { errorMessage } = useMessage(); |
|||
errorMessage(e as Result); |
|||
} |
|||
}; |
|||
|
|||
const handleTransChange = (targetKeys: Array<string>) => { |
|||
targetKeysModel.value = targetKeys; |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="less"> |
|||
.db-template-selected { |
|||
:deep(.ant-transfer-list) { |
|||
flex: none; |
|||
width: 46%; |
|||
height: 450px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,40 @@ |
|||
export default { |
|||
generator: { |
|||
views: { |
|||
database: { |
|||
common: { |
|||
chooseTemplate: 'Select template', |
|||
}, |
|||
table: { |
|||
connectionName: 'Connection name', |
|||
databaseName: 'DB name', |
|||
type: 'Type', |
|||
project: 'Project', |
|||
url: 'URL', |
|||
username: 'Username', |
|||
tableSchema: 'Table schema', |
|||
password: 'Password', |
|||
}, |
|||
button: { |
|||
testConnected: 'Test connection', |
|||
createDic: 'Generate database dic', |
|||
}, |
|||
validate: { |
|||
type: 'Please select database type', |
|||
connectionName: 'Please enter connection name', |
|||
databaseName: 'Please enter database name', |
|||
project: 'Please enter database', |
|||
url: 'Please enter URL', |
|||
username: 'Please enter username', |
|||
password: 'Please enter password', |
|||
template: 'Please select template', |
|||
}, |
|||
message: { |
|||
deleteOwn: 'You can only delete database connections that you have created', |
|||
connectSuccess: 'Database connection succeeded', |
|||
connectFail: 'Database connection failed', |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,40 @@ |
|||
export default { |
|||
generator: { |
|||
views: { |
|||
database: { |
|||
common: { |
|||
chooseTemplate: '选择模板', |
|||
}, |
|||
table: { |
|||
connectionName: '连接名称', |
|||
databaseName: '数据库名称', |
|||
type: '类型', |
|||
project: '项目', |
|||
url: 'URL', |
|||
username: '用户名', |
|||
tableSchema: 'TableSchema', |
|||
password: '密码', |
|||
}, |
|||
button: { |
|||
testConnected: '测试连接', |
|||
createDic: '生成数据库字典', |
|||
}, |
|||
validate: { |
|||
type: '请选择数据库类型', |
|||
connectionName: '请输入连接名称', |
|||
databaseName: '请输入数据库名称', |
|||
project: '请输入项目', |
|||
url: '请输入URL', |
|||
username: '请输入用户名', |
|||
password: '请输入密码', |
|||
template: '请选择模板', |
|||
}, |
|||
message: { |
|||
deleteOwn: '只能删除自己创建的数据库连接', |
|||
connectSuccess: '数据库连接成功', |
|||
connectFail: '数据库连接失败', |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,85 @@ |
|||
<template> |
|||
<div style="padding: 10px" class="full-height"> |
|||
<vxe-grid |
|||
v-bind="tableProps" |
|||
:tree-config="treeConfig" |
|||
:columns="columns" |
|||
highlight-hover-row |
|||
height="auto" |
|||
stripe |
|||
border |
|||
/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, onMounted } from 'vue'; |
|||
|
|||
import { useVxeTable } from '@/hooks/web/useCrud'; |
|||
import { tableBooleanColumn } from '@/components/SmartTable'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
const doLoadData = () => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/main/getTemplateDataDocument', |
|||
}); |
|||
}; |
|||
|
|||
export default defineComponent({ |
|||
name: 'TemplateDataDocumentView', |
|||
setup() { |
|||
const { tableProps, loadData } = useVxeTable(doLoadData, { |
|||
paging: false, |
|||
}); |
|||
|
|||
onMounted(loadData); |
|||
|
|||
return { |
|||
tableProps, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
treeConfig: { |
|||
children: 'fieldList', |
|||
}, |
|||
columns: [ |
|||
{ |
|||
title: '属性', |
|||
field: 'name', |
|||
width: 240, |
|||
fixed: 'left', |
|||
treeNode: true, |
|||
}, |
|||
{ |
|||
title: '说明', |
|||
field: 'remark', |
|||
minWidth: 240, |
|||
}, |
|||
{ |
|||
title: '参数|返回值', |
|||
field: 'type', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '可选值', |
|||
field: 'optional', |
|||
width: 180, |
|||
}, |
|||
{ |
|||
title: '默认值', |
|||
field: 'defaultValue', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
...tableBooleanColumn(this.$t, '是否可null', 'nullable').createColumn(), |
|||
width: 120, |
|||
}, |
|||
], |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,39 @@ |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
enum Api { |
|||
list = 'db/code/template/list', |
|||
saveUpdate = 'db/code/template/saveUpdate', |
|||
delete = 'db/code/template/batchDeleteById', |
|||
getById = 'db/code/template/getById', |
|||
} |
|||
|
|||
export const listApi = (params) => |
|||
defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: Api.list, |
|||
data: params, |
|||
}); |
|||
|
|||
export const saveUpdateApi = (model) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: Api.saveUpdate, |
|||
data: model, |
|||
}); |
|||
}; |
|||
|
|||
export const deleteApi = (ids: number[]) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: Api.delete, |
|||
data: ids, |
|||
}); |
|||
}; |
|||
|
|||
export const getByIdApi = (id: number) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: Api.getById, |
|||
data: id, |
|||
}); |
|||
}; |
|||
@ -0,0 +1,160 @@ |
|||
import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable'; |
|||
import type { FormSchema } from '@/components/Form'; |
|||
|
|||
import { TemplateType as templateTypeConstants } from '../../constants/DatabaseConstants'; |
|||
import { extensionLanguageMap } from '../../constants/Constants'; |
|||
|
|||
export const getTableColumns = (t: Function): SmartColumn[] => { |
|||
return [ |
|||
{ |
|||
type: 'checkbox', |
|||
width: 60, |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'name', |
|||
title: '{generator.views.template.table.name}', |
|||
width: 200, |
|||
fixed: 'left', |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
field: 'templateType', |
|||
title: '{generator.views.template.table.templateType}', |
|||
width: 140, |
|||
formatter: ({ row }: any) => { |
|||
const templateType = templateTypeConstants[row.templateType]; |
|||
if (templateType) { |
|||
return t(templateType.label); |
|||
} |
|||
return ''; |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'language', |
|||
title: '{generator.views.template.table.language}', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
field: 'remark', |
|||
title: '{generator.views.template.table.remark}', |
|||
minWidth: 200, |
|||
align: 'left', |
|||
headerAlign: 'center', |
|||
}, |
|||
{ |
|||
title: '{common.table.createTime}', |
|||
field: 'createTime', |
|||
width: 165, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
title: '{common.table.createUser}', |
|||
field: 'createBy', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.updateTime}', |
|||
field: 'updateTime', |
|||
width: 165, |
|||
sortable: true, |
|||
}, |
|||
{ |
|||
title: '{common.table.updateUser}', |
|||
field: 'updateBy', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
title: '{common.table.operation}', |
|||
field: 'operation', |
|||
width: 120, |
|||
fixed: 'right', |
|||
slots: { |
|||
default: 'table-operation', |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
export const getSearchSchemas = (t: Function): SmartSearchFormSchema[] => { |
|||
return [ |
|||
{ |
|||
label: t('generator.views.template.table.name'), |
|||
field: 'name', |
|||
component: 'Input', |
|||
searchSymbol: 'like', |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
export const getAddEditFormSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
label: '', |
|||
field: 'templateId', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: '', |
|||
field: 'groupId', |
|||
component: 'Input', |
|||
show: false, |
|||
}, |
|||
{ |
|||
label: t('generator.views.template.table.templateType'), |
|||
field: 'templateType', |
|||
component: 'Select', |
|||
required: true, |
|||
componentProps: { |
|||
options: Object.keys(templateTypeConstants).map((item) => { |
|||
const value = templateTypeConstants[item]; |
|||
return { |
|||
value: value.value, |
|||
label: t(value.label), |
|||
}; |
|||
}), |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('generator.views.template.table.name'), |
|||
field: 'name', |
|||
component: 'Input', |
|||
required: true, |
|||
}, |
|||
{ |
|||
label: t('generator.views.template.table.remark'), |
|||
field: 'remark', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: t('generator.views.template.table.filenameSuffix'), |
|||
field: 'filenameSuffix', |
|||
component: 'Input', |
|||
}, |
|||
{ |
|||
label: t('generator.views.template.table.language'), |
|||
field: 'language', |
|||
component: 'Select', |
|||
componentProps: { |
|||
options: Object.keys(extensionLanguageMap).map((item) => { |
|||
return { |
|||
label: extensionLanguageMap[item], |
|||
value: item, |
|||
}; |
|||
}), |
|||
}, |
|||
}, |
|||
{ |
|||
label: '', |
|||
field: 'template', |
|||
slot: 'addEditForm-language', |
|||
colProps: { |
|||
span: 24, |
|||
}, |
|||
labelWidth: 0, |
|||
disabledLabelWidth: true, |
|||
}, |
|||
]; |
|||
}; |
|||
@ -0,0 +1,180 @@ |
|||
<template> |
|||
<div class="full-height code-container" id="codeTemplateContainer" style="padding: 10px"> |
|||
<LayoutSeparate :show-line="false" first-size="240px" class="full-height"> |
|||
<template #first> |
|||
<div class="full-height" style=" margin-right: 5px;background: white"> |
|||
<TemplateGroup @change="handleGroupChange" /> |
|||
</div> |
|||
</template> |
|||
<template #second> |
|||
<SmartTable @register="registerTable" :addEditConfig="getAddEditConfig"> |
|||
<template #table-operation="{ row }"> |
|||
<SmartVxeTableAction :actions="getActions(row)" /> |
|||
</template> |
|||
<template #addEditForm-language="{ model }"> |
|||
<div class="code-edit-container"> |
|||
<CodeEditor |
|||
:read-only="isReadonly" |
|||
v-model:value="model.template" |
|||
:mode="model.language" |
|||
/> |
|||
</div> |
|||
</template> |
|||
</SmartTable> |
|||
</template> |
|||
</LayoutSeparate> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import type { ActionItem, SmartTableAddEditConfig } from '@/components/SmartTable'; |
|||
|
|||
import { computed, ref, unref } from 'vue'; |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { merge } from 'lodash-es'; |
|||
import { message } from 'ant-design-vue'; |
|||
|
|||
import { SmartTable, SmartVxeTableAction, useSmartTable } from '@/components/SmartTable'; |
|||
import { LayoutSeparate } from '@/components/LayoutSeparate'; |
|||
import TemplateGroup from './components/TemplateGroup.vue'; |
|||
import { CodeEditor } from '@/components/CodeEditor'; |
|||
|
|||
import { |
|||
getTableColumns, |
|||
getSearchSchemas, |
|||
getAddEditFormSchemas, |
|||
} from './CodeTemplateList.config'; |
|||
import { listApi, getByIdApi, deleteApi, saveUpdateApi } from './CodeTemplateList.api'; |
|||
|
|||
const { t } = useI18n(); |
|||
|
|||
const currentGroupIdRef = ref<number | undefined>(); |
|||
|
|||
const handleGroupChange = (id: number | undefined) => { |
|||
currentGroupIdRef.value = id; |
|||
reload(); |
|||
}; |
|||
|
|||
const getActions = (row): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('common.button.edit'), |
|||
onClick: () => { |
|||
isReadonly.value = false; |
|||
editByRowModal(row); |
|||
}, |
|||
}, |
|||
{ |
|||
label: t('common.button.look'), |
|||
onClick: () => { |
|||
isReadonly.value = true; |
|||
editByRowModal(row); |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const isReadonly = ref(false); |
|||
|
|||
const getAddEditConfig = computed<SmartTableAddEditConfig>(() => { |
|||
return { |
|||
modalConfig: { |
|||
defaultFullscreen: true, |
|||
getContainer: () => { |
|||
return document.getElementById('codeTemplateContainer') as HTMLElement; |
|||
}, |
|||
}, |
|||
formConfig: { |
|||
schemas: getAddEditFormSchemas(t), |
|||
baseColProps: { |
|||
span: 8, |
|||
}, |
|||
colon: true, |
|||
disabled: unref(isReadonly), |
|||
baseRowStyle: { |
|||
height: '100%', |
|||
}, |
|||
}, |
|||
}; |
|||
}); |
|||
|
|||
const [registerTable, { editByRowModal, showAddModal, reload }] = useSmartTable({ |
|||
height: 'auto', |
|||
highlightHoverRow: true, |
|||
stripe: true, |
|||
columns: getTableColumns(t), |
|||
useSearchForm: true, |
|||
searchFormConfig: { |
|||
schemas: getSearchSchemas(t), |
|||
searchWithSymbol: true, |
|||
colon: true, |
|||
layout: 'inline', |
|||
actionColOptions: { |
|||
span: undefined, |
|||
}, |
|||
}, |
|||
toolbarConfig: { |
|||
refresh: true, |
|||
resizable: true, |
|||
buttons: [ |
|||
{ |
|||
code: 'ModalAdd', |
|||
props: { |
|||
onClick: () => { |
|||
isReadonly.value = false; |
|||
const currentGroupId = unref(currentGroupIdRef); |
|||
if (!currentGroupId) { |
|||
message.warn(t('generator.views.template.notice.choseGroup')); |
|||
return false; |
|||
} |
|||
showAddModal({ |
|||
groupId: currentGroupId, |
|||
}); |
|||
}, |
|||
}, |
|||
}, |
|||
{ |
|||
code: 'delete', |
|||
}, |
|||
], |
|||
}, |
|||
proxyConfig: { |
|||
ajax: { |
|||
query: (params) => { |
|||
const parameter = merge(params.ajaxParameter, { |
|||
parameter: { |
|||
'groupId@=': unref(currentGroupIdRef), |
|||
}, |
|||
}); |
|||
return listApi(parameter); |
|||
}, |
|||
save: ({ body: { insertRecords, updateRecords } }) => |
|||
saveUpdateApi([...insertRecords, ...updateRecords][0]), |
|||
delete: ({ body: { removeRecords } }) => |
|||
deleteApi(removeRecords.map((item) => item.templateId)), |
|||
getById: (params) => getByIdApi(params.templateId), |
|||
}, |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped lang="less"> |
|||
.code-container { |
|||
:deep(.ant-form) { |
|||
height: 100%; |
|||
} |
|||
|
|||
:deep(.ant-col-24) { |
|||
height: calc(100% - 106px); |
|||
|
|||
.ant-form-item { |
|||
height: 100%; |
|||
overflow: auto; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.code-edit-container { |
|||
height: 100%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,248 @@ |
|||
<template> |
|||
<div class="full-height"> |
|||
<div class="table-container"> |
|||
<vxe-grid |
|||
ref="gridRef" |
|||
highlight-current-row |
|||
stripe |
|||
:columns="columns" |
|||
height="auto" |
|||
size="small" |
|||
v-bind="tableProps" |
|||
@cell-click="handleChange" |
|||
> |
|||
<template #table-groupName="{ row }"> |
|||
<div style="cursor: pointer" @contextmenu="handleContext"> |
|||
{{ row.groupName }} |
|||
</div> |
|||
<!-- <ContextMenu event="contextmenu">--> |
|||
<!-- {{ row.groupName }}--> |
|||
<!-- <template #menu>--> |
|||
<!-- <a-menu @click="({ key, domEvent }) => handleMenuClick(key, row.groupId, domEvent)">--> |
|||
<!-- <a-menu-item key="edit">--> |
|||
<!-- <EditOutlined />--> |
|||
<!-- {{ $t('common.button.edit') }}--> |
|||
<!-- </a-menu-item>--> |
|||
<!-- <a-menu-item key="delete">--> |
|||
<!-- <DeleteOutlined />--> |
|||
<!-- {{ $t('common.button.delete') }}--> |
|||
<!-- </a-menu-item>--> |
|||
<!-- </a-menu>--> |
|||
<!-- </template>--> |
|||
<!-- </ContextMenu>--> |
|||
<!-- </div>--> |
|||
</template> |
|||
</vxe-grid> |
|||
</div> |
|||
<div class="button-container"> |
|||
<a-button class="button" block type="primary" @click="() => handleAddEdit(true, null)"> |
|||
{{ $t('common.button.add') }} |
|||
</a-button> |
|||
</div> |
|||
|
|||
<a-modal v-bind="modalProps"> |
|||
<a-spin :spinning="spinning"> |
|||
<a-form |
|||
v-bind="formProps" |
|||
:rules="rules" |
|||
:label-col="{ span: 6 }" |
|||
:wrapper-col="{ span: 17 }" |
|||
> |
|||
<a-form-item :label="$t('generator.views.template.title.templateGroup')" name="groupName"> |
|||
<a-input |
|||
v-model:value="formProps.model.groupName" |
|||
:placeholder="$t('generator.views.template.validate.templateGroup')" |
|||
/> |
|||
</a-form-item> |
|||
<a-form-item :label="$t('generator.views.template.title.seq')" name="seq"> |
|||
<a-input-number |
|||
v-model:value="formProps.model.seq" |
|||
style="width: 100%" |
|||
:placeholder="$t('generator.views.template.validate.seq')" |
|||
/> |
|||
</a-form-item> |
|||
</a-form> |
|||
</a-spin> |
|||
</a-modal> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, onMounted, ref } from 'vue'; |
|||
import { useI18n } from 'vue-i18n'; |
|||
|
|||
// import { ContextMenu } from '@/components/ContextMenu'; |
|||
import { useVxeTable, useAddEdit, useVxeDelete } from '@/hooks/web/useCrud'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
import { useContextMenu } from '@/hooks/web/useContextMenu'; |
|||
|
|||
const handleLoadData = async () => { |
|||
const result = [ |
|||
{ |
|||
groupName: 'ALL', |
|||
}, |
|||
]; |
|||
return result.concat( |
|||
(await defHttp.post({ |
|||
url: 'db/code/template/listGroup', |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
})) || [], |
|||
); |
|||
}; |
|||
|
|||
/** |
|||
* 通过ID查询 |
|||
*/ |
|||
const handleGet = (id: any) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/getGroupById', |
|||
data: id, |
|||
}); |
|||
}; |
|||
|
|||
const handleSaveUpdate = async (model: any) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/saveUpdateGroup', |
|||
data: model, |
|||
}); |
|||
}; |
|||
|
|||
const handleDelete = async (idList: Array<any>) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/deleteGroupById', |
|||
data: idList, |
|||
}); |
|||
}; |
|||
|
|||
export default defineComponent({ |
|||
name: 'TemplateGroup', |
|||
emits: ['change'], |
|||
setup() { |
|||
const { t } = useI18n(); |
|||
const gridRef = ref(); |
|||
const { tableProps, loadData } = useVxeTable(handleLoadData, { |
|||
paging: false, |
|||
}); |
|||
// 编辑 |
|||
const { modalProps, handleAddEdit, spinning, formProps, formRef } = useAddEdit( |
|||
gridRef, |
|||
handleGet, |
|||
loadData, |
|||
handleSaveUpdate, |
|||
t, |
|||
{ |
|||
defaultModel: { |
|||
seq: 1, |
|||
}, |
|||
}, |
|||
); |
|||
|
|||
const [createContextMenu] = useContextMenu(); |
|||
|
|||
const handleContext = (e: MouseEvent) => { |
|||
return createContextMenu({ |
|||
event: e, |
|||
items: [ |
|||
{ |
|||
label: t('common.button.edit'), |
|||
icon: 'ant-design:edit-outlined', |
|||
}, |
|||
{ |
|||
label: t('common.button.delete'), |
|||
icon: 'ant-design:delete-outlined', |
|||
}, |
|||
], |
|||
}); |
|||
}; |
|||
|
|||
const { handleDeleteById } = useVxeDelete(gridRef, t, handleDelete, { |
|||
idField: 'groupId', |
|||
listHandler: loadData, |
|||
}); |
|||
|
|||
const handleMenuClick = (ident: string, groupId: number, event: Event) => { |
|||
event.preventDefault(); |
|||
switch (ident) { |
|||
case 'edit': { |
|||
handleAddEdit(false, groupId); |
|||
break; |
|||
} |
|||
case 'delete': { |
|||
handleDeleteById(groupId); |
|||
break; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
onMounted(loadData); |
|||
return { |
|||
gridRef, |
|||
tableProps, |
|||
loadData, |
|||
handleMenuClick, |
|||
modalProps, |
|||
handleAddEdit, |
|||
spinning, |
|||
formProps, |
|||
formRef, |
|||
handleContext, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
columns: [ |
|||
{ |
|||
title: '{generator.views.template.title.templateGroup}', |
|||
field: 'groupName', |
|||
slots: { |
|||
default: 'table-groupName', |
|||
}, |
|||
}, |
|||
], |
|||
rules: { |
|||
groupName: [ |
|||
{ |
|||
required: true, |
|||
message: this.$t('generator.views.template.validate.templateGroup'), |
|||
trigger: 'blur', |
|||
}, |
|||
], |
|||
seq: [ |
|||
{ |
|||
required: true, |
|||
message: this.$t('generator.views.template.validate.seq'), |
|||
trigger: 'blur', |
|||
type: 'number', |
|||
}, |
|||
], |
|||
}, |
|||
}; |
|||
}, |
|||
methods: { |
|||
handleChange({ row }: any) { |
|||
this.$emit('change', row.groupId); |
|||
}, |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
@buttonContainerHeight: 50px; |
|||
|
|||
.table-container { |
|||
height: calc(100% - @buttonContainerHeight); |
|||
} |
|||
|
|||
.button-container { |
|||
height: @buttonContainerHeight; |
|||
line-height: @buttonContainerHeight; |
|||
text-align: center; |
|||
|
|||
.button { |
|||
width: 90%; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,171 @@ |
|||
<template> |
|||
<a-layout class="full-height"> |
|||
<a-layout-header style="height: 56px; background: white; text-align: center"> |
|||
<h3>{{ $t('generator.views.template.title.userGroup') }}</h3> |
|||
</a-layout-header> |
|||
<a-divider style="margin: 0" /> |
|||
<a-layout-content style="background: white"> |
|||
<div class="full-height"> |
|||
<a-spin class="full-height" :spinning="dataLoading"> |
|||
<a-table |
|||
class="full-height" |
|||
size="small" |
|||
row-key="groupId" |
|||
:row-selection="rowSelection" |
|||
:columns="columns" |
|||
:show-header="false" |
|||
:pagination="false" |
|||
:data-source="allUserGroup" |
|||
/> |
|||
</a-spin> |
|||
</div> |
|||
</a-layout-content> |
|||
<a-divider style="margin: 0" /> |
|||
<a-layout-footer style="height: 50px; padding: 10px 0; background: white; text-align: center"> |
|||
<div style="padding: 0 5px"> |
|||
<a-button |
|||
:disabled="!saveButtonVisible" |
|||
:loading="saveLoading" |
|||
block |
|||
type="primary" |
|||
@click="handleSave" |
|||
> |
|||
{{ $t('common.button.save') }} |
|||
</a-button> |
|||
</div> |
|||
</a-layout-footer> |
|||
</a-layout> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { defineComponent, toRefs, onMounted, ref, reactive, watch, computed } from 'vue'; |
|||
import type { PropType } from 'vue'; |
|||
|
|||
import { isSuperAdmin, getCurrentUserId } from '@/utils/auth'; |
|||
|
|||
import { message } from 'ant-design-vue'; |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
/**CodeListView |
|||
* 模板设置关联的用户组 |
|||
*/ |
|||
export default defineComponent({ |
|||
name: 'TemplateSetUserGroup', |
|||
props: { |
|||
template: { |
|||
type: Object as PropType<any>, |
|||
default: null, |
|||
}, |
|||
}, |
|||
setup(props) { |
|||
const { template } = toRefs(props); |
|||
const dataLoading = ref(false); |
|||
// 保存状态 |
|||
const saveLoading = ref(false); |
|||
const allUserGroup = ref<Array<any>>([]); |
|||
const rowSelection = reactive({ |
|||
columnWidth: 60, |
|||
selectedRowKeys: [] as Array<number>, |
|||
onChange: (selectedRowKeys: Array<number>) => { |
|||
rowSelection.selectedRowKeys = selectedRowKeys; |
|||
}, |
|||
}); |
|||
/** |
|||
* 保存安装显示状态 |
|||
*/ |
|||
const saveButtonVisible = computed(() => { |
|||
if (isSuperAdmin()) { |
|||
return true; |
|||
} |
|||
const currentUserId = getCurrentUserId; |
|||
const templateValue: any = template.value; |
|||
return templateValue ? templateValue.createUserId === currentUserId : false; |
|||
}); |
|||
/** |
|||
* 加载所有用户组数据 |
|||
*/ |
|||
const loadAllUserGroup = async () => { |
|||
try { |
|||
dataLoading.value = true; |
|||
allUserGroup.value = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_SYSTEM, |
|||
url: 'sys/userGroup/list', |
|||
data: { |
|||
sortName: 'seq', |
|||
parameter: { |
|||
'useYn@=': true, |
|||
}, |
|||
}, |
|||
}); |
|||
} finally { |
|||
dataLoading.value = false; |
|||
} |
|||
}; |
|||
/** |
|||
* 加载模板对应的用户组信息 |
|||
*/ |
|||
const loadTemplateUserGroup = async () => { |
|||
const templateValue: any = template.value; |
|||
if (templateValue === null) { |
|||
rowSelection.selectedRowKeys = []; |
|||
} |
|||
try { |
|||
dataLoading.value = true; |
|||
const result: Array<any> = await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/listUserGroupByTemplate', |
|||
data: templateValue.templateId, |
|||
}); |
|||
rowSelection.selectedRowKeys = result.map((item) => item.groupId); |
|||
} finally { |
|||
dataLoading.value = false; |
|||
} |
|||
}; |
|||
/** |
|||
* 保存操作 |
|||
*/ |
|||
const handleSave = async () => { |
|||
const templateValue: any = template.value; |
|||
if (!templateValue) { |
|||
message.error('请先指定模板'); |
|||
return false; |
|||
} |
|||
try { |
|||
saveLoading.value = true; |
|||
await defHttp.post({ |
|||
service: ApiServiceEnum.SMART_CODE, |
|||
url: 'db/code/template/saveTemplateUserGroup', |
|||
data: { |
|||
templateId: templateValue.templateId, |
|||
groupIdList: rowSelection.selectedRowKeys, |
|||
}, |
|||
}); |
|||
message.success('保存成功'); |
|||
} finally { |
|||
saveLoading.value = false; |
|||
} |
|||
}; |
|||
watch(template, loadTemplateUserGroup); |
|||
onMounted(loadAllUserGroup); |
|||
return { |
|||
dataLoading, |
|||
allUserGroup, |
|||
rowSelection, |
|||
handleSave, |
|||
saveLoading, |
|||
saveButtonVisible, |
|||
}; |
|||
}, |
|||
data() { |
|||
return { |
|||
columns: [ |
|||
{ |
|||
dataIndex: 'groupName', |
|||
}, |
|||
], |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped></style> |
|||
@ -0,0 +1,37 @@ |
|||
export default { |
|||
generator: { |
|||
views: { |
|||
template: { |
|||
label: { |
|||
templateType: { |
|||
templateCode: 'Code template', |
|||
templateDbDict: 'DB dict template', |
|||
}, |
|||
}, |
|||
title: { |
|||
userGroup: 'User group', |
|||
templateGroup: 'Template group', |
|||
seq: 'Seq', |
|||
}, |
|||
table: { |
|||
name: 'Name', |
|||
templateType: 'Template Type', |
|||
language: 'Language', |
|||
remark: 'Remark', |
|||
filenameSuffix: 'Filename Suffix', |
|||
}, |
|||
notice: { |
|||
onlyDeleteMy: 'Only self created templates can be deleted', |
|||
choseGroup: 'Please select a template group first', |
|||
}, |
|||
validate: { |
|||
templateType: 'Please enter template type', |
|||
name: 'Please enter name', |
|||
remark: 'Please enter remark', |
|||
seq: 'Please enter seq', |
|||
templateGroup: 'Please enter template group', |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,37 @@ |
|||
export default { |
|||
generator: { |
|||
views: { |
|||
template: { |
|||
label: { |
|||
templateType: { |
|||
templateCode: '代码模板', |
|||
templateDbDict: '数据库字典模板', |
|||
}, |
|||
}, |
|||
title: { |
|||
userGroup: '用户组', |
|||
templateGroup: '模板分组', |
|||
seq: '序号', |
|||
}, |
|||
table: { |
|||
name: '名称', |
|||
templateType: '模板类型', |
|||
language: '语言', |
|||
remark: '备注', |
|||
filenameSuffix: '文件名后缀', |
|||
}, |
|||
notice: { |
|||
onlyDeleteMy: '只能删除自己创建的模板', |
|||
choseGroup: '请先选择模板分组', |
|||
}, |
|||
validate: { |
|||
templateType: '请输入模板类型', |
|||
name: '请输入模板名称', |
|||
remark: '请输入备注', |
|||
seq: '请输入序号', |
|||
templateGroup: '请输入模板分组', |
|||
}, |
|||
}, |
|||
}, |
|||
}, |
|||
}; |
|||
@ -0,0 +1,42 @@ |
|||
import { ApiServiceEnum, defHttp } from '@/utils/http/axios'; |
|||
|
|||
enum Api { |
|||
list = '/sys/auth/accessSecret/list', |
|||
getById = '/sys/auth/accessSecret/getById', |
|||
saveUpdate = '/sys/auth/accessSecret/saveUpdate', |
|||
delete = '/sys/auth/accessSecret/batchDeleteById', |
|||
} |
|||
|
|||
export const listApi = (params) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_SYSTEM, |
|||
url: Api.list, |
|||
data: { |
|||
...params, |
|||
}, |
|||
}); |
|||
}; |
|||
|
|||
export const saveUpdateApi = (modelList: any[]) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_SYSTEM, |
|||
url: Api.saveUpdate, |
|||
data: modelList[0], |
|||
}); |
|||
}; |
|||
|
|||
export const deleteApi = (removeRecords: Recordable[]) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_SYSTEM, |
|||
url: Api.delete, |
|||
data: removeRecords.map((item) => item.id), |
|||
}); |
|||
}; |
|||
|
|||
export const getByIdApi = (id: number) => { |
|||
return defHttp.post({ |
|||
service: ApiServiceEnum.SMART_SYSTEM, |
|||
url: Api.getById, |
|||
data: id, |
|||
}); |
|||
}; |
|||
@ -0,0 +1,186 @@ |
|||
import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable'; |
|||
import type { FormSchema } from '@/components/Form'; |
|||
|
|||
import { tableUseYnClass } from '@/components/SmartTable'; |
|||
|
|||
/** |
|||
* 表格列表 |
|||
*/ |
|||
export const getTableColumns = (): SmartColumn[] => { |
|||
return [ |
|||
{ |
|||
type: 'checkbox', |
|||
width: 60, |
|||
align: 'center', |
|||
fixed: 'left', |
|||
}, |
|||
{ |
|||
field: 'seq', |
|||
sortable: true, |
|||
title: '{common.table.seq}', |
|||
width: 100, |
|||
}, |
|||
{ |
|||
field: 'accessKey', |
|||
title: '{system.views.auth.acccessSecret.title.accessKey}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'secretKey', |
|||
title: '{system.views.auth.acccessSecret.title.secretKey}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'expireDate', |
|||
title: '{system.views.auth.acccessSecret.title.expireDate}', |
|||
width: 165, |
|||
}, |
|||
{ |
|||
field: 'accessIp', |
|||
title: '{system.views.auth.acccessSecret.title.accessIp}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'remark', |
|||
title: '{common.table.remark}', |
|||
width: 200, |
|||
}, |
|||
{ |
|||
...tableUseYnClass(), |
|||
}, |
|||
{ |
|||
field: 'createBy', |
|||
title: '{common.table.createUser}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'createTime', |
|||
title: '{common.table.createTime}', |
|||
width: 165, |
|||
}, |
|||
{ |
|||
field: 'updateBy', |
|||
title: '{common.table.updateUser}', |
|||
width: 120, |
|||
}, |
|||
{ |
|||
field: 'updateTime', |
|||
title: '{common.table.updateTime}', |
|||
width: 165, |
|||
}, |
|||
{ |
|||
title: '{common.table.operation}', |
|||
field: 'operation', |
|||
width: 120, |
|||
fixed: 'right', |
|||
slots: { |
|||
default: 'table-operation', |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
/** |
|||
* 添加修改表单 |
|||
*/ |
|||
export const getFormSchemas = (t: Function): FormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'id', |
|||
show: false, |
|||
label: '', |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
}, |
|||
{ |
|||
field: 'accessKey', |
|||
label: t('system.views.auth.acccessSecret.title.accessKey'), |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
dynamicDisabled: true, |
|||
}, |
|||
{ |
|||
field: 'secretKey', |
|||
label: t('system.views.auth.acccessSecret.title.secretKey'), |
|||
component: 'Input', |
|||
componentProps: {}, |
|||
dynamicDisabled: true, |
|||
}, |
|||
{ |
|||
field: 'expireDate', |
|||
label: t('system.views.auth.acccessSecret.title.expireDate'), |
|||
component: 'DatePicker', |
|||
componentProps: { |
|||
showTime: true, |
|||
style: { width: '100%' }, |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'accessIp', |
|||
label: t('system.views.auth.acccessSecret.title.accessIp'), |
|||
component: 'InputTextArea', |
|||
componentProps: { |
|||
placeholder: t('system.views.auth.acccessSecret.validate.accessIp'), |
|||
}, |
|||
}, |
|||
{ |
|||
field: 'remark', |
|||
label: t('common.table.remark'), |
|||
component: 'InputTextArea', |
|||
componentProps: {}, |
|||
}, |
|||
{ |
|||
field: 'useYn', |
|||
label: t('common.table.useYn'), |
|||
component: 'Switch', |
|||
componentProps: {}, |
|||
defaultValue: true, |
|||
}, |
|||
{ |
|||
field: 'seq', |
|||
label: t('common.table.seq'), |
|||
component: 'InputNumber', |
|||
componentProps: {}, |
|||
required: true, |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
export const getSearchFormSchemas = (t: Function): SmartSearchFormSchema[] => { |
|||
return [ |
|||
{ |
|||
field: 'accessKey', |
|||
label: t('system.views.auth.acccessSecret.title.accessKey'), |
|||
component: 'Input', |
|||
searchSymbol: 'like', |
|||
}, |
|||
{ |
|||
field: 'secretKey', |
|||
label: t('system.views.auth.acccessSecret.title.secretKey'), |
|||
component: 'Input', |
|||
searchSymbol: 'like', |
|||
}, |
|||
{ |
|||
field: 'useYn', |
|||
label: t('common.table.useYn'), |
|||
component: 'Select', |
|||
searchSymbol: '=', |
|||
defaultValue: 1, |
|||
componentProps: { |
|||
style: { |
|||
width: '120px', |
|||
}, |
|||
options: [ |
|||
{ |
|||
label: t('common.form.use'), |
|||
value: 1, |
|||
}, |
|||
{ |
|||
label: t('common.form.noUse'), |
|||
value: 0, |
|||
}, |
|||
], |
|||
}, |
|||
}, |
|||
]; |
|||
}; |
|||
@ -0,0 +1,98 @@ |
|||
<template> |
|||
<div class="full-height page-container"> |
|||
<SmartTable @register="registerTable" :size="getTableSize"> |
|||
<template #table-operation="{ row }"> |
|||
<SmartVxeTableAction :actions="getActions(row)" /> |
|||
</template> |
|||
</SmartTable> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useI18n } from '@/hooks/web/useI18n'; |
|||
import { useSizeSetting } from '@/hooks/setting/UseSizeSetting'; |
|||
|
|||
import { |
|||
ActionItem, |
|||
SmartTable, |
|||
SmartVxeTableAction, |
|||
useSmartTable, |
|||
} from '@/components/SmartTable'; |
|||
|
|||
import { |
|||
getTableColumns, |
|||
getFormSchemas, |
|||
getSearchFormSchemas, |
|||
} from './SysAuthAccessSecretListView.config'; |
|||
import { listApi, deleteApi, getByIdApi, saveUpdateApi } from './SysAuthAccessSecretListView.api'; |
|||
|
|||
const { t } = useI18n(); |
|||
const { getTableSize } = useSizeSetting(); |
|||
|
|||
const getActions = (row: Recordable): ActionItem[] => { |
|||
return [ |
|||
{ |
|||
label: t('common.button.edit'), |
|||
onClick: () => editByRowModal(row), |
|||
}, |
|||
]; |
|||
}; |
|||
|
|||
const [registerTable, { editByRowModal }] = useSmartTable({ |
|||
id: 'smart-system-tool-accessSecret', |
|||
customConfig: { storage: true }, |
|||
columns: getTableColumns(), |
|||
height: 'auto', |
|||
border: true, |
|||
sortConfig: { |
|||
remote: true, |
|||
}, |
|||
rowConfig: { |
|||
isHover: true, |
|||
}, |
|||
showOverflow: 'tooltip', |
|||
pagerConfig: true, |
|||
useSearchForm: true, |
|||
searchFormConfig: { |
|||
schemas: getSearchFormSchemas(t), |
|||
searchWithSymbol: true, |
|||
colon: true, |
|||
layout: 'inline', |
|||
actionColOptions: { |
|||
span: undefined, |
|||
}, |
|||
compact: true, |
|||
}, |
|||
addEditConfig: { |
|||
formConfig: { |
|||
schemas: getFormSchemas(t), |
|||
colon: true, |
|||
baseColProps: { span: 24 }, |
|||
labelCol: { span: 6 }, |
|||
wrapperCol: { span: 17 }, |
|||
}, |
|||
}, |
|||
proxyConfig: { |
|||
ajax: { |
|||
query: (params) => listApi(params.ajaxParameter), |
|||
save: ({ body: { insertRecords, updateRecords } }) => |
|||
saveUpdateApi([...insertRecords, ...updateRecords]), |
|||
delete: ({ body: { removeRecords } }) => deleteApi(removeRecords), |
|||
getById: (params) => getByIdApi(params.id), |
|||
}, |
|||
}, |
|||
toolbarConfig: { |
|||
zoom: true, |
|||
refresh: true, |
|||
column: { columnOrder: true }, |
|||
buttons: [ |
|||
{ |
|||
code: 'ModalAdd', |
|||
}, |
|||
{ |
|||
code: 'delete', |
|||
}, |
|||
], |
|||
}, |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* 国际化信息 |
|||
*/ |
|||
export default { |
|||
trans: true, |
|||
key: 'system.views.auth.acccessSecret', |
|||
data: { |
|||
title: { |
|||
accessKey: 'Access key', |
|||
secretKey: 'Secret key', |
|||
expireDate: '过期时间', |
|||
accessIp: '授权IP或域名', |
|||
createBy: 'createBy', |
|||
updateBy: 'updateBy', |
|||
}, |
|||
validate: { |
|||
accessKey: '请输入Access key', |
|||
secretKey: '请输入Secret key', |
|||
expireDate: '请输入过期时间', |
|||
accessIp: '请输入授权IP或域名,以逗号分隔', |
|||
}, |
|||
rules: {}, |
|||
search: { |
|||
accessKey: '请输入Access key', |
|||
secretKey: '请输入Secret key', |
|||
}, |
|||
}, |
|||
}; |
|||
Loading…
Reference in new issue