# shop-admin-server-nodejs **Repository Path**: usaliva/shop-admin-server-nodejs ## Basic Information - **Project Name**: shop-admin-server-nodejs - **Description**: 本地文件系统管理数据库的商品后台管理 API 服务 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-04-15 - **Last Updated**: 2022-05-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 介绍 - 基于 Express 开发的商品后台管理服务器。 - node 版本 v16.13.0。 - 提供 RESTful 规范的业务 API。 ## 数据存储 内容存储在本地 json 文件中,不使用数据库。 数据库目录:`db/*.json` 可通过 `npm run init` 初始化数据库文件,或恢复丢失的文件。 **注意:**初始化 user 表时会重新生成 admin 账户,如果修改了接口默认的密码加密规则,需要手动修改初始密码。 ## 运行 ```shell # 安装依赖 npm install # 启动服务 npm start # 或者 node app.js ``` 浏览器访问 `http://localhost:5000/api/admin/demo` 测试是否成功 ## pm2 配置了 pm2 启动方式。 ```shell npm i -g pm2 # windows pm2 start ./pm2.win.js # linux pm2 start ./pm2.config.json ``` ## 接口格式 基础路径:`http://localhost:5000/api/admin` `Content-Type` 默认为 `application/json` 正常情况下,接口全部响应 `200` HTTP Status,业务处理使用 Response 响应体中的自定义状态码,Response 格式: | 名称 | 类型 | 是否必须 | 备注 | | ------ | ------ | -------- | -------- | | status | number | 是 | 状态 | | msg | string | 否 | 错误提示 | | data | any | 否 | 数据 | ## 自定义状态码 | 状态码 | 备注 | | ------ | ---------- | | 200 | 成功 | | 400 | 错误 | | 401 | token 无效 | ## 配置文件 `config\config.default.js` 存储全局配置,主要包括密钥等信息。 ## 密码加密 接口使用明文传递密码,数据库(JSON 文件)存储 PBKDF2 加密后的字符串。 如需处理明文传输问题,请自行扩展。 ## 超级管理员 超级管理员默认:账号`admin` + 密码 `123456`。 接口通过 `id === 1` 判断超级管理员(用户)身份,并进行了删除校验,限制以下操作: 1. 修改 `id===1` 管理员(用户)的状态 2. 修改 `id===1` 管理员(用户)的角色 3. 删除 `id===1` 管理员(用户) 请不要手动修改或删除数据库中的超管账号。 ## Postman Collection [postman_collection.json](./docs/postman_collection.json) # 基础接口 ## 验证码 ### 基本信息 接口路径:`GET`/captcha ## 管理员登录 ### 基本信息 接口路径:`POST`/login ### 请求参数 #### Body ```js { account: 'admin', // 必填 账号 pwd: '123456', // 必填 密码(明文,可自行扩展) imgcode: 'abcd' // 必填 验证码 } ``` ### 返回数据 ```js { status: 200, data: { token: 'xxxx', userInfo: { id: 1, account: 'admin', realName: '超级管理员' }, menus: [{ id: 1, // 菜单id routePath: '/product', // 菜单 path+params routeName: '', // 菜单 uniqueAuth name: '商品', // 菜单名称 icon: 'apple', // 图标 children: [{ id: 2, routePath: '/product/list', routeName: 'product_list', name: '商品列表', icon: 'coin', children: [] }, ...] // 子菜单 }], uniqueAuth: ['product_list', ...] } } ``` # 管理员相关 ## 获取管理员列表 ### 基本信息 接口路径:`GET`/setting/admin ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Query ```js { page: 1, // 非必填 页码,默认 1 limit: 10, // 非必填 每页条数,默认 10 name: '', // 非必填 管理员姓名或账号关键字 status: 1 // 非必填 状态,`0`禁用,`1`启用,默认 falsey 查询所有 } ``` ### 返回数据 ```js { status: 200, data: { list: [ { id: 1, // 管理员 id account: 'admin', // 账号 realName: '超级管理员', // 姓名 roles: [ { name: '超级管理员', // 角色名称 id: 1 // 角色id } ], // 角色列表 status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _lastIp: '127.0.0.1', // 最后一次登录IP _lastTime: "2022-01-01 00:00:00", // 最后一次登录时间 _addTime: "2022-01-01 00:00:00", // 创建时间 _updateTime: "2022-01-01 00:00:00" // 最后一次更新时间 } ], count: 10 // 总条数 } } ``` ## 添加管理员 ### 基本信息 接口路径:`POST`/setting/admin ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Body ```js { account: 'admin', // 必填 账号 pwd: '123456', // 必填 密码(明文,可自行扩展) pwdConfirm: '123456', // 必填 确认密码 roles: [1, 2], // 必填 角色 id 数组 status: 1, // 必填 状态,`0`禁用,`1`启用 realName: '超级管理员' // 必填 姓名 } ``` ### ## 修改管理员 ### 基本信息 接口路径:`PUT`/setting/admin/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | -------- | | id | number | 是 | 管理员id | #### Body ```js { roles: [1, 2], // 必填 角色 id 数组 status: 1, // 必填 状态,`0`禁用,`1`启用 realName: '超级管理员' // 必填 姓名 } ``` ## 获取管理员 ### 基本信息 接口路径:`GET`/setting/admin/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | -------- | | id | number | 是 | 管理员id | ### 返回数据 ```js { status: 200, data: { id: 1, // 管理员 id account: 'admin', // 账号 realName: '超级管理员', // 姓名 roles: [ { name: '超级管理员', // 角色名称 id: 1 // 角色id } ], // 角色列表 status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _lastIp: '127.0.0.1', // 最后一次登录IP _lastTime: "2022-01-01 00:00:00", // 最后一次登录时间 _addTime: "2022-01-01 00:00:00", // 创建时间 _updateTime: "2022-01-01 00:00:00" // 最后一次更新时间 } } ``` ## 删除管理员 ### 基本信息 接口路径:`DELETE`/setting/admin/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | -------- | | id | number | 是 | 管理员id | ## 修改管理员状态 ### 基本信息 接口路径:`PUT`/setting/admin/:id/set_status/:status ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ---------------------- | | id | number | 是 | 管理员id | | status | number | 是 | 状态,`0`禁用,`1`启用 | ## 修改管理员密码 ### 基本信息 接口路径:`PUT`/setting/admin/:id/set_password ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | -------- | | id | number | 是 | 管理员id | #### Body ```js { pwd: '123456', // 必填 密码(明文,可自行扩展) pwdConfirm: '123456', // 必填 确认密码 } ``` # 角色相关 ## 获取角色列表 ### 基本信息 接口路径:`GET`/setting/role ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Query ```js { page: 1, // 非必填 页码,默认 1 limit: 10, // 非必填 每页条数,默认 10 name: '', // 非必填 角色名称 status: 1 // 非必填 状态,`0`禁用,`1`启用,默认 falsey 查询所有 } ``` ### 返回数据 ```js { status: 200, data: { list: [ { id: 1, // 角色 id name: '库存管理员', // 角色名称 menus: [ { id: 1, // 菜单id name: '商品列表', // } ], // 菜单权限 status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _addTime: "2022-01-01 00:00:00", // 创建时间 _updateTime: "2022-01-01 00:00:00" // 最后一次更新时间 } ], count: 10 // 总条数 } } ``` ## 添加角色 ### 基本信息 接口路径:`POST`/setting/role ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Body ```js { name: '库存管理员', // 必填 角色名称 status: 1, // 必填 状态,`0`禁用,`1`启用 menus: [1, 2] // 必填 菜单权限 id 列表 } ``` ## 修改角色 ### 基本信息 接口路径:`PUT`/setting/role/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 角色id | #### Body ```js { name: '库存管理员', // 必填 角色名称 menus: [1, 2], // 必填 菜单权限 status: 1, //, 必填 状态,`0`禁用,`1`启用 } ``` ## 获取角色 ### 基本信息 接口路径:`GET`/setting/role/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 角色id | ### 返回数据 ```js { status: 200, data: { id: 1, // 管理员 id name: '库存管理员', // 角色名称 menus: [ { id: 1, // 菜单id name: '商品列表', // 菜单名称 } ], // 菜单权限 status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _addTime: "2022-01-01 00:00:00", // 创建时间 _updateTime: "2022-01-01 00:00:00" // 最后一次更新时间 } } ``` ## 删除角色 ### 基本信息 接口路径:`DELETE`/setting/role/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 角色id | ## 修改角色状态 ### 基本信息 接口路径:`PUT`/setting/role/:id/set_status/:status ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ---------------------- | | id | number | 是 | 角色id | | status | number | 是 | 状态,`0`禁用,`1`启用 | # 菜单相关 ## 获取菜单列表(树型结构) ### 基本信息 接口路径:`GET`/setting/menu ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Query ```js { page: 1, // 非必填 页码,默认 1 limit: 10, // 非必填 每页条数,默认 10 status: 1 // 非必填 状态,`0`禁用,`1`启用,默认 falsey 查询所有 } ``` ### 返回数据 ```js { status: 200, data: { list: [ { id: 1, // 菜单 id pid: 0, // 父级菜单 id name: '商品', // 菜单名称 icon: 'user', // 图标 params: '', // 路由参数(拼接到路由地址) path: '', // 路由地址(客户端路由地址) uniqueAuth: '', // 唯一标识(客户端使用) order: 1, // 排序 isHidden: 0, // 是否为隐藏菜单 children: [ { ... } ], // 下级菜单 status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _addTime: "2022-01-01 00:00:00", // 创建时间 _updateTime: "2022-01-01 00:00:00" // 最后一次更新时间 } ], count: 10 // 总条数 } } ``` ## 添加菜单 ### 基本信息 接口路径:`POST`/setting/menu ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Body ```js { pid: 0, // 非必填 父级菜单 id(falsey 表示顶级菜单) name: '商品', // 必填 菜单名称 icon: 'user', // 非必填 图标 params: '', // 非必填 路由参数(拼接到路由地址) path: '', // 非必填 路由地址(客户端路由地址) uniqueAuth: '', // 非必填 唯一标识(客户端使用) order: 1, // 必填 排序 isHidden: 0, // 必填 是否为隐藏菜单 1是 0否 status: 1 // 必填 状态,`0`禁用,`1`启用 } ``` ## 修改菜单 ### 基本信息 接口路径:`PUT`/setting/menu/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 菜单id | #### Body ```js { pid: 0, // 非必填 父级菜单 id(falsey 表示顶级菜单) name: '商品', // 必填 菜单名称 icon: 'user', // 非必填 图标 params: '', // 非必填 路由参数(拼接到路由地址) path: '', // 非必填 路由地址(客户端路由地址) uniqueAuth: '', // 非必填 唯一标识(客户端使用) order: 1, // 必填 排序 isHidden: 0, // 必填 是否为隐藏菜单 1是 0否 status: 1 // 必填 状态,`0`禁用,`1`启用 } ``` ## 获取菜单 ### 基本信息 接口路径:`GET`/setting/menu/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 菜单id | ### 返回数据 ```js { status: 200, data: { id: 1, // 菜单 id pid: 0, // 父级菜单 id(falsey 表示顶级菜单) name: '商品', // 菜单名称 icon: 'user', // 图标 params: '', // 路由参数(拼接到路由地址) path: '', // 路由地址(客户端路由地址) uniqueAuth: '', // 唯一标识(客户端使用) order: 1, // 排序 isHidden: 0, // 是否为隐藏菜单 1是 0否 status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _addTime: "2022-01-01 00:00:00", // 创建时间 _updateTime: "2022-01-01 00:00:00" // 最后一次更新时间 } } ``` ## 删除菜单 ### 基本信息 接口路径:`DELETE`/setting/menu/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 菜单id | ## 修改菜单状态 ### 基本信息 接口路径:`PUT`/setting/menu/:id/set_status/:status ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ---------------------- | | id | number | 是 | 菜单id | | status | number | 是 | 状态,`0`禁用,`1`启用 | # 产品分类 ## 获取分类列表(树型结构) ### 基本信息 接口路径:`GET`/product/category ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Query ```js { page: 1, // 非必填 页码,默认 1 limit: 10, // 非必填 每页条数,默认 10 status: 1 // 非必填 状态,`0`禁用,`1`启用,默认 falsey 查询所有 } ``` ### 返回数据 ```js { status: 200, data: [ { id: 1, // 分类 id pid: 0, // 父级分类 id name: '手机数码', // 分类名称 order: 1, // 排序 children: [ { ... } ], // 下级分类(最多一级) status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _addTime: '2022-01-01 00:00:00', // 创建时间 _updateTime: '2022-01-01 00:00:00' // 最后一次更新时间 } ] } ``` ## 添加分类 ### 基本信息 接口路径:`POST`/product/category ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### Body ```js { pid: 0, // 非必填 父级分类 id(falsey 表示一级分类) name: '手机数码', // 必填 分类名称 order: 1, // 必填 排序 status: 1 // 必填 状态,`0`禁用,`1`启用 } ``` ## 修改分类 ### 基本信息 接口路径:`PUT`/product/category/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 分类id | #### Body ```js { pid: 0, // 非必填 父级分类 id(falsey 表示一级分类) name: '手机数码', // 必填 分类名称 order: 1, // 必填 排序 status: 1 // 必填 状态,`0`禁用,`1`启用 } ``` ## 获取分类 ### 基本信息 接口路径:`GET`/product/category/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 分类id | ### 返回数据 ```js { status: 200, data: { id: 1, // 分类 id pid: 0, // 父级分类 id(falsey 表示一级分类) name: '手机数码', // 分类名称 order: 1, // 排序 status: 1, // 状态,`0`禁用,`1`启用 isDel: 0, // 删除状态,`0`是,`1`否 _addTime: "2022-01-01 00:00:00", // 创建时间 _updateTime: "2022-01-01 00:00:00" // 最后一次更新时间 } } ``` ## 删除分类 ### 基本信息 接口路径:`DELETE`/product/category/:id ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ------ | | id | number | 是 | 分类id | ## 修改分类状态 ### 基本信息 接口路径:`PUT`/product/category/:id/set_status/:status ### 请求参数 #### Headers | 参数名称 | 是否必须 | 备注 | | ------------- | -------- | ----------------------------------------- | | Authorization | 是 | 认证token,格式 `Bearer ` | #### 路径参数 | 参数名称 | 类型 | 是否必须 | 备注 | | -------- | ------ | -------- | ---------------------- | | id | number | 是 | 分类id | | status | number | 是 | 状态,`0`禁用,`1`启用 |