「3」基于Next.js的低代码平台:用户服务开发(中)

前言

本节开始我们实现用户服务中心的其他模块,分别为:

  • 系统管理
  • 资源管理
  • 权限管理
  • 角色管理
  • 用户管理

这一节基本上是体力劳动,重复集中CRUD

系统管理

现在需要实现schema来定义创建系统数据的校验

新建helpers/constants.ts

ts 复制代码
export enum STATUS {
  DISABLED = 'DISABLED',
  ENABLED = 'ENABLED',
}

新建schemas/system.ts

ts 复制代码
import { z } from 'zod';
import { STATUS } from '@/helpers/constants';

export const systemSchema = z.object({
  name: z.string().min(2),
  description: z.string().min(2).optional(),
  status: z.enum([STATUS.DISABLED, STATUS.ENABLED]).optional(),
  creatorId: z.string(),
  updatorId: z.any().optional(),
});

export type systemSchemaType = z.infer<typeof systemSchema>;

定义操作数据库的方法helpers/dbRepo.ts

ts 复制代码
import prisma from '@/helpers/prisma';
import { systemSchemaType } from '@/schemas/system';

const include = {
  creator: {
    select: {
      id: true,
      email: true,
      name: true,
    },
  },
  updator: {
    select: {
      id: true,
      email: true,
      name: true,
    },
  },
};
async function create(system: systemSchemaType) {
  return await prisma.system.create({
    data: system,
    include,
  });
}

async function update(id: string, system: any) {
  return await prisma.system.update({
    where: { id },
    data: system,
    include,
  });
}

async function remove(id: string) {
  return await prisma.system.delete({
    where: { id },
  });
}

async function findById(id: string) {
  return await prisma.system.findUnique({
    where: { id },
    include,
  });
}

async function findByIds(ids: string[]) {
  return await prisma.system.findMany({
    where: {
      id: {
        in: ids,
      },
    },
    include,
  });
}

async function list() {
  return await prisma.system.findMany({
    include,
  });
}

const systemRepo = {
  create,
  update,
  remove,
  findById,
  findByIds,
  list,
};

export default systemRepo;

定义接口app/api/system/route.ts

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import systemRepo from '@/helpers/dbRepo/system';
import prisma from '@/helpers/prisma';
import type { NextRequest } from 'next/server';

const create = apiHandler(async (req: NextRequest) => {
  const body = await req.json();
  const userId = await req.headers.get('userId');

  if (userId) {
    const user = await prisma.user.findUnique({
      where: {
        id: userId,
      },
    });
    const result = await systemRepo.create({
      ...body,
      creator: {
        connectOrCreate: {
          where: {
            id: userId,
          },
          create: {
            id: userId,
            name: user?.name,
            email: user?.email,
            password: user?.password,
          },
        },
      },
    });
    return transformInterceptor({
      data: result,
    });
  } else {
    throw new Error('请先登录');
  }
});

const list = apiHandler(async (req: NextRequest) => {
  const result = await systemRepo.list();
  return transformInterceptor({
    data: result,
  });
});

export const POST = create;
export const GET = list;

定义app/api/systen/[id]/route.ts

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import systemRepo from '@/helpers/dbRepo/system';
import type { NextRequest } from 'next/server';
import prisma from '@/helpers/prisma';

const getSystem = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await systemRepo.findById(id);
  return transformInterceptor({
    data: result,
  });
});

const updateSystem = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const userId = await req.headers.get('userId');
  const body = await req.json();
  if (userId) {
    const user = await prisma.user.findUnique({
      where: {
        id: userId,
      },
    });
    const result = await systemRepo.update(id, {
      ...body,
      updator: {
        connectOrCreate: {
          where: {
            id: userId,
          },
          create: {
            id: userId,
            name: user?.name,
            email: user?.email,
            password: user?.password,
          },
        },
      },
    });
    return transformInterceptor({
      data: result,
    });
  } else {
    throw new Error('请先登录');
  }
});

const removeSystem = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await systemRepo.remove(id);
  return transformInterceptor({
    data: result,
  });
});

export const GET = getSystem;
export const PATCH = updateSystem;
export const DELETE = removeSystem;

