151 lines
4.9 KiB
TypeScript
151 lines
4.9 KiB
TypeScript
|
|
/**
|
||
|
|
* 表信息API接口
|
||
|
|
* Table Information API Endpoint
|
||
|
|
*/
|
||
|
|
import { createSqlQueryBuilder } from '../lib/sql-query-builder'
|
||
|
|
import { prisma } from '../lib/prisma'
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 支持的表名映射
|
||
|
|
* Supported table names mapping
|
||
|
|
*/
|
||
|
|
const ALLOWED_TABLES = {
|
||
|
|
Post: 'posts' // 支持Post表
|
||
|
|
} as const
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 字段类型映射
|
||
|
|
* Field type mapping
|
||
|
|
*/
|
||
|
|
const FIELD_TYPES: Record<string, Record<string, string>> = {
|
||
|
|
posts: {
|
||
|
|
id: 'number',
|
||
|
|
title: 'string',
|
||
|
|
content: 'string',
|
||
|
|
published: 'boolean',
|
||
|
|
createdAt: 'datetime',
|
||
|
|
updatedAt: 'datetime',
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 默认搜索字段配置
|
||
|
|
* Default search fields configuration
|
||
|
|
*/
|
||
|
|
const DEFAULT_SEARCH_FIELDS: Record<string, string[]> = {
|
||
|
|
posts: ['title', 'content'], // posts表搜索字段
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 默认排序字段配置
|
||
|
|
* Default sortable fields configuration
|
||
|
|
*/
|
||
|
|
const DEFAULT_SORTABLE_FIELDS: Record<string, string[]> = {
|
||
|
|
posts: ['id', 'title', 'content', 'published', 'createdAt', 'updatedAt'], // posts表排序字段
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 表信息API处理器
|
||
|
|
* Table information API handler
|
||
|
|
*/
|
||
|
|
export default defineEventHandler(async event => {
|
||
|
|
try {
|
||
|
|
// 获取查询参数
|
||
|
|
const query = getQuery(event)
|
||
|
|
const tableName = query.table as string
|
||
|
|
|
||
|
|
// 如果没有指定表名,返回所有支持的表
|
||
|
|
if (!tableName) {
|
||
|
|
const supportedTables = Object.keys(ALLOWED_TABLES).map(key => ({
|
||
|
|
key,
|
||
|
|
name: ALLOWED_TABLES[key as keyof typeof ALLOWED_TABLES],
|
||
|
|
searchFields:
|
||
|
|
DEFAULT_SEARCH_FIELDS[ALLOWED_TABLES[key as keyof typeof ALLOWED_TABLES]] || [],
|
||
|
|
sortableFields:
|
||
|
|
DEFAULT_SORTABLE_FIELDS[ALLOWED_TABLES[key as keyof typeof ALLOWED_TABLES]] || [],
|
||
|
|
}))
|
||
|
|
|
||
|
|
return {
|
||
|
|
success: true,
|
||
|
|
data: {
|
||
|
|
tables: supportedTables,
|
||
|
|
},
|
||
|
|
message: '获取支持的表列表成功',
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 验证表名是否允许
|
||
|
|
const actualTableName = ALLOWED_TABLES[tableName as keyof typeof ALLOWED_TABLES]
|
||
|
|
if (!actualTableName) {
|
||
|
|
throw createError({
|
||
|
|
statusCode: 400,
|
||
|
|
statusMessage: `不支持的表: ${tableName}`,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建SQL查询构造器
|
||
|
|
const queryBuilder = createSqlQueryBuilder(prisma)
|
||
|
|
|
||
|
|
// 获取表字段信息
|
||
|
|
const fields = await queryBuilder.getTableFields(actualTableName)
|
||
|
|
|
||
|
|
// 构建字段详细信息
|
||
|
|
const fieldDetails = fields.map(field => ({
|
||
|
|
name: field,
|
||
|
|
type: FIELD_TYPES[actualTableName]?.[field] || 'string',
|
||
|
|
searchable: DEFAULT_SEARCH_FIELDS[actualTableName]?.includes(field) || false,
|
||
|
|
sortable: DEFAULT_SORTABLE_FIELDS[actualTableName]?.includes(field) || true,
|
||
|
|
}))
|
||
|
|
|
||
|
|
// 获取支持的操作符
|
||
|
|
const operators = [
|
||
|
|
{ value: 'equals', label: '等于', types: ['string', 'number', 'boolean'] },
|
||
|
|
{ value: 'not_equals', label: '不等于', types: ['string', 'number', 'boolean'] },
|
||
|
|
{ value: 'greater_than', label: '大于', types: ['number', 'datetime'] },
|
||
|
|
{ value: 'greater_than_or_equal', label: '大于等于', types: ['number', 'datetime'] },
|
||
|
|
{ value: 'less_than', label: '小于', types: ['number', 'datetime'] },
|
||
|
|
{ value: 'less_than_or_equal', label: '小于等于', types: ['number', 'datetime'] },
|
||
|
|
{ value: 'contains', label: '包含', types: ['string'] },
|
||
|
|
{ value: 'starts_with', label: '开始于', types: ['string'] },
|
||
|
|
{ value: 'ends_with', label: '结束于', types: ['string'] },
|
||
|
|
{ value: 'in', label: '在列表中', types: ['string', 'number'] },
|
||
|
|
{ value: 'not_in', label: '不在列表中', types: ['string', 'number'] },
|
||
|
|
{ value: 'is_null', label: '为空', types: ['string', 'number', 'datetime'] },
|
||
|
|
{ value: 'is_not_null', label: '不为空', types: ['string', 'number', 'datetime'] },
|
||
|
|
{ value: 'between', label: '在范围内', types: ['number', 'datetime'] },
|
||
|
|
{ value: 'date_equals', label: '日期等于', types: ['datetime'] },
|
||
|
|
{ value: 'date_before', label: '日期之前', types: ['datetime'] },
|
||
|
|
{ value: 'date_after', label: '日期之后', types: ['datetime'] },
|
||
|
|
{ value: 'date_between', label: '日期范围', types: ['datetime'] },
|
||
|
|
]
|
||
|
|
|
||
|
|
return {
|
||
|
|
success: true,
|
||
|
|
data: {
|
||
|
|
table: {
|
||
|
|
name: actualTableName,
|
||
|
|
key: tableName,
|
||
|
|
fields: fieldDetails,
|
||
|
|
searchFields: DEFAULT_SEARCH_FIELDS[actualTableName] || [],
|
||
|
|
sortableFields: DEFAULT_SORTABLE_FIELDS[actualTableName] || fields,
|
||
|
|
operators,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
message: '获取表信息成功',
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Table info API error:', error)
|
||
|
|
|
||
|
|
// 如果是已知错误,直接抛出
|
||
|
|
if (error && typeof error === 'object' && 'statusCode' in error) {
|
||
|
|
throw error
|
||
|
|
}
|
||
|
|
|
||
|
|
// 处理未知错误
|
||
|
|
throw createError({
|
||
|
|
statusCode: 500,
|
||
|
|
statusMessage: `获取表信息失败: ${error instanceof Error ? error.message : '未知错误'}`,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
})
|