refactor: 代码生成生成信息表单

pull/69/head
puhui999 2025-04-09 12:21:14 +08:00
parent 10baedfc07
commit 54152d65f2
4 changed files with 571 additions and 479 deletions

View File

@ -9,14 +9,14 @@
// 全局通用状态枚举
export const CommonStatusEnum = {
ENABLE: 0, // 开启
DISABLE: 1 // 禁用
}
DISABLE: 1, // 禁用
};
// 全局用户类型枚举
export const UserTypeEnum = {
MEMBER: 1, // 会员
ADMIN: 2 // 管理员
}
ADMIN: 2, // 管理员
};
// ========== SYSTEM 模块 ==========
/**
@ -25,16 +25,16 @@ export const UserTypeEnum = {
export const SystemMenuTypeEnum = {
DIR: 1, // 目录
MENU: 2, // 菜单
BUTTON: 3 // 按钮
}
BUTTON: 3, // 按钮
};
/**
*
*/
export const SystemRoleTypeEnum = {
SYSTEM: 1, // 内置角色
CUSTOM: 2 // 自定义角色
}
CUSTOM: 2, // 自定义角色
};
/**
*
@ -44,8 +44,8 @@ export const SystemDataScopeEnum = {
DEPT_CUSTOM: 2, // 指定部门数据权限
DEPT_ONLY: 3, // 部门数据权限
DEPT_AND_CHILD: 4, // 部门及以下数据权限
DEPT_SELF: 5 // 仅本人数据权限
}
DEPT_SELF: 5, // 仅本人数据权限
};
/**
*
@ -55,15 +55,15 @@ export const SystemUserSocialTypeEnum = {
title: '钉钉',
type: 20,
source: 'dingtalk',
img: 'https://s1.ax1x.com/2022/05/22/OzMDRs.png'
img: 'https://s1.ax1x.com/2022/05/22/OzMDRs.png',
},
WECHAT_ENTERPRISE: {
title: '企业微信',
type: 30,
source: 'wechat_enterprise',
img: 'https://s1.ax1x.com/2022/05/22/OzMrzn.png'
}
}
img: 'https://s1.ax1x.com/2022/05/22/OzMrzn.png',
},
};
// ========== INFRA 模块 ==========
/**
@ -72,8 +72,8 @@ export const SystemUserSocialTypeEnum = {
export const InfraCodegenTemplateTypeEnum = {
CRUD: 1, // 基础 CRUD
TREE: 2, // 树形 CRUD
SUB: 3 // 主子表 CRUD
}
SUB: 15, // 主子表 CRUD
};
/**
*
@ -81,8 +81,8 @@ export const InfraCodegenTemplateTypeEnum = {
export const InfraJobStatusEnum = {
INIT: 0, // 初始化中
NORMAL: 1, // 运行中
STOP: 2 // 暂停运行
}
STOP: 2, // 暂停运行
};
/**
* API
@ -90,8 +90,8 @@ export const InfraJobStatusEnum = {
export const InfraApiErrorLogProcessStatusEnum = {
INIT: 0, // 未处理
DONE: 1, // 已处理
IGNORE: 2 // 已忽略
}
IGNORE: 2, // 已忽略
};
// ========== PAY 模块 ==========
/**
@ -100,78 +100,78 @@ export const InfraApiErrorLogProcessStatusEnum = {
export const PayChannelEnum = {
WX_PUB: {
code: 'wx_pub',
name: '微信 JSAPI 支付'
name: '微信 JSAPI 支付',
},
WX_LITE: {
code: 'wx_lite',
name: '微信小程序支付'
name: '微信小程序支付',
},
WX_APP: {
code: 'wx_app',
name: '微信 APP 支付'
name: '微信 APP 支付',
},
WX_NATIVE: {
code: 'wx_native',
name: '微信 Native 支付'
name: '微信 Native 支付',
},
WX_WAP: {
code: 'wx_wap',
name: '微信 WAP 网站支付'
name: '微信 WAP 网站支付',
},
WX_BAR: {
code: 'wx_bar',
name: '微信条码支付'
name: '微信条码支付',
},
ALIPAY_PC: {
code: 'alipay_pc',
name: '支付宝 PC 网站支付'
name: '支付宝 PC 网站支付',
},
ALIPAY_WAP: {
code: 'alipay_wap',
name: '支付宝 WAP 网站支付'
name: '支付宝 WAP 网站支付',
},
ALIPAY_APP: {
code: 'alipay_app',
name: '支付宝 APP 支付'
name: '支付宝 APP 支付',
},
ALIPAY_QR: {
code: 'alipay_qr',
name: '支付宝扫码支付'
name: '支付宝扫码支付',
},
ALIPAY_BAR: {
code: 'alipay_bar',
name: '支付宝条码支付'
name: '支付宝条码支付',
},
WALLET: {
code: 'wallet',
name: '钱包支付'
name: '钱包支付',
},
MOCK: {
code: 'mock',
name: '模拟支付'
}
}
name: '模拟支付',
},
};
/**
*
*/
export const PayDisplayModeEnum = {
URL: {
mode: 'url'
mode: 'url',
},
IFRAME: {
mode: 'iframe'
mode: 'iframe',
},
FORM: {
mode: 'form'
mode: 'form',
},
QR_CODE: {
mode: 'qr_code'
mode: 'qr_code',
},
APP: {
mode: 'app'
}
}
mode: 'app',
},
};
/**
*
@ -179,8 +179,8 @@ export const PayDisplayModeEnum = {
export const PayType = {
WECHAT: 'WECHAT',
ALIPAY: 'ALIPAY',
MOCK: 'MOCK'
}
MOCK: 'MOCK',
};
/**
*
@ -188,17 +188,17 @@ export const PayType = {
export const PayOrderStatusEnum = {
WAITING: {
status: 0,
name: '未支付'
name: '未支付',
},
SUCCESS: {
status: 10,
name: '已支付'
name: '已支付',
},
CLOSED: {
status: 20,
name: '未支付'
}
}
name: '未支付',
},
};
// ========== MALL - 商品模块 ==========
/**
@ -207,17 +207,17 @@ export const PayOrderStatusEnum = {
export const ProductSpuStatusEnum = {
RECYCLE: {
status: -1,
name: '回收站'
name: '回收站',
},
DISABLE: {
status: 0,
name: '下架'
name: '下架',
},
ENABLE: {
status: 1,
name: '上架'
}
}
name: '上架',
},
};
// ========== MALL - 营销模块 ==========
/**
@ -226,13 +226,13 @@ export const ProductSpuStatusEnum = {
export const CouponTemplateValidityTypeEnum = {
DATE: {
type: 1,
name: '固定日期可用'
name: '固定日期可用',
},
TERM: {
type: 2,
name: '领取之后可用'
}
}
name: '领取之后可用',
},
};
/**
*
@ -240,17 +240,17 @@ export const CouponTemplateValidityTypeEnum = {
export const CouponTemplateTakeTypeEnum = {
USER: {
type: 1,
name: '直接领取'
name: '直接领取',
},
ADMIN: {
type: 2,
name: '指定发放'
name: '指定发放',
},
REGISTER: {
type: 3,
name: '新人券'
}
}
name: '新人券',
},
};
/**
*
@ -258,17 +258,17 @@ export const CouponTemplateTakeTypeEnum = {
export const PromotionProductScopeEnum = {
ALL: {
scope: 1,
name: '通用劵'
name: '通用劵',
},
SPU: {
scope: 2,
name: '商品劵'
name: '商品劵',
},
CATEGORY: {
scope: 3,
name: '品类劵'
}
}
name: '品类劵',
},
};
/**
*
@ -276,13 +276,13 @@ export const PromotionProductScopeEnum = {
export const PromotionConditionTypeEnum = {
PRICE: {
type: 10,
name: '满 N 元'
name: '满 N 元',
},
COUNT: {
type: 20,
name: '满 N 件'
}
}
name: '满 N 件',
},
};
/**
*
@ -290,13 +290,13 @@ export const PromotionConditionTypeEnum = {
export const PromotionDiscountTypeEnum = {
PRICE: {
type: 1,
name: '满减'
name: '满减',
},
PERCENT: {
type: 2,
name: '折扣'
}
}
name: '折扣',
},
};
// ========== MALL - 交易模块 ==========
/**
@ -305,89 +305,89 @@ export const PromotionDiscountTypeEnum = {
export const BrokerageBindModeEnum = {
ANYTIME: {
mode: 1,
name: '首次绑定'
name: '首次绑定',
},
REGISTER: {
mode: 2,
name: '注册绑定'
name: '注册绑定',
},
OVERRIDE: {
mode: 3,
name: '覆盖绑定'
}
}
name: '覆盖绑定',
},
};
/**
*
*/
export const BrokerageEnabledConditionEnum = {
ALL: {
condition: 1,
name: '人人分销'
name: '人人分销',
},
ADMIN: {
condition: 2,
name: '指定分销'
}
}
name: '指定分销',
},
};
/**
*
*/
export const BrokerageRecordBizTypeEnum = {
ORDER: {
type: 1,
name: '获得推广佣金'
name: '获得推广佣金',
},
WITHDRAW: {
type: 2,
name: '提现申请'
}
}
name: '提现申请',
},
};
/**
*
*/
export const BrokerageWithdrawStatusEnum = {
AUDITING: {
status: 0,
name: '审核中'
name: '审核中',
},
AUDIT_SUCCESS: {
status: 10,
name: '审核通过'
name: '审核通过',
},
AUDIT_FAIL: {
status: 20,
name: '审核不通过'
name: '审核不通过',
},
WITHDRAW_SUCCESS: {
status: 11,
name: '提现成功'
name: '提现成功',
},
WITHDRAW_FAIL: {
status: 21,
name: '提现失败'
}
}
name: '提现失败',
},
};
/**
*
*/
export const BrokerageWithdrawTypeEnum = {
WALLET: {
type: 1,
name: '钱包'
name: '钱包',
},
BANK: {
type: 2,
name: '银行卡'
name: '银行卡',
},
WECHAT: {
type: 3,
name: '微信'
name: '微信',
},
ALIPAY: {
type: 4,
name: '支付宝'
}
}
name: '支付宝',
},
};
/**
*
@ -395,38 +395,38 @@ export const BrokerageWithdrawTypeEnum = {
export const DeliveryTypeEnum = {
EXPRESS: {
type: 1,
name: '快递发货'
name: '快递发货',
},
PICK_UP: {
type: 2,
name: '到店自提'
}
}
name: '到店自提',
},
};
/**
* -
*/
export const TradeOrderStatusEnum = {
UNPAID: {
status: 0,
name: '待支付'
name: '待支付',
},
UNDELIVERED: {
status: 10,
name: '待发货'
name: '待发货',
},
DELIVERED: {
status: 20,
name: '已发货'
name: '已发货',
},
COMPLETED: {
status: 30,
name: '已完成'
name: '已完成',
},
CANCELED: {
status: 40,
name: '已取消'
}
}
name: '已取消',
},
};
// ========== ERP - 企业资源计划 ==========
@ -436,31 +436,31 @@ export const ErpBizType = {
PURCHASE_RETURN: 12,
SALE_ORDER: 20,
SALE_OUT: 21,
SALE_RETURN: 22
}
SALE_RETURN: 22,
};
// ========== BPM 模块 ==========
export const BpmModelType = {
BPMN: 10, // BPMN 设计器
SIMPLE: 20 // 简易设计器
}
SIMPLE: 20, // 简易设计器
};
export const BpmModelFormType = {
NORMAL: 10, // 流程表单
CUSTOM: 20 // 业务表单
}
CUSTOM: 20, // 业务表单
};
export const BpmProcessInstanceStatus = {
NOT_START: -1, // 未开始
RUNNING: 1, // 审批中
APPROVE: 2, // 审批通过
REJECT: 3, // 审批不通过
CANCEL: 4 // 已取消
}
CANCEL: 4, // 已取消
};
export const BpmAutoApproveType = {
NONE: 0, // 不自动通过
APPROVE_ALL: 1, // 仅审批一次,后续重复的审批节点均自动通过
APPROVE_SEQUENT: 2, // 仅针对连续审批的节点自动通过
}
};