分别实现系统的:

  • 获取列表
  • 获取当前系统详情
  • 创建系统
  • 更新系统
  • 删除系统

资源管理

修改helpers/constants.ts添加一个枚举,暂时用不到

ts 复制代码
export enum RESOURCE_TYPE {
  MENU = 'MENU',
  NORMAL = 'NORMAL',
}

新建helpers/dbRepo/resource.ts,作数据库操作函数封装,实现增删改查,分页查找

ts 复制代码
import prisma from '@/helpers/prisma';

const include = {
  system: true,
  parent: true,
};
async function create(resource: any) {
  return await prisma.resource.create({
    data: resource,
    include,
  });
}

async function update(id: string, resource: any) {
  return await prisma.resource.update({
    where: { id },
    data: resource,
    include,
  });
}

async function remove(id: string) {
  return await prisma.resource.delete({
    where: { id },
  });
}

async function findById(id: string) {
  return await prisma.resource.findUnique({
    where: { id },
    include,
  });
}

async function paginate({ page, pageSize, ...params }: { page: number; pageSize: number }) {
  const skip = (page - 1) * pageSize;
  const take = pageSize;
  return await prisma.resource.findMany({
    skip,
    take,
    where: {
      ...params,
    },
    include,
  });
}

const resourceRepo = {
  create,
  update,
  remove,
  findById,
  paginate,
};

export default resourceRepo;

先来最基本的创建接口app/api/resource/route.ts

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import resourceRepo from '@/helpers/dbRepo/resource';
import type { NextRequest } from 'next/server';

const create = apiHandler(async (req: NextRequest) => {
  const body = await req.json();

  const result = await resourceRepo.create(body);

  return transformInterceptor({
    data: result,
  });
});

export const POST = create;

然后是分页查找app/api/resource/paginate/route.ts, 因为不能在同一个route下面有两个POST接口,所以多了一个路径

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import resourceRepo from '@/helpers/dbRepo/resource';
import type { NextRequest } from 'next/server';

const paginate = apiHandler(async (req: NextRequest) => {
  const body = await req.json();
  const result = await resourceRepo.paginate(body);
  return transformInterceptor({
    data: result,
  });
});

export const POST = paginate;

最后是针对一个resource的操作app/api/resource/[id]/route.ts

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import resourceRepo from '@/helpers/dbRepo/resource';
import type { NextRequest } from 'next/server';

const getResource = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await resourceRepo.findById(id);
  return transformInterceptor({
    data: result,
  });
});

const removeResource = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await resourceRepo.remove(id);
  return transformInterceptor({
    data: result,
  });
});

const updateResource = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const body = await req.json();
  const result = await resourceRepo.update(id, body);
  return transformInterceptor({
    data: result,
  });
});

export const GET = getResource;
export const DELETE = removeResource;
export const PATCH = updateResource;

这也不需要解释了吧,[id]下面的就可以在{params}里面拿到这个id,如下为创建接口测试示例,外键的话就传对应id就行

权限管理

新建helpers/dbRepo/privilege.ts

ts 复制代码
import prisma from '@/helpers/prisma';

async function create(privilege: any) {
  return await prisma.privilege.create({
    data: privilege,
  });
}

async function update(id: string, privilege: any) {
  return await prisma.privilege.update({
    where: { id },
    data: privilege,
  });
}

async function remove(id: string) {
  return await prisma.privilege.delete({
    where: { id },
  });
}

async function findById(id: string) {
  return await prisma.privilege.findUnique({
    where: { id },
  });
}

async function paginate({ page, pageSize, ...params }: { page: number; pageSize: number }) {
  const skip = (page - 1) * pageSize;
  const take = pageSize;
  return await prisma.privilege.findMany({
    skip,
    take,
    where: {
      ...params,
    },
  });
}

const privilegeRepo = {
  create,
  update,
  remove,
  findById,
  paginate,
};

export default privilegeRepo;

新建app/api/privilege/route.ts实现创建

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import privilegeRepo from '@/helpers/dbRepo/privilege';
import type { NextRequest } from 'next/server';

