Browse Source

feat(代码生成器): 添加代码生成器模块

shizhongming 2 years ago
parent
commit
6436a493c7
  1. 1
      src/components/SmartTable/index.ts
  2. 40
      src/components/SmartTable/src/hooks/useVxeTableSortable.ts
  3. 64
      src/modules/codeGenerator/components/template/TemplateGroup.vue
  4. 8
      src/modules/codeGenerator/constants/Constants.ts
  5. 13
      src/modules/codeGenerator/constants/DatabaseConstants.ts
  6. 11
      src/modules/codeGenerator/router/CodeBasicRouter.ts
  7. 11
      src/modules/codeGenerator/views/codeCreate/CodeCreateSupport.ts
  8. 63
      src/modules/codeGenerator/views/codeCreate/CodeCreateView.vue
  9. 80
      src/modules/codeGenerator/views/codeCreate/CodeCreateViewOld.vue
  10. 30
      src/modules/codeGenerator/views/codeDesign/CodeDesignPage.api.ts
  11. 330
      src/modules/codeGenerator/views/codeDesign/CodeDesignPage.config.ts
  12. 250
      src/modules/codeGenerator/views/codeDesign/CodeDesignPage.vue
  13. 142
      src/modules/codeGenerator/views/codeDesign/CodeDesignPageHook.ts
  14. 54
      src/modules/codeGenerator/views/codeDesign/componenets/DatabaseSelect/DatabaseSelect.vue
  15. 210
      src/modules/codeGenerator/views/codeDesign/componenets/PageAddendumTableChoseModal.vue
  16. 222
      src/modules/codeGenerator/views/codeDesign/componenets/PageFromSetting/FormRuleSetModal.vue
  17. 362
      src/modules/codeGenerator/views/codeDesign/componenets/PageFromSetting/PageFormSetting.vue
  18. 380
      src/modules/codeGenerator/views/codeDesign/componenets/PageSearchSetting/PageSearchSetting.vue
  19. 174
      src/modules/codeGenerator/views/codeDesign/componenets/PageSettingSupport.ts
  20. 331
      src/modules/codeGenerator/views/codeDesign/componenets/PageTableSetting/PageTableSetting.vue
  21. 107
      src/modules/codeGenerator/views/codeDesign/componenets/TableFieldTable/TableFieldTable.vue
  22. 20
      src/modules/codeGenerator/views/codeDesign/lang/en_US.ts
  23. 20
      src/modules/codeGenerator/views/codeDesign/lang/zh_CN.ts
  24. 16
      src/modules/codeGenerator/views/codeList/CodeListView.api.ts
  25. 136
      src/modules/codeGenerator/views/codeList/CodeListView.config.tsx
  26. 175
      src/modules/codeGenerator/views/codeList/CodeListView.vue
  27. 187
      src/modules/codeGenerator/views/codeList/components/CodeCreateForm.vue
  28. 147
      src/modules/codeGenerator/views/codeList/components/CodeCreateModal.vue
  29. 9
      src/modules/codeGenerator/views/codeList/components/CodeListAddEditModal.vue
  30. 150
      src/modules/codeGenerator/views/codeList/components/TemplateSelectTable.vue
  31. 55
      src/modules/codeGenerator/views/codeList/hooks/useLoadDbData.ts
  32. 166
      src/modules/codeGenerator/views/codeList/lang/en_US.ts
  33. 167
      src/modules/codeGenerator/views/codeList/lang/zh_CN.ts
  34. 19
      src/modules/codeGenerator/views/database/DatabaseListHooks.ts
  35. 70
      src/modules/codeGenerator/views/database/DatabaseListView.api.ts
  36. 203
      src/modules/codeGenerator/views/database/DatabaseListView.data.ts
  37. 172
      src/modules/codeGenerator/views/database/DatabaseListView.vue
  38. 77
      src/modules/codeGenerator/views/database/components/DatabaseListViewAddEditModal.vue
  39. 84
      src/modules/codeGenerator/views/database/components/TemplateSelected.vue
  40. 97
      src/modules/codeGenerator/views/database/components/TemplateSelectedModal.vue
  41. 40
      src/modules/codeGenerator/views/database/lang/en_US.ts
  42. 40
      src/modules/codeGenerator/views/database/lang/zh_CN.ts
  43. 85
      src/modules/codeGenerator/views/document/TemplateDataDocumentView.vue
  44. 39
      src/modules/codeGenerator/views/template/CodeTemplateList.api.ts
  45. 160
      src/modules/codeGenerator/views/template/CodeTemplateList.config.ts
  46. 180
      src/modules/codeGenerator/views/template/CodeTemplateList.vue
  47. 248
      src/modules/codeGenerator/views/template/components/TemplateGroup.vue
  48. 171
      src/modules/codeGenerator/views/template/components/TemplateSetUserGroup.vue
  49. 37
      src/modules/codeGenerator/views/template/lang/en_US.ts
  50. 37
      src/modules/codeGenerator/views/template/lang/zh_CN.ts
  51. 42
      src/modules/system/views/accessSecret/SysAuthAccessSecretListView.api.ts
  52. 186
      src/modules/system/views/accessSecret/SysAuthAccessSecretListView.config.ts
  53. 98
      src/modules/system/views/accessSecret/SysAuthAccessSecretListView.vue
  54. 28
      src/modules/system/views/accessSecret/lang/zh_CN.ts
  55. 27
      src/utils/http/axios/Axios.ts
  56. 16
      src/utils/http/axios/index.ts