View File

@ -1,357 +0,0 @@
<script lang="ts" setup>
import type { InfraCodegenApi } from '#/api/infra/codegen';
import type { SystemMenuApi } from '#/api/system/menu';
import { CircleHelp } from '@vben/icons';
import { Col, Divider, Form, FormItem, Input, Row, Select, SelectOption, Tooltip, TreeSelect } from 'ant-design-vue';
import { getCodegenTableList } from '#/api/infra/codegen';
import { getSimpleMenusList } from '#/api/system/menu';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { onMounted, ref, unref, watch } from 'vue';
defineOptions({ name: 'InfraCodegenGenerateInfoForm' });
const props = defineProps<Props>();
interface Props {
columns?: InfraCodegenApi.CodegenColumn[];
table?: InfraCodegenApi.CodegenTable;
}
const formRef = ref();
const formData = ref<InfraCodegenApi.CodegenTable>({} as InfraCodegenApi.CodegenTable);
const subColumns = ref<InfraCodegenApi.CodegenColumn[]>([]);
const tables = ref<InfraCodegenApi.CodegenTable[]>([]);
const menus = ref<SystemMenuApi.SystemMenu[]>([]);
/** 菜单树选项 */
const menuTreeProps = {
value: 'id',
title: 'name',
children: 'children',
};
const rules = {
templateType: [{ required: true, message: '生成模板不能为空', trigger: 'blur' }],
frontType: [{ required: true, message: '前端类型不能为空', trigger: 'blur' }],
scene: [{ required: true, message: '生成场景不能为空', trigger: 'blur' }],
moduleName: [{ required: true, message: '模块名不能为空', trigger: 'blur' }],
businessName: [{ required: true, message: '业务名不能为空', trigger: 'blur' }],
className: [{ required: true, message: '类名称不能为空', trigger: 'blur' }],
classComment: [{ required: true, message: '类描述不能为空', trigger: 'blur' }],
};
/** 监听 table 属性,复制给 formData 属性 */
watch(
() => props.table,
(table) => {
if (!table) return;
formData.value = { ...table };
},
{
deep: true,
immediate: true,
},
);
/** 子表名称选中 */
async function subTableNameSelected(value) {
// 使ID
const subTableColumns = await getSubCodegenColumns(formData.value.dataSourceConfigId, value);
subColumns.value = subTableColumns;
//
formData.value.subTableFkColumnId = undefined;
formData.value.mainTableFKColumnId = undefined;
}
/** 获取子表的列 */
async function getSubCodegenColumns(dataSourceConfigId: number, tableName: string) {
const tableList = await getCodegenTableList(dataSourceConfigId);
const subTable = tableList.find((item) => item.tableName === tableName);
if (subTable) {
// API
//
return [];
}
return [];
}
/** 初始化 */
onMounted(async () => {
//
menus.value = await getSimpleMenusList();
//
tables.value = await getCodegenTableList(formData.value.dataSourceConfigId);
});
/** 暴露方法 */
defineExpose({
validate: async () => {
try {
await unref(formRef).validate();
return true;
} catch {
return false;
}
},
});
</script>
<template>
<Form ref="formRef" :model="formData" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<Row :gutter="16">
<Col :span="12">
<FormItem label="生成模板" name="templateType">
<Select v-model:value="formData.templateType">
<SelectOption
v-for="dict in getDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE, 'number')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</SelectOption>
</Select>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="前端类型" name="frontType">
<Select v-model:value="formData.frontType">
<SelectOption
v-for="dict in getDictOptions(DICT_TYPE.INFRA_CODEGEN_FRONT_TYPE, 'number')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</SelectOption>
</Select>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="生成场景" name="scene">
<Select v-model:value="formData.scene">
<SelectOption
v-for="dict in getDictOptions(DICT_TYPE.INFRA_CODEGEN_SCENE, 'number')"
:key="dict.value"
:value="dict.value"
>
{{ dict.label }}
</SelectOption>
</Select>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="上级菜单">
<Tooltip placement="top">
<template #title>分配到指定菜单下例如 系统管理</template>
<template #default>
<TreeSelect
v-model:value="formData.parentMenuId"
:tree-data="menus"
:field-names="menuTreeProps"
show-search
tree-node-filter-prop="title"
:tree-checkable="false"
:tree-default-expand-all="false"
placeholder="请选择系统菜单"
style="width: 100%"
/>
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="模块名" name="moduleName">
<Tooltip placement="top">
<template #title>模块名即一级目录例如 systeminfratool 等等</template>
<template #default>
<Input v-model:value="formData.moduleName" />
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="业务名" name="businessName">
<Tooltip placement="top">
<template #title>业务名即二级目录例如 userpermissiondict 等等</template>
<template #default>
<Input v-model:value="formData.businessName" />
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="类名称" name="className">
<Tooltip placement="top">
<template #title>类名称首字母大写例如SysUserSysMenuSysDictData 等等</template>
<template #default>
<Input v-model:value="formData.className" />
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="类描述" name="classComment">
<Tooltip placement="top">
<template #title>用作类描述例如 用户</template>
<template #default>
<Input v-model:value="formData.classComment" />
</template>
</Tooltip>
</FormItem>
</Col>
</Row>
<!-- 树表信息 -->
<template v-if="formData.templateType === 2">
<Divider>树表信息</Divider>
<Row :gutter="16">
<Col :span="12">
<FormItem label="父编号字段" name="treeParentColumnId">
<Tooltip placement="top">
<template #title>树显示的父编码字段名 parent_Id</template>
<template #icon><CircleHelp /></template>
<template #default>
<Select v-model:value="formData.treeParentColumnId" placeholder="请选择" allow-clear>
<SelectOption v-for="column in columns" :key="column.id" :value="column.id">
{{ column.columnName }}
</SelectOption>
</Select>
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="名称字段" name="treeNameColumnId">
<Tooltip placement="top">
<template #title>树节点显示的名称字段一般是name</template>
<template #icon><CircleHelp /></template>
<template #default>
<Select v-model:value="formData.treeNameColumnId" placeholder="请选择" allow-clear>
<SelectOption v-for="column in columns" :key="column.id" :value="column.id">
{{ column.columnName }}
</SelectOption>
</Select>
</template>
</Tooltip>
</FormItem>
</Col>
</Row>
</template>
<!-- 主子表信息 -->
<template v-if="formData.templateType === 3">
<Divider>主子表信息</Divider>
<Row :gutter="16">
<Col :span="24">
<FormItem label="关联子表的成员变量名" name="subJoinColumnId">
<Tooltip placement="top">
<template #title>子表的成员变量名默认为子表的名称</template>
<template #icon><CircleHelp /></template>
<template #default>
<Input v-model:value="formData.subJoinColumnId" placeholder="请输入" />
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="子表的表名" name="subTableName">
<Tooltip placement="top">
<template #title>关联的子表的表名 sys_user_post</template>
<template #icon><CircleHelp /></template>
<template #default>
<Select
v-model:value="formData.subTableName"
placeholder="请选择"
allow-clear
@change="subTableNameSelected"
>
<SelectOption v-for="table in tables" :key="table.tableName" :value="table.tableName">
{{ `${table.tableName}${table.tableComment}` }}
</SelectOption>
</Select>
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="子表的类名" name="subTableClassName">
<Tooltip placement="top">
<template #title>子表的类名 SysUserPost</template>
<template #icon><CircleHelp /></template>
<template #default>
<Input v-model:value="formData.subTableClassName" placeholder="请输入" />
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="子表的外键字段" name="subTableFkColumnId">
<Tooltip placement="top">
<template #title>子表的外键字段的编号对应主表的主键</template>
<template #icon><CircleHelp /></template>
<template #default>
<Select v-model:value="formData.subTableFkColumnId" placeholder="请选择" allow-clear>
<SelectOption v-for="column in subColumns" :key="column.id" :value="column.id">
{{ column.columnName }}
</SelectOption>
</Select>
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="主表的类名" name="mainTableClassName">
<Tooltip placement="top">
<template #title>主表的类名 SysUser</template>
<template #icon><CircleHelp /></template>
<template #default>
<Input v-model:value="formData.mainTableClassName" placeholder="请输入" />
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="主表的外键字段" name="mainTableFKColumnId">
<Tooltip placement="top">
<template #title>子表的外键关联到主表的主键字段编号</template>
<template #icon><CircleHelp /></template>
<template #default>
<Select v-model:value="formData.mainTableFKColumnId" placeholder="请选择" allow-clear>
<SelectOption v-for="column in columns" :key="column.id" :value="column.id">
{{ column.columnName }}
</SelectOption>
</Select>
</template>
</Tooltip>
</FormItem>
</Col>
<Col :span="12">
<FormItem label="子表的类描述" name="subTableClassComment">
<Tooltip placement="top">
<template #title>子表的描述例如 用户岗位</template>
<template #icon><CircleHelp /></template>
<template #default>
<Input v-model:value="formData.subTableClassComment" placeholder="请输入" />
</template>
</Tooltip>
</FormItem>
</Col>
</Row>
</template>
</Form>
</template>
<style scoped>
.form-header {
padding-left: 8px;
margin-bottom: 16px;
font-size: 16px;
border-left: 3px solid #1890ff;
}
</style>

