生成器
This commit is contained in:
parent
c09f41f40c
commit
618bf4285a
@ -25,6 +25,13 @@
|
||||
>
|
||||
下载 .vue 文件
|
||||
</button>
|
||||
<button
|
||||
@click="downloadApiFile"
|
||||
:disabled="!generatedApiCode"
|
||||
class="action-button download-api-button"
|
||||
>
|
||||
下载 API 文件
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="generatedCode" class="generated-code-preview">
|
||||
@ -106,6 +113,8 @@ import { ref } from 'vue';
|
||||
const sqlInput = ref('');
|
||||
const generatedCode = ref('');
|
||||
const generatedFileName = ref('');
|
||||
const generatedApiCode = ref('');
|
||||
const generatedApiFileName = ref('');
|
||||
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 组件代码
|
||||
* @param {object} tableInfo - 解析后的表结构
|
||||
@ -211,115 +278,17 @@ const generateVueComponent = (tableInfo) => {
|
||||
.map(c => `
|
||||
<div class="form-group">
|
||||
<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('');
|
||||
|
||||
const dataFields = tableInfo.columns.map(c => ` ${c.name}: '',`).join('\n');
|
||||
|
||||
const scriptContent = `
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
// 假设的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;
|
||||
const tableColumns = tableInfo.columns.map(c => {
|
||||
if (c.type.toLowerCase().includes('datetime') || c.type.toLowerCase().includes('timestamp')) {
|
||||
return ` <td>{{ formatDate(item.${c.name}) }}</td>`;
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
`;
|
||||
return ` <td>{{ item.${c.name} }}</td>`;
|
||||
}).join('\n');
|
||||
|
||||
const styleContent = `
|
||||
.generated-component-container {
|
||||
@ -489,11 +458,9 @@ const formatDate = (dateString) => {
|
||||
.error-message {
|
||||
color: #dc3545;
|
||||
margin-top: 15px;
|
||||
}
|
||||
`;
|
||||
}`;
|
||||
|
||||
return `
|
||||
<template>
|
||||
return `<template>
|
||||
<div class="generated-component-container">
|
||||
<div class="actions-bar">
|
||||
<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>
|
||||
</tr>
|
||||
<tr v-for="item in items" :key="item.${tableInfo.primaryKey}">
|
||||
${tableInfo.columns.map(c => ` <td>{{ item.${c.name} }}</td>`).join('\n')}
|
||||
${tableColumns}
|
||||
<td>
|
||||
<button @click="openModal(item)" class="action-button edit">编辑</button>
|
||||
<button @click="confirmDeleteItem(item.${tableInfo.primaryKey})" class="action-button delete">删除</button>
|
||||
@ -547,19 +514,117 @@ ${formFields}
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
${scriptContent}
|
||||
</scr` + `ipt>
|
||||
import { ref, onMounted } from 'vue';
|
||||
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>
|
||||
${styleContent}
|
||||
</style>
|
||||
`;
|
||||
</style>`;
|
||||
};
|
||||
|
||||
const generateCode = () => {
|
||||
if (!sqlInput.value.trim()) {
|
||||
parsedTableInfo.value = null;
|
||||
generatedCode.value = '';
|
||||
generatedApiCode.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
@ -568,26 +633,37 @@ const generateCode = () => {
|
||||
if (tableInfo) {
|
||||
generatedCode.value = generateVueComponent(tableInfo);
|
||||
generatedFileName.value = `${toPascalCase(tableInfo.tableName)}.vue`;
|
||||
generatedApiCode.value = generateApiFile(tableInfo);
|
||||
generatedApiFileName.value = `${tableInfo.tableName}.js`;
|
||||
parsedTableInfo.value = tableInfo;
|
||||
} else {
|
||||
generatedCode.value = '';
|
||||
generatedFileName.value = '';
|
||||
generatedApiCode.value = '';
|
||||
generatedApiFileName.value = '';
|
||||
parsedTableInfo.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
const downloadCode = () => {
|
||||
if (!generatedCode.value) return;
|
||||
|
||||
const blob = new Blob([generatedCode.value], { type: 'text/plain;charset=utf-8' });
|
||||
const downloadFile = (filename, content) => {
|
||||
if (!content) return;
|
||||
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
|
||||
const href = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = href;
|
||||
link.download = generatedFileName.value;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(href);
|
||||
}
|
||||
|
||||
const downloadCode = () => {
|
||||
downloadFile(generatedFileName.value, generatedCode.value);
|
||||
};
|
||||
|
||||
const downloadApiFile = () => {
|
||||
downloadFile(generatedApiFileName.value, generatedApiCode.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -681,6 +757,14 @@ textarea {
|
||||
background-color: #0069d9;
|
||||
}
|
||||
|
||||
.download-api-button {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.download-api-button:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.action-button:disabled {
|
||||
background-color: #ccc;
|
||||
cursor: not-allowed;
|
||||
|
Loading…
x
Reference in New Issue
Block a user