const create = apiHandler(async (req: NextRequest) => {
  const body = await req.json();

  const result = await privilegeRepo.create(body);

  return transformInterceptor({
    data: result,
  });
});

export const POST = create;

新建app/api/privilege/paginate/route.ts 实现分页查找

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import privilegeRepo from '@/helpers/dbRepo/privilege';
import type { NextRequest } from 'next/server';

const paginate = apiHandler(async (req: NextRequest) => {
  const body = await req.json();
  const result = await privilegeRepo.paginate(body);
  return transformInterceptor({
    data: result,
  });
});

export const POST = paginate;

新建app/api/privilege/[id]/route.ts 实现更新,删除,详情

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import privilegeRepo from '@/helpers/dbRepo/privilege';
import type { NextRequest } from 'next/server';

const update = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const body = await req.json();
  const result = await privilegeRepo.update(id, body);
  return transformInterceptor({
    data: result,
  });
});

const remove = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await privilegeRepo.remove(id);
  return transformInterceptor({
    data: result,
  });
});

const findById = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await privilegeRepo.findById(id);
  return transformInterceptor({
    data: result,
  });
});

export const PATCH = update;
export const DELETE = remove;
export const GET = findById;

重复劳动,基本copilot都已经自动能生成了

角色管理

新建helpers/dbRepo/role.ts实现数据库操作函数

ts 复制代码
import prisma from '@/helpers/prisma';

async function create(role: any) {
  return await prisma.role.create({
    data: role,
  });
}

async function update(id: string, role: any) {
  return await prisma.role.update({
    where: { id },
    data: role,
  });
}

async function remove(id: string) {
  return await prisma.role.delete({
    where: { id },
  });
}

async function findById(id: string) {
  return await prisma.role.findUnique({
    where: { id },
  });
}

async function paginate({ page, pageSize, ...params }: { page: number; pageSize: number }) {
  const skip = (page - 1) * pageSize;
  const take = pageSize;
  return await prisma.role.findMany({
    skip,
    take,
    where: {
      ...params,
    },
  });
}

const roleRepo = {
  create,
  update,
  remove,
  findById,
  paginate,
};

export default roleRepo;

新建app/api/role/route.ts实现创建接口

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import roleRepo from '@/helpers/dbRepo/role';
import type { NextRequest } from 'next/server';

const create = apiHandler(async (req: NextRequest) => {
  const { systemId, ...args } = await req.json();
  const userId = await req.headers.get('userId');

  if (userId) {
    const result = await roleRepo.create({
      ...args,
      creator: {
        connect: {
          id: userId,
        },
      },
      updator: {
        connect: {
          id: userId,
        },
      },
      system: {
        connect: {
          id: systemId,
        },
      },
    });
    return transformInterceptor({
      data: result,
    });
  } else {
    throw new Error('请先登录');
  }
});

export const POST = create;

新建app/api/role/paginate/route.ts实现分页接口

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import roleRepo from '@/helpers/dbRepo/role';
import type { NextRequest } from 'next/server';

const paginate = apiHandler(async (req: NextRequest) => {
  const { page, pageSize, ...params } = await req.json();
  const result = await roleRepo.paginate({ page, pageSize, ...params });
  return transformInterceptor({
    data: result,
  });
});

export const POST = paginate;

新建app/api/role/[id]/route.ts实现更新、删除、详情接口

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import roleRepo from '@/helpers/dbRepo/role';
import type { NextRequest } from 'next/server';

const update = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const body = await req.json();
  const userId = await req.headers.get('userId');

  const result = await roleRepo.update(id, {
    ...body,
    updator: {
      connect: {
        id: userId,
      },
    },
  });
  return transformInterceptor({
    data: result,
  });
});

const remove = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await roleRepo.remove(id);
  return transformInterceptor({
    data: result,
  });
});

const findById = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const { id } = params;
  const result = await roleRepo.findById(id);
  return transformInterceptor({
    data: result,
  });
});

export const PATCH = update;
export const DELETE = remove;
export const GET = findById;

用户管理

新建helpers/dbRepo/user.ts 封装数据库操作

ts 复制代码
import prisma from '@/helpers/prisma';

