code review:vue2 主子表的生成

This commit is contained in:
YunaiV 2023-11-27 17:09:53 +08:00
parent 12bcee2a72
commit df51a678eb
6 changed files with 701 additions and 792 deletions

View File

@ -63,7 +63,7 @@ export function export${simpleClassName}Excel(params) {
responseType: 'blob' responseType: 'blob'
}) })
} }
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑 TODO @puhui999下面方法的【空格】不太对
#foreach ($subTable in $subTables) #foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1) #set ($index = $foreach.count - 1)
#set ($subSimpleClassName = $subSimpleClassNames.get($index)) #set ($subSimpleClassName = $subSimpleClassNames.get($index))

View File

@ -7,7 +7,7 @@
label-width="100px" label-width="100px"
v-loading="formLoading" v-loading="formLoading"
> >
#foreach($column in $columns) #foreach($column in $columns)
#if ($column.createOperation || $column.updateOperation) #if ($column.createOperation || $column.updateOperation)
#set ($dictType = $column.dictType) #set ($dictType = $column.dictType)
#set ($javaField = $column.javaField) #set ($javaField = $column.javaField)
@ -115,10 +115,10 @@
</el-form-item> </el-form-item>
#end #end
#end #end
#end #end
</el-form> </el-form>
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 ) #if ( $table.templateType == 10 || $table.templateType == 12 )
<!-- 子表的表单 --> <!-- 子表的表单 -->
<el-tabs v-model="subTabsName"> <el-tabs v-model="subTabsName">
#foreach ($subTable in $subTables) #foreach ($subTable in $subTables)
@ -131,7 +131,7 @@
</el-tab-pane> </el-tab-pane>
#end #end
</el-tabs> </el-tabs>
#end #end
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
<el-button @click="dialogVisible = false">取 消</el-button> <el-button @click="dialogVisible = false">取 消</el-button>
@ -139,28 +139,28 @@
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}' import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
import { defaultProps, handleTree } from '@/utils/tree' import { defaultProps, handleTree } from '@/utils/tree'
#end #end
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 ) #if ( $table.templateType == 10 || $table.templateType == 12 )
#foreach ($subSimpleClassName in $subSimpleClassNames) #foreach ($subSimpleClassName in $subSimpleClassNames)
import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue' import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue'
#end #end
#end #end
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示 const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题 const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用 const formLoading = ref(false) // 表单的加载中1修改时的数据加载2提交的按钮禁用
const formType = ref('') // 表单的类型create - 新增update - 修改 const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({ const formData = ref({
#foreach ($column in $columns) #foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation) #if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox") #if ($column.htmlType == "checkbox")
$column.javaField: [], $column.javaField: [],
@ -168,35 +168,35 @@
$column.javaField: undefined, $column.javaField: undefined,
#end #end
#end #end
#end #end
}) })
const formRules = reactive({ const formRules = reactive({
#foreach ($column in $columns) #foreach ($column in $columns)
#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键 #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
$column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }], $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
#end #end
#end #end
}) })
const formRef = ref() // 表单 Ref const formRef = ref() // 表单 Ref
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
const ${classNameVar}Tree = ref() // 树形结构 const ${classNameVar}Tree = ref() // 树形结构
#end #end
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 ) #if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 ) #if ( $subTables && $subTables.size() > 0 )
/** 子表的表单 */ /** 子表的表单 */
const subTabsName = ref('$subClassNameVars.get(0)') const subTabsName = ref('$subClassNameVars.get(0)')
#foreach ($subClassNameVar in $subClassNameVars) #foreach ($subClassNameVar in $subClassNameVars)
const ${subClassNameVar}FormRef = ref() const ${subClassNameVar}FormRef = ref()
#end #end
#end #end
#end #end
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (type: string, id?: number) => { const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
@ -210,21 +210,21 @@
formLoading.value = false formLoading.value = false
} }
} }
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
await get${simpleClassName}Tree() await get${simpleClassName}Tree()
#end #end
} }
defineExpose({ open }) // 提供 open 方法,用于打开弹窗 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => { const submitForm = async () => {
// 校验表单 // 校验表单
await formRef.value.validate() await formRef.value.validate()
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 ) #if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 ) #if ( $subTables && $subTables.size() > 0 )
// 校验子表单 // 校验子表单
#foreach ($subTable in $subTables) #foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1) #set ($index = $foreach.count - 1)
@ -236,23 +236,23 @@
return return
} }
#end #end
#end #end
#end #end
// 提交请求 // 提交请求
formLoading.value = true formLoading.value = true
try { try {
const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 10 || $table.templateType == 12 ) #if ( $table.templateType == 10 || $table.templateType == 12 )
#if ( $subTables && $subTables.size() > 0 ) #if ( $subTables && $subTables.size() > 0 )
// 拼接子表的数据 // 拼接子表的数据
#foreach ($subTable in $subTables) #foreach ($subTable in $subTables)
#set ($index = $foreach.count - 1) #set ($index = $foreach.count - 1)
#set ($subClassNameVar = $subClassNameVars.get($index)) #set ($subClassNameVar = $subClassNameVars.get($index))
data.${subClassNameVar}#if ( $subTable.subJoinMany)s#end = ${subClassNameVar}FormRef.value.getData() data.${subClassNameVar}#if ( $subTable.subJoinMany)s#end = ${subClassNameVar}FormRef.value.getData()
#end #end
#end #end
#end #end
if (formType.value === 'create') { if (formType.value === 'create') {
await ${simpleClassName}Api.create${simpleClassName}(data) await ${simpleClassName}Api.create${simpleClassName}(data)
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
@ -266,12 +266,12 @@
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
} }
/** 重置表单 */ /** 重置表单 */
const resetForm = () => { const resetForm = () => {
formData.value = { formData.value = {
#foreach ($column in $columns) #foreach ($column in $columns)
#if ($column.createOperation || $column.updateOperation) #if ($column.createOperation || $column.updateOperation)
#if ($column.htmlType == "checkbox") #if ($column.htmlType == "checkbox")
$column.javaField: [], $column.javaField: [],
@ -279,20 +279,20 @@
$column.javaField: undefined, $column.javaField: undefined,
#end #end
#end #end
#end #end
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
/** 获得${table.classComment}树 */ /** 获得${table.classComment}树 */
const get${simpleClassName}Tree = async () => { const get${simpleClassName}Tree = async () => {
${classNameVar}Tree.value = [] ${classNameVar}Tree.value = []
const data = await ${simpleClassName}Api.get${simpleClassName}List() const data = await ${simpleClassName}Api.get${simpleClassName}List()
const root: Tree = { id: 0, name: '顶级${table.classComment}', children: [] } const root: Tree = { id: 0, name: '顶级${table.classComment}', children: [] }
root.children = handleTree(data, 'id', '${treeParentColumn.javaField}') root.children = handleTree(data, 'id', '${treeParentColumn.javaField}')
${classNameVar}Tree.value.push(root) ${classNameVar}Tree.value.push(root)
} }
#end #end
</script> </script>

View File

@ -101,20 +101,20 @@
> >
<Icon icon="ep:download" class="mr-5px" /> 导出 <Icon icon="ep:download" class="mr-5px" /> 导出
</el-button> </el-button>
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
<el-button type="danger" plain @click="toggleExpandAll"> <el-button type="danger" plain @click="toggleExpandAll">
<Icon icon="ep:sort" class="mr-5px" /> 展开/折叠 <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
</el-button> </el-button>
#end #end
</el-form-item> </el-form-item>
</el-form> </el-form>
</ContentWrap> </ContentWrap>
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 ) #if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="list" :data="list"
@ -123,8 +123,8 @@
highlight-current-row highlight-current-row
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
> >
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#elseif ( $table.templateType == 2 ) #elseif ( $table.templateType == 2 )
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="list" :data="list"
@ -134,11 +134,11 @@
:default-expand-all="isExpandAll" :default-expand-all="isExpandAll"
v-if="refreshTable" v-if="refreshTable"
> >
#else #else
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
#end #end
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 ) #if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
<!-- 子表的列表 --> <!-- 子表的列表 -->
<el-table-column type="expand"> <el-table-column type="expand">
<template #default="scope"> <template #default="scope">
@ -155,7 +155,7 @@
</el-tabs> </el-tabs>
</template> </template>
</el-table-column> </el-table-column>
#end #end
#foreach($column in $columns) #foreach($column in $columns)
#if ($column.listOperationResult) #if ($column.listOperationResult)
#set ($dictType=$column.dictType) #set ($dictType=$column.dictType)
@ -202,8 +202,6 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
## 特殊:树表专属逻辑(树不需要分页)
#if ( $table.templateType != 2 )
<!-- 分页 --> <!-- 分页 -->
<Pagination <Pagination
:total="total" :total="total"
@ -211,13 +209,12 @@
v-model:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
@pagination="getList" @pagination="getList"
/> />
#end
</ContentWrap> </ContentWrap>
<!-- 表单弹窗:添加/修改 --> <!-- 表单弹窗:添加/修改 -->
<${simpleClassName}Form ref="formRef" @success="getList" /> <${simpleClassName}Form ref="formRef" @success="getList" />
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 ) #if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
<!-- 子表的列表 --> <!-- 子表的列表 -->
<ContentWrap> <ContentWrap>
<el-tabs model-value="$subClassNameVars.get(0)"> <el-tabs model-value="$subClassNameVars.get(0)">
@ -232,43 +229,43 @@
#end #end
</el-tabs> </el-tabs>
</ContentWrap> </ContentWrap>
#end #end
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
import { handleTree } from '@/utils/tree' import { handleTree } from '@/utils/tree'
#end #end
import download from '@/utils/download' import download from '@/utils/download'
import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}' import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
import ${simpleClassName}Form from './${simpleClassName}Form.vue' import ${simpleClassName}Form from './${simpleClassName}Form.vue'
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType != 10 ) #if ( $table.templateType != 10 )
#foreach ($subSimpleClassName in $subSimpleClassNames) #foreach ($subSimpleClassName in $subSimpleClassNames)
import ${subSimpleClassName}List from './components/${subSimpleClassName}List.vue' import ${subSimpleClassName}List from './components/${subSimpleClassName}List.vue'
#end #end
#end #end
defineOptions({ name: '${table.className}' }) defineOptions({ name: '${table.className}' })
const message = useMessage() // 消息弹窗 const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化 const { t } = useI18n() // 国际化
const loading = ref(true) // 列表的加载中 const loading = ref(true) // 列表的加载中
const list = ref([]) // 列表的数据 const list = ref([]) // 列表的数据
## 特殊:树表专属逻辑(树不需要分页接口) ## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 ) #if ( $table.templateType != 2 )
const total = ref(0) // 列表的总页数 const total = ref(0) // 列表的总页数
#end #end
const queryParams = reactive({ const queryParams = reactive({
## 特殊:树表专属逻辑(树不需要分页接口) ## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType != 2 ) #if ( $table.templateType != 2 )
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
#end #end
#foreach ($column in $columns) #foreach ($column in $columns)
#if ($column.listOperation) #if ($column.listOperation)
#if ($column.listOperationCondition != 'BETWEEN') #if ($column.listOperationCondition != 'BETWEEN')
@ -279,15 +276,15 @@
#end #end
#end #end
#end #end
}) })
const queryFormRef = ref() // 搜索的表单 const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中 const exportLoading = ref(false) // 导出的加载中
/** 查询列表 */ /** 查询列表 */
const getList = async () => { const getList = async () => {
loading.value = true loading.value = true
try { try {
## 特殊:树表专属逻辑(树不需要分页接口) ## 特殊:树表专属逻辑(树不需要分页接口)
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
const data = await ${simpleClassName}Api.get${simpleClassName}List(queryParams) const data = await ${simpleClassName}Api.get${simpleClassName}List(queryParams)
list.value = handleTree(data, 'id', '${treeParentColumn.javaField}') list.value = handleTree(data, 'id', '${treeParentColumn.javaField}')
@ -299,28 +296,28 @@
} finally { } finally {
loading.value = false loading.value = false
} }
} }
/** 搜索按钮操作 */ /** 搜索按钮操作 */
const handleQuery = () => { const handleQuery = () => {
queryParams.pageNo = 1 queryParams.pageNo = 1
getList() getList()
} }
/** 重置按钮操作 */ /** 重置按钮操作 */
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value.resetFields() queryFormRef.value.resetFields()
handleQuery() handleQuery()
} }
/** 添加/修改操作 */ /** 添加/修改操作 */
const formRef = ref() const formRef = ref()
const openForm = (type: string, id?: number) => { const openForm = (type: string, id?: number) => {
formRef.value.open(type, id) formRef.value.open(type, id)
} }
/** 删除按钮操作 */ /** 删除按钮操作 */
const handleDelete = async (id: number) => { const handleDelete = async (id: number) => {
try { try {
// 删除的二次确认 // 删除的二次确认
await message.delConfirm() await message.delConfirm()
@ -330,10 +327,10 @@
// 刷新列表 // 刷新列表
await getList() await getList()
} catch {} } catch {}
} }
/** 导出按钮操作 */ /** 导出按钮操作 */
const handleExport = async () => { const handleExport = async () => {
try { try {
// 导出的二次确认 // 导出的二次确认
await message.exportConfirm() await message.exportConfirm()
@ -345,32 +342,32 @@
} finally { } finally {
exportLoading.value = false exportLoading.value = false
} }
} }
## 特殊:主子表专属逻辑 ## 特殊:主子表专属逻辑
#if ( $table.templateType == 11 ) #if ( $table.templateType == 11 )
/** 选中行操作 */ /** 选中行操作 */
const currentRow = ref({}) // 选中行 const currentRow = ref({}) // 选中行
const handleCurrentChange = (row) => { const handleCurrentChange = (row) => {
currentRow.value = row currentRow.value = row
} }
#end #end
## 特殊:树表专属逻辑 ## 特殊:树表专属逻辑
#if ( $table.templateType == 2 ) #if ( $table.templateType == 2 )
/** 展开/折叠操作 */ /** 展开/折叠操作 */
const isExpandAll = ref(true) // 是否展开,默认全部展开 const isExpandAll = ref(true) // 是否展开,默认全部展开
const refreshTable = ref(true) // 重新渲染表格状态 const refreshTable = ref(true) // 重新渲染表格状态
const toggleExpandAll = async () => { const toggleExpandAll = async () => {
refreshTable.value = false refreshTable.value = false
isExpandAll.value = !isExpandAll.value isExpandAll.value = !isExpandAll.value
await nextTick() await nextTick()
refreshTable.value = true refreshTable.value = true
} }
#end #end
/** 初始化 **/ /** 初始化 **/
onMounted(() => { onMounted(() => {
getList() getList()
}) })
</script> </script>