View File

@ -2,8 +2,11 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
import type { InfraCodegenApi } from '#/api/infra/codegen';
import type { InfraDataSourceConfigApi } from '#/api/infra/data-source-config';
import type { SystemMenuApi } from '#/api/system/menu';
import { z } from '#/adapter/form';
import { getRangePickerDefaultProps } from '#/utils/date';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { useAccess } from '@vben/access';
@ -102,6 +105,245 @@ export function useBasicInfoFormSchema(): VbenFormSchema[] {
];
}
/** 生成信息表单基础 schema */
export function useGenerationInfoBaseFormSchema(menus: SystemMenuApi.SystemMenu[]): VbenFormSchema[] {
/** 菜单树选项 */
const menuTreeProps = {
value: 'id',
title: 'name',
children: 'children',
};
return [
{
component: 'Select',
fieldName: 'templateType',
label: '生成模板',
componentProps: {
class: 'w-full',
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE, 'number'),
},
rules: z.number().min(1, { message: '生成模板不能为空' }),
},
{
component: 'Select',
fieldName: 'frontType',
label: '前端类型',
componentProps: {
class: 'w-full',
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_FRONT_TYPE, 'number'),
},
rules: z.number().min(1, { message: '前端类型不能为空' }),
},
{
component: 'Select',
fieldName: 'scene',
label: '生成场景',
componentProps: {
class: 'w-full',
options: getDictOptions(DICT_TYPE.INFRA_CODEGEN_SCENE, 'number'),
},
rules: z.number().min(1, { message: '生成场景不能为空' }),
},
{
component: 'TreeSelect',
fieldName: 'parentMenuId',
label: '上级菜单',
help: '分配到指定菜单下,例如 系统管理',
componentProps: {
class: 'w-full',
showSearch: true,
treeData: menus,
fieldNames: menuTreeProps,
treeNodeFilterProp: 'title',
treeDefaultExpandAll: false,
treeCheckable: false,
placeholder: '请选择系统菜单',
},
},
{
component: 'Input',
fieldName: 'moduleName',
label: '模块名',
help: '模块名,即一级目录,例如 system、infra、tool 等等',
rules: z.string().min(1, { message: '模块名不能为空' }),
},
{
component: 'Input',
fieldName: 'businessName',
label: '业务名',
help: '业务名,即二级目录,例如 user、permission、dict 等等',
rules: z.string().min(1, { message: '业务名不能为空' }),
},
{
component: 'Input',
fieldName: 'className',
label: '类名称',
help: '类名称首字母大写例如SysUser、SysMenu、SysDictData 等等',
rules: z.string().min(1, { message: '类名称不能为空' }),
},
{
component: 'Input',
fieldName: 'classComment',
label: '类描述',
help: '用作类描述,例如 用户',
rules: z.string().min(1, { message: '类描述不能为空' }),
},
];
}
/** 树表信息 schema */
export function useTreeTableFormSchema(columns: InfraCodegenApi.CodegenColumn[] = []): VbenFormSchema[] {
return [
{
component: 'Divider',
fieldName: 'treeDivider',
label: '',
renderComponentContent: () => {
return {
default: () => ['树表信息'],
};
},
formItemClass: 'md:col-span-2',
},
{
component: 'Select',
fieldName: 'treeParentColumnId',
label: '父编号字段',
help: '树显示的父编码字段名, 如parent_Id',
componentProps: {
class: 'w-full',
allowClear: true,
placeholder: '请选择',
options: columns.map((column) => ({
label: column.columnName,
value: column.id,
})),
},
},
{
component: 'Select',
fieldName: 'treeNameColumnId',
label: '名称字段',
help: '树节点显示的名称字段一般是name',
componentProps: {
class: 'w-full',
allowClear: true,
placeholder: '请选择',
options: columns.map((column) => ({
label: column.columnName,
value: column.id,
})),
},
},
];
}
/** 主子表信息 schema */
export function useSubTableFormSchema(
columns: InfraCodegenApi.CodegenColumn[] = [],
tables: InfraCodegenApi.CodegenTable[] = [],
subColumns: InfraCodegenApi.CodegenColumn[] = [],
onSubTableNameSelected: (value: string) => void,
): VbenFormSchema[] {
return [
{
component: 'Divider',
fieldName: 'subDivider',
label: '',
renderComponentContent: () => {
return {
default: () => ['主子表信息'],
};
},
formItemClass: 'md:col-span-2',
},
{
component: 'Input',
fieldName: 'subJoinColumnId',
label: '关联子表的成员变量名',
help: '子表的成员变量名,默认为子表的名称',
componentProps: {
placeholder: '请输入',
},
formItemClass: 'md:col-span-2',
},
{
component: 'Select',
fieldName: 'subTableName',
label: '子表的表名',
help: '关联的子表的表名, 如sys_user_post',
componentProps: {
class: 'w-full',
allowClear: true,
placeholder: '请选择',
options: tables.map((table) => ({
label: `${table.tableName}${table.tableComment}`,
value: table.tableName,
})),
onChange: onSubTableNameSelected,
},
},
{
component: 'Input',
fieldName: 'subTableClassName',
label: '子表的类名',
help: '子表的类名, 如SysUserPost',
componentProps: {
placeholder: '请输入',
},
},
{
component: 'Select',
fieldName: 'subTableFkColumnId',
label: '子表的外键字段',
help: '子表的外键字段的编号,对应主表的主键',
componentProps: {
class: 'w-full',
allowClear: true,
placeholder: '请选择',
options: subColumns.map((column) => ({
label: column.columnName,
value: column.id,
})),
},
},
{
component: 'Input',
fieldName: 'mainTableClassName',
label: '主表的类名',
help: '主表的类名, 如SysUser',
componentProps: {
placeholder: '请输入',
},
},
{
component: 'Select',
fieldName: 'mainTableFKColumnId',
label: '主表的外键字段',
help: '子表的外键关联到主表的主键字段编号',
componentProps: {
class: 'w-full',
allowClear: true,
placeholder: '请选择',
options: columns.map((column) => ({
label: column.columnName,
value: column.id,
})),
},
},
{
component: 'Input',
fieldName: 'subTableClassComment',
label: '子表的类描述',
help: '子表的描述,例如 用户岗位',
componentProps: {
placeholder: '请输入',
},
},
];
}
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
return [

View File

@ -0,0 +1,207 @@
<script lang="ts" setup>
import type { InfraCodegenApi } from '#/api/infra/codegen';
import type { SystemMenuApi } from '#/api/system/menu';
import { useVbenForm } from '#/adapter/form';
import { getCodegenTableList } from '#/api/infra/codegen';
import { getSimpleMenusList } from '#/api/system/menu';
import { InfraCodegenTemplateTypeEnum } from '#/utils/constants';
import { computed, onMounted, ref, watch } from 'vue';
import { useGenerationInfoBaseFormSchema, useSubTableFormSchema, useTreeTableFormSchema } from '../data';
defineOptions({ name: 'InfraCodegenGenerateInfoForm' });
const props = defineProps<{
columns?: InfraCodegenApi.CodegenColumn[];
table?: InfraCodegenApi.CodegenTable;
}>();
const subColumns = ref<InfraCodegenApi.CodegenColumn[]>([]);
const tables = ref<InfraCodegenApi.CodegenTable[]>([]);
const menus = ref<SystemMenuApi.SystemMenu[]>([]);
const currentTemplateType = ref<number>();
const wrapperClass = 'grid grid-cols-1 md:grid-cols-2 gap-4 mb-4'; //
//
const isTreeTable = computed(() => currentTemplateType.value === InfraCodegenTemplateTypeEnum.TREE);
const isSubTable = computed(() => currentTemplateType.value === InfraCodegenTemplateTypeEnum.SUB);
/** 基础表单实例 */
const [BaseForm, baseFormApi] = useVbenForm({
wrapperClass,
layout: 'horizontal',
showDefaultActions: false,
schema: [],
handleValuesChange: (values) => {
//
if (values.templateType !== undefined && values.templateType !== currentTemplateType.value) {
currentTemplateType.value = values.templateType;
}
},
});
/** 树表信息表单实例 */
const [TreeForm, treeFormApi] = useVbenForm({
wrapperClass,
layout: 'horizontal',
showDefaultActions: false,
schema: [],
});
/** 主子表信息表单实例 */
const [SubForm, subFormApi] = useVbenForm({
wrapperClass,
layout: 'horizontal',
showDefaultActions: false,
schema: [],
});
/** 子表名称选中事件 */
async function subTableNameSelected(value: string): Promise<void> {
// 使ID
const subTableColumns = await getSubCodegenColumns(props.table?.dataSourceConfigId, value);
subColumns.value = subTableColumns;
//
await subFormApi.setFieldValue('subTableFkColumnId', undefined);
await subFormApi.setFieldValue('mainTableFKColumnId', undefined);
}
/** 获取子表的列 */
async function getSubCodegenColumns(
dataSourceConfigId: number | undefined,
tableName: string,
): Promise<InfraCodegenApi.CodegenColumn[]> {
if (!dataSourceConfigId || !tableName) return [];
const tableList = await getCodegenTableList(dataSourceConfigId);
const subTable = tableList.find((item) => item.tableName === tableName);
if (subTable) {
// API
//
return [];
}
return [];
}
/** 更新基础表单schema */
function updateBaseSchema(): void {
const schema = useGenerationInfoBaseFormSchema(menus.value);
baseFormApi.setState({ schema });
}
/** 更新树表信息表单schema */
function updateTreeSchema(): void {
const schema = useTreeTableFormSchema(props.columns);
treeFormApi.setState({ schema });
}
/** 更新主子表信息表单schema */
function updateSubSchema(): void {
const schema = useSubTableFormSchema(props.columns, tables.value, subColumns.value, subTableNameSelected);
subFormApi.setState({ schema });
}
/** 获取合并的表单值 */
async function getAllFormValues(): Promise<Record<string, any>> {
//
const baseValues = await baseFormApi.getValues();
//
let extraValues = {};
if (isTreeTable.value) {
extraValues = await treeFormApi.getValues();
} else if (isSubTable.value) {
extraValues = await subFormApi.getValues();
}
//
return { ...baseValues, ...extraValues };
}
/** 验证所有表单 */
async function validateAllForms() {
//
await baseFormApi.validate();
//
if (isTreeTable.value) {
await treeFormApi.validate();
} else if (isSubTable.value) {
await subFormApi.validate();
}
}
/** 设置表单值 */
function setAllFormValues(values: Record<string, any>): void {
if (!values) return;
//
currentTemplateType.value = values.templateType;
//
baseFormApi.setValues(values);
//
if (isTreeTable.value) {
treeFormApi.setValues(values);
} else if (isSubTable.value) {
subFormApi.setValues(values);
}
}
/** 监听表格数据变化 */
watch(
() => props.table,
(val) => {
if (!val) return;
// schema
updateBaseSchema();
updateTreeSchema();
updateSubSchema();
//
setAllFormValues(val);
},
{ immediate: true },
);
/** 初始化 */
onMounted(async () => {
//
menus.value = await getSimpleMenusList();
//
if (props.table?.dataSourceConfigId) {
tables.value = await getCodegenTableList(props.table.dataSourceConfigId);
}
// schema
updateBaseSchema();
updateTreeSchema();
updateSubSchema();
//
if (props.table) {
setAllFormValues(props.table);
}
});
/** 暴露出表单校验方法和表单值获取方法 */
defineExpose({
validate: validateAllForms,
getValues: getAllFormValues,
});
</script>
<template>
<div>
<!-- 基础表单 -->
<BaseForm />
<!-- 树表信息表单 -->
<TreeForm v-if="isTreeTable" />
<!-- 主子表信息表单 -->
<SubForm v-if="isSubTable" />
</div>
</template>