const selectField = {
  email: true,
  name: true,
  userRoles: true,
};
async function create(user: any) {
  return await prisma.user.create({
    data: user,
    select: selectField,
  });
}

async function update(id: string, user: any) {
  return await prisma.user.update({
    where: { id },
    data: user,
    select: selectField,
  });
}

async function remove(id: string) {
  return await prisma.user.delete({
    where: { id },
  });
}

async function findById(id: string) {
  return await prisma.user.findUnique({
    where: { id },
    select: selectField,
  });
}

async function paginate({ page, pageSize, ...params }: { page: number; pageSize: number }) {
  const skip = (page - 1) * pageSize;
  const take = pageSize;
  return await prisma.user.findMany({
    skip,
    take,
    where: {
      ...params,
    },
    select: selectField,
  });
}

const userRepo = {
  create,
  update,
  remove,
  findById,
  paginate,
};

export default userRepo;

新建app/api/user/route.ts实现创建用户

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import userRepo from '@/helpers/dbRepo/user';
import type { NextRequest } from 'next/server';

const create = apiHandler(async (req: NextRequest) => {
  const body = await req.json();
  const result = await userRepo.create(body);
  return transformInterceptor({
    data: result,
  });
});

export const POST = create;

新建app/api/user/paginate/route.ts实现分页

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import userRepo from '@/helpers/dbRepo/user';
import type { NextRequest } from 'next/server';

const paginate = apiHandler(async (req: NextRequest) => {
  const { page, pageSize, ...params } = await req.json();
  const result = await userRepo.paginate({ page, pageSize, ...params });
  return transformInterceptor({
    data: result,
  });
});

export const POST = paginate;

新建app/api/user/[id]/route.ts实现更新、删除、详情

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import userRepo from '@/helpers/dbRepo/user';
import type { NextRequest } from 'next/server';

const update = apiHandler(async (req: NextRequest) => {
  const body = await req.json();
  const userId = await req.headers.get('userId');
  if (!userId) {
    throw new Error('请先登录');
  }
  const result = await userRepo.update(userId, body);
  return transformInterceptor({
    data: result,
  });
});

const remove = apiHandler(async (req: NextRequest) => {
  const userId = await req.headers.get('userId');
  if (!userId) {
    throw new Error('请先登录');
  }

  const result = await userRepo.remove(userId);
  return transformInterceptor({
    data: result,
  });
});

const findById = apiHandler(async (req: NextRequest) => {
  const userId = await req.headers.get('userId');
  if (!userId) {
    throw new Error('请先登录');
  }
  const result = await userRepo.findById(userId);
  return transformInterceptor({
    data: result,
  });
});

export const PATCH = update;
export const DELETE = remove;
export const GET = findById;

⭐️用户-角色管理

现在我们来实现用户-角色管理

新建helpers/dbRepo/user-role.ts

ts 复制代码
import prisma from '@/helpers/prisma';

const selectField = {
  user: {
    select: {
      email: true,
      name: true,
    },
  },
  role: true,
};
async function create(userId: string, roleId: string) {
  return await prisma.userRole.create({
    data: {
      user: {
        connect: {
          id: userId,
        },
      },
      role: {
        connect: {
          id: roleId,
        },
      },
    },
    select: selectField,
  });
}

async function remove(userId: string, roleId: string) {
  return await prisma.userRole.delete({
    where: {
      userId_roleId: {
        userId,
        roleId,
      },
    },
  });
}

async function findByUserId(userId: string) {
  return await prisma.userRole.findMany({
    where: {
      userId,
    },
    select: selectField,
  });
}

async function findByRoleId(roleId: string) {
  return await prisma.userRole.findMany({
    where: {
      roleId,
    },
    select: selectField,
  });
}

async function paginate({ page, pageSize, ...params }: { page: number; pageSize: number }) {
  const skip = (page - 1) * pageSize;
  const take = pageSize;
  return await prisma.userRole.findMany({
    skip,
    take,
    where: {
      ...params,
    },
    select: selectField,
  });
}

const userRoleRepo = {
  create,
  remove,
  findByUserId,
  findByRoleId,
  paginate,
};

export default userRoleRepo;

