|
|
@@ -0,0 +1,294 @@
|
|
|
+import { OpenAPIHono } from '@hono/zod-openapi';
|
|
|
+import { createRoute, z } from '@hono/zod-openapi';
|
|
|
+import { authMiddleware } from '@/server/middleware/auth.middleware';
|
|
|
+import { AreaService } from '@/server/modules/areas/area.service';
|
|
|
+import { AreaLevel } from '@/server/modules/areas/area.entity';
|
|
|
+
|
|
|
+
|
|
|
+// 获取完整树形结构
|
|
|
+const getAreaTreeRoute = createRoute({
|
|
|
+ method: 'get',
|
|
|
+ path: '/tree',
|
|
|
+ description: '获取完整的省市区树形结构',
|
|
|
+ tags: ['省市区管理'],
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '成功获取树形结构',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ data: z.array(z.object({
|
|
|
+ id: z.number(),
|
|
|
+ parentId: z.number().nullable(),
|
|
|
+ name: z.string(),
|
|
|
+ level: z.number(),
|
|
|
+ code: z.string(),
|
|
|
+ isDisabled: z.number(),
|
|
|
+ children: z.array(z.any()).optional()
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 500: {
|
|
|
+ description: '服务器错误',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ error: z.string()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 根据层级获取树形结构
|
|
|
+const getAreaTreeByLevelRoute = createRoute({
|
|
|
+ method: 'get',
|
|
|
+ path: '/tree/level/{level}',
|
|
|
+ description: '根据层级获取树形结构',
|
|
|
+ tags: ['省市区管理'],
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ request: {
|
|
|
+ params: z.object({
|
|
|
+ level: z.nativeEnum(AreaLevel)
|
|
|
+ })
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '成功获取层级树形结构',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ data: z.array(z.object({
|
|
|
+ id: z.number(),
|
|
|
+ parentId: z.number().nullable(),
|
|
|
+ name: z.string(),
|
|
|
+ level: z.number(),
|
|
|
+ code: z.string(),
|
|
|
+ isDisabled: z.number(),
|
|
|
+ children: z.array(z.any()).optional()
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 500: {
|
|
|
+ description: '服务器错误',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ error: z.string()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 获取子树
|
|
|
+const getSubTreeRoute = createRoute({
|
|
|
+ method: 'get',
|
|
|
+ path: '/tree/{id}',
|
|
|
+ description: '获取指定节点的子树',
|
|
|
+ tags: ['省市区管理'],
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ request: {
|
|
|
+ params: z.object({
|
|
|
+ id: z.coerce.number().positive('区域ID必须为正整数')
|
|
|
+ })
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '成功获取子树',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ data: z.object({
|
|
|
+ id: z.number(),
|
|
|
+ parentId: z.number().nullable(),
|
|
|
+ name: z.string(),
|
|
|
+ level: z.number(),
|
|
|
+ code: z.string(),
|
|
|
+ isDisabled: z.number(),
|
|
|
+ children: z.array(z.any()).optional()
|
|
|
+ }).nullable()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 404: {
|
|
|
+ description: '区域不存在',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ error: z.string()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 500: {
|
|
|
+ description: '服务器错误',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ error: z.string()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 获取区域路径
|
|
|
+const getAreaPathRoute = createRoute({
|
|
|
+ method: 'get',
|
|
|
+ path: '/path/{id}',
|
|
|
+ description: '获取区域路径(从根节点到当前节点)',
|
|
|
+ tags: ['省市区管理'],
|
|
|
+ middleware: [authMiddleware],
|
|
|
+ request: {
|
|
|
+ params: z.object({
|
|
|
+ id: z.coerce.number().positive('区域ID必须为正整数')
|
|
|
+ })
|
|
|
+ },
|
|
|
+ responses: {
|
|
|
+ 200: {
|
|
|
+ description: '成功获取区域路径',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ data: z.array(z.object({
|
|
|
+ id: z.number(),
|
|
|
+ parentId: z.number().nullable(),
|
|
|
+ name: z.string(),
|
|
|
+ level: z.number(),
|
|
|
+ code: z.string(),
|
|
|
+ isDisabled: z.number()
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 404: {
|
|
|
+ description: '区域不存在',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ error: z.string()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 500: {
|
|
|
+ description: '服务器错误',
|
|
|
+ content: {
|
|
|
+ 'application/json': {
|
|
|
+ schema: z.object({
|
|
|
+ success: z.boolean(),
|
|
|
+ error: z.string()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const app = new OpenAPIHono()
|
|
|
+ // 注册路由 - 使用链式结构
|
|
|
+ .openapi(getAreaTreeRoute, async (c) => {
|
|
|
+ const areaService = new AreaService();
|
|
|
+ try {
|
|
|
+ const treeData = await areaService.getAreaTree();
|
|
|
+ return c.json({
|
|
|
+ success: true,
|
|
|
+ data: treeData
|
|
|
+ }, 200);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取省市区树形结构失败:', error);
|
|
|
+ return c.json({
|
|
|
+ success: false,
|
|
|
+ error: '获取省市区树形结构失败'
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .openapi(getAreaTreeByLevelRoute, async (c) => {
|
|
|
+ const areaService = new AreaService();
|
|
|
+ try {
|
|
|
+ const { level } = c.req.valid('param');
|
|
|
+ const treeData = await areaService.getAreaTreeByLevel(level);
|
|
|
+ return c.json({
|
|
|
+ success: true,
|
|
|
+ data: treeData
|
|
|
+ }, 200);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取层级树形结构失败:', error);
|
|
|
+ return c.json({
|
|
|
+ success: false,
|
|
|
+ error: '获取层级树形结构失败'
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .openapi(getSubTreeRoute, async (c) => {
|
|
|
+ const areaService = new AreaService();
|
|
|
+ try {
|
|
|
+ const { id } = c.req.valid('param');
|
|
|
+ const subTree = await areaService.getSubTree(id);
|
|
|
+
|
|
|
+ if (!subTree) {
|
|
|
+ return c.json({
|
|
|
+ success: false,
|
|
|
+ error: '区域不存在'
|
|
|
+ }, 404);
|
|
|
+ }
|
|
|
+
|
|
|
+ return c.json({
|
|
|
+ success: true,
|
|
|
+ data: subTree
|
|
|
+ }, 200);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取子树失败:', error);
|
|
|
+ return c.json({
|
|
|
+ success: false,
|
|
|
+ error: '获取子树失败'
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .openapi(getAreaPathRoute, async (c) => {
|
|
|
+ const areaService = new AreaService();
|
|
|
+ try {
|
|
|
+ const { id } = c.req.valid('param');
|
|
|
+ const path = await areaService.getAreaPath(id);
|
|
|
+
|
|
|
+ if (path.length === 0) {
|
|
|
+ return c.json({
|
|
|
+ success: false,
|
|
|
+ error: '区域不存在'
|
|
|
+ }, 404);
|
|
|
+ }
|
|
|
+
|
|
|
+ return c.json({
|
|
|
+ success: true,
|
|
|
+ data: path
|
|
|
+ }, 200);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取区域路径失败:', error);
|
|
|
+ return c.json({
|
|
|
+ success: false,
|
|
|
+ error: '获取区域路径失败'
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+export default app;
|