| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- <template>
- <cacp-page-layout>
- <el-card>
- <el-tabs v-model="state.activeName" type="border-card">
- <el-tab-pane label="基本信息" name="basic">
- <basic-info-form ref="basicInfoRef" :info="state.info" />
- </el-tab-pane>
- <el-tab-pane label="字段信息" name="columnInfo">
- <el-table
- ref="dragTableRef"
- :data="state.columns"
- row-key="columnId"
- :height="state.tableHeight"
- border
- stripe
- >
- <el-table-column
- label="序号"
- type="index"
- width="55"
- align="center"
- class-name="allowDrag"
- />
- <el-table-column
- label="字段列名"
- prop="columnName"
- min-width="120"
- :show-overflow-tooltip="true"
- align="center"
- />
- <el-table-column label="字段描述" min-width="120" align="center">
- <template #default="scope">
- <el-input
- v-model="scope.row.columnComment"
- placeholder="请输入字段描述"
- clearable
- />
- </template>
- </el-table-column>
- <el-table-column
- label="物理类型"
- prop="columnType"
- min-width="120"
- :show-overflow-tooltip="true"
- align="center"
- />
- <el-table-column label="Java类型" min-width="130" align="center">
- <template #default="scope">
- <el-select
- v-model="scope.row.javaType"
- placeholder="请选择"
- style="width: 100%"
- >
- <el-option label="Long" value="Long" />
- <el-option label="String" value="String" />
- <el-option label="Integer" value="Integer" />
- <el-option label="Double" value="Double" />
- <el-option label="BigDecimal" value="BigDecimal" />
- <el-option label="Date" value="Date" />
- <el-option label="Boolean" value="Boolean" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="java属性" min-width="120" align="center">
- <template #default="scope">
- <el-input
- v-model="scope.row.javaField"
- placeholder="请输入java属性"
- clearable
- @blur="handleJavaFieldBlur(scope.row)"
- />
- </template>
- </el-table-column>
- <el-table-column label="插入" width="70" align="center">
- <template #default="scope">
- <el-checkbox
- v-model="scope.row.isInsert"
- true-label="1"
- false-label="0"
- />
- </template>
- </el-table-column>
- <el-table-column label="编辑" width="70" align="center">
- <template #default="scope">
- <el-checkbox
- v-model="scope.row.isEdit"
- true-label="1"
- false-label="0"
- />
- </template>
- </el-table-column>
- <el-table-column label="列表" width="70" align="center">
- <template #default="scope">
- <el-checkbox
- v-model="scope.row.isList"
- true-label="1"
- false-label="0"
- />
- </template>
- </el-table-column>
- <el-table-column label="查询" width="70" align="center">
- <template #default="scope">
- <el-checkbox
- v-model="scope.row.isQuery"
- true-label="1"
- false-label="0"
- />
- </template>
- </el-table-column>
- <el-table-column label="查询方式" min-width="120" align="center">
- <template #default="scope">
- <el-select
- v-model="scope.row.queryType"
- placeholder="请选择"
- style="width: 100%"
- >
- <el-option label="=" value="EQ" />
- <el-option label="!=" value="NE" />
- <el-option label=">" value="GT" />
- <el-option label=">=" value="GTE" />
- <el-option label="<" value="LT" />
- <el-option label="<=" value="LTE" />
- <el-option label="LIKE" value="LIKE" />
- <el-option label="BETWEEN" value="BETWEEN" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="必填" width="70" align="center">
- <template #default="scope">
- <el-checkbox
- v-model="scope.row.isRequired"
- true-label="1"
- false-label="0"
- />
- </template>
- </el-table-column>
- <el-table-column label="显示类型" min-width="140" align="center">
- <template #default="scope">
- <el-select
- v-model="scope.row.htmlType"
- placeholder="请选择"
- style="width: 100%"
- >
- <el-option label="文本框" value="input" />
- <el-option label="文本域" value="textarea" />
- <el-option label="下拉框" value="select" />
- <el-option label="单选框" value="radio" />
- <el-option label="复选框" value="checkbox" />
- <el-option label="日期控件" value="datetime" />
- <el-option label="图片上传" value="imageUpload" />
- <el-option label="文件上传" value="fileUpload" />
- <el-option label="富文本控件" value="editor" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="字典类型" min-width="140" align="center">
- <template #default="scope">
- <el-select
- v-model="scope.row.dictType"
- placeholder="请选择字典类型"
- clearable
- filterable
- style="width: 100%"
- >
- <el-option
- v-for="dict in state.dictOptions"
- :key="dict.dictType"
- :label="dict.dictName"
- :value="dict.dictType"
- >
- <span style="float: left">{{ dict.dictName }}</span>
- <span style="float: right; color: #8492a6; font-size: 13px">
- {{ dict.dictType }}
- </span>
- </el-option>
- </el-select>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- <el-tab-pane label="生成信息" name="genInfo">
- <gen-info-form
- ref="genInfoRef"
- :info="state.info"
- :tables="state.tables"
- :menus="state.menus"
- />
- </el-tab-pane>
- </el-tabs>
- <div class="footer-action">
- <el-button type="primary" @click="onSubmit">提交</el-button>
- <el-button @click="onCancel">返回</el-button>
- </div>
- </el-card>
- </cacp-page-layout>
- </template>
- <script lang="ts" setup>
- import { reactive, ref, onMounted, nextTick } from 'vue'
- import { useRoute, useRouter } from 'vue-router'
- import { ElMessage } from 'element-plus'
- import Sortable from 'sortablejs'
- import type { GenTable } from '@/types/gen/GenTable'
- import type { GenTableColumn } from '@/types/gen/GenTableColumn'
- import { getDetail, update } from "@/apis/gen/gen"
- // import { optionselect as getDictOptionselect } from "@/api/system/dict/type"
- // import { listMenu as getMenuTreeselect } from "@/api/system/menu"
- import basicInfoForm from "./basicInfoForm.vue"
- import genInfoForm from "./genInfoForm.vue"
- import { SuccessResultCode } from '@cacp/ui'
- // 组件引用
- const basicInfoRef = ref<InstanceType<typeof basicInfoForm>>()
- const genInfoRef = ref<InstanceType<typeof genInfoForm>>()
- const dragTableRef = ref()
- // 路由
- const route = useRoute()
- const router = useRouter()
- // 工具函数:检查是否为驼峰命名
- const isCamelCase = (str: string): boolean => {
- if (!str) return false
- // 驼峰命名规则:以小写字母开头,后续可以包含大写字母
- return /^[a-z]+([A-Z][a-z]*)*$/.test(str)
- }
- // 工具函数:格式化java属性
- const formatJavaField = (field: string = ''): string => {
- if (!field) return ''
- // 如果是驼峰命名,保持原样
- if (isCamelCase(field)) {
- return field
- }
- // 其他情况全部转为小写
- return field.toLowerCase()
- }
- // 处理java属性输入框失去焦点事件 - 明确指定参数类型
- const handleJavaFieldBlur = (column: GenTableColumn) => {
- if (column.javaField) {
- const formatted = formatJavaField(column.javaField)
- if (column.javaField !== formatted) {
- column.javaField = formatted
- }
- }
- }
- // 响应式状态
- interface DictOption {
- dictType: string
- dictName: string
- }
- interface Menu {
- menuId: number
- [key: string]: any
- }
- interface State {
- activeName: string
- tableHeight: string
- info: Partial<GenTable>
- columns: GenTableColumn[]
- tables: any[]
- dictOptions: DictOption[]
- menus: Menu[]
- }
- const state = reactive<State>({
- activeName: 'columnInfo',
- tableHeight: `${document.documentElement.scrollHeight - 300}px`,
- info: {},
- columns: [],
- tables: [],
- dictOptions: [],
- menus: []
- })
- // 修改 onSubmit 方法
- const onSubmit = async () => {
- try {
- if (!basicInfoRef.value || !genInfoRef.value) {
- ElMessage.error('表单组件未正确加载')
- return
- }
- // 直接从子组件获取最新的表单数据
- let basicInfoData = {}
- let genInfoData = {}
- try {
- basicInfoData = await basicInfoRef.value.validate?.()
- } catch (error) {
- console.error('基础表单验证失败:', error)
- ElMessage.error('基本信息表单验证失败,请检查必填项')
- state.activeName = 'basic'
- return
- }
- try {
- genInfoData = await genInfoRef.value.validate?.()
- } catch (error) {
- console.error('生成信息表单验证失败:', error)
- ElMessage.error('生成信息表单验证失败,请检查必填项')
- state.activeName = 'genInfo'
- return
- }
- // 合并所有数据
- const mergedInfo: { [key: string]: any } = {
- ...state.info,
- ...basicInfoData,
- ...genInfoData
- }
- // 检查必填字段
- const requiredFields = [
- 'packageName', 'tableName', 'functionName', 'functionAuthor',
- 'businessName', 'moduleName', 'className', 'tableComment'
- ]
- const missingFields = requiredFields.filter(field => !mergedInfo[field])
- if (missingFields.length > 0) {
- ElMessage.error(`以下字段不能为空: ${missingFields.join(', ')}`)
- state.activeName = 'basic'
- return
- }
- // 准备提交的数据
- const genTable = {
- ...mergedInfo,
- columns: state.columns,
- params: {
- treeCode: mergedInfo.treeCode || '',
- treeName: mergedInfo.treeName || '',
- treeParentCode: mergedInfo.treeParentCode || '',
- parentMenuId: mergedInfo.parentMenuId || ''
- }
- }
- console.log('准备提交的数据:', JSON.stringify(genTable, null, 2))
- const res = await update(genTable)
- if (res.code === SuccessResultCode) {
- ElMessage.success(res.message || '提交成功')
- onCancel()
- } else {
- console.error('提交失败响应:', res)
- ElMessage.error(res.message || '提交失败')
- }
- } catch (error) {
- console.error('提交过程中发生错误:', error)
- ElMessage.error('提交失败,请检查表单数据')
- }
- }
- // 返回
- const onCancel = () => {
- router.push({
- path: '/gen-index',
- query: {
- t: Date.now(),
- pageNum: route.query.pageNum
- }
- })
- }
- // 初始化拖拽
- const initSortable = () => {
- nextTick(() => {
- if (!dragTableRef.value) return
- const el = dragTableRef.value.$el.querySelectorAll('.el-table__body-wrapper > table > tbody')[0]
- if (!el) return
- Sortable.create(el, {
- handle: '.allowDrag',
- onEnd: (evt: { oldIndex?: number; newIndex?: number }) => {
- const { oldIndex, newIndex } = evt
- if (oldIndex === undefined || newIndex === undefined) return
- const targetRow = state.columns.splice(oldIndex, 1)[0]
- state.columns.splice(newIndex, 0, targetRow)
- // 更新排序 - 明确指定参数类型
- state.columns.forEach((column: GenTableColumn, index: number) => {
- column.sort = index + 1
- })
- }
- })
- })
- }
- // 初始化数据
- const initData = async () => {
- const tableId = route.params?.tableId as string
- if (!tableId) return
- try {
- const res = await getDetail(tableId)
- if (res.code === SuccessResultCode) {
- // 初始化时格式化所有 javaField,非驼峰命名的转为小写
- state.columns = (res.data.rows || []).map((column: GenTableColumn) => ({
- ...column,
- javaField: formatJavaField(column.javaField)
- }))
- state.info = res.data.info || {}
- state.tables = res.data.tables || []
- // 查询字典下拉列表
- // const dictRes = await getDictOptionselect()
- // state.dictOptions = dictRes.data || []
- // 查询菜单下拉列表
- // const menuRes = await getMenuTreeselect()
- // state.menus = handleTree(menuRes.data || [], 'menuId')
- // 初始化拖拽
- initSortable()
- } else {
- ElMessage.error(res.message || '获取数据失败')
- }
- } catch (error) {
- console.error('初始化数据失败:', error)
- ElMessage.error('初始化数据失败,请稍后重试')
- }
- }
- // 组件挂载
- onMounted(() => {
- initData()
- })
- // 监听窗口大小变化调整表格高度
- window.addEventListener('resize', () => {
- state.tableHeight = `${document.documentElement.scrollHeight - 300}px`
- })
- </script>
- <style scoped>
- .footer-action {
- display: flex;
- justify-content: center;
- margin-top: 20px;
- padding-top: 20px;
- border-top: 1px solid #ebeef5;
- }
- :deep(.el-tabs--border-card) {
- box-shadow: none;
- border: 1px solid #dcdfe6;
- }
- :deep(.el-table) {
- margin-top: 10px;
- }
- :deep(.el-tabs__content) {
- padding: 20px;
- }
- </style>
|