2·1
This commit is contained in:
parent
932eae46ad
commit
7cbea2a3ef
|
|
@ -6,6 +6,14 @@ import Http from "@/core/utils/Http";
|
|||
export default class CodeGenerationService {
|
||||
static urlPrefix = "/api/v1/admin/CodeGeneration";
|
||||
|
||||
/**
|
||||
* 获取数据库列表
|
||||
* @returns
|
||||
*/
|
||||
static getDatabases() {
|
||||
return Http.get(`${this.urlPrefix}/GetDatabases`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据列表
|
||||
* @param current
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const state = reactive({
|
|||
tableName: undefined,
|
||||
entityName: undefined,
|
||||
displayName: undefined,
|
||||
dataBase: undefined,
|
||||
},
|
||||
sort: [] as any[],
|
||||
},
|
||||
|
|
@ -28,6 +29,7 @@ const state = reactive({
|
|||
total: 100,
|
||||
columns: [] as any,
|
||||
data: [] as any,
|
||||
databaseList: [] as any,
|
||||
});
|
||||
|
||||
//表格
|
||||
|
|
@ -43,9 +45,47 @@ const refTableEditor = ref<InstanceType<typeof TableEditor>>();
|
|||
* 初始化
|
||||
*/
|
||||
onMounted(() => {
|
||||
loadDatabases();
|
||||
findList();
|
||||
});
|
||||
|
||||
/**
|
||||
* 加载数据库列表
|
||||
*/
|
||||
async function loadDatabases() {
|
||||
const result = await CodeGenerationService.getDatabases();
|
||||
if (result.code != 200) return;
|
||||
state.databaseList = result.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库切换事件
|
||||
*/
|
||||
function handleDatabaseChange() {
|
||||
state.page = 1;
|
||||
findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库颜色
|
||||
*/
|
||||
function getDatabaseColor(dataBaseKey: string): string {
|
||||
const colorMap: Record<string, string> = {
|
||||
'Admin': 'blue',
|
||||
'MiaoYuChat': 'green',
|
||||
'LiveForum': 'orange'
|
||||
};
|
||||
return colorMap[dataBaseKey] || 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库显示名称
|
||||
*/
|
||||
function getDatabaseDisplayName(dataBaseKey: string): string {
|
||||
const db = state.databaseList.find((d: any) => d.key === dataBaseKey);
|
||||
return db?.displayName || dataBaseKey;
|
||||
}
|
||||
|
||||
/**
|
||||
*获取数据
|
||||
*/
|
||||
|
|
@ -139,6 +179,24 @@ function openTableEditor() {
|
|||
<template #search>
|
||||
<a-form ref="refSearchForm" :model="state.search.vm">
|
||||
<a-row :gutter="[16, 0]">
|
||||
<a-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
|
||||
<a-form-item class="mb-0" name="dataBase" label="数据库">
|
||||
<a-select
|
||||
v-model:value="state.search.vm.dataBase"
|
||||
placeholder="全部数据库"
|
||||
@change="handleDatabaseChange"
|
||||
>
|
||||
<a-select-option value="">全部数据库</a-select-option>
|
||||
<a-select-option
|
||||
v-for="db in state.databaseList"
|
||||
:key="db.key"
|
||||
:value="db.key"
|
||||
>
|
||||
{{ db.displayName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
|
||||
<a-form-item class="mb-0" name="tableName" label="表名称">
|
||||
<a-input v-model:value="state.search.vm.tableName" placeholder="表名称" />
|
||||
|
|
@ -228,6 +286,13 @@ function openTableEditor() {
|
|||
<template #toolbar-right> </template>
|
||||
<!-- table-col -->
|
||||
<template #table-col>
|
||||
<a-table-column title="数据库" data-index="dataBase" width="120px">
|
||||
<template #default="{ record }">
|
||||
<a-tag :color="getDatabaseColor(record.dataBase)">
|
||||
{{ getDatabaseDisplayName(record.dataBase) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column title="表名称" data-index="tableName" />
|
||||
<a-table-column title="显示名称" data-index="displayName">
|
||||
<template #default="{ record }"> <a-input v-model:value="record.displayName" /></template>
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ async function getCode() {
|
|||
loading.value = true;
|
||||
const result = await CodeGenerationService.getCode({
|
||||
tableName: props.rowData.tableName,
|
||||
dataBase: props.rowData.dataBase,
|
||||
type: codeType.value,
|
||||
codeText: "",
|
||||
});
|
||||
|
|
@ -88,6 +89,7 @@ async function getCode() {
|
|||
function download() {
|
||||
CodeGenerationService.download({
|
||||
tableName: props.rowData.tableName,
|
||||
dataBase: props.rowData.dataBase,
|
||||
type: codeType.value,
|
||||
codeText: "",
|
||||
});
|
||||
|
|
@ -99,6 +101,7 @@ function download() {
|
|||
function downloadAll() {
|
||||
CodeGenerationService.download({
|
||||
tableName: props.rowData.tableName,
|
||||
dataBase: props.rowData.dataBase,
|
||||
type: codeType.value,
|
||||
codeText: "",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -73,7 +73,10 @@ function saveForm(successCallBack: Function | null = null) {
|
|||
function autoImport() {
|
||||
saveForm(async () => {
|
||||
state.loading = true;
|
||||
const result = await CodeGenerationService.autoImprotProject({ tableName: props.rowData.tableName });
|
||||
const result = await CodeGenerationService.autoImprotProject({
|
||||
tableName: props.rowData.tableName,
|
||||
dataBase: props.rowData.dataBase
|
||||
});
|
||||
state.loading = false;
|
||||
if (result.code !== 1) return;
|
||||
Tools.message.success("代码载入项目成功!");
|
||||
|
|
|
|||
591
admin-client/前端接口对接文档.md
Normal file
591
admin-client/前端接口对接文档.md
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
# 低代码生成平台 - 前端接口对接文档
|
||||
|
||||
## 📋 更新概述
|
||||
|
||||
本次后端更新新增了数据库选择功能,支持按数据库筛选表列表。前端需要相应修改以支持以下功能:
|
||||
|
||||
1. **新增接口**:获取数据库列表
|
||||
2. **增强接口**:表列表接口支持按数据库筛选
|
||||
3. **返回数据变更**:表列表返回数据新增 `dataBase` 字段
|
||||
|
||||
---
|
||||
|
||||
## 🆕 1. 新增接口:获取数据库列表
|
||||
|
||||
### 接口信息
|
||||
|
||||
- **请求路径**:`GET /api/CodeGeneration/databases`
|
||||
- **请求方法**:`GET`
|
||||
- **是否需要认证**:是
|
||||
- **描述**:获取所有可用的数据库列表,用于前端下拉框选择
|
||||
|
||||
### 请求参数
|
||||
|
||||
无
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"key": "Admin",
|
||||
"displayName": "主数据库"
|
||||
},
|
||||
{
|
||||
"key": "MiaoYuChat",
|
||||
"displayName": "喵语聊天"
|
||||
},
|
||||
{
|
||||
"key": "LiveForum",
|
||||
"displayName": "论坛系统"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 响应字段说明
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| key | string | 数据库标识,用于后续接口传参 |
|
||||
| displayName | string | 显示名称,用于前端展示 |
|
||||
|
||||
### 前端使用示例
|
||||
|
||||
```typescript
|
||||
// 1. 定义接口类型
|
||||
interface DataSource {
|
||||
key: string;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
// 2. 调用接口
|
||||
const getDatabases = async (): Promise<DataSource[]> => {
|
||||
const response = await axios.get('/api/CodeGeneration/databases');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// 3. 使用示例(页面加载时)
|
||||
onMounted(async () => {
|
||||
const databases = await getDatabases();
|
||||
// 填充到下拉框
|
||||
databaseOptions.value = databases;
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ 2. 修改接口:表列表查询
|
||||
|
||||
### 接口信息
|
||||
|
||||
- **请求路径**:`POST /api/CodeGeneration/{size}/{page}`
|
||||
- **请求方法**:`POST`
|
||||
- **是否需要认证**:是
|
||||
- **描述**:获取表列表,支持按表名和数据库筛选
|
||||
|
||||
### 请求参数
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| size | number | 是 | 每页条数 |
|
||||
| page | number | 是 | 页码 |
|
||||
|
||||
**Body 参数(JSON):**
|
||||
|
||||
```json
|
||||
{
|
||||
"tableName": "User", // 可选,表名模糊搜索
|
||||
"dataBase": "Admin" // 🆕 新增,数据库标识筛选
|
||||
}
|
||||
```
|
||||
|
||||
### 请求字段说明
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| tableName | string | 否 | 表名,支持模糊搜索 |
|
||||
| dataBase | string | 否 | 🆕 数据库标识,不传则返回所有数据库的表 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 25,
|
||||
"page": 1,
|
||||
"size": 10,
|
||||
"pageCount": 3,
|
||||
"dataSource": [
|
||||
{
|
||||
"tableName": "Users",
|
||||
"remark": "用户表",
|
||||
"dataBase": "Admin" // 🆕 新增字段
|
||||
},
|
||||
{
|
||||
"tableName": "T_Image_Config",
|
||||
"remark": "图片配置表",
|
||||
"dataBase": "MiaoYuChat" // 🆕 新增字段
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应字段说明
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| tableName | string | 表名 |
|
||||
| remark | string | 表备注/描述 |
|
||||
| dataBase | string | 🆕 表所属的数据库标识 |
|
||||
|
||||
### 前端使用示例
|
||||
|
||||
```typescript
|
||||
// 1. 定义接口类型
|
||||
interface TableListItem {
|
||||
tableName: string;
|
||||
remark: string;
|
||||
dataBase: string; // 🆕 新增字段
|
||||
}
|
||||
|
||||
interface TableListRequest {
|
||||
tableName?: string;
|
||||
dataBase?: string; // 🆕 新增字段
|
||||
}
|
||||
|
||||
// 2. 调用接口
|
||||
const getTableList = async (
|
||||
page: number,
|
||||
size: number,
|
||||
search: TableListRequest
|
||||
): Promise<PagingResult<TableListItem>> => {
|
||||
const response = await axios.post(
|
||||
`/api/CodeGeneration/${size}/${page}`,
|
||||
search
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// 3. 使用示例(带数据库筛选)
|
||||
const loadTableList = async () => {
|
||||
const result = await getTableList(1, 10, {
|
||||
tableName: searchKeyword.value,
|
||||
dataBase: selectedDatabase.value // 🆕 传递选中的数据库
|
||||
});
|
||||
tableList.value = result.dataSource;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 3. 代码生成接口参数调整
|
||||
|
||||
### 影响的接口
|
||||
|
||||
以下接口在调用时,需要确保 `dataBase` 参数正确传递:
|
||||
|
||||
1. **获取代码**:`POST /api/CodeGeneration/GetCodeAsync`
|
||||
2. **下载代码**:`POST /api/CodeGeneration/DownloadAsync`
|
||||
3. **下载所有代码**:`POST /api/CodeGeneration/DownloadAllAsync`
|
||||
4. **自动导入项目**:`POST /api/CodeGeneration/AutoImprotProjectAsync`
|
||||
|
||||
### 请求 Body 示例
|
||||
|
||||
```json
|
||||
{
|
||||
"tableName": "T_Image_Config",
|
||||
"dataBase": "MiaoYuChat", // ⚠️ 必须传递,确保准确匹配表
|
||||
"type": "MiaoYu.Models"
|
||||
}
|
||||
```
|
||||
|
||||
### 前端使用示例
|
||||
|
||||
```typescript
|
||||
// 生成代码时,从表列表中获取 dataBase 并传递
|
||||
const generateCode = async (table: TableListItem, type: string) => {
|
||||
const response = await axios.post('/api/CodeGeneration/GetCodeAsync', {
|
||||
tableName: table.tableName,
|
||||
dataBase: table.dataBase, // 🆕 必须传递
|
||||
type: type
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 4. 前端需要修改的地方
|
||||
|
||||
### 4.1 页面布局调整
|
||||
|
||||
在表列表页面顶部新增数据库选择器:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="code-generation-page">
|
||||
<!-- 🆕 新增:数据库选择器 -->
|
||||
<div class="filter-section">
|
||||
<a-select
|
||||
v-model:value="selectedDatabase"
|
||||
placeholder="选择数据库"
|
||||
style="width: 200px"
|
||||
@change="handleDatabaseChange"
|
||||
>
|
||||
<a-select-option value="">全部数据库</a-select-option>
|
||||
<a-select-option
|
||||
v-for="db in databaseList"
|
||||
:key="db.key"
|
||||
:value="db.key"
|
||||
>
|
||||
{{ db.displayName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<!-- 原有的搜索框 -->
|
||||
<a-input
|
||||
v-model:value="searchKeyword"
|
||||
placeholder="搜索表名"
|
||||
style="width: 300px; margin-left: 10px"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table :columns="columns" :data-source="tableList">
|
||||
<!-- 🆕 新增:显示数据库标识列 -->
|
||||
<a-table-column key="dataBase" title="数据库" data-index="dataBase" />
|
||||
<a-table-column key="tableName" title="表名" data-index="tableName" />
|
||||
<a-table-column key="remark" title="说明" data-index="remark" />
|
||||
<!-- 其他列... -->
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 4.2 状态管理
|
||||
|
||||
```typescript
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
// 🆕 新增状态
|
||||
const databaseList = ref<DataSource[]>([]);
|
||||
const selectedDatabase = ref<string>(''); // 空字符串表示全部
|
||||
|
||||
// 原有状态
|
||||
const tableList = ref<TableListItem[]>([]);
|
||||
const searchKeyword = ref<string>('');
|
||||
|
||||
// 🆕 页面加载时获取数据库列表
|
||||
onMounted(async () => {
|
||||
await loadDatabases();
|
||||
await loadTableList();
|
||||
});
|
||||
|
||||
const loadDatabases = async () => {
|
||||
databaseList.value = await getDatabases();
|
||||
};
|
||||
|
||||
// 🆕 数据库切换事件
|
||||
const handleDatabaseChange = () => {
|
||||
loadTableList();
|
||||
};
|
||||
|
||||
// 修改:加载表列表时传递数据库参数
|
||||
const loadTableList = async () => {
|
||||
const result = await getTableList(1, 10, {
|
||||
tableName: searchKeyword.value,
|
||||
dataBase: selectedDatabase.value // 🆕 传递数据库参数
|
||||
});
|
||||
tableList.value = result.dataSource;
|
||||
};
|
||||
```
|
||||
|
||||
### 4.3 生成代码时传递数据库
|
||||
|
||||
```typescript
|
||||
// ⚠️ 重要:生成代码时必须传递 dataBase
|
||||
const handleGenerateCode = async (record: TableListItem) => {
|
||||
const code = await generateCode({
|
||||
tableName: record.tableName,
|
||||
dataBase: record.dataBase, // 🆕 从表列表记录中获取
|
||||
type: selectedCodeType.value
|
||||
});
|
||||
// 展示生成的代码...
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 5. 注意事项
|
||||
|
||||
### 5.1 兼容性说明
|
||||
|
||||
- **向后兼容**:`dataBase` 字段为可选,不传时返回所有数据库的表(保持原有行为)
|
||||
- **推荐实践**:建议前端始终传递 `dataBase` 参数,避免同名表冲突
|
||||
|
||||
### 5.2 同名表处理
|
||||
|
||||
后端支持不同数据库中存在同名表,因此:
|
||||
|
||||
- 表列表中可能出现多个同名的表,通过 `dataBase` 字段区分
|
||||
- 生成代码时**必须**传递 `dataBase` 参数,确保操作正确的表
|
||||
|
||||
### 5.3 UI/UX 建议
|
||||
|
||||
1. **数据库标识显示**:
|
||||
- 在表名前添加数据库标签,如 `[Admin] Users`、`[MiaoYuChat] T_Image_Config`
|
||||
- 使用不同颜色或图标区分不同数据库
|
||||
|
||||
2. **默认选择**:
|
||||
- 建议默认选择第一个数据库,而不是"全部"
|
||||
- 可根据用户最近使用的数据库进行智能默认
|
||||
|
||||
3. **表格列顺序**:
|
||||
- 建议顺序:数据库 → 表名 → 说明 → 操作
|
||||
- 数据库列可以考虑使用标签样式展示
|
||||
|
||||
---
|
||||
|
||||
## 📚 6. 完整示例代码
|
||||
|
||||
```typescript
|
||||
// types.ts
|
||||
export interface DataSource {
|
||||
key: string;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export interface TableListItem {
|
||||
tableName: string;
|
||||
remark: string;
|
||||
dataBase: string;
|
||||
}
|
||||
|
||||
export interface TableListRequest {
|
||||
tableName?: string;
|
||||
dataBase?: string;
|
||||
}
|
||||
|
||||
// api.ts
|
||||
import axios from 'axios';
|
||||
|
||||
export const codeGenerationApi = {
|
||||
// 🆕 获取数据库列表
|
||||
getDatabases: (): Promise<DataSource[]> => {
|
||||
return axios.get('/api/CodeGeneration/databases').then(res => res.data);
|
||||
},
|
||||
|
||||
// 获取表列表(已修改)
|
||||
getTableList: (page: number, size: number, search: TableListRequest) => {
|
||||
return axios.post(`/api/CodeGeneration/${size}/${page}`, search)
|
||||
.then(res => res.data);
|
||||
},
|
||||
|
||||
// 生成代码(已修改)
|
||||
generateCode: (params: {
|
||||
tableName: string;
|
||||
dataBase: string;
|
||||
type: string;
|
||||
}) => {
|
||||
return axios.post('/api/CodeGeneration/GetCodeAsync', params)
|
||||
.then(res => res.data);
|
||||
},
|
||||
|
||||
// 其他接口...
|
||||
};
|
||||
|
||||
// page.vue
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { codeGenerationApi } from '@/api/codeGeneration';
|
||||
import type { DataSource, TableListItem } from '@/types/codeGeneration';
|
||||
|
||||
// 状态
|
||||
const databaseList = ref<DataSource[]>([]);
|
||||
const selectedDatabase = ref<string>('');
|
||||
const tableList = ref<TableListItem[]>([]);
|
||||
const searchKeyword = ref<string>('');
|
||||
const pagination = ref({ page: 1, size: 10, total: 0 });
|
||||
|
||||
// 生命周期
|
||||
onMounted(async () => {
|
||||
await loadDatabases();
|
||||
await loadTableList();
|
||||
});
|
||||
|
||||
// 加载数据库列表
|
||||
const loadDatabases = async () => {
|
||||
try {
|
||||
databaseList.value = await codeGenerationApi.getDatabases();
|
||||
// 可选:默认选择第一个数据库
|
||||
// if (databaseList.value.length > 0) {
|
||||
// selectedDatabase.value = databaseList.value[0].key;
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error('加载数据库列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载表列表
|
||||
const loadTableList = async () => {
|
||||
try {
|
||||
const result = await codeGenerationApi.getTableList(
|
||||
pagination.value.page,
|
||||
pagination.value.size,
|
||||
{
|
||||
tableName: searchKeyword.value,
|
||||
dataBase: selectedDatabase.value
|
||||
}
|
||||
);
|
||||
tableList.value = result.dataSource;
|
||||
pagination.value.total = result.total;
|
||||
} catch (error) {
|
||||
console.error('加载表列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 事件处理
|
||||
const handleDatabaseChange = () => {
|
||||
pagination.value.page = 1; // 重置页码
|
||||
loadTableList();
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.value.page = 1; // 重置页码
|
||||
loadTableList();
|
||||
};
|
||||
|
||||
const handleGenerateCode = async (record: TableListItem) => {
|
||||
try {
|
||||
const code = await codeGenerationApi.generateCode({
|
||||
tableName: record.tableName,
|
||||
dataBase: record.dataBase,
|
||||
type: 'MiaoYu.Models'
|
||||
});
|
||||
// 展示代码...
|
||||
} catch (error) {
|
||||
console.error('生成代码失败:', error);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="code-generation-page">
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<a-space>
|
||||
<a-select
|
||||
v-model:value="selectedDatabase"
|
||||
placeholder="选择数据库"
|
||||
style="width: 200px"
|
||||
@change="handleDatabaseChange"
|
||||
>
|
||||
<a-select-option value="">全部数据库</a-select-option>
|
||||
<a-select-option
|
||||
v-for="db in databaseList"
|
||||
:key="db.key"
|
||||
:value="db.key"
|
||||
>
|
||||
{{ db.displayName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-input
|
||||
v-model:value="searchKeyword"
|
||||
placeholder="搜索表名"
|
||||
style="width: 300px"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<a-table
|
||||
:data-source="tableList"
|
||||
:pagination="{
|
||||
current: pagination.page,
|
||||
pageSize: pagination.size,
|
||||
total: pagination.total,
|
||||
onChange: (page) => {
|
||||
pagination.page = page;
|
||||
loadTableList();
|
||||
}
|
||||
}"
|
||||
>
|
||||
<a-table-column key="dataBase" title="数据库" data-index="dataBase">
|
||||
<template #default="{ record }">
|
||||
<a-tag :color="getDatabaseColor(record.dataBase)">
|
||||
{{ getDatabaseDisplayName(record.dataBase) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column key="tableName" title="表名" data-index="tableName" />
|
||||
<a-table-column key="remark" title="说明" data-index="remark" />
|
||||
<a-table-column key="actions" title="操作">
|
||||
<template #default="{ record }">
|
||||
<a-button type="link" @click="handleGenerateCode(record)">
|
||||
生成代码
|
||||
</a-button>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.code-generation-page {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 7. 视觉效果建议
|
||||
|
||||
### 数据库标签颜色方案
|
||||
|
||||
```typescript
|
||||
const getDatabaseColor = (databaseKey: string): string => {
|
||||
const colorMap: Record<string, string> = {
|
||||
'Admin': 'blue',
|
||||
'MiaoYuChat': 'green',
|
||||
'LiveForum': 'orange'
|
||||
};
|
||||
return colorMap[databaseKey] || 'default';
|
||||
};
|
||||
|
||||
const getDatabaseDisplayName = (databaseKey: string): string => {
|
||||
const database = databaseList.value.find(db => db.key === databaseKey);
|
||||
return database?.displayName || databaseKey;
|
||||
};
|
||||
```
|
||||
|
||||
### 表格展示效果
|
||||
|
||||
```
|
||||
┌────────────┬─────────────────┬──────────────┬────────┐
|
||||
│ 数据库 │ 表名 │ 说明 │ 操作 │
|
||||
├────────────┼─────────────────┼──────────────┼────────┤
|
||||
│ [Admin] │ Users │ 用户表 │ 生成 │
|
||||
│ [MiaoYuChat]│ T_Image_Config │ 图片配置表 │ 生成 │
|
||||
│ [Admin] │ Roles │ 角色表 │ 生成 │
|
||||
└────────────┴─────────────────┴──────────────┴────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 8. 技术支持
|
||||
|
||||
如有疑问,请联系后端开发团队。
|
||||
|
||||
**文档版本**:v1.0
|
||||
**更新日期**:2024年
|
||||
**后端版本**:v2.0(支持多数据源)
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 18
|
||||
VisualStudioVersion = 18.0.11201.2 d18.0
|
||||
VisualStudioVersion = 18.0.11201.2
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "00 Core", "00 Core", "{DB46F54A-9F53-44EC-80F8-9E53F0B871CF}"
|
||||
EndProject
|
||||
|
|
@ -56,6 +56,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MiaoYu.Core.Cos", "MiaoYu.C
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiaoYu.Repository.LiveForum.Admin", "MiaoYu.Repository.LiveForum.Admin\MiaoYu.Repository.LiveForum.Admin.csproj", "{2AF20E5B-478F-46FE-8F8C-A385BB5D5EC7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiaoYu.Core.CodeGenerator", "MiaoYu.Core.CodeGenerator\MiaoYu.Core.CodeGenerator.csproj", "{428143F9-9D59-4DF6-A43A-41CA52C4E113}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -138,6 +140,10 @@ Global
|
|||
{2AF20E5B-478F-46FE-8F8C-A385BB5D5EC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2AF20E5B-478F-46FE-8F8C-A385BB5D5EC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2AF20E5B-478F-46FE-8F8C-A385BB5D5EC7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{428143F9-9D59-4DF6-A43A-41CA52C4E113}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{428143F9-9D59-4DF6-A43A-41CA52C4E113}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{428143F9-9D59-4DF6-A43A-41CA52C4E113}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{428143F9-9D59-4DF6-A43A-41CA52C4E113}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -162,6 +168,7 @@ Global
|
|||
{39C765DB-41E7-4BC6-B75E-2A90CFF3A8EF} = {451BE0BB-26ED-47ED-ABC7-23001D21410C}
|
||||
{3FBBDE5E-2D2C-428B-A2BF-298499ABA5A7} = {DB46F54A-9F53-44EC-80F8-9E53F0B871CF}
|
||||
{2AF20E5B-478F-46FE-8F8C-A385BB5D5EC7} = {451BE0BB-26ED-47ED-ABC7-23001D21410C}
|
||||
{428143F9-9D59-4DF6-A43A-41CA52C4E113} = {DB46F54A-9F53-44EC-80F8-9E53F0B871CF}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E3C61955-46C1-4D06-994F-C86A72B2B0E2}
|
||||
|
|
|
|||
|
|
@ -64,5 +64,20 @@ public class DataSourceConfig
|
|||
/// 排序权重(数字越小越靠前)
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用实体类名前缀(用于避免多数据源同名表冲突)
|
||||
/// </summary>
|
||||
public bool EnableEntityPrefix { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 实体类名前缀(如:Chat、Forum)
|
||||
/// </summary>
|
||||
public string EntityPrefix { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用复数形式的路径(如 /Users/ vs /User/)
|
||||
/// </summary>
|
||||
public bool UsesPluralPath { get; set; } = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,28 +31,37 @@ public class PathResolver : IScopedDependency
|
|||
var rootPath = _environment.ContentRootPath
|
||||
.Replace("\\" + _environment.ApplicationName, "");
|
||||
|
||||
var entityName = GetEntityName(tableName, config.NamingStrategy);
|
||||
var entityName = GetEntityName(tableName, config);
|
||||
var entityNamePlural = config.UsesPluralPath ? entityName + "s" : entityName;
|
||||
|
||||
return template
|
||||
.Replace("{RootPath}", rootPath)
|
||||
.Replace("{AppPath}", _environment.ContentRootPath)
|
||||
.Replace("{Namespace}", config.EntityNamespace)
|
||||
.Replace("{EntityName}", entityName)
|
||||
.Replace("{EntityNamePlural}", entityName + "s")
|
||||
.Replace("{EntityNamePlural}", entityNamePlural)
|
||||
.Replace("{TableName}", tableName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据命名策略获取实体名
|
||||
/// 根据命名策略和配置获取实体名
|
||||
/// </summary>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <param name="strategy">命名策略</param>
|
||||
/// <param name="config">数据源配置</param>
|
||||
/// <returns>实体名</returns>
|
||||
private string GetEntityName(string tableName, EntityNamingStrategy strategy)
|
||||
public string GetEntityName(string tableName, DataSourceConfig config)
|
||||
{
|
||||
return strategy == EntityNamingStrategy.ToPascalCase
|
||||
var baseName = config.NamingStrategy == EntityNamingStrategy.ToPascalCase
|
||||
? tableName.ToLineConvertHump()
|
||||
: tableName;
|
||||
|
||||
// 应用前缀(如果启用)
|
||||
if (config.EnableEntityPrefix && !string.IsNullOrWhiteSpace(config.EntityPrefix))
|
||||
{
|
||||
return config.EntityPrefix + baseName;
|
||||
}
|
||||
|
||||
return baseName;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ public interface ICodeGenerationService : IScopedDependency
|
|||
/// 获取表字段集合
|
||||
/// </summary>
|
||||
/// <param name="tableName"></param>
|
||||
/// <param name="databaseKey">数据库标识(可选)</param>
|
||||
/// <returns></returns>
|
||||
GenDbTableDto GetGenContextDtoByTableName(string tableName);
|
||||
GenDbTableDto GetGenContextDtoByTableName(string tableName, string? databaseKey = null);
|
||||
|
||||
/// <summary>
|
||||
/// 根据 lowCodeTable 填充路径
|
||||
|
|
@ -114,4 +115,10 @@ public interface ICodeGenerationService : IScopedDependency
|
|||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task AutoImprotProjectAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有数据库列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<DataSourceDto> GetAllDataSources();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
var result = new List<Dictionary<string, object>>();
|
||||
|
||||
var query = _databaseTableService.GetAllTablesByCache()
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(search.TableName), w => w.TableName.Contains(search.TableName));
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(search.TableName), w => w.TableName.Contains(search.TableName))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(search.DataBase), w => w.DataBase == search.DataBase);
|
||||
|
||||
var tables = query
|
||||
.Skip((page - 1) * size)
|
||||
|
|
@ -73,6 +74,7 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
var dic = new Dictionary<string, object>();
|
||||
dic.Add(nameof(item.TableName), item.TableName);
|
||||
dic.Add(nameof(item.Remark), item.Remark);
|
||||
dic.Add(nameof(item.DataBase), item.DataBase);
|
||||
|
||||
result.Add(dic);
|
||||
}
|
||||
|
|
@ -88,12 +90,29 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
/// <summary>
|
||||
/// 获取所有表集合信息
|
||||
/// </summary>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <param name="databaseKey">数据库标识(可选)</param>
|
||||
/// <returns></returns>
|
||||
public GenDbTableDto GetGenContextDtoByTableName(string tableName)
|
||||
public GenDbTableDto GetGenContextDtoByTableName(string tableName, string? databaseKey = null)
|
||||
{
|
||||
var genDbTableDto = _databaseTableService.GetAllTables().FirstOrDefault(w => w.TableName == tableName);
|
||||
var query = _databaseTableService.GetAllTables().AsEnumerable();
|
||||
|
||||
FillPathByLowCodeTable(genDbTableDto);
|
||||
// 如果指定了数据库,则精确匹配
|
||||
if (!string.IsNullOrWhiteSpace(databaseKey))
|
||||
{
|
||||
query = query.Where(w => w.TableName == tableName && w.DataBase == databaseKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where(w => w.TableName == tableName);
|
||||
}
|
||||
|
||||
var genDbTableDto = query.FirstOrDefault();
|
||||
|
||||
if (genDbTableDto != null)
|
||||
{
|
||||
FillPathByLowCodeTable(genDbTableDto);
|
||||
}
|
||||
|
||||
return genDbTableDto;
|
||||
}
|
||||
|
|
@ -161,8 +180,7 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
public GenDbTableDto GetGenContextDto(GenFormDto genFormDto)
|
||||
{
|
||||
var tableName = genFormDto.TableName;
|
||||
|
||||
var tableInfo = GetGenContextDtoByTableName(tableName);
|
||||
var tableInfo = GetGenContextDtoByTableName(tableName, genFormDto.DataBase);
|
||||
|
||||
if (tableInfo == null) return null;
|
||||
tableInfo.Namespace = Tools.GetNamespacePrefix<CodeGenerationService>();
|
||||
|
|
@ -280,6 +298,7 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
foreach (var item in tables)
|
||||
{
|
||||
genFormDto.TableName = item.TableName;
|
||||
genFormDto.DataBase = item.DataBase;
|
||||
await CreateCodeFilesAsync(genFormDto);
|
||||
await Task.Delay(25);
|
||||
}
|
||||
|
|
@ -445,21 +464,42 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
if (context == null)
|
||||
{
|
||||
MessageBox.Show("找不到此数据表!");
|
||||
return;
|
||||
}
|
||||
|
||||
//获取表路径信息
|
||||
var tables = _databaseTableService.GetAllTablesByCache();
|
||||
var tableInfo = tables.FirstOrDefault(w => w.TableName == genFormDto.TableName);
|
||||
var tableInfo = tables.FirstOrDefault(w =>
|
||||
w.TableName == genFormDto.TableName &&
|
||||
w.DataBase == genFormDto.DataBase);
|
||||
|
||||
var fileTyps = Enum.GetValues<FileTypeEnum>();
|
||||
|
||||
foreach (var fileType in fileTyps)
|
||||
{
|
||||
var (filePath, oldName, replaceName) = GetFileAbsolutelyPath(genFormDto.TableName, fileType);
|
||||
var (filePath, oldName, replaceName) = GetFileAbsolutelyPath(
|
||||
genFormDto.TableName, fileType, genFormDto.DataBase);
|
||||
await SaveToFileAsync(genFormDto.TableName, fileType, filePath, oldName, replaceName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有数据库列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<DataSourceDto> GetAllDataSources()
|
||||
{
|
||||
var providers = _dataSourceManager.GetAllProviders()
|
||||
.OrderBy(p => p.Config.Order)
|
||||
.ToList();
|
||||
|
||||
return providers.Select(p => new DataSourceDto
|
||||
{
|
||||
Key = p.Config.DatabaseKey,
|
||||
DisplayName = p.Config.DisplayName
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
|
||||
#region 私有方法
|
||||
|
||||
|
|
@ -518,20 +558,17 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
/// <returns></returns>
|
||||
private string FindCodeFileClassName(GenFormDto genFormDto)
|
||||
{
|
||||
var tableName = genFormDto.TableName.ToLineConvertHump();
|
||||
if (genFormDto.TableName.Contains("T_")|| genFormDto.TableName.Contains("M_"))
|
||||
{
|
||||
tableName = genFormDto.TableName;
|
||||
}
|
||||
var provider = _dataSourceManager.GetProvider(genFormDto.DataBase ?? DataSourceConstants.Admin);
|
||||
var entityName = _pathResolver.GetEntityName(genFormDto.TableName, provider.Config);
|
||||
|
||||
return genFormDto.Type switch
|
||||
{
|
||||
"MiaoYu.Models" => $"{tableName}.cs",
|
||||
// "MiaoYu.Repository.DbSet" => ,
|
||||
"MiaoYu.Services.Admin" => $"{tableName}Service.cs",
|
||||
"MiaoYu.Controllers.Admin" => $"{tableName}Controller.cs",
|
||||
"MiaoYu.Models" => $"{entityName}.cs",
|
||||
"MiaoYu.Services.Admin" => $"{entityName}Service.cs",
|
||||
"MiaoYu.Controllers.Admin" => $"{entityName}Controller.cs",
|
||||
"Client.Index" => $"Index.vue",
|
||||
"Client.Info" => $"Info.vue",
|
||||
"Client.Service" => $"{tableName}Service.ts",
|
||||
"Client.Service" => $"{entityName}Service.ts",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
|
@ -541,51 +578,39 @@ public class CodeGenerationService : ICodeGenerationService
|
|||
/// </summary>
|
||||
/// <param name="tableName"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="databaseKey">数据库标识(可选)</param>
|
||||
/// <returns></returns>
|
||||
private (string, string, string) GetFileAbsolutelyPath(string tableName, FileTypeEnum type)
|
||||
private (string, string, string) GetFileAbsolutelyPath(string tableName, FileTypeEnum type, string? databaseKey = null)
|
||||
{
|
||||
var replaceName = string.Empty;
|
||||
var oldFileName = string.Empty;
|
||||
var dto = new GenFormDto() { TableName = tableName, Type = GetEnumDescription(type) };
|
||||
var humpTableName = tableName.ToLineConvertHump();
|
||||
var dto = new GenFormDto() { TableName = tableName, Type = GetEnumDescription(type), DataBase = databaseKey };
|
||||
|
||||
var provider = _dataSourceManager.GetProvider(databaseKey ?? DataSourceConstants.Admin);
|
||||
var entityName = _pathResolver.GetEntityName(tableName, provider.Config);
|
||||
var entityNameWithPath = provider.Config.UsesPluralPath ? entityName + "s" : entityName;
|
||||
|
||||
var fileName = FindCodeFileClassName(dto);
|
||||
var path = string.Empty;
|
||||
//获取表路径信息
|
||||
var tableInfo = GetGenContextDtoByTableName(tableName);
|
||||
var tableInfo = GetGenContextDtoByTableName(tableName, databaseKey);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FileTypeEnum.Model:
|
||||
if (tableInfo.DataBase == "MiaoYuChat")
|
||||
{
|
||||
path = tableInfo.ModelPath + $"/";
|
||||
}
|
||||
else
|
||||
{
|
||||
path = tableInfo.ModelPath + $"/{humpTableName}s";
|
||||
}
|
||||
|
||||
path = provider.Config.UsesPluralPath
|
||||
? $"{tableInfo.ModelPath}/{entityNameWithPath}"
|
||||
: tableInfo.ModelPath;
|
||||
break;
|
||||
case FileTypeEnum.Service:
|
||||
if (tableInfo.DataBase == "MiaoYuChat")
|
||||
{
|
||||
path = tableInfo.ServicePath + $"/MiaoYuChat";
|
||||
}
|
||||
else
|
||||
{
|
||||
path = tableInfo.ServicePath + $"/{humpTableName}s";
|
||||
}
|
||||
|
||||
path = provider.Config.UsesPluralPath
|
||||
? $"{tableInfo.ServicePath}/{entityNameWithPath}"
|
||||
: tableInfo.ServicePath;
|
||||
break;
|
||||
case FileTypeEnum.Controller:
|
||||
if (tableInfo.DataBase == "MiaoYuChat")
|
||||
{
|
||||
path = tableInfo.ControllerPath + $"/MiaoYuChat";
|
||||
}
|
||||
else
|
||||
{
|
||||
path = tableInfo.ControllerPath + $"/{humpTableName}s";
|
||||
}
|
||||
|
||||
path = provider.Config.UsesPluralPath
|
||||
? $"{tableInfo.ControllerPath}/{entityNameWithPath}"
|
||||
: tableInfo.ControllerPath;
|
||||
break;
|
||||
case FileTypeEnum.ClientIndex:
|
||||
path = tableInfo.ClientIndexPath + $"/{tableName}s";
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
using MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Core;
|
||||
|
||||
namespace MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -84,7 +86,13 @@ public class LowCodeTableInfoService : ApplicationService<IRepository<LowCodeTab
|
|||
{
|
||||
var allTables = _databaseTableService.GetAllTableInfos();
|
||||
var table = await _lowCodeTableRepository.FindAsync(w => w.Id == tableId);
|
||||
var tableInfo = allTables.Find(w => w.Name == table.TableName);
|
||||
|
||||
// 修复:同时匹配表名和数据库标识
|
||||
var tableInfo = allTables.Find(w =>
|
||||
{
|
||||
var dbKey = w.Schema.ExtractDatabaseKey();
|
||||
return w.Name == table.TableName && dbKey == table.DataBase;
|
||||
});
|
||||
|
||||
//查询出当前表所有的字段
|
||||
var tableColumns = await _defaultRepository.ToListAsync(w => w.Low_Code_TableId == table.Id);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,10 @@ public class AdminDataSourceProvider : IDataSourceProvider, IScopedDependency
|
|||
ClientServicePathTemplate = "{RootPath}\\admin-client\\src\\services\\apps\\{TableName}s",
|
||||
TemplatePath = "/wwwroot/code_generation/template/",
|
||||
NamingStrategy = EntityNamingStrategy.ToPascalCase,
|
||||
Order = 1
|
||||
Order = 1,
|
||||
EnableEntityPrefix = false,
|
||||
EntityPrefix = "",
|
||||
UsesPluralPath = true
|
||||
};
|
||||
|
||||
public List<DbTableInfo> GetTables()
|
||||
|
|
|
|||
|
|
@ -30,7 +30,10 @@ public class MiaoYuChatDataSourceProvider : IDataSourceProvider, IScopedDependen
|
|||
ClientServicePathTemplate = "{RootPath}\\admin-client\\src\\services\\apps\\{TableName}s",
|
||||
TemplatePath = "/wwwroot/code_generation/templatev4/",
|
||||
NamingStrategy = EntityNamingStrategy.KeepOriginal,
|
||||
Order = 2
|
||||
Order = 2,
|
||||
EnableEntityPrefix = false,
|
||||
EntityPrefix = "Chat",
|
||||
UsesPluralPath = false
|
||||
};
|
||||
|
||||
public List<DbTableInfo> GetTables()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,17 @@ public class CodeGenerationController : AdminControllerBase<ICodeGenerationServi
|
|||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有数据库列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ActionDescriptor(DisplayName = "获取数据库列表")]
|
||||
[HttpGet]
|
||||
public List<DataSourceDto> GetDatabasesAsync()
|
||||
{
|
||||
return _defaultService.GetAllDataSources();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取列表
|
||||
/// </summary>
|
||||
|
|
@ -41,7 +52,9 @@ public class CodeGenerationController : AdminControllerBase<ICodeGenerationServi
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(genFormDto.TableName))
|
||||
{
|
||||
var table = _defaultService.GetGenContextDtoByTableName(genFormDto.TableName);
|
||||
var table = _defaultService.GetGenContextDtoByTableName(
|
||||
genFormDto.TableName,
|
||||
genFormDto.DataBase);
|
||||
|
||||
//lowCodeTableInfos = table.TableInfos;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1449,6 +1449,21 @@
|
|||
排序权重(数字越小越靠前)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Abstractions.DataSourceConfig.EnableEntityPrefix">
|
||||
<summary>
|
||||
是否启用实体类名前缀(用于避免多数据源同名表冲突)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Abstractions.DataSourceConfig.EntityPrefix">
|
||||
<summary>
|
||||
实体类名前缀(如:Chat、Forum)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Abstractions.DataSourceConfig.UsesPluralPath">
|
||||
<summary>
|
||||
是否使用复数形式的路径(如 /Users/ vs /User/)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Abstractions.DataSourceConstants">
|
||||
<summary>
|
||||
数据源常量
|
||||
|
|
@ -1569,12 +1584,12 @@
|
|||
<param name="tableName">表名</param>
|
||||
<returns>解析后的完整路径</returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Core.PathResolver.GetEntityName(System.String,MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Abstractions.EntityNamingStrategy)">
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Core.PathResolver.GetEntityName(System.String,MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Abstractions.DataSourceConfig)">
|
||||
<summary>
|
||||
根据命名策略获取实体名
|
||||
根据命名策略和配置获取实体名
|
||||
</summary>
|
||||
<param name="tableName">表名</param>
|
||||
<param name="strategy">命名策略</param>
|
||||
<param name="config">数据源配置</param>
|
||||
<returns>实体名</returns>
|
||||
</member>
|
||||
<member name="T:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.ICodeGenerationService">
|
||||
|
|
@ -1588,11 +1603,12 @@
|
|||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.ICodeGenerationService.GetGenContextDtoByTableName(System.String)">
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.ICodeGenerationService.GetGenContextDtoByTableName(System.String,System.String)">
|
||||
<summary>
|
||||
获取表字段集合
|
||||
</summary>
|
||||
<param name="tableName"></param>
|
||||
<param name="databaseKey">数据库标识(可选)</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.ICodeGenerationService.FillPathByLowCodeTable(MiaoYu.Repository.Admin.Entities.LowCode.LowCodeTable)">
|
||||
|
|
@ -1692,6 +1708,12 @@
|
|||
<param name="genFormDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.ICodeGenerationService.GetAllDataSources">
|
||||
<summary>
|
||||
获取所有数据库列表
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService">
|
||||
<summary>
|
||||
代码生成服务
|
||||
|
|
@ -1713,10 +1735,12 @@
|
|||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.GetGenContextDtoByTableName(System.String)">
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.GetGenContextDtoByTableName(System.String,System.String)">
|
||||
<summary>
|
||||
获取所有表集合信息
|
||||
</summary>
|
||||
<param name="tableName">表名</param>
|
||||
<param name="databaseKey">数据库标识(可选)</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.FillPathByLowCodeTable(MiaoYu.Repository.Admin.Entities.LowCode.LowCodeTable)">
|
||||
|
|
@ -1816,6 +1840,12 @@
|
|||
<param name="genFormDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.GetAllDataSources">
|
||||
<summary>
|
||||
获取所有数据库列表
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.ClearSymbol(System.Text.StringBuilder)">
|
||||
<summary>
|
||||
清除多余符号
|
||||
|
|
@ -1837,12 +1867,13 @@
|
|||
<param name="genFormDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.GetFileAbsolutelyPath(System.String,MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.FileTypeEnum)">
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.GetFileAbsolutelyPath(System.String,MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.FileTypeEnum,System.String)">
|
||||
<summary>
|
||||
获取要生成文件的绝对路径
|
||||
</summary>
|
||||
<param name="tableName"></param>
|
||||
<param name="type"></param>
|
||||
<param name="databaseKey">数据库标识(可选)</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.CodeGenerationService.SaveToFileAsync(System.String,MiaoYu.Api.Admin.ApplicationServices.DevelopmentTools.LowCode.Impl.FileTypeEnum,System.String,System.String,System.String)">
|
||||
|
|
@ -3822,6 +3853,12 @@
|
|||
代码生成器控制器
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.Controllers.DevelopmentTools.CodeGenerationController.GetDatabasesAsync">
|
||||
<summary>
|
||||
获取所有数据库列表
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:MiaoYu.Api.Admin.Controllers.DevelopmentTools.CodeGenerationController.FindListAsync(System.Int32,System.Int32,MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool.GenFormDto)">
|
||||
<summary>
|
||||
获取列表
|
||||
|
|
@ -4724,6 +4761,21 @@
|
|||
域名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool.DataSourceDto">
|
||||
<summary>
|
||||
数据源信息 DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool.DataSourceDto.Key">
|
||||
<summary>
|
||||
数据库标识(Admin, MiaoYuChat, LiveForum)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool.DataSourceDto.DisplayName">
|
||||
<summary>
|
||||
显示名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool.GenContextDto">
|
||||
<summary>
|
||||
生成代码上下文
|
||||
|
|
@ -4744,6 +4796,11 @@
|
|||
表名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool.GenFormDto.DataBase">
|
||||
<summary>
|
||||
数据库标识(Admin, MiaoYuChat, LiveForum)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool.GenFormDto.Type">
|
||||
<summary>
|
||||
类型代码
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
namespace MiaoYu.Api.Admin.Models.Dtos.DevelopmentTool;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源信息 DTO
|
||||
/// </summary>
|
||||
public class DataSourceDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库标识(Admin, MiaoYuChat, LiveForum)
|
||||
/// </summary>
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
|
@ -10,6 +10,11 @@ public class GenFormDto
|
|||
/// </summary>
|
||||
public string? TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库标识(Admin, MiaoYuChat, LiveForum)
|
||||
/// </summary>
|
||||
public string? DataBase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型代码
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源配置
|
||||
/// </summary>
|
||||
public class DataSourceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库标识(如:Admin, MiaoYuChat, LiveForum)
|
||||
/// </summary>
|
||||
public string DatabaseKey { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 实体项目命名空间
|
||||
/// </summary>
|
||||
public string EntityNamespace { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 实体类路径模板(支持占位符:{RootPath}, {Namespace}, {EntityName}, {EntityNamePlural}, {TableName})
|
||||
/// </summary>
|
||||
public string ModelPathTemplate { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 服务层路径模板
|
||||
/// </summary>
|
||||
public string ServicePathTemplate { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 控制器路径模板
|
||||
/// </summary>
|
||||
public string ControllerPathTemplate { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 前端Index页面路径模板
|
||||
/// </summary>
|
||||
public string ClientIndexPathTemplate { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 前端Info页面路径模板
|
||||
/// </summary>
|
||||
public string ClientInfoPathTemplate { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 前端Service路径模板
|
||||
/// </summary>
|
||||
public string ClientServicePathTemplate { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成模板目录
|
||||
/// </summary>
|
||||
public string TemplatePath { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 实体类命名规则(保持原名 or 驼峰转换)
|
||||
/// </summary>
|
||||
public EntityNamingStrategy NamingStrategy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序权重(数字越小越靠前)
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用实体类名前缀(用于避免多数据源同名表冲突)
|
||||
/// </summary>
|
||||
public bool EnableEntityPrefix { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 实体类名前缀(如:Chat、Forum)
|
||||
/// </summary>
|
||||
public string EntityPrefix { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用复数形式的路径(如 /Users/ vs /User/)
|
||||
/// </summary>
|
||||
public bool UsesPluralPath { get; set; } = true;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源常量
|
||||
/// </summary>
|
||||
public static class DataSourceConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// 后台管理系统数据库
|
||||
/// </summary>
|
||||
public const string Admin = "Admin";
|
||||
|
||||
/// <summary>
|
||||
/// 喵语AI聊天数据库
|
||||
/// </summary>
|
||||
public const string MiaoYuChat = "MiaoYuChat";
|
||||
|
||||
/// <summary>
|
||||
/// 直播论坛数据库(预留)
|
||||
/// </summary>
|
||||
public const string LiveForum = "LiveForum";
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 实体命名策略
|
||||
/// </summary>
|
||||
public enum EntityNamingStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// 保持数据库表名原样
|
||||
/// </summary>
|
||||
KeepOriginal = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 转换为驼峰命名(去除前缀下划线)
|
||||
/// </summary>
|
||||
ToPascalCase = 1
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源提供者接口
|
||||
/// </summary>
|
||||
public interface IDataSourceProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据源配置
|
||||
/// </summary>
|
||||
DataSourceConfig Config { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取该数据源的所有表信息
|
||||
/// </summary>
|
||||
/// <returns>表信息列表</returns>
|
||||
List<DbTableInfo> GetTables();
|
||||
|
||||
/// <summary>
|
||||
/// 获取DbContext(用于获取FreeSql实例)
|
||||
/// </summary>
|
||||
/// <returns>数据库上下文</returns>
|
||||
object GetDbContext();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
|
||||
namespace MiaoYu.Core.CodeGenerator.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源扩展方法
|
||||
/// </summary>
|
||||
public static class DataSourceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 从 Schema 中提取数据库标识
|
||||
/// </summary>
|
||||
/// <param name="schema">Schema字符串</param>
|
||||
/// <returns>数据库标识</returns>
|
||||
public static string ExtractDatabaseKey(this string schema)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schema))
|
||||
return DataSourceConstants.Admin;
|
||||
|
||||
if (schema.Contains("."))
|
||||
{
|
||||
var parts = schema.Split('.');
|
||||
return parts.Length > 1 ? parts[1] : DataSourceConstants.Admin;
|
||||
}
|
||||
|
||||
return DataSourceConstants.Admin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理 Schema(移除数据库标识)
|
||||
/// </summary>
|
||||
/// <param name="schema">Schema字符串</param>
|
||||
/// <returns>清理后的Schema</returns>
|
||||
public static string CleanSchema(this string schema)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schema))
|
||||
return schema;
|
||||
|
||||
return schema.Contains(".")
|
||||
? schema.Split('.')[0]
|
||||
: schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
using MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
|
||||
namespace MiaoYu.Core.CodeGenerator.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源管理器
|
||||
/// </summary>
|
||||
[Component]
|
||||
public class DataSourceManager : IScopedDependency
|
||||
{
|
||||
private readonly IEnumerable<IDataSourceProvider> _providers;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数(通过依赖注入自动收集所有IDataSourceProvider实现)
|
||||
/// </summary>
|
||||
/// <param name="providers">所有数据源提供者</param>
|
||||
public DataSourceManager(IEnumerable<IDataSourceProvider> providers)
|
||||
{
|
||||
_providers = providers.OrderBy(p => p.Config.Order);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有数据源提供者
|
||||
/// </summary>
|
||||
/// <returns>数据源提供者集合</returns>
|
||||
public IEnumerable<IDataSourceProvider> GetAllProviders() => _providers;
|
||||
|
||||
/// <summary>
|
||||
/// 根据数据库标识获取数据源提供者
|
||||
/// </summary>
|
||||
/// <param name="databaseKey">数据库标识(如:Admin, MiaoYuChat)</param>
|
||||
/// <returns>数据源提供者,如果未找到返回null</returns>
|
||||
public IDataSourceProvider? GetProvider(string databaseKey)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(databaseKey))
|
||||
return null;
|
||||
|
||||
return _providers.FirstOrDefault(p =>
|
||||
p.Config.DatabaseKey.Equals(databaseKey, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有数据源的表信息
|
||||
/// </summary>
|
||||
/// <returns>所有表信息列表</returns>
|
||||
public List<DbTableInfo> GetAllTables()
|
||||
{
|
||||
var allTables = new List<DbTableInfo>();
|
||||
|
||||
foreach (var provider in _providers)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tables = provider.GetTables();
|
||||
if (tables != null && tables.Count > 0)
|
||||
{
|
||||
allTables.AddRange(tables);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogUtil.Log.Warning($"获取数据源 {provider.Config.DatabaseKey} 的表信息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return allTables;
|
||||
}
|
||||
}
|
||||
|
||||
93
admin-server/MiaoYu.Core.CodeGenerator/Core/PathResolver.cs
Normal file
93
admin-server/MiaoYu.Core.CodeGenerator/Core/PathResolver.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
|
||||
namespace MiaoYu.Core.CodeGenerator.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 路径解析器
|
||||
/// </summary>
|
||||
[Component]
|
||||
public class PathResolver : IScopedDependency
|
||||
{
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
public PathResolver(IWebHostEnvironment environment)
|
||||
{
|
||||
_environment = environment;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析路径模板
|
||||
/// </summary>
|
||||
/// <param name="template">路径模板(支持占位符)</param>
|
||||
/// <param name="config">数据源配置</param>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <returns>解析后的完整路径</returns>
|
||||
public string ResolvePath(string template, DataSourceConfig config, string tableName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(template))
|
||||
return string.Empty;
|
||||
|
||||
var rootPath = _environment.ContentRootPath
|
||||
.Replace("\\" + _environment.ApplicationName, "");
|
||||
|
||||
var entityName = GetEntityName(tableName, config);
|
||||
var entityNamePlural = config.UsesPluralPath ? entityName + "s" : entityName;
|
||||
|
||||
return template
|
||||
.Replace("{RootPath}", rootPath)
|
||||
.Replace("{AppPath}", _environment.ContentRootPath)
|
||||
.Replace("{Namespace}", config.EntityNamespace)
|
||||
.Replace("{EntityName}", entityName)
|
||||
.Replace("{EntityNamePlural}", entityNamePlural)
|
||||
.Replace("{TableName}", tableName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据命名策略和配置获取实体名
|
||||
/// </summary>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <param name="config">数据源配置</param>
|
||||
/// <returns>实体名</returns>
|
||||
public string GetEntityName(string tableName, DataSourceConfig config)
|
||||
{
|
||||
var baseName = config.NamingStrategy == EntityNamingStrategy.ToPascalCase
|
||||
? ConvertToPascalCase(tableName)
|
||||
: tableName;
|
||||
|
||||
// 应用前缀(如果启用)
|
||||
if (config.EnableEntityPrefix && !string.IsNullOrWhiteSpace(config.EntityPrefix))
|
||||
{
|
||||
return config.EntityPrefix + baseName;
|
||||
}
|
||||
|
||||
return baseName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将下划线命名转换为 PascalCase
|
||||
/// </summary>
|
||||
private static string ConvertToPascalCase(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return input;
|
||||
|
||||
var words = input.Split(new[] { '_', '-' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var result = new System.Text.StringBuilder();
|
||||
|
||||
foreach (var word in words)
|
||||
{
|
||||
if (word.Length > 0)
|
||||
{
|
||||
result.Append(char.ToUpper(word[0]));
|
||||
if (word.Length > 1)
|
||||
{
|
||||
result.Append(word.Substring(1).ToLower());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\projects\project.targets" />
|
||||
|
||||
<ItemGroup>
|
||||
<!-- 基础框架 -->
|
||||
<ProjectReference Include="..\MiaoYu.Core\MiaoYu.Core.csproj" />
|
||||
<ProjectReference Include="..\MiaoYu.Core.Razor\MiaoYu.Core.Razor.csproj" />
|
||||
<ProjectReference Include="..\MiaoYu.Core.FreeSql\MiaoYu.Core.FreeSql.csproj" />
|
||||
<ProjectReference Include="..\MiaoYu.Core.Logs\MiaoYu.Core.Logs.csproj" />
|
||||
<ProjectReference Include="..\MiaoYu.Shared\MiaoYu.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- 数据访问和工具包 -->
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
|
||||
<PackageReference Include="FreeSql" Version="3.2.806" />
|
||||
<PackageReference Include="NPOI" Version="2.6.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
1182
admin-server/MiaoYu.Core.CodeGenerator/MiaoYu.Core.CodeGenerator.xml
Normal file
1182
admin-server/MiaoYu.Core.CodeGenerator/MiaoYu.Core.CodeGenerator.xml
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,43 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 列元信息配置
|
||||
/// </summary>
|
||||
public class ColumnMetaConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列描述
|
||||
/// </summary>
|
||||
public string? Describe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// C# 字段名
|
||||
/// </summary>
|
||||
public string? CsField { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否查询
|
||||
/// </summary>
|
||||
public bool? IsTableSelect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是图片Id
|
||||
/// </summary>
|
||||
public bool? IsImageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示在Column上
|
||||
/// </summary>
|
||||
public bool? IsTableColumnShow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 宽度
|
||||
/// </summary>
|
||||
public int? Width { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源信息 DTO
|
||||
/// </summary>
|
||||
public class DataSourceDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库标识(如:Admin, MiaoYuChat)
|
||||
/// </summary>
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库列信息(从数据库元数据查询)
|
||||
/// </summary>
|
||||
public class DbColumnInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 列名
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库类型
|
||||
/// </summary>
|
||||
public string? DbType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// C# 类型
|
||||
/// </summary>
|
||||
public string? CsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否主键
|
||||
/// </summary>
|
||||
public bool IsPrimary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否自增
|
||||
/// </summary>
|
||||
public bool IsIdentity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可为空
|
||||
/// </summary>
|
||||
public bool IsNullable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大长度
|
||||
/// </summary>
|
||||
public int? MaxLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列位置
|
||||
/// </summary>
|
||||
public int Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列注释
|
||||
/// </summary>
|
||||
public string? Comment { get; set; }
|
||||
}
|
||||
|
||||
38
admin-server/MiaoYu.Core.CodeGenerator/Models/DbTableInfo.cs
Normal file
38
admin-server/MiaoYu.Core.CodeGenerator/Models/DbTableInfo.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表信息(从数据库元数据查询)
|
||||
/// </summary>
|
||||
public class DbTableInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 表名
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表架构
|
||||
/// </summary>
|
||||
public string? Schema { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属数据库标识
|
||||
/// </summary>
|
||||
public string? DataBase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表类型
|
||||
/// </summary>
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表注释
|
||||
/// </summary>
|
||||
public string? Comment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列信息
|
||||
/// </summary>
|
||||
public List<DbColumnInfo>? Columns { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成表 DTO
|
||||
/// </summary>
|
||||
public class GenDbTableDto : LowCodeTable
|
||||
{
|
||||
/// <summary>
|
||||
/// 表字段信息
|
||||
/// </summary>
|
||||
public List<LowCodeTableInfo>? TableInfos { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 命名空间
|
||||
/// </summary>
|
||||
public string? Namespace { get; set; }
|
||||
}
|
||||
|
||||
28
admin-server/MiaoYu.Core.CodeGenerator/Models/GenFormDto.cs
Normal file
28
admin-server/MiaoYu.Core.CodeGenerator/Models/GenFormDto.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成表单模型
|
||||
/// </summary>
|
||||
public class GenFormDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 表名称
|
||||
/// </summary>
|
||||
public string? TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库标识(Admin, MiaoYuChat, LiveForum)
|
||||
/// </summary>
|
||||
public string? DataBase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型代码
|
||||
/// </summary>
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代码文本
|
||||
/// </summary>
|
||||
public string? CodeText { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 低代码表(不依赖数据库实体)
|
||||
/// </summary>
|
||||
public class LowCodeTable
|
||||
{
|
||||
/// <summary>
|
||||
/// 表架构
|
||||
/// </summary>
|
||||
public string? Schema { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属数据库
|
||||
/// </summary>
|
||||
public string? DataBase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
public string? Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表名称
|
||||
/// </summary>
|
||||
public string? TableName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称 描述
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体名称
|
||||
/// </summary>
|
||||
public string? EntityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体保存路径
|
||||
/// </summary>
|
||||
public string? ModelPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务保存路径
|
||||
/// </summary>
|
||||
public string? ServicePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 控制器保存路径
|
||||
/// </summary>
|
||||
public string? ControllerPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前端视图保存路径
|
||||
/// </summary>
|
||||
public string? ClientIndexPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前端信息弹窗保存位置
|
||||
/// </summary>
|
||||
public string? ClientInfoPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前端服务保存位置
|
||||
/// </summary>
|
||||
public string? ClientServicePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否覆盖生成
|
||||
/// </summary>
|
||||
public bool? IsCover { get; set; } = false;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 低代码表列信息(不依赖数据库实体)
|
||||
/// </summary>
|
||||
public class LowCodeTableInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键
|
||||
/// </summary>
|
||||
public bool IsPrimary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自增标识
|
||||
/// </summary>
|
||||
public bool IsIdentity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可DBNull
|
||||
/// </summary>
|
||||
public bool IsNullable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字段位置
|
||||
/// </summary>
|
||||
public int Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列名
|
||||
/// </summary>
|
||||
public string? ColumnName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 列描述
|
||||
/// </summary>
|
||||
public string? Describe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库列类型
|
||||
/// </summary>
|
||||
public string? DatabaseColumnType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// c# 数据类型
|
||||
/// </summary>
|
||||
public string? CsType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// c# 字段
|
||||
/// </summary>
|
||||
public string? CsField { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大长度
|
||||
/// </summary>
|
||||
public int? MaxLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否查询
|
||||
/// </summary>
|
||||
public bool? IsTableSelect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是图片Id
|
||||
/// </summary>
|
||||
public bool? IsImageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示在Column上
|
||||
/// </summary>
|
||||
public bool? IsTableColumnShow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 宽度
|
||||
/// </summary>
|
||||
public string? Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int? OrderById { get; set; }
|
||||
}
|
||||
|
||||
44
admin-server/MiaoYu.Core.CodeGenerator/Models/PagingView.cs
Normal file
44
admin-server/MiaoYu.Core.CodeGenerator/Models/PagingView.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 简化的分页视图模型
|
||||
/// </summary>
|
||||
public class PagingView
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据源
|
||||
/// </summary>
|
||||
public object? DataSource { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总数
|
||||
/// </summary>
|
||||
public long Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总页数
|
||||
/// </summary>
|
||||
public long PageCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 一页显示多少条
|
||||
/// </summary>
|
||||
public int Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public int Page { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="size"></param>
|
||||
public PagingView(int page, int size)
|
||||
{
|
||||
Page = page;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 表元信息配置
|
||||
/// </summary>
|
||||
public class TableMetaConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
public string? DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体名称
|
||||
/// </summary>
|
||||
public string? EntityName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实体保存路径
|
||||
/// </summary>
|
||||
public string? ModelPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务保存路径
|
||||
/// </summary>
|
||||
public string? ServicePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 控制器保存路径
|
||||
/// </summary>
|
||||
public string? ControllerPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前端视图保存路径
|
||||
/// </summary>
|
||||
public string? ClientIndexPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前端信息弹窗保存位置
|
||||
/// </summary>
|
||||
public string? ClientInfoPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前端服务保存位置
|
||||
/// </summary>
|
||||
public string? ClientServicePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否覆盖生成
|
||||
/// </summary>
|
||||
public bool IsCover { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 列配置(Key: ColumnName)
|
||||
/// </summary>
|
||||
public Dictionary<string, ColumnMetaConfig>? Columns { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,765 @@
|
|||
using MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
using MiaoYu.Core.CodeGenerator.Core;
|
||||
|
||||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成服务
|
||||
/// </summary>
|
||||
public class CodeGenerationService : ICodeGenerationService
|
||||
{
|
||||
private readonly string _webRootPath;
|
||||
private readonly string templateRootPath = "/wwwroot/code_generation/template/";
|
||||
private readonly string templateRootPath_v4 = "/wwwroot/code_generation/templatev4/";
|
||||
private readonly string codesRootPath = "/code_generation/codes";
|
||||
private readonly string zipRootPath = "/code_generation/zip";
|
||||
|
||||
//domain 模板文件
|
||||
private readonly string templateModel = "tempModel.cshtml";
|
||||
private readonly string templateService = "tempService.cshtml";
|
||||
private readonly string templateController = "tempController.cshtml";
|
||||
private readonly string templateServiceJs = "tempClientService.cshtml";
|
||||
private readonly string templateIndex = "tempClientIndex.cshtml";
|
||||
private readonly string templateInfo = "tempClientInfo.cshtml";
|
||||
|
||||
// 客户端名称
|
||||
private readonly string projectClientName = "admin-client";
|
||||
|
||||
private readonly IDatabaseTableService _databaseTableService;
|
||||
private readonly IRazorViewRender _razorViewRender;
|
||||
private readonly DataSourceManager _dataSourceManager;
|
||||
private readonly PathResolver _pathResolver;
|
||||
private readonly ITableMetaConfigService _tableMetaConfigService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="databaseTableService">数据库表服务</param>
|
||||
/// <param name="razorViewRender">Razor视图渲染器</param>
|
||||
/// <param name="webHostEnvironment">Web宿主环境</param>
|
||||
/// <param name="dataSourceManager">数据源管理器</param>
|
||||
/// <param name="pathResolver">路径解析器</param>
|
||||
/// <param name="tableMetaConfigService">表元信息配置服务</param>
|
||||
public CodeGenerationService(IDatabaseTableService databaseTableService,
|
||||
IRazorViewRender razorViewRender,
|
||||
IWebHostEnvironment webHostEnvironment,
|
||||
DataSourceManager dataSourceManager,
|
||||
PathResolver pathResolver,
|
||||
ITableMetaConfigService tableMetaConfigService)
|
||||
{
|
||||
_databaseTableService = databaseTableService;
|
||||
_razorViewRender = razorViewRender;
|
||||
_webRootPath = webHostEnvironment.WebRootPath;
|
||||
_dataSourceManager = dataSourceManager;
|
||||
_pathResolver = pathResolver;
|
||||
_tableMetaConfigService = tableMetaConfigService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成上下文集合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public PagingView GetGenContextDtos(int page, int size, GenFormDto search)
|
||||
{
|
||||
var PagingView = new PagingView(page, size);
|
||||
var result = new List<Dictionary<string, object>>();
|
||||
|
||||
var query = _databaseTableService.GetAllTablesByCache().AsEnumerable();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(search.TableName))
|
||||
{
|
||||
query = query.Where(w => w.TableName != null && w.TableName.Contains(search.TableName));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(search.DataBase))
|
||||
{
|
||||
query = query.Where(w => w.DataBase == search.DataBase);
|
||||
}
|
||||
|
||||
var tables = query
|
||||
.Skip((page - 1) * size)
|
||||
.Take(size)
|
||||
.ToList();
|
||||
|
||||
foreach (var item in tables)
|
||||
{
|
||||
var dic = new Dictionary<string, object>();
|
||||
dic.Add(nameof(item.TableName), item.TableName);
|
||||
dic.Add(nameof(item.Remark), item.Remark);
|
||||
dic.Add(nameof(item.DataBase), item.DataBase);
|
||||
|
||||
result.Add(dic);
|
||||
}
|
||||
|
||||
PagingView.Total = query.LongCount();
|
||||
PagingView.Page = page;
|
||||
PagingView.Size = size;
|
||||
PagingView.DataSource = result;
|
||||
PagingView.PageCount = PagingView.Total / size;
|
||||
return PagingView;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有表集合信息
|
||||
/// </summary>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <param name="databaseKey">数据库标识(可选)</param>
|
||||
/// <returns></returns>
|
||||
public GenDbTableDto GetGenContextDtoByTableName(string tableName, string? databaseKey = null)
|
||||
{
|
||||
var query = _databaseTableService.GetAllTables().AsEnumerable();
|
||||
|
||||
// 如果指定了数据库,则精确匹配
|
||||
if (!string.IsNullOrWhiteSpace(databaseKey))
|
||||
{
|
||||
query = query.Where(w => w.TableName == tableName && w.DataBase == databaseKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where(w => w.TableName == tableName);
|
||||
}
|
||||
|
||||
var genDbTableDto = query.FirstOrDefault();
|
||||
|
||||
if (genDbTableDto != null)
|
||||
{
|
||||
FillPathByLowCodeTable(genDbTableDto);
|
||||
}
|
||||
|
||||
return genDbTableDto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据 lowCodeTable 填充路径(支持多数据源)
|
||||
/// </summary>
|
||||
/// <param name="lowCodeTable">低代码表配置</param>
|
||||
/// <returns>填充路径后的低代码表配置</returns>
|
||||
public LowCodeTable FillPathByLowCodeTable(LowCodeTable lowCodeTable)
|
||||
{
|
||||
var provider = _dataSourceManager.GetProvider(lowCodeTable.DataBase ?? DataSourceConstants.Admin);
|
||||
if (provider == null)
|
||||
{
|
||||
LogUtil.Log.Warning($"未找到数据源 {lowCodeTable.DataBase},使用默认Admin配置");
|
||||
provider = _dataSourceManager.GetProvider(DataSourceConstants.Admin);
|
||||
}
|
||||
|
||||
var config = provider!.Config;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(lowCodeTable.ModelPath))
|
||||
{
|
||||
lowCodeTable.ModelPath = _pathResolver.ResolvePath(
|
||||
config.ModelPathTemplate, config, lowCodeTable.TableName);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(lowCodeTable.ServicePath))
|
||||
{
|
||||
lowCodeTable.ServicePath = _pathResolver.ResolvePath(
|
||||
config.ServicePathTemplate, config, lowCodeTable.TableName);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(lowCodeTable.ControllerPath))
|
||||
{
|
||||
lowCodeTable.ControllerPath = _pathResolver.ResolvePath(
|
||||
config.ControllerPathTemplate, config, lowCodeTable.TableName);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(lowCodeTable.ClientIndexPath))
|
||||
{
|
||||
lowCodeTable.ClientIndexPath = _pathResolver.ResolvePath(
|
||||
config.ClientIndexPathTemplate, config, lowCodeTable.TableName);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(lowCodeTable.ClientInfoPath))
|
||||
{
|
||||
lowCodeTable.ClientInfoPath = _pathResolver.ResolvePath(
|
||||
config.ClientInfoPathTemplate, config, lowCodeTable.TableName);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(lowCodeTable.ClientServicePath))
|
||||
{
|
||||
lowCodeTable.ClientServicePath = _pathResolver.ResolvePath(
|
||||
config.ClientServicePathTemplate, config, lowCodeTable.TableName);
|
||||
}
|
||||
|
||||
return lowCodeTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成上下文
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public GenDbTableDto GetGenContextDto(GenFormDto genFormDto)
|
||||
{
|
||||
var tableName = genFormDto.TableName;
|
||||
var tableInfo = GetGenContextDtoByTableName(tableName, genFormDto.DataBase);
|
||||
|
||||
if (tableInfo == null) return null;
|
||||
tableInfo.Namespace = Tools.GetNamespacePrefix<CodeGenerationService>();
|
||||
return tableInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成model(支持多数据源)
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GenModelAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var context = GetGenContextDto(genFormDto);
|
||||
var provider = _dataSourceManager.GetProvider(context.DataBase ?? DataSourceConstants.Admin);
|
||||
var templatePath = provider?.Config.TemplatePath ?? templateRootPath;
|
||||
return ClearSymbol(await _razorViewRender.RenderAsync(templatePath + templateModel, context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成service(支持多数据源)
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GenServiceAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var context = GetGenContextDto(genFormDto);
|
||||
var provider = _dataSourceManager.GetProvider(context.DataBase ?? DataSourceConstants.Admin);
|
||||
var templatePath = provider?.Config.TemplatePath ?? templateRootPath;
|
||||
return ClearSymbol(await _razorViewRender.RenderAsync(templatePath + templateService, context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成controller(支持多数据源)
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GenControllerAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var context = GetGenContextDto(genFormDto);
|
||||
var provider = _dataSourceManager.GetProvider(context.DataBase ?? DataSourceConstants.Admin);
|
||||
var templatePath = provider?.Config.TemplatePath ?? templateRootPath;
|
||||
return ClearSymbol(await _razorViewRender.RenderAsync(templatePath + templateController, context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成service js(支持多数据源)
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GenServiceJsAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var context = GetGenContextDto(genFormDto);
|
||||
var provider = _dataSourceManager.GetProvider(context.DataBase ?? DataSourceConstants.Admin);
|
||||
var templatePath = provider?.Config.TemplatePath ?? templateRootPath;
|
||||
return ClearSymbol(await _razorViewRender.RenderAsync(templatePath + templateServiceJs, context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成 index vue(支持多数据源)
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GenIndexAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var context = GetGenContextDto(genFormDto);
|
||||
var provider = _dataSourceManager.GetProvider(context.DataBase ?? DataSourceConstants.Admin);
|
||||
var templatePath = provider?.Config.TemplatePath ?? templateRootPath;
|
||||
return ClearSymbol(await _razorViewRender.RenderAsync(templatePath + templateIndex, context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成 info vue(支持多数据源)
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GenInfoAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var context = GetGenContextDto(genFormDto);
|
||||
var provider = _dataSourceManager.GetProvider(context.DataBase ?? DataSourceConstants.Admin);
|
||||
var templatePath = provider?.Config.TemplatePath ?? templateRootPath;
|
||||
return ClearSymbol(await _razorViewRender.RenderAsync(templatePath + templateInfo, context));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> GetCodeByTypeAndTableNameAsync(GenFormDto genFormDto)
|
||||
{
|
||||
return genFormDto.Type switch
|
||||
{
|
||||
"MiaoYu.Models" => await GenModelAsync(genFormDto),
|
||||
//"MiaoYu.Repository.DbSet" => await this.CreateRepositoryDbSetAsync(),
|
||||
"MiaoYu.Services.Admin" => await GenServiceAsync(genFormDto),
|
||||
"MiaoYu.Controllers.Admin" => await GenControllerAsync(genFormDto),
|
||||
"Client.Index" => await GenIndexAsync(genFormDto),
|
||||
"Client.Info" => await GenInfoAsync(genFormDto),
|
||||
"Client.Service" => await GenServiceJsAsync(genFormDto),
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建所有代码文件
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CreateAllCodeFilesAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var tables = _databaseTableService.GetAllTablesByCache();
|
||||
|
||||
foreach (var item in tables)
|
||||
{
|
||||
genFormDto.TableName = item.TableName;
|
||||
genFormDto.DataBase = item.DataBase;
|
||||
await CreateCodeFilesAsync(genFormDto);
|
||||
|
||||
// 保存元信息到配置文件
|
||||
await SaveTableMetaConfigAsync(item);
|
||||
|
||||
await Task.Delay(25);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取下载代码信息
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(byte[] codeBytes, string contentType, string fileName)> DownloadAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var fileName = FindCodeFileClassName(genFormDto);
|
||||
|
||||
var contentType = Tools.GetFileContentType[".cs"];
|
||||
if (fileName == "Index.vue" || fileName == "Info.vue")
|
||||
{
|
||||
contentType = Tools.GetFileContentType[".txt"];
|
||||
}
|
||||
|
||||
return (Encoding.UTF8.GetBytes(await GetCodeByTypeAndTableNameAsync(genFormDto)), contentType, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型下载所有代码
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<(byte[] codeBytes, string contentType, string fileName)> DownloadAllAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var isViews = genFormDto.Type == "Client.Index" || genFormDto.Type == "Client.Info";
|
||||
var success = await CreateAllCodeFilesAsync(genFormDto);
|
||||
|
||||
if (!success) LogUtil.Log.Warning("无法下载,代码创建失败!");
|
||||
|
||||
string path;
|
||||
string zipPath;
|
||||
|
||||
if (isViews)
|
||||
{
|
||||
path = $"{_webRootPath}{codesRootPath}/pages";
|
||||
zipPath = $"{_webRootPath}{zipRootPath}";
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(zipPath))
|
||||
{
|
||||
Directory.CreateDirectory(zipPath);
|
||||
}
|
||||
|
||||
zipPath += "/pages.zip";
|
||||
}
|
||||
else
|
||||
{
|
||||
path = $"{_webRootPath}{codesRootPath}/{genFormDto.Type}";
|
||||
zipPath = $"{_webRootPath}{zipRootPath}";
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(zipPath))
|
||||
{
|
||||
Directory.CreateDirectory(zipPath);
|
||||
}
|
||||
|
||||
zipPath += $"/{genFormDto.Type}.zip";
|
||||
}
|
||||
|
||||
//开始压缩
|
||||
var zip = new MiaoYu.Core.Zips.Zip(path, zipPath);
|
||||
var bytes = await File.ReadAllBytesAsync(zipPath);
|
||||
|
||||
//删除文件
|
||||
if (File.Exists(zipPath)) File.Delete(zipPath);
|
||||
if (Directory.Exists(path)) Directory.Delete(path, true);
|
||||
|
||||
return (bytes, Tools.GetFileContentType[".zip"], $"{(isViews ? "pages" : genFormDto.Type)}.zip");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建数据库字典文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public (byte[] excel, string dataBase) CreateDataDictionary()
|
||||
{
|
||||
var tables = _databaseTableService.GetAllTablesByCache();
|
||||
var workbook = new XSSFWorkbook();
|
||||
var dataBaseName = _databaseTableService.GetDatabaseName();
|
||||
|
||||
foreach (var item in tables)
|
||||
{
|
||||
var sheet = workbook.CreateSheet(item.TableName + (string.IsNullOrWhiteSpace(item.Remark) ? "" : "_" + item.Remark));
|
||||
|
||||
var i = 0;
|
||||
|
||||
#region 配置表头
|
||||
|
||||
var rowTitle = sheet.CreateRow(i);
|
||||
rowTitle.CreateCell(0).SetCellValue("表空间");
|
||||
sheet.SetColumnWidth(0, 20 * 256);
|
||||
rowTitle.CreateCell(1).SetCellValue("表名");
|
||||
sheet.SetColumnWidth(1, 20 * 256);
|
||||
rowTitle.CreateCell(2).SetCellValue("表描述");
|
||||
sheet.SetColumnWidth(2, 20 * 256);
|
||||
rowTitle.CreateCell(3).SetCellValue("字段");
|
||||
sheet.SetColumnWidth(3, 20 * 256);
|
||||
rowTitle.CreateCell(4).SetCellValue("字段描述");
|
||||
sheet.SetColumnWidth(4, 20 * 256);
|
||||
rowTitle.CreateCell(5).SetCellValue("是否主键");
|
||||
sheet.SetColumnWidth(5, 20 * 256);
|
||||
rowTitle.CreateCell(6).SetCellValue("是否自增");
|
||||
sheet.SetColumnWidth(6, 20 * 256);
|
||||
rowTitle.CreateCell(7).SetCellValue("可否为 Null");
|
||||
sheet.SetColumnWidth(7, 20 * 256);
|
||||
rowTitle.CreateCell(8).SetCellValue("数据库类型");
|
||||
sheet.SetColumnWidth(8, 20 * 256);
|
||||
rowTitle.CreateCell(9).SetCellValue("C#类型");
|
||||
sheet.SetColumnWidth(9, 20 * 256);
|
||||
rowTitle.CreateCell(10).SetCellValue("数据长度");
|
||||
sheet.SetColumnWidth(10, 20 * 256);
|
||||
|
||||
#endregion
|
||||
//组装数据
|
||||
foreach (var tableInfo in item.TableInfos)
|
||||
{
|
||||
i++;
|
||||
var index = item.TableInfos.IndexOf(tableInfo);
|
||||
var row = sheet.CreateRow(i);
|
||||
//row.CreateCell(0).SetCellValue(item.Schema);
|
||||
row.CreateCell(1).SetCellValue(item.TableName);
|
||||
row.CreateCell(2).SetCellValue(item.Remark);
|
||||
row.CreateCell(3).SetCellValue(tableInfo.ColumnName);
|
||||
row.CreateCell(4).SetCellValue(tableInfo.Describe);
|
||||
row.CreateCell(5).SetCellValue(tableInfo.IsPrimary ? "是" : "否");
|
||||
row.CreateCell(6).SetCellValue(tableInfo.IsIdentity ? "是" : "否");
|
||||
row.CreateCell(7).SetCellValue(tableInfo.IsNullable ? "是" : "否");
|
||||
row.CreateCell(8).SetCellValue(tableInfo.DatabaseColumnType);
|
||||
row.CreateCell(9).SetCellValue(tableInfo.CsType);
|
||||
row.CreateCell(10).SetCellValue(tableInfo.MaxLength ?? 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//填充byte
|
||||
using var ms = new MemoryStream();
|
||||
workbook.Write(ms);
|
||||
return (ms.ToArray(), dataBaseName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动导入文件到项目
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
public async Task AutoImprotProjectAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var context = GetGenContextDto(genFormDto);
|
||||
if (context == null)
|
||||
{
|
||||
LogUtil.Log.Warning($"找不到数据表: {genFormDto.TableName} (数据库: {genFormDto.DataBase})");
|
||||
return;
|
||||
}
|
||||
|
||||
//获取表路径信息
|
||||
var tables = _databaseTableService.GetAllTablesByCache();
|
||||
var tableInfo = tables.FirstOrDefault(w =>
|
||||
w.TableName == genFormDto.TableName &&
|
||||
w.DataBase == genFormDto.DataBase);
|
||||
|
||||
var fileTyps = Enum.GetValues<FileTypeEnum>();
|
||||
|
||||
foreach (var fileType in fileTyps)
|
||||
{
|
||||
var (filePath, oldName, replaceName) = GetFileAbsolutelyPath(
|
||||
genFormDto.TableName, fileType, genFormDto.DataBase);
|
||||
await SaveToFileAsync(genFormDto.TableName, fileType, filePath, oldName, replaceName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有数据库列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<DataSourceDto> GetAllDataSources()
|
||||
{
|
||||
var providers = _dataSourceManager.GetAllProviders()
|
||||
.OrderBy(p => p.Config.Order)
|
||||
.ToList();
|
||||
|
||||
return providers.Select(p => new DataSourceDto
|
||||
{
|
||||
Key = p.Config.DatabaseKey,
|
||||
DisplayName = p.Config.DisplayName
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 清除多余符号
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <returns></returns>
|
||||
private string ClearSymbol(StringBuilder code)
|
||||
{
|
||||
return code
|
||||
.ToString()
|
||||
.Replace("<pre>", "")
|
||||
.Replace("</pre>", "")
|
||||
.Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建代码文件
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<string> CreateCodeFilesAsync(GenFormDto genFormDto)
|
||||
{
|
||||
var path = $"{_webRootPath}{codesRootPath}";
|
||||
|
||||
if (genFormDto.Type == "Client.Index" || genFormDto.Type == "Client.Info")
|
||||
{
|
||||
path += $"/pages"; //
|
||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||
path += $"/{genFormDto.TableName}";
|
||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||
//Index
|
||||
var codeString = await GenIndexAsync(genFormDto);
|
||||
await File.WriteAllTextAsync($"{path}/Index.vue", codeString, Encoding.UTF8);
|
||||
//Info
|
||||
codeString = await GenInfoAsync(genFormDto);
|
||||
await File.WriteAllTextAsync($"{path}/Info.vue", codeString, Encoding.UTF8);
|
||||
return path;
|
||||
}
|
||||
|
||||
//
|
||||
path = $"{_webRootPath}{codesRootPath}/{genFormDto.Type}";
|
||||
var className = FindCodeFileClassName(genFormDto);
|
||||
var code = await GetCodeByTypeAndTableNameAsync(genFormDto);
|
||||
//
|
||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||
await File.WriteAllTextAsync($"{path}/{className}", code, Encoding.UTF8);
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码文件名称
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
private string FindCodeFileClassName(GenFormDto genFormDto)
|
||||
{
|
||||
var provider = _dataSourceManager.GetProvider(genFormDto.DataBase ?? DataSourceConstants.Admin);
|
||||
var entityName = _pathResolver.GetEntityName(genFormDto.TableName, provider.Config);
|
||||
|
||||
return genFormDto.Type switch
|
||||
{
|
||||
"MiaoYu.Models" => $"{entityName}.cs",
|
||||
"MiaoYu.Services.Admin" => $"{entityName}Service.cs",
|
||||
"MiaoYu.Controllers.Admin" => $"{entityName}Controller.cs",
|
||||
"Client.Index" => $"Index.vue",
|
||||
"Client.Info" => $"Info.vue",
|
||||
"Client.Service" => $"{entityName}Service.ts",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取要生成文件的绝对路径
|
||||
/// </summary>
|
||||
/// <param name="tableName"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="databaseKey">数据库标识(可选)</param>
|
||||
/// <returns></returns>
|
||||
private (string, string, string) GetFileAbsolutelyPath(string tableName, FileTypeEnum type, string? databaseKey = null)
|
||||
{
|
||||
var replaceName = string.Empty;
|
||||
var oldFileName = string.Empty;
|
||||
var dto = new GenFormDto() { TableName = tableName, Type = GetEnumDescription(type), DataBase = databaseKey };
|
||||
|
||||
var provider = _dataSourceManager.GetProvider(databaseKey ?? DataSourceConstants.Admin);
|
||||
var entityName = _pathResolver.GetEntityName(tableName, provider.Config);
|
||||
var entityNameWithPath = provider.Config.UsesPluralPath ? entityName + "s" : entityName;
|
||||
|
||||
var fileName = FindCodeFileClassName(dto);
|
||||
var path = string.Empty;
|
||||
//获取表路径信息
|
||||
var tableInfo = GetGenContextDtoByTableName(tableName, databaseKey);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FileTypeEnum.Model:
|
||||
path = provider.Config.UsesPluralPath
|
||||
? $"{tableInfo.ModelPath}/{entityNameWithPath}"
|
||||
: tableInfo.ModelPath;
|
||||
break;
|
||||
case FileTypeEnum.Service:
|
||||
path = provider.Config.UsesPluralPath
|
||||
? $"{tableInfo.ServicePath}/{entityNameWithPath}"
|
||||
: tableInfo.ServicePath;
|
||||
break;
|
||||
case FileTypeEnum.Controller:
|
||||
path = provider.Config.UsesPluralPath
|
||||
? $"{tableInfo.ControllerPath}/{entityNameWithPath}"
|
||||
: tableInfo.ControllerPath;
|
||||
break;
|
||||
case FileTypeEnum.ClientIndex:
|
||||
path = tableInfo.ClientIndexPath + $"/{tableName}s";
|
||||
break;
|
||||
case FileTypeEnum.ClientInfo:
|
||||
path = tableInfo.ClientInfoPath + $"/{tableName}s";
|
||||
break;
|
||||
case FileTypeEnum.ClientService:
|
||||
path = tableInfo.ClientServicePath + $"/{tableName}s";
|
||||
break;
|
||||
}
|
||||
|
||||
var fileDirPath = Path.Combine(path);
|
||||
if (!Directory.Exists(fileDirPath))
|
||||
{
|
||||
Directory.CreateDirectory(fileDirPath);
|
||||
}
|
||||
|
||||
// 组合成完整路劲
|
||||
var filePath = $"{fileDirPath}/{fileName}";
|
||||
// 判断是否覆盖文件
|
||||
if (!(tableInfo.IsCover ?? false))
|
||||
{
|
||||
// 如果文件已存在 加尾缀 重新创建文件夹
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
oldFileName = FindCodeFileClassName(dto);
|
||||
replaceName = $"{oldFileName}{DateTime.Now.ToString("yyyyMMddHHmmss")}";
|
||||
filePath = $"{fileDirPath}/{replaceName}";
|
||||
}
|
||||
}
|
||||
|
||||
return (filePath, oldFileName, replaceName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存到文件
|
||||
/// </summary>
|
||||
/// <param name="tableName"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="oldName"></param>
|
||||
/// <param name="replaceName"></param>
|
||||
/// <returns></returns>
|
||||
private async Task SaveToFileAsync(string tableName, FileTypeEnum type, string filePath, string oldName, string replaceName)
|
||||
{
|
||||
var dto = new GenFormDto() { TableName = tableName, Type = GetEnumDescription(type) };
|
||||
var codeString = await GetCodeByTypeAndTableNameAsync(dto);
|
||||
if (!string.IsNullOrWhiteSpace(replaceName) && !string.IsNullOrWhiteSpace(oldName))
|
||||
{
|
||||
if (type == FileTypeEnum.Model || type == FileTypeEnum.Service || type == FileTypeEnum.Controller)
|
||||
{
|
||||
codeString = codeString.Replace(oldName, replaceName);
|
||||
}
|
||||
}
|
||||
await Task.Delay(500);
|
||||
await File.WriteAllTextAsync(filePath, codeString, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取枚举上的描述特性
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private string GetEnumDescription(FileTypeEnum type)
|
||||
{
|
||||
return type.GetType().GetField(Enum.GetName(type)).GetCustomAttribute<DescriptionAttribute>().Description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存表元信息到配置文件
|
||||
/// </summary>
|
||||
/// <param name="tableDto">表信息</param>
|
||||
private async Task SaveTableMetaConfigAsync(GenDbTableDto tableDto)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tableDto.DataBase) || string.IsNullOrEmpty(tableDto.TableName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var config = new TableMetaConfig
|
||||
{
|
||||
DisplayName = tableDto.DisplayName,
|
||||
EntityName = tableDto.EntityName,
|
||||
Remark = tableDto.Remark,
|
||||
ModelPath = tableDto.ModelPath,
|
||||
ServicePath = tableDto.ServicePath,
|
||||
ControllerPath = tableDto.ControllerPath,
|
||||
ClientIndexPath = tableDto.ClientIndexPath,
|
||||
ClientInfoPath = tableDto.ClientInfoPath,
|
||||
ClientServicePath = tableDto.ClientServicePath,
|
||||
IsCover = tableDto.IsCover ?? false,
|
||||
Columns = new Dictionary<string, ColumnMetaConfig>()
|
||||
};
|
||||
|
||||
// 保存列配置
|
||||
if (tableDto.TableInfos != null)
|
||||
{
|
||||
foreach (var column in tableDto.TableInfos)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(column.ColumnName))
|
||||
{
|
||||
config.Columns[column.ColumnName] = new ColumnMetaConfig
|
||||
{
|
||||
DisplayName = column.DisplayName,
|
||||
Describe = column.Describe,
|
||||
CsField = column.CsField,
|
||||
IsTableSelect = column.IsTableSelect,
|
||||
IsImageId = column.IsImageId,
|
||||
IsTableColumnShow = column.IsTableColumnShow
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _tableMetaConfigService.SaveConfigAsync(tableDto.DataBase, tableDto.TableName, config);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public enum FileTypeEnum
|
||||
{
|
||||
[Description("MiaoYu.Models")]
|
||||
Model,
|
||||
[Description("MiaoYu.Services.Admin")]
|
||||
Service,
|
||||
[Description("MiaoYu.Controllers.Admin")]
|
||||
Controller,
|
||||
[Description("Client.Index")]
|
||||
ClientIndex,
|
||||
[Description("Client.Info")]
|
||||
ClientInfo,
|
||||
[Description("Client.Service")]
|
||||
ClientService
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表服务
|
||||
/// </summary>
|
||||
public class DatabaseTableService : IDatabaseTableService
|
||||
{
|
||||
private readonly ITableSchemaCache _tableSchemaCache;
|
||||
private readonly ITableMetaConfigService _tableMetaConfigService;
|
||||
private readonly ILogger<DatabaseTableService> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="tableSchemaCache">表结构缓存</param>
|
||||
/// <param name="tableMetaConfigService">表元信息配置服务</param>
|
||||
/// <param name="logger">日志</param>
|
||||
public DatabaseTableService(
|
||||
ITableSchemaCache tableSchemaCache,
|
||||
ITableMetaConfigService tableMetaConfigService,
|
||||
ILogger<DatabaseTableService> logger)
|
||||
{
|
||||
_tableSchemaCache = tableSchemaCache;
|
||||
_tableMetaConfigService = tableMetaConfigService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的表 包含表下面的列(支持多数据源)
|
||||
/// </summary>
|
||||
/// <returns>所有表信息列表</returns>
|
||||
public virtual List<DbTableInfo> GetAllTableInfos()
|
||||
{
|
||||
return _tableSchemaCache.GetAllTables();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的表(合并缓存和配置文件)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual List<GenDbTableDto> GetAllTables()
|
||||
{
|
||||
var schemaTables = _tableSchemaCache.GetAllTables();
|
||||
var result = new List<GenDbTableDto>();
|
||||
|
||||
foreach (var schemaTable in schemaTables)
|
||||
{
|
||||
var genTable = MergeTableWithConfig(schemaTable);
|
||||
result.Add(genTable);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取表信息根据缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<GenDbTableDto> GetAllTablesByCache() => GetAllTables();
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有表缓存信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool ClearAllTablesByCache()
|
||||
{
|
||||
_tableSchemaCache.ClearCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓存
|
||||
/// </summary>
|
||||
public void RefreshCache()
|
||||
{
|
||||
_tableSchemaCache.RefreshCache();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库名称
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string? GetDatabaseName()
|
||||
{
|
||||
var tables = _tableSchemaCache.GetAllTables();
|
||||
return tables.FirstOrDefault()?.DataBase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 合并表结构和配置文件信息
|
||||
/// </summary>
|
||||
private GenDbTableDto MergeTableWithConfig(DbTableInfo schemaTable)
|
||||
{
|
||||
var genTable = new GenDbTableDto
|
||||
{
|
||||
TableName = schemaTable.Name,
|
||||
DataBase = schemaTable.DataBase,
|
||||
Schema = schemaTable.Schema,
|
||||
Type = schemaTable.Type,
|
||||
Remark = schemaTable.Comment,
|
||||
TableInfos = schemaTable.Columns?.Select(c => new LowCodeTableInfo
|
||||
{
|
||||
ColumnName = c.Name,
|
||||
IsPrimary = c.IsPrimary,
|
||||
IsIdentity = c.IsIdentity,
|
||||
IsNullable = c.IsNullable,
|
||||
Position = c.Position,
|
||||
DatabaseColumnType = c.DbType,
|
||||
CsType = c.CsType,
|
||||
MaxLength = c.MaxLength,
|
||||
Describe = c.Comment
|
||||
}).ToList() ?? new List<LowCodeTableInfo>()
|
||||
};
|
||||
|
||||
// 尝试从配置文件加载元信息
|
||||
if (!string.IsNullOrEmpty(schemaTable.DataBase) && !string.IsNullOrEmpty(schemaTable.Name))
|
||||
{
|
||||
var config = _tableMetaConfigService.LoadConfig(schemaTable.DataBase, schemaTable.Name);
|
||||
if (config != null)
|
||||
{
|
||||
// 使用配置文件中的元信息覆盖
|
||||
genTable.DisplayName = config.DisplayName;
|
||||
genTable.EntityName = config.EntityName;
|
||||
genTable.Remark = config.Remark ?? genTable.Remark;
|
||||
genTable.ModelPath = config.ModelPath;
|
||||
genTable.ServicePath = config.ServicePath;
|
||||
genTable.ControllerPath = config.ControllerPath;
|
||||
genTable.ClientIndexPath = config.ClientIndexPath;
|
||||
genTable.ClientInfoPath = config.ClientInfoPath;
|
||||
genTable.ClientServicePath = config.ClientServicePath;
|
||||
genTable.IsCover = config.IsCover;
|
||||
|
||||
// 合并列配置
|
||||
if (config.Columns != null && genTable.TableInfos != null)
|
||||
{
|
||||
foreach (var columnInfo in genTable.TableInfos)
|
||||
{
|
||||
if (config.Columns.TryGetValue(columnInfo.ColumnName ?? "", out var columnConfig))
|
||||
{
|
||||
columnInfo.DisplayName = columnConfig.DisplayName;
|
||||
columnInfo.Describe = columnConfig.Describe ?? columnInfo.Describe;
|
||||
columnInfo.CsField = columnConfig.CsField;
|
||||
columnInfo.IsTableSelect = columnConfig.IsTableSelect;
|
||||
columnInfo.IsImageId = columnConfig.IsImageId;
|
||||
columnInfo.IsTableColumnShow = columnConfig.IsTableColumnShow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return genTable;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成服务
|
||||
/// </summary>
|
||||
public interface ICodeGenerationService : IScopedDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成上下文集合
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
PagingView GetGenContextDtos(int page, int size, GenFormDto search);
|
||||
|
||||
/// <summary>
|
||||
/// 获取表字段集合
|
||||
/// </summary>
|
||||
/// <param name="tableName"></param>
|
||||
/// <param name="databaseKey">数据库标识(可选)</param>
|
||||
/// <returns></returns>
|
||||
GenDbTableDto GetGenContextDtoByTableName(string tableName, string? databaseKey = null);
|
||||
|
||||
/// <summary>
|
||||
/// 根据 lowCodeTable 填充路径
|
||||
/// </summary>
|
||||
/// <param name="lowCodeTable"></param>
|
||||
/// <returns></returns>
|
||||
LowCodeTable FillPathByLowCodeTable(LowCodeTable lowCodeTable);
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成上下文
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
GenDbTableDto GetGenContextDto(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 生成 model
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GenModelAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 生成 service
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GenServiceAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 生成 controller
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GenControllerAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 生成 serviceJs
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GenServiceJsAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 生成 Index
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GenIndexAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 生成 Info
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GenInfoAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GetCodeByTypeAndTableNameAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 下载
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<(byte[] codeBytes, string contentType, string fileName)> DownloadAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型下载类型下所有的代码
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<(byte[] codeBytes, string contentType, string fileName)> DownloadAllAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 创建所有代码文件
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> CreateAllCodeFilesAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 创建数据字典文件 excel
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
(byte[] excel, string dataBase) CreateDataDictionary();
|
||||
|
||||
/// <summary>
|
||||
/// 代码生成自动导入项目
|
||||
/// </summary>
|
||||
/// <param name="genFormDto"></param>
|
||||
/// <returns></returns>
|
||||
Task AutoImprotProjectAsync(GenFormDto genFormDto);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有数据库列表
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<DataSourceDto> GetAllDataSources();
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表服务接口
|
||||
/// </summary>
|
||||
public interface IDatabaseTableService : IScopedDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有的表 包含表下面的列(支持多数据源)
|
||||
/// </summary>
|
||||
/// <returns>所有表信息列表</returns>
|
||||
List<DbTableInfo> GetAllTableInfos();
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的表 包含表下面的列
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<GenDbTableDto> GetAllTables();
|
||||
|
||||
/// <summary>
|
||||
/// 获取表信息根据缓存
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<GenDbTableDto> GetAllTablesByCache();
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有表缓存信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool ClearAllTablesByCache();
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓存
|
||||
/// </summary>
|
||||
void RefreshCache();
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库名称
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string? GetDatabaseName();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 表元信息配置服务接口
|
||||
/// </summary>
|
||||
public interface ITableMetaConfigService : IScopedDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载表元信息配置
|
||||
/// </summary>
|
||||
/// <param name="databaseKey">数据库标识</param>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <returns>配置对象,不存在则返回 null</returns>
|
||||
TableMetaConfig? LoadConfig(string databaseKey, string tableName);
|
||||
|
||||
/// <summary>
|
||||
/// 保存表元信息配置
|
||||
/// </summary>
|
||||
/// <param name="databaseKey">数据库标识</param>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <param name="config">配置对象</param>
|
||||
/// <returns></returns>
|
||||
Task SaveConfigAsync(string databaseKey, string tableName, TableMetaConfig config);
|
||||
|
||||
/// <summary>
|
||||
/// 检查配置文件是否存在
|
||||
/// </summary>
|
||||
/// <param name="databaseKey">数据库标识</param>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <returns></returns>
|
||||
bool ExistsConfig(string databaseKey, string tableName);
|
||||
|
||||
/// <summary>
|
||||
/// 删除配置文件
|
||||
/// </summary>
|
||||
/// <param name="databaseKey">数据库标识</param>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <returns></returns>
|
||||
Task DeleteConfigAsync(string databaseKey, string tableName);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 表结构缓存接口
|
||||
/// </summary>
|
||||
public interface ITableSchemaCache : IScopedDependency
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有表信息(从缓存或数据库)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
List<DbTableInfo> GetAllTables();
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓存
|
||||
/// </summary>
|
||||
void RefreshCache();
|
||||
|
||||
/// <summary>
|
||||
/// 清除缓存
|
||||
/// </summary>
|
||||
void ClearCache();
|
||||
|
||||
/// <summary>
|
||||
/// 根据数据库和表名获取表信息
|
||||
/// </summary>
|
||||
/// <param name="databaseKey">数据库标识</param>
|
||||
/// <param name="tableName">表名</param>
|
||||
/// <returns></returns>
|
||||
DbTableInfo? GetTable(string databaseKey, string tableName);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
using System.Text.Json;
|
||||
|
||||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 表元信息配置服务实现
|
||||
/// </summary>
|
||||
[Component]
|
||||
public class TableMetaConfigService : ITableMetaConfigService
|
||||
{
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
private readonly ILogger<TableMetaConfigService> _logger;
|
||||
|
||||
// JSON 序列化选项
|
||||
private static readonly JsonSerializerOptions _jsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
|
||||
public TableMetaConfigService(IWebHostEnvironment environment, ILogger<TableMetaConfigService> logger)
|
||||
{
|
||||
_environment = environment;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取配置文件路径
|
||||
/// </summary>
|
||||
private string GetConfigFilePath(string databaseKey, string tableName)
|
||||
{
|
||||
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
var configDir = Path.Combine(baseDir, "CodeGenConfig", databaseKey);
|
||||
|
||||
// 确保目录存在
|
||||
if (!Directory.Exists(configDir))
|
||||
{
|
||||
Directory.CreateDirectory(configDir);
|
||||
}
|
||||
|
||||
return Path.Combine(configDir, $"{tableName}.json");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载表元信息配置
|
||||
/// </summary>
|
||||
public TableMetaConfig? LoadConfig(string databaseKey, string tableName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = GetConfigFilePath(databaseKey, tableName);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var json = File.ReadAllText(filePath);
|
||||
var config = JsonSerializer.Deserialize<TableMetaConfig>(json, _jsonOptions);
|
||||
|
||||
_logger.LogDebug("成功加载配置: {DatabaseKey}/{TableName}", databaseKey, tableName);
|
||||
|
||||
return config;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "加载配置文件失败: {DatabaseKey}/{TableName}", databaseKey, tableName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存表元信息配置
|
||||
/// </summary>
|
||||
public async Task SaveConfigAsync(string databaseKey, string tableName, TableMetaConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = GetConfigFilePath(databaseKey, tableName);
|
||||
var json = JsonSerializer.Serialize(config, _jsonOptions);
|
||||
|
||||
await File.WriteAllTextAsync(filePath, json);
|
||||
|
||||
_logger.LogInformation("成功保存配置: {DatabaseKey}/{TableName}", databaseKey, tableName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "保存配置文件失败: {DatabaseKey}/{TableName}", databaseKey, tableName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查配置文件是否存在
|
||||
/// </summary>
|
||||
public bool ExistsConfig(string databaseKey, string tableName)
|
||||
{
|
||||
var filePath = GetConfigFilePath(databaseKey, tableName);
|
||||
return File.Exists(filePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除配置文件
|
||||
/// </summary>
|
||||
public async Task DeleteConfigAsync(string databaseKey, string tableName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filePath = GetConfigFilePath(databaseKey, tableName);
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
await Task.Run(() => File.Delete(filePath));
|
||||
_logger.LogInformation("成功删除配置: {DatabaseKey}/{TableName}", databaseKey, tableName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "删除配置文件失败: {DatabaseKey}/{TableName}", databaseKey, tableName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
namespace MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 表结构缓存服务实现
|
||||
/// </summary>
|
||||
[Component]
|
||||
public class TableSchemaCache : ITableSchemaCache
|
||||
{
|
||||
private readonly IMemoryCache _memoryCache;
|
||||
private readonly DataSourceManager _dataSourceManager;
|
||||
private readonly ILogger<TableSchemaCache> _logger;
|
||||
|
||||
private const string CACHE_KEY = "CodeGenerator:AllTables";
|
||||
private static readonly TimeSpan CACHE_DURATION = TimeSpan.FromMinutes(20);
|
||||
|
||||
public TableSchemaCache(
|
||||
IMemoryCache memoryCache,
|
||||
DataSourceManager dataSourceManager,
|
||||
ILogger<TableSchemaCache> logger)
|
||||
{
|
||||
_memoryCache = memoryCache;
|
||||
_dataSourceManager = dataSourceManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有表信息(从缓存或数据库)
|
||||
/// </summary>
|
||||
public List<DbTableInfo> GetAllTables()
|
||||
{
|
||||
return _memoryCache.GetOrCreate(CACHE_KEY, entry =>
|
||||
{
|
||||
entry.SlidingExpiration = CACHE_DURATION;
|
||||
|
||||
_logger.LogInformation("缓存未命中,从数据库查询表结构信息");
|
||||
|
||||
var tables = _dataSourceManager.GetAllTables();
|
||||
|
||||
_logger.LogInformation("成功加载 {Count} 个表到缓存", tables.Count);
|
||||
|
||||
return tables;
|
||||
}) ?? new List<DbTableInfo>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新缓存
|
||||
/// </summary>
|
||||
public void RefreshCache()
|
||||
{
|
||||
_logger.LogInformation("手动刷新表结构缓存");
|
||||
|
||||
_memoryCache.Remove(CACHE_KEY);
|
||||
|
||||
// 重新加载
|
||||
GetAllTables();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除缓存
|
||||
/// </summary>
|
||||
public void ClearCache()
|
||||
{
|
||||
_logger.LogInformation("清除表结构缓存");
|
||||
_memoryCache.Remove(CACHE_KEY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据数据库和表名获取表信息
|
||||
/// </summary>
|
||||
public DbTableInfo? GetTable(string databaseKey, string tableName)
|
||||
{
|
||||
var allTables = GetAllTables();
|
||||
|
||||
return allTables.FirstOrDefault(t =>
|
||||
t.DataBase?.Equals(databaseKey, StringComparison.OrdinalIgnoreCase) == true &&
|
||||
t.Name?.Equals(tableName, StringComparison.OrdinalIgnoreCase) == true);
|
||||
}
|
||||
}
|
||||
|
||||
22
admin-server/MiaoYu.Core.CodeGenerator/Usings.cs
Normal file
22
admin-server/MiaoYu.Core.CodeGenerator/Usings.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
global using System.Text;
|
||||
global using System.Threading.Tasks;
|
||||
global using System.IO;
|
||||
global using System.Reflection;
|
||||
global using System.ComponentModel;
|
||||
global using Microsoft.Extensions.DependencyInjection;
|
||||
global using Microsoft.Extensions.Caching.Memory;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using Microsoft.AspNetCore.Hosting;
|
||||
global using NPOI.XSSF.UserModel;
|
||||
global using HZY.Framework.DependencyInjection;
|
||||
global using HZY.Framework.DependencyInjection.Attributes;
|
||||
global using MiaoYu.Core.Logs;
|
||||
global using MiaoYu.Core.Razor.Services;
|
||||
global using MiaoYu.Core.CodeGenerator.Abstractions;
|
||||
global using MiaoYu.Core.CodeGenerator.Core;
|
||||
global using MiaoYu.Core.CodeGenerator.Models;
|
||||
global using MiaoYu.Core.CodeGenerator.Services;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>MiaoYu.Core.FreeSql</name>
|
||||
|
|
|
|||
591
admin-server/前端接口对接文档.md
Normal file
591
admin-server/前端接口对接文档.md
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
# 低代码生成平台 - 前端接口对接文档
|
||||
|
||||
## 📋 更新概述
|
||||
|
||||
本次后端更新新增了数据库选择功能,支持按数据库筛选表列表。前端需要相应修改以支持以下功能:
|
||||
|
||||
1. **新增接口**:获取数据库列表
|
||||
2. **增强接口**:表列表接口支持按数据库筛选
|
||||
3. **返回数据变更**:表列表返回数据新增 `dataBase` 字段
|
||||
|
||||
---
|
||||
|
||||
## 🆕 1. 新增接口:获取数据库列表
|
||||
|
||||
### 接口信息
|
||||
|
||||
- **请求路径**:`GET /api/CodeGeneration/databases`
|
||||
- **请求方法**:`GET`
|
||||
- **是否需要认证**:是
|
||||
- **描述**:获取所有可用的数据库列表,用于前端下拉框选择
|
||||
|
||||
### 请求参数
|
||||
|
||||
无
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"key": "Admin",
|
||||
"displayName": "主数据库"
|
||||
},
|
||||
{
|
||||
"key": "MiaoYuChat",
|
||||
"displayName": "喵语聊天"
|
||||
},
|
||||
{
|
||||
"key": "LiveForum",
|
||||
"displayName": "论坛系统"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 响应字段说明
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| key | string | 数据库标识,用于后续接口传参 |
|
||||
| displayName | string | 显示名称,用于前端展示 |
|
||||
|
||||
### 前端使用示例
|
||||
|
||||
```typescript
|
||||
// 1. 定义接口类型
|
||||
interface DataSource {
|
||||
key: string;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
// 2. 调用接口
|
||||
const getDatabases = async (): Promise<DataSource[]> => {
|
||||
const response = await axios.get('/api/CodeGeneration/databases');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// 3. 使用示例(页面加载时)
|
||||
onMounted(async () => {
|
||||
const databases = await getDatabases();
|
||||
// 填充到下拉框
|
||||
databaseOptions.value = databases;
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ 2. 修改接口:表列表查询
|
||||
|
||||
### 接口信息
|
||||
|
||||
- **请求路径**:`POST /api/CodeGeneration/{size}/{page}`
|
||||
- **请求方法**:`POST`
|
||||
- **是否需要认证**:是
|
||||
- **描述**:获取表列表,支持按表名和数据库筛选
|
||||
|
||||
### 请求参数
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| size | number | 是 | 每页条数 |
|
||||
| page | number | 是 | 页码 |
|
||||
|
||||
**Body 参数(JSON):**
|
||||
|
||||
```json
|
||||
{
|
||||
"tableName": "User", // 可选,表名模糊搜索
|
||||
"dataBase": "Admin" // 🆕 新增,数据库标识筛选
|
||||
}
|
||||
```
|
||||
|
||||
### 请求字段说明
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| tableName | string | 否 | 表名,支持模糊搜索 |
|
||||
| dataBase | string | 否 | 🆕 数据库标识,不传则返回所有数据库的表 |
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 25,
|
||||
"page": 1,
|
||||
"size": 10,
|
||||
"pageCount": 3,
|
||||
"dataSource": [
|
||||
{
|
||||
"tableName": "Users",
|
||||
"remark": "用户表",
|
||||
"dataBase": "Admin" // 🆕 新增字段
|
||||
},
|
||||
{
|
||||
"tableName": "T_Image_Config",
|
||||
"remark": "图片配置表",
|
||||
"dataBase": "MiaoYuChat" // 🆕 新增字段
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 响应字段说明
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| tableName | string | 表名 |
|
||||
| remark | string | 表备注/描述 |
|
||||
| dataBase | string | 🆕 表所属的数据库标识 |
|
||||
|
||||
### 前端使用示例
|
||||
|
||||
```typescript
|
||||
// 1. 定义接口类型
|
||||
interface TableListItem {
|
||||
tableName: string;
|
||||
remark: string;
|
||||
dataBase: string; // 🆕 新增字段
|
||||
}
|
||||
|
||||
interface TableListRequest {
|
||||
tableName?: string;
|
||||
dataBase?: string; // 🆕 新增字段
|
||||
}
|
||||
|
||||
// 2. 调用接口
|
||||
const getTableList = async (
|
||||
page: number,
|
||||
size: number,
|
||||
search: TableListRequest
|
||||
): Promise<PagingResult<TableListItem>> => {
|
||||
const response = await axios.post(
|
||||
`/api/CodeGeneration/${size}/${page}`,
|
||||
search
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
// 3. 使用示例(带数据库筛选)
|
||||
const loadTableList = async () => {
|
||||
const result = await getTableList(1, 10, {
|
||||
tableName: searchKeyword.value,
|
||||
dataBase: selectedDatabase.value // 🆕 传递选中的数据库
|
||||
});
|
||||
tableList.value = result.dataSource;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 3. 代码生成接口参数调整
|
||||
|
||||
### 影响的接口
|
||||
|
||||
以下接口在调用时,需要确保 `dataBase` 参数正确传递:
|
||||
|
||||
1. **获取代码**:`POST /api/CodeGeneration/GetCodeAsync`
|
||||
2. **下载代码**:`POST /api/CodeGeneration/DownloadAsync`
|
||||
3. **下载所有代码**:`POST /api/CodeGeneration/DownloadAllAsync`
|
||||
4. **自动导入项目**:`POST /api/CodeGeneration/AutoImprotProjectAsync`
|
||||
|
||||
### 请求 Body 示例
|
||||
|
||||
```json
|
||||
{
|
||||
"tableName": "T_Image_Config",
|
||||
"dataBase": "MiaoYuChat", // ⚠️ 必须传递,确保准确匹配表
|
||||
"type": "MiaoYu.Models"
|
||||
}
|
||||
```
|
||||
|
||||
### 前端使用示例
|
||||
|
||||
```typescript
|
||||
// 生成代码时,从表列表中获取 dataBase 并传递
|
||||
const generateCode = async (table: TableListItem, type: string) => {
|
||||
const response = await axios.post('/api/CodeGeneration/GetCodeAsync', {
|
||||
tableName: table.tableName,
|
||||
dataBase: table.dataBase, // 🆕 必须传递
|
||||
type: type
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 4. 前端需要修改的地方
|
||||
|
||||
### 4.1 页面布局调整
|
||||
|
||||
在表列表页面顶部新增数据库选择器:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="code-generation-page">
|
||||
<!-- 🆕 新增:数据库选择器 -->
|
||||
<div class="filter-section">
|
||||
<a-select
|
||||
v-model:value="selectedDatabase"
|
||||
placeholder="选择数据库"
|
||||
style="width: 200px"
|
||||
@change="handleDatabaseChange"
|
||||
>
|
||||
<a-select-option value="">全部数据库</a-select-option>
|
||||
<a-select-option
|
||||
v-for="db in databaseList"
|
||||
:key="db.key"
|
||||
:value="db.key"
|
||||
>
|
||||
{{ db.displayName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<!-- 原有的搜索框 -->
|
||||
<a-input
|
||||
v-model:value="searchKeyword"
|
||||
placeholder="搜索表名"
|
||||
style="width: 300px; margin-left: 10px"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 表格列表 -->
|
||||
<a-table :columns="columns" :data-source="tableList">
|
||||
<!-- 🆕 新增:显示数据库标识列 -->
|
||||
<a-table-column key="dataBase" title="数据库" data-index="dataBase" />
|
||||
<a-table-column key="tableName" title="表名" data-index="tableName" />
|
||||
<a-table-column key="remark" title="说明" data-index="remark" />
|
||||
<!-- 其他列... -->
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 4.2 状态管理
|
||||
|
||||
```typescript
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
// 🆕 新增状态
|
||||
const databaseList = ref<DataSource[]>([]);
|
||||
const selectedDatabase = ref<string>(''); // 空字符串表示全部
|
||||
|
||||
// 原有状态
|
||||
const tableList = ref<TableListItem[]>([]);
|
||||
const searchKeyword = ref<string>('');
|
||||
|
||||
// 🆕 页面加载时获取数据库列表
|
||||
onMounted(async () => {
|
||||
await loadDatabases();
|
||||
await loadTableList();
|
||||
});
|
||||
|
||||
const loadDatabases = async () => {
|
||||
databaseList.value = await getDatabases();
|
||||
};
|
||||
|
||||
// 🆕 数据库切换事件
|
||||
const handleDatabaseChange = () => {
|
||||
loadTableList();
|
||||
};
|
||||
|
||||
// 修改:加载表列表时传递数据库参数
|
||||
const loadTableList = async () => {
|
||||
const result = await getTableList(1, 10, {
|
||||
tableName: searchKeyword.value,
|
||||
dataBase: selectedDatabase.value // 🆕 传递数据库参数
|
||||
});
|
||||
tableList.value = result.dataSource;
|
||||
};
|
||||
```
|
||||
|
||||
### 4.3 生成代码时传递数据库
|
||||
|
||||
```typescript
|
||||
// ⚠️ 重要:生成代码时必须传递 dataBase
|
||||
const handleGenerateCode = async (record: TableListItem) => {
|
||||
const code = await generateCode({
|
||||
tableName: record.tableName,
|
||||
dataBase: record.dataBase, // 🆕 从表列表记录中获取
|
||||
type: selectedCodeType.value
|
||||
});
|
||||
// 展示生成的代码...
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 5. 注意事项
|
||||
|
||||
### 5.1 兼容性说明
|
||||
|
||||
- **向后兼容**:`dataBase` 字段为可选,不传时返回所有数据库的表(保持原有行为)
|
||||
- **推荐实践**:建议前端始终传递 `dataBase` 参数,避免同名表冲突
|
||||
|
||||
### 5.2 同名表处理
|
||||
|
||||
后端支持不同数据库中存在同名表,因此:
|
||||
|
||||
- 表列表中可能出现多个同名的表,通过 `dataBase` 字段区分
|
||||
- 生成代码时**必须**传递 `dataBase` 参数,确保操作正确的表
|
||||
|
||||
### 5.3 UI/UX 建议
|
||||
|
||||
1. **数据库标识显示**:
|
||||
- 在表名前添加数据库标签,如 `[Admin] Users`、`[MiaoYuChat] T_Image_Config`
|
||||
- 使用不同颜色或图标区分不同数据库
|
||||
|
||||
2. **默认选择**:
|
||||
- 建议默认选择第一个数据库,而不是"全部"
|
||||
- 可根据用户最近使用的数据库进行智能默认
|
||||
|
||||
3. **表格列顺序**:
|
||||
- 建议顺序:数据库 → 表名 → 说明 → 操作
|
||||
- 数据库列可以考虑使用标签样式展示
|
||||
|
||||
---
|
||||
|
||||
## 📚 6. 完整示例代码
|
||||
|
||||
```typescript
|
||||
// types.ts
|
||||
export interface DataSource {
|
||||
key: string;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export interface TableListItem {
|
||||
tableName: string;
|
||||
remark: string;
|
||||
dataBase: string;
|
||||
}
|
||||
|
||||
export interface TableListRequest {
|
||||
tableName?: string;
|
||||
dataBase?: string;
|
||||
}
|
||||
|
||||
// api.ts
|
||||
import axios from 'axios';
|
||||
|
||||
export const codeGenerationApi = {
|
||||
// 🆕 获取数据库列表
|
||||
getDatabases: (): Promise<DataSource[]> => {
|
||||
return axios.get('/api/CodeGeneration/databases').then(res => res.data);
|
||||
},
|
||||
|
||||
// 获取表列表(已修改)
|
||||
getTableList: (page: number, size: number, search: TableListRequest) => {
|
||||
return axios.post(`/api/CodeGeneration/${size}/${page}`, search)
|
||||
.then(res => res.data);
|
||||
},
|
||||
|
||||
// 生成代码(已修改)
|
||||
generateCode: (params: {
|
||||
tableName: string;
|
||||
dataBase: string;
|
||||
type: string;
|
||||
}) => {
|
||||
return axios.post('/api/CodeGeneration/GetCodeAsync', params)
|
||||
.then(res => res.data);
|
||||
},
|
||||
|
||||
// 其他接口...
|
||||
};
|
||||
|
||||
// page.vue
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { codeGenerationApi } from '@/api/codeGeneration';
|
||||
import type { DataSource, TableListItem } from '@/types/codeGeneration';
|
||||
|
||||
// 状态
|
||||
const databaseList = ref<DataSource[]>([]);
|
||||
const selectedDatabase = ref<string>('');
|
||||
const tableList = ref<TableListItem[]>([]);
|
||||
const searchKeyword = ref<string>('');
|
||||
const pagination = ref({ page: 1, size: 10, total: 0 });
|
||||
|
||||
// 生命周期
|
||||
onMounted(async () => {
|
||||
await loadDatabases();
|
||||
await loadTableList();
|
||||
});
|
||||
|
||||
// 加载数据库列表
|
||||
const loadDatabases = async () => {
|
||||
try {
|
||||
databaseList.value = await codeGenerationApi.getDatabases();
|
||||
// 可选:默认选择第一个数据库
|
||||
// if (databaseList.value.length > 0) {
|
||||
// selectedDatabase.value = databaseList.value[0].key;
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error('加载数据库列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载表列表
|
||||
const loadTableList = async () => {
|
||||
try {
|
||||
const result = await codeGenerationApi.getTableList(
|
||||
pagination.value.page,
|
||||
pagination.value.size,
|
||||
{
|
||||
tableName: searchKeyword.value,
|
||||
dataBase: selectedDatabase.value
|
||||
}
|
||||
);
|
||||
tableList.value = result.dataSource;
|
||||
pagination.value.total = result.total;
|
||||
} catch (error) {
|
||||
console.error('加载表列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 事件处理
|
||||
const handleDatabaseChange = () => {
|
||||
pagination.value.page = 1; // 重置页码
|
||||
loadTableList();
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.value.page = 1; // 重置页码
|
||||
loadTableList();
|
||||
};
|
||||
|
||||
const handleGenerateCode = async (record: TableListItem) => {
|
||||
try {
|
||||
const code = await codeGenerationApi.generateCode({
|
||||
tableName: record.tableName,
|
||||
dataBase: record.dataBase,
|
||||
type: 'MiaoYu.Models'
|
||||
});
|
||||
// 展示代码...
|
||||
} catch (error) {
|
||||
console.error('生成代码失败:', error);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="code-generation-page">
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<a-space>
|
||||
<a-select
|
||||
v-model:value="selectedDatabase"
|
||||
placeholder="选择数据库"
|
||||
style="width: 200px"
|
||||
@change="handleDatabaseChange"
|
||||
>
|
||||
<a-select-option value="">全部数据库</a-select-option>
|
||||
<a-select-option
|
||||
v-for="db in databaseList"
|
||||
:key="db.key"
|
||||
:value="db.key"
|
||||
>
|
||||
{{ db.displayName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-input
|
||||
v-model:value="searchKeyword"
|
||||
placeholder="搜索表名"
|
||||
style="width: 300px"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<a-table
|
||||
:data-source="tableList"
|
||||
:pagination="{
|
||||
current: pagination.page,
|
||||
pageSize: pagination.size,
|
||||
total: pagination.total,
|
||||
onChange: (page) => {
|
||||
pagination.page = page;
|
||||
loadTableList();
|
||||
}
|
||||
}"
|
||||
>
|
||||
<a-table-column key="dataBase" title="数据库" data-index="dataBase">
|
||||
<template #default="{ record }">
|
||||
<a-tag :color="getDatabaseColor(record.dataBase)">
|
||||
{{ getDatabaseDisplayName(record.dataBase) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column key="tableName" title="表名" data-index="tableName" />
|
||||
<a-table-column key="remark" title="说明" data-index="remark" />
|
||||
<a-table-column key="actions" title="操作">
|
||||
<template #default="{ record }">
|
||||
<a-button type="link" @click="handleGenerateCode(record)">
|
||||
生成代码
|
||||
</a-button>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.code-generation-page {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 7. 视觉效果建议
|
||||
|
||||
### 数据库标签颜色方案
|
||||
|
||||
```typescript
|
||||
const getDatabaseColor = (databaseKey: string): string => {
|
||||
const colorMap: Record<string, string> = {
|
||||
'Admin': 'blue',
|
||||
'MiaoYuChat': 'green',
|
||||
'LiveForum': 'orange'
|
||||
};
|
||||
return colorMap[databaseKey] || 'default';
|
||||
};
|
||||
|
||||
const getDatabaseDisplayName = (databaseKey: string): string => {
|
||||
const database = databaseList.value.find(db => db.key === databaseKey);
|
||||
return database?.displayName || databaseKey;
|
||||
};
|
||||
```
|
||||
|
||||
### 表格展示效果
|
||||
|
||||
```
|
||||
┌────────────┬─────────────────┬──────────────┬────────┐
|
||||
│ 数据库 │ 表名 │ 说明 │ 操作 │
|
||||
├────────────┼─────────────────┼──────────────┼────────┤
|
||||
│ [Admin] │ Users │ 用户表 │ 生成 │
|
||||
│ [MiaoYuChat]│ T_Image_Config │ 图片配置表 │ 生成 │
|
||||
│ [Admin] │ Roles │ 角色表 │ 生成 │
|
||||
└────────────┴─────────────────┴──────────────┴────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📞 8. 技术支持
|
||||
|
||||
如有疑问,请联系后端开发团队。
|
||||
|
||||
**文档版本**:v1.0
|
||||
**更新日期**:2024年
|
||||
**后端版本**:v2.0(支持多数据源)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user