新建app/api/user-role/route.ts实现创建、删除、根据userId查询角色

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import userRoleRepo from '@/helpers/dbRepo/user-role';
import type { NextRequest } from 'next/server';

const createUserRole = apiHandler(async (req: NextRequest) => {
  const { roleId } = await req.json();
  const userId = await req.headers.get('userId');
  if (!userId) {
    throw new Error('请先登录');
  }
  const result = await userRoleRepo.create(userId, roleId);
  return transformInterceptor({
    data: result,
  });
});

const removeUserRole = apiHandler(async (req: NextRequest) => {
  const { roleId } = await req.json();
  const userId = await req.headers.get('userId');
  if (!userId) {
    throw new Error('请先登录');
  }
  const result = await userRoleRepo.remove(userId, roleId);
  return transformInterceptor({
    data: result,
  });
});

const findUserRole = apiHandler(async (req: NextRequest) => {
  const userId = await req.headers.get('userId');
  if (!userId) {
    throw new Error('请先登录');
  }
  const result = await userRoleRepo.findByUserId(userId);
  return transformInterceptor({
    data: result,
  });
});

export const POST = createUserRole;
export const DELETE = removeUserRole;
export const GET = findUserRole;

新建app/api/user-role/paginate/route.ts实现分页

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import userRoleRepo from '@/helpers/dbRepo/user-role';
import type { NextRequest } from 'next/server';

const paginate = apiHandler(async (req: NextRequest) => {
  const { page, pageSize, ...params } = await req.json();
  const result = await userRoleRepo.paginate({ page, pageSize, ...params });
  return transformInterceptor({
    data: result,
  });
});

export const POST = paginate;

角色-权限管理

新建helper/dbRepo/role-privilege.ts实现数据库操作

ts 复制代码
import prisma from '@/helpers/prisma';

async function create(roleId: string, privilegeId: string) {
  return await prisma.rolePrivilege.create({
    data: {
      role: {
        connect: {
          id: roleId,
        },
      },
      privilege: {
        connect: {
          id: privilegeId,
        },
      },
    },
  });
}

async function remove(roleId: string, privilegeId: string) {
  return await prisma.rolePrivilege.delete({
    where: {
      roleId_privilegeId: {
        roleId,
        privilegeId,
      },
    },
  });
}

async function findByRoleId(roleId: string) {
  return await prisma.rolePrivilege.findMany({
    where: {
      roleId,
    },
  });
}

const rolePrivilegeRepo = {
  create,
  remove,
  findByRoleId,
};

export default rolePrivilegeRepo;

新建app/api/role-privilege/route.ts实现创建、删除接口

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import rolePrivilegeRoleRepo from '@/helpers/dbRepo/role-privilege';
import type { NextRequest } from 'next/server';

const createRolePrivilege = apiHandler(async (req: NextRequest) => {
  const { roleId, privilegeId } = await req.json();
  const result = await rolePrivilegeRoleRepo.create(roleId, privilegeId);
  return transformInterceptor({
    data: result,
  });
});

const removeRolePrivilege = apiHandler(async (req: NextRequest) => {
  const { roleId, privilegeId } = await req.json();
  const result = await rolePrivilegeRoleRepo.remove(roleId, privilegeId);
  return transformInterceptor({
    data: result,
  });
});

export const POST = createRolePrivilege;
export const DELETE = removeRolePrivilege;

新建app/api/role-privilege/[id]/route.ts实现根据roleId查找

ts 复制代码
import { apiHandler, transformInterceptor } from '@/helpers';
import rolePrivilegeRoleRepo from '@/helpers/dbRepo/role-privilege';
import type { NextRequest } from 'next/server';

const findRolePrivilege = apiHandler(async (req: NextRequest, { params }: { params: any }) => {
  const result = await rolePrivilegeRoleRepo.findByRoleId(params.id);
  return transformInterceptor({
    data: result,
  });
});

export const GET = findRolePrivilege;

现在每个管理模块还是单独的,没有构成完整系统的,下一章我们会基于Next.js开发简单的后台管理系统,将接口串联,也会有一些对应的走流程出现的bug改动

代码仓库:github.com/liyunfu1998...

相关推荐
Martin -Tang3 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发4 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端