1
src/components/SmartTable/index.ts

@ -16,3 +16,4 @@ export * from './src/types/SmartTableColumnType';
export * from './src/types/SmartTableAuthType';
export * from './src/types/SmartTableToolbarConfigType';
export * from './src/utils/TableCommon';
export * from './src/hooks/useVxeTableSortable';

40
src/components/SmartTable/src/hooks/useVxeTableSortable.ts

@ -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,
};
};

64
src/modules/codeGenerator/components/template/TemplateGroup.vue

@ -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>

8
src/modules/codeGenerator/constants/Constants.ts

@ -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',
};

13
src/modules/codeGenerator/constants/DatabaseConstants.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',
},
};

11
src/modules/codeGenerator/router/CodeBasicRouter.ts

@ -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,
};

11
src/modules/codeGenerator/views/codeCreate/CodeCreateSupport.ts

@ -0,0 +1,11 @@
/**
*
*/
export const extensionLanguageMap: any = {
'text/x-java': 'java',
xml: 'xml',
javascript: 'js',
html: 'html',
'text/x-vue': 'vue',
typescript: 'ts',
};

63
src/modules/codeGenerator/views/codeCreate/CodeCreateView.vue

@ -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>

80
src/modules/codeGenerator/views/codeCreate/CodeCreateViewOld.vue

@ -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>

30
src/modules/codeGenerator/views/codeDesign/CodeDesignPage.api.ts

@ -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,
});
};

330
src/modules/codeGenerator/views/codeDesign/CodeDesignPage.config.ts

@ -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',
},
];

250
src/modules/codeGenerator/views/codeDesign/CodeDesignPage.vue

@ -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>

142
src/modules/codeGenerator/views/codeDesign/CodeDesignPageHook.ts

@ -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,
};
};

54
src/modules/codeGenerator/views/codeDesign/componenets/DatabaseSelect/DatabaseSelect.vue

@ -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>

210
src/modules/codeGenerator/views/codeDesign/componenets/PageAddendumTableChoseModal.vue

@ -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>

222
src/modules/codeGenerator/views/codeDesign/componenets/PageFromSetting/FormRuleSetModal.vue

@ -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>

362
src/modules/codeGenerator/views/codeDesign/componenets/PageFromSetting/PageFormSetting.vue

@ -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>

380
src/modules/codeGenerator/views/codeDesign/componenets/PageSearchSetting/PageSearchSetting.vue

@ -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>

174
src/modules/codeGenerator/views/codeDesign/componenets/PageSettingSupport.ts

@ -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,
};
};

331
src/modules/codeGenerator/views/codeDesign/componenets/PageTableSetting/PageTableSetting.vue

@ -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>

107
src/modules/codeGenerator/views/codeDesign/componenets/TableFieldTable/TableFieldTable.vue

@ -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>

20
src/modules/codeGenerator/views/codeDesign/lang/en_US.ts

@ -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',
},
},
},
};

20
src/modules/codeGenerator/views/codeDesign/lang/zh_CN.ts

@ -0,0 +1,20 @@
export default {
trans: true,
key: 'generator.views.design',
data: {
title: {
controlList: {
dataDict: '数据字典',
categoryDict: '分类字典',
},
colNum: {
zero: '单行',
},
},
formSetting: {
title: {
tableName: '实体类名',
},
},
},
};

16
src/modules/codeGenerator/views/codeList/CodeListView.api.ts

@ -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),
});

136
src/modules/codeGenerator/views/codeList/CodeListView.config.tsx

@ -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),
};
}),
},
},
];
};

175
src/modules/codeGenerator/views/codeList/CodeListView.vue

@ -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>

187
src/modules/codeGenerator/views/codeList/components/CodeCreateForm.vue

@ -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>

147
src/modules/codeGenerator/views/codeList/components/CodeCreateModal.vue

@ -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>

9
src/modules/codeGenerator/views/codeList/components/CodeListAddEditModal.vue

@ -0,0 +1,9 @@
<template>
<BasicModal />
</template>
<script lang="ts" setup>
import BasicModal from '@/components/Modal/src/BasicModal.vue';
</script>
<style scoped></style>

150
src/modules/codeGenerator/views/codeList/components/TemplateSelectTable.vue

@ -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>

55
src/modules/codeGenerator/views/codeList/hooks/useLoadDbData.ts

@ -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,
};
};

166
src/modules/codeGenerator/views/codeList/lang/en_US.ts

@ -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}',
},
},
},
},
};

167
src/modules/codeGenerator/views/codeList/lang/zh_CN.ts