View File

@ -10,33 +10,32 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.enums.codegen.*;
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import org.apache.ibatis.type.JdbcType;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Spy; import org.mockito.Spy;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
* {@link CodegenEngine} 的单元测试 * {@link CodegenEngine} 的单元测试抽象基类
* *
* @author 芋道源码 * @author 芋道源码
*/ */
public class CodegenEngineTest extends BaseMockitoUnitTest { public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest {
@InjectMocks @InjectMocks
private CodegenEngine codegenEngine; protected CodegenEngine codegenEngine;
@Spy @Spy
private CodegenProperties codegenProperties = new CodegenProperties() protected CodegenProperties codegenProperties = new CodegenProperties()
.setBasePackage("cn.iocoder.yudao"); .setBasePackage("cn.iocoder.yudao");
@BeforeEach @BeforeEach
@ -44,87 +43,12 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
codegenEngine.initGlobalBindingMap(); codegenEngine.initGlobalBindingMap();
} }
@Test protected static CodegenTableDO getTable(String name) {
public void testExecute_vue3_one() {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue3_one");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one");
}
@Test
public void testExecute_vue3_tree() {
// 准备参数
CodegenTableDO table = getTable("category")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(CodegenTemplateTypeEnum.TREE.getType());
List<CodegenColumnDO> columns = getColumnList("category");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue3_tree");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree");
// writeFile(result, "/Users/yunai/test/demo66.zip");
}
@Test
public void testExecute_vue3_master_normal() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "codegen/vue3_master_normal");
}
@Test
public void testExecute_vue3_master_erp() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_ERP, "codegen/vue3_master_erp");
}
@Test
public void testExecute_vue3_master_inner() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_INNER, "codegen/vue3_master_inner");
}
private void testExecute_vue3_master(CodegenTemplateTypeEnum templateType,
String path) {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(templateType.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 准备参数子表
CodegenTableDO contactTable = getTable("contact")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setSubJoinColumnId(100L).setSubJoinMany(true);
List<CodegenColumnDO> contactColumns = getColumnList("contact");
// 准备参数班主任
CodegenTableDO teacherTable = getTable("teacher")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setSubJoinColumnId(200L).setSubJoinMany(false);
List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns,
Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
// 断言
assertResult(result, path);
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/" + path);
// writeFile(result, "/Users/yunai/test/demo11.zip");
}
private static CodegenTableDO getTable(String name) {
String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json"); String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
return JsonUtils.parseObject(content, "table", CodegenTableDO.class); return JsonUtils.parseObject(content, "table", CodegenTableDO.class);
} }
private static List<CodegenColumnDO> getColumnList(String name) { protected static List<CodegenColumnDO> getColumnList(String name) {
String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json"); String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
List<CodegenColumnDO> list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class); List<CodegenColumnDO> list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class);
list.forEach(column -> { list.forEach(column -> {
@ -148,7 +72,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private static void assertResult(Map<String, String> result, String path) { protected static void assertResult(Map<String, String> result, String path) {
String assertContent = ResourceUtil.readUtf8Str(path + "/assert.json"); String assertContent = ResourceUtil.readUtf8Str(path + "/assert.json");
List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class); List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class);
assertEquals(asserts.size(), result.size()); assertEquals(asserts.size(), result.size());
@ -169,7 +93,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
* @param result 生成的代码 * @param result 生成的代码
* @param path 写入文件的路径 * @param path 写入文件的路径
*/ */
private void writeFile(Map<String, String> result, String path) { protected void writeFile(Map<String, String> result, String path) {
// 生成压缩包 // 生成压缩包
String[] paths = result.keySet().toArray(new String[0]); String[] paths = result.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new); ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
@ -185,7 +109,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
* @param result 生成的代码 * @param result 生成的代码
* @param basePath 写入文件的路径绝对路径 * @param basePath 写入文件的路径绝对路径
*/ */
private void writeResult(Map<String, String> result, String basePath) { protected void writeResult(Map<String, String> result, String basePath) {
// 写入文件内容 // 写入文件内容
List<Map<String, String>> asserts = new ArrayList<>(); List<Map<String, String>> asserts = new ArrayList<>();
result.forEach((filePath, fileContent) -> { result.forEach((filePath, fileContent) -> {

View File

@ -1,47 +1,21 @@
package cn.iocoder.yudao.module.infra.service.codegen.inner; package cn.iocoder.yudao.module.infra.service.codegen.inner;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Spy;
import java.io.ByteArrayInputStream; import java.util.Arrays;
import java.io.ByteArrayOutputStream; import java.util.List;
import java.util.*; import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* {@link CodegenEngine} 单元测试 * {@link CodegenEngine} Vue2 + Element UI 单元测试
* *
* @author 芋道源码 * @author 芋道源码
*/ */
public class CodegenEngineVue2Test extends BaseMockitoUnitTest { public class CodegenEngineVue2Test extends CodegenEngineAbstractTest {
@InjectMocks
private CodegenEngine codegenEngine;
@Spy
private CodegenProperties codegenProperties = new CodegenProperties()
.setBasePackage("cn.iocoder.yudao");
@BeforeEach
public void setUp() {
codegenEngine.initGlobalBindingMap();
}
@Test @Test
public void testExecute_vue2_one() { public void testExecute_vue2_one() {
@ -118,85 +92,4 @@ public class CodegenEngineVue2Test extends BaseMockitoUnitTest {
// writeFile(result, "/Users/yunai/test/demo11.zip"); // writeFile(result, "/Users/yunai/test/demo11.zip");
} }
private static CodegenTableDO getTable(String name) {
String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
return JsonUtils.parseObject(content, "table", CodegenTableDO.class);
}
private static List<CodegenColumnDO> getColumnList(String name) {
String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
List<CodegenColumnDO> list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class);
list.forEach(column -> {
if (column.getNullable() == null) {
column.setNullable(false);
}
if (column.getCreateOperation() == null) {
column.setCreateOperation(false);
}
if (column.getUpdateOperation() == null) {
column.setUpdateOperation(false);
}
if (column.getListOperation() == null) {
column.setListOperation(false);
}
if (column.getListOperationResult() == null) {
column.setListOperationResult(false);
}
});
return list;
}
@SuppressWarnings("rawtypes")
private static void assertResult(Map<String, String> result, String path) {
String assertContent = ResourceUtil.readUtf8Str(path + "/assert.json");
List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class);
assertEquals(asserts.size(), result.size());
// 校验每个文件
asserts.forEach(assertMap -> {
String contentPath = (String) assertMap.get("contentPath");
String filePath = (String) assertMap.get("filePath");
String content = ResourceUtil.readUtf8Str(path + "/" + contentPath);
assertEquals(content, result.get(filePath), filePath + ":不匹配");
});
}
// ==================== 调试专用 ====================
/**
* 调试使用将生成的代码写入到文件
*
* @param result 生成的代码
* @param path 写入文件的路径
*/
private void writeFile(Map<String, String> result, String path) {
// 生成压缩包
String[] paths = result.keySet().toArray(new String[0]);
ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipUtil.zip(outputStream, paths, ins);
// 写入文件
FileUtil.writeBytes(outputStream.toByteArray(), path);
}
/**
* 调试使用将生成的结果写入到文件
*
* @param result 生成的代码
* @param basePath 写入文件的路径绝对路径
*/
private void writeResult(Map<String, String> result, String basePath) {
// 写入文件内容
List<Map<String, String>> asserts = new ArrayList<>();
result.forEach((filePath, fileContent) -> {
String lastFilePath = StrUtil.subAfter(filePath, '/', true);
String contentPath = StrUtil.subAfter(lastFilePath, '.', true)
+ '/' + StrUtil.subBefore(lastFilePath, '.', true);
asserts.add(MapUtil.<String, String>builder().put("filePath", filePath)
.put("contentPath", contentPath).build());
FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath);
});
// 写入 assert.json 文件
FileUtil.writeUtf8String(JsonUtils.toJsonPrettyString(asserts), basePath +"/assert.json");
}
} }

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.infra.service.codegen.inner;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* {@link CodegenEngine} Vue2 + Element Plus 单元测试
*
* @author 芋道源码
*/
public class CodegenEngineVue3Test extends CodegenEngineAbstractTest {
@Test
public void testExecute_vue3_one() {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue3_one");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one");
}
@Test
public void testExecute_vue3_tree() {
// 准备参数
CodegenTableDO table = getTable("category")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(CodegenTemplateTypeEnum.TREE.getType());
List<CodegenColumnDO> columns = getColumnList("category");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns, null, null);
// 断言
assertResult(result, "codegen/vue3_tree");
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree");
// writeFile(result, "/Users/yunai/test/demo66.zip");
}
@Test
public void testExecute_vue3_master_normal() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "codegen/vue3_master_normal");
}
@Test
public void testExecute_vue3_master_erp() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_ERP, "codegen/vue3_master_erp");
}
@Test
public void testExecute_vue3_master_inner() {
testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_INNER, "codegen/vue3_master_inner");
}
private void testExecute_vue3_master(CodegenTemplateTypeEnum templateType,
String path) {
// 准备参数
CodegenTableDO table = getTable("student")
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setTemplateType(templateType.getType());
List<CodegenColumnDO> columns = getColumnList("student");
// 准备参数子表
CodegenTableDO contactTable = getTable("contact")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setSubJoinColumnId(100L).setSubJoinMany(true);
List<CodegenColumnDO> contactColumns = getColumnList("contact");
// 准备参数班主任
CodegenTableDO teacherTable = getTable("teacher")
.setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
.setFrontType(CodegenFrontTypeEnum.VUE3.getType())
.setSubJoinColumnId(200L).setSubJoinMany(false);
List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
// 调用
Map<String, String> result = codegenEngine.execute(table, columns,
Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
// 断言
assertResult(result, path);
// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/" + path);
// writeFile(result, "/Users/yunai/test/demo11.zip");
}
}