生成器
This commit is contained in:
parent
c09f41f40c
commit
618bf4285a
@ -25,6 +25,13 @@
|
|||||||
>
|
>
|
||||||
下载 .vue 文件
|
下载 .vue 文件
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
@click="downloadApiFile"
|
||||||
|
:disabled="!generatedApiCode"
|
||||||
|
class="action-button download-api-button"
|
||||||
|
>
|
||||||
|
下载 API 文件
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="generatedCode" class="generated-code-preview">
|
<div v-if="generatedCode" class="generated-code-preview">
|
||||||
@ -106,6 +113,8 @@ import { ref } from 'vue';
|
|||||||
const sqlInput = ref('');
|
const sqlInput = ref('');
|
||||||
const generatedCode = ref('');
|
const generatedCode = ref('');
|
||||||
const generatedFileName = ref('');
|
const generatedFileName = ref('');
|
||||||
|
const generatedApiCode = ref('');
|
||||||
|
const generatedApiFileName = ref('');
|
||||||
const parsedTableInfo = ref(null);
|
const parsedTableInfo = ref(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,6 +205,64 @@ const parseSql = (sql) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据表结构生成 API 文件代码
|
||||||
|
* @param {object} tableInfo - 解析后的表结构
|
||||||
|
* @returns {string} API 文件代码字符串
|
||||||
|
*/
|
||||||
|
const generateApiFile = (tableInfo) => {
|
||||||
|
const componentName = toPascalCase(tableInfo.tableName);
|
||||||
|
const resourceName = tableInfo.tableName;
|
||||||
|
const primaryKey = tableInfo.primaryKey || 'id';
|
||||||
|
|
||||||
|
return `
|
||||||
|
import axiosInstance from './axiosConfig';
|
||||||
|
|
||||||
|
const API_BASE_URL = '/api/${resourceName}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取${tableInfo.tableComment || componentName}列表
|
||||||
|
* @param {object} params - 查询参数
|
||||||
|
*/
|
||||||
|
export const get${componentName}List = (params) => {
|
||||||
|
return axiosInstance.get(API_BASE_URL, { params });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个${tableInfo.tableComment || componentName}详情
|
||||||
|
* @param {number|string} id - 主键ID
|
||||||
|
*/
|
||||||
|
export const get${componentName}ById = (id) => {
|
||||||
|
return axiosInstance.get(\`\${API_BASE_URL}/\${id}\`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建新的${tableInfo.tableComment || componentName}
|
||||||
|
* @param {object} data - ${tableInfo.tableComment || componentName}数据
|
||||||
|
*/
|
||||||
|
export const create${componentName} = (data) => {
|
||||||
|
return axiosInstance.post(API_BASE_URL, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新${tableInfo.tableComment || componentName}
|
||||||
|
* @param {number|string} id - 主键ID
|
||||||
|
* @param {object} data - 需要更新的数据
|
||||||
|
*/
|
||||||
|
export const update${componentName} = (id, data) => {
|
||||||
|
return axiosInstance.put(\`\${API_BASE_URL}/\${id}\`, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除${tableInfo.tableComment || componentName}
|
||||||
|
* @param {number|string} id - 主键ID
|
||||||
|
*/
|
||||||
|
export const delete${componentName} = (id) => {
|
||||||
|
return axiosInstance.delete(\`\${API_BASE_URL}/\${id}\`);
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据表结构生成 Vue 组件代码
|
* 根据表结构生成 Vue 组件代码
|
||||||
* @param {object} tableInfo - 解析后的表结构
|
* @param {object} tableInfo - 解析后的表结构
|
||||||
@ -211,115 +278,17 @@ const generateVueComponent = (tableInfo) => {
|
|||||||
.map(c => `
|
.map(c => `
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="add-${c.name}">${c.comment || c.name}:</label>
|
<label for="add-${c.name}">${c.comment || c.name}:</label>
|
||||||
<input id="add-${c.name}" type="text" v-model="editableItem.${c.name}" placeholder="请输入${c.comment || c.name}">
|
<input id="add-${c.name}" type="text" v-model="editableItem.${c.name}" placeholder="请输入${c.comment || c.name}" />
|
||||||
</div>`).join('');
|
</div>`).join('');
|
||||||
|
|
||||||
const dataFields = tableInfo.columns.map(c => ` ${c.name}: '',`).join('\n');
|
const dataFields = tableInfo.columns.map(c => ` ${c.name}: '',`).join('\n');
|
||||||
|
|
||||||
const scriptContent = `
|
const tableColumns = tableInfo.columns.map(c => {
|
||||||
import { ref, onMounted } from 'vue';
|
if (c.type.toLowerCase().includes('datetime') || c.type.toLowerCase().includes('timestamp')) {
|
||||||
|
return ` <td>{{ formatDate(item.${c.name}) }}</td>`;
|
||||||
// 假设的API函数,需要您自己在/api/index.js或类似文件中创建
|
|
||||||
// import { get${componentName}List, create${componentName}, update${componentName}, delete${componentName} } from '@/api';
|
|
||||||
|
|
||||||
const items = ref([]);
|
|
||||||
const loading = ref(false);
|
|
||||||
const showModal = ref(false);
|
|
||||||
const isEditing = ref(false);
|
|
||||||
const editableItem = ref({
|
|
||||||
${dataFields}
|
|
||||||
});
|
|
||||||
const editError = ref('');
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
fetchItems();
|
|
||||||
});
|
|
||||||
|
|
||||||
const API_URL = '/api/${tableInfo.tableName}'; // 模拟API路径
|
|
||||||
|
|
||||||
const fetchItems = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
try {
|
|
||||||
// const response = await get${componentName}List();
|
|
||||||
// items.value = response.data;
|
|
||||||
|
|
||||||
// --- 示例数据 ---
|
|
||||||
items.value = [
|
|
||||||
{ ${tableInfo.columns.map((c, i) => `${c.name}: "示例值 ${i + 1}"`).join(', ')} },
|
|
||||||
{ ${tableInfo.columns.map((c, i) => `${c.name}: "示例值 ${i + 2}"`).join(', ')} }
|
|
||||||
];
|
|
||||||
// --- 示例数据结束 ---
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取列表失败:', error);
|
|
||||||
items.value = [];
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
};
|
return ` <td>{{ item.${c.name} }}</td>`;
|
||||||
|
}).join('\n');
|
||||||
const openModal = (item = null) => {
|
|
||||||
if (item) {
|
|
||||||
isEditing.value = true;
|
|
||||||
editableItem.value = { ...item };
|
|
||||||
} else {
|
|
||||||
isEditing.value = false;
|
|
||||||
editableItem.value = {
|
|
||||||
${dataFields}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
editError.value = '';
|
|
||||||
showModal.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeModal = () => {
|
|
||||||
showModal.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveItem = async () => {
|
|
||||||
editError.value = '';
|
|
||||||
try {
|
|
||||||
if (isEditing.value) {
|
|
||||||
// await update${componentName}(editableItem.value.${tableInfo.primaryKey}, editableItem.value);
|
|
||||||
console.log('更新项目:', editableItem.value);
|
|
||||||
} else {
|
|
||||||
// await create${componentName}(editableItem.value);
|
|
||||||
console.log('创建项目:', editableItem.value);
|
|
||||||
}
|
|
||||||
closeModal();
|
|
||||||
fetchItems();
|
|
||||||
alert('操作成功!');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('保存失败:', error);
|
|
||||||
editError.value = error.message || '操作失败,请重试。';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const confirmDeleteItem = async (id) => {
|
|
||||||
if (window.confirm('确定要删除此项吗?')) {
|
|
||||||
try {
|
|
||||||
// await delete${componentName}(id);
|
|
||||||
console.log('删除项目, id:', id);
|
|
||||||
fetchItems();
|
|
||||||
alert('删除成功!');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('删除失败:', error);
|
|
||||||
alert('删除失败: ' + (error.message || '请稍后重试'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 辅助函数
|
|
||||||
const formatDate = (dateString) => {
|
|
||||||
if (!dateString) return 'N/A';
|
|
||||||
try {
|
|
||||||
const date = new Date(dateString);
|
|
||||||
return isNaN(date.getTime()) ? dateString : date.toLocaleString();
|
|
||||||
} catch (e) {
|
|
||||||
return dateString;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const styleContent = `
|
const styleContent = `
|
||||||
.generated-component-container {
|
.generated-component-container {
|
||||||
@ -489,11 +458,9 @@ const formatDate = (dateString) => {
|
|||||||
.error-message {
|
.error-message {
|
||||||
color: #dc3545;
|
color: #dc3545;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}`;
|
||||||
`;
|
|
||||||
|
|
||||||
return `
|
return `<template>
|
||||||
<template>
|
|
||||||
<div class="generated-component-container">
|
<div class="generated-component-container">
|
||||||
<div class="actions-bar">
|
<div class="actions-bar">
|
||||||
<h3>${tableTitle}</h3>
|
<h3>${tableTitle}</h3>
|
||||||
@ -519,7 +486,7 @@ ${tableInfo.columns.map(c => ` <th>${c.comment || c.name}</th>`).join
|
|||||||
<td :colspan="${tableInfo.columns.length + 1}" style="text-align: center;">暂无数据</td>
|
<td :colspan="${tableInfo.columns.length + 1}" style="text-align: center;">暂无数据</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="item in items" :key="item.${tableInfo.primaryKey}">
|
<tr v-for="item in items" :key="item.${tableInfo.primaryKey}">
|
||||||
${tableInfo.columns.map(c => ` <td>{{ item.${c.name} }}</td>`).join('\n')}
|
${tableColumns}
|
||||||
<td>
|
<td>
|
||||||
<button @click="openModal(item)" class="action-button edit">编辑</button>
|
<button @click="openModal(item)" class="action-button edit">编辑</button>
|
||||||
<button @click="confirmDeleteItem(item.${tableInfo.primaryKey})" class="action-button delete">删除</button>
|
<button @click="confirmDeleteItem(item.${tableInfo.primaryKey})" class="action-button delete">删除</button>
|
||||||
@ -547,19 +514,117 @@ ${formFields}
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
${scriptContent}
|
import { ref, onMounted } from 'vue';
|
||||||
</scr` + `ipt>
|
import {
|
||||||
|
get${componentName}List,
|
||||||
|
get${componentName}ById,
|
||||||
|
create${componentName},
|
||||||
|
update${componentName},
|
||||||
|
delete${componentName}
|
||||||
|
} from '@/api/${tableInfo.tableName}';
|
||||||
|
|
||||||
|
const items = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const showModal = ref(false);
|
||||||
|
const isEditing = ref(false);
|
||||||
|
const editableItem = ref({
|
||||||
|
${dataFields}
|
||||||
|
});
|
||||||
|
const editError = ref('');
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchItems();
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchItems = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const response = await get${componentName}List();
|
||||||
|
items.value = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error);
|
||||||
|
items.value = [];
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const openModal = async (item = null) => {
|
||||||
|
if (item) {
|
||||||
|
isEditing.value = true;
|
||||||
|
try {
|
||||||
|
const response = await get${componentName}ById(item.${tableInfo.primaryKey});
|
||||||
|
editableItem.value = response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取详情失败:', error);
|
||||||
|
editableItem.value = { ...item };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isEditing.value = false;
|
||||||
|
editableItem.value = {
|
||||||
|
${dataFields}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
editError.value = '';
|
||||||
|
showModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
showModal.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveItem = async () => {
|
||||||
|
editError.value = '';
|
||||||
|
try {
|
||||||
|
if (isEditing.value) {
|
||||||
|
await update${componentName}(editableItem.value.${tableInfo.primaryKey}, editableItem.value);
|
||||||
|
} else {
|
||||||
|
await create${componentName}(editableItem.value);
|
||||||
|
}
|
||||||
|
closeModal();
|
||||||
|
fetchItems();
|
||||||
|
alert('操作成功!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error);
|
||||||
|
editError.value = error.response?.data?.message || '操作失败,请重试。';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmDeleteItem = async (id) => {
|
||||||
|
if (window.confirm('确定要删除此项吗?')) {
|
||||||
|
try {
|
||||||
|
await delete${componentName}(id);
|
||||||
|
fetchItems();
|
||||||
|
alert('删除成功!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除失败:', error);
|
||||||
|
alert('删除失败: ' + (error.response?.data?.message || '请稍后重试'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 辅助函数
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
if (!dateString) return 'N/A';
|
||||||
|
try {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return isNaN(date.getTime()) ? dateString : date.toLocaleString();
|
||||||
|
} catch (e) {
|
||||||
|
return dateString;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</sc' + 'ript>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
${styleContent}
|
${styleContent}
|
||||||
</style>
|
</style>`;
|
||||||
`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateCode = () => {
|
const generateCode = () => {
|
||||||
if (!sqlInput.value.trim()) {
|
if (!sqlInput.value.trim()) {
|
||||||
parsedTableInfo.value = null;
|
parsedTableInfo.value = null;
|
||||||
generatedCode.value = '';
|
generatedCode.value = '';
|
||||||
|
generatedApiCode.value = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,26 +633,37 @@ const generateCode = () => {
|
|||||||
if (tableInfo) {
|
if (tableInfo) {
|
||||||
generatedCode.value = generateVueComponent(tableInfo);
|
generatedCode.value = generateVueComponent(tableInfo);
|
||||||
generatedFileName.value = `${toPascalCase(tableInfo.tableName)}.vue`;
|
generatedFileName.value = `${toPascalCase(tableInfo.tableName)}.vue`;
|
||||||
|
generatedApiCode.value = generateApiFile(tableInfo);
|
||||||
|
generatedApiFileName.value = `${tableInfo.tableName}.js`;
|
||||||
parsedTableInfo.value = tableInfo;
|
parsedTableInfo.value = tableInfo;
|
||||||
} else {
|
} else {
|
||||||
generatedCode.value = '';
|
generatedCode.value = '';
|
||||||
generatedFileName.value = '';
|
generatedFileName.value = '';
|
||||||
|
generatedApiCode.value = '';
|
||||||
|
generatedApiFileName.value = '';
|
||||||
parsedTableInfo.value = null;
|
parsedTableInfo.value = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadCode = () => {
|
const downloadFile = (filename, content) => {
|
||||||
if (!generatedCode.value) return;
|
if (!content) return;
|
||||||
|
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
|
||||||
const blob = new Blob([generatedCode.value], { type: 'text/plain;charset=utf-8' });
|
|
||||||
const href = URL.createObjectURL(blob);
|
const href = URL.createObjectURL(blob);
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = href;
|
link.href = href;
|
||||||
link.download = generatedFileName.value;
|
link.download = filename;
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
URL.revokeObjectURL(href);
|
URL.revokeObjectURL(href);
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadCode = () => {
|
||||||
|
downloadFile(generatedFileName.value, generatedCode.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadApiFile = () => {
|
||||||
|
downloadFile(generatedApiFileName.value, generatedApiCode.value);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -681,6 +757,14 @@ textarea {
|
|||||||
background-color: #0069d9;
|
background-color: #0069d9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.download-api-button {
|
||||||
|
background-color: #28a745;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-api-button:hover {
|
||||||
|
background-color: #218838;
|
||||||
|
}
|
||||||
|
|
||||||
.action-button:disabled {
|
.action-button:disabled {
|
||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user