@ -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}',
},
},
},
},
};

19
src/modules/codeGenerator/views/database/DatabaseListHooks.ts

@ -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);
}
};

70
src/modules/codeGenerator/views/database/DatabaseListView.api.ts

@ -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}`;
};

203
src/modules/codeGenerator/views/database/DatabaseListView.data.ts

@ -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: '',
},
];
};

172
src/modules/codeGenerator/views/database/DatabaseListView.vue

@ -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>

77
src/modules/codeGenerator/views/database/components/DatabaseListViewAddEditModal.vue

@ -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>

84
src/modules/codeGenerator/views/database/components/TemplateSelected.vue

@ -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>

97
src/modules/codeGenerator/views/database/components/TemplateSelectedModal.vue

@ -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>

40
src/modules/codeGenerator/views/database/lang/en_US.ts

@ -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',
},
},
},
},
};

40
src/modules/codeGenerator/views/database/lang/zh_CN.ts

@ -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: '数据库连接失败',
},
},
},
},
};

85
src/modules/codeGenerator/views/document/TemplateDataDocumentView.vue

@ -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>

39
src/modules/codeGenerator/views/template/CodeTemplateList.api.ts

@ -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,
});
};

160
src/modules/codeGenerator/views/template/CodeTemplateList.config.ts

@ -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,
},
];
};

180
src/modules/codeGenerator/views/template/CodeTemplateList.vue

@ -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>

248
src/modules/codeGenerator/views/template/components/TemplateGroup.vue

@ -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 />-->
<!-- &nbsp;&nbsp;{{ $t('common.button.edit') }}-->
<!-- </a-menu-item>-->
<!-- <a-menu-item key="delete">-->
<!-- <DeleteOutlined />-->
<!-- &nbsp;&nbsp;{{ $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>

171
src/modules/codeGenerator/views/template/components/TemplateSetUserGroup.vue

@ -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>

37
src/modules/codeGenerator/views/template/lang/en_US.ts

@ -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',
},
},
},
},
};

37
src/modules/codeGenerator/views/template/lang/zh_CN.ts

@ -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: '请输入模板分组',
},
},
},
},
};

42
src/modules/system/views/accessSecret/SysAuthAccessSecretListView.api.ts

@ -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,
});
};

186
src/modules/system/views/accessSecret/SysAuthAccessSecretListView.config.ts

@ -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,
},
],
},
},
];
};

98
src/modules/system/views/accessSecret/SysAuthAccessSecretListView.vue

@ -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>

28
src/modules/system/views/accessSecret/lang/zh_CN.ts

@ -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',
},
},
};

27
src/utils/http/axios/Axios.ts

@ -1,5 +1,11 @@
import type { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios';
import type { SmartAxiosRequestConfig, RequestOptions, Result, UploadFileParams } from '#/axios';
import type {
SmartAxiosRequestConfig,
RequestOptions,
Result,
UploadFileParams,
UploadFileItemParams,
} from '#/axios';
import type { CreateAxiosOptions } from './axiosTransform';
import axios from 'axios';
import qs from 'qs';
@ -9,6 +15,7 @@ import { cloneDeep } from 'lodash-es';
import { ContentTypeEnum, RequestEnum } from '@/enums/httpEnum';
import { useGlobSetting } from '@/hooks/setting';
import { downloadByData } from '@/utils/file/download';
import { isArray } from 'xe-utils';
export * from './axiosTransform';
@ -124,13 +131,23 @@ export class VAxios {
*/
uploadFile<T = any>(config: SmartAxiosRequestConfig, params: UploadFileParams) {
const formData = new window.FormData();
const customFilename = params.name || 'file';
// const customFilename = params.name || 'file';
if (params.filename) {
formData.append(customFilename, params.file, params.filename);
const file = params.file;
let uploadFileList: UploadFileItemParams[];
if (isArray(file)) {
uploadFileList = file;
} else {
formData.append(customFilename, params.file);
uploadFileList = [file];
}
uploadFileList.forEach((item) => {
const customFilename = item.name || 'file';
if (item.filename) {
formData.append(customFilename, item.file, item.filename);
} else {
formData.append(customFilename, item.file);
}
});
if (params.data) {
Object.keys(params.data).forEach((key) => {

16
src/utils/http/axios/index.ts

@ -104,8 +104,22 @@ const transform: AxiosTransform = {
config.url = `${urlPrefix}${config.url}`;
}
// 处理URL
const { isStandalone } = useGlobSetting();
if (!isStandalone) {
let spi = '';
if (!config.url?.startsWith('/')) {
spi = '/';
}
config.url = `${config.service}${spi}${config.url}`;
}
if (apiUrl && isString(apiUrl)) {
config.url = `${apiUrl}${config.url}`;
let spi = '';
if (!config.url?.startsWith('/')) {
spi = '/';
}
config.url = `${apiUrl}${spi}${config.url}`;
}
const params = config.params || {};
const data = config.data || false;

Loading…
Cancel
Save