若依搭建 帝可得 售货机 笔记

一、搭建项目

1.后端gitee链接:

启动项目时记得修改mysql和redis的相关信息;创建项目相关数据库,并导入初始化的SQL脚本

dkd-parent: 帝可得后台管理系统 (gitee.com)

2.前端gitee链接:

启动项目时记得安装依赖:npm install

dkd-vue: 帝可得前端 (gitee.com)

二、 点位管理

2.1 需求说明:

2.2 相关数据库设计

区域表:主键id、区域名称、备注说明(BaseEntity里有该字段,无需多余创建)

合作商表:主键id、合作商名称、联系人、联系电话、分成比例·、账号、密码

点位表:主键id、点位名称、详细地址、商圈类型、区域外键、合作商外键

使用大模型进行数据库的生成:

你是一位软件工程师,帮我生成MySQL的表结构,需求如下:

1.区域表:表名tb_region,字段有id、区域名称;

2.合作商表:表名tb_partner,字段有id、合作商名称、联系人、联系电话、分成比例(int)、账号、密码;

3.点位表:表名tb_node 字段id、点位名称、详细地址、商圈类型(int);

其他要求:

1.每张表中的都有创建的时间create_time、修改时间date_time、创建人create_by、修改人update_by、备注remark这些字段;

2.每张表的主键都是自增的;

3.区域与点位是一对多的关系,合作商与点位是一对多的关系,请用字段表示出来,并建立外键的约束;

4.请为每个字段都添加上comment;

5.帮我给生成的表中插入一些北京城市相关的区域、点位、合作商的测试数据

将所生成的数据导入数据库中

对于点位管理数据的  关系字段:region_id、partner_id; 数据字典:business_type

2.3 点位管理相关代码生成

2.3.1 理论部分

2.3.2 实操部分

(1)添加点位管理菜单栏

 (2)添加商圈类型的字典类型

分别添加字典类型的字键和对应字键值;结果显示:

 (3)代码生成(分别生成3张表的信息)
  • 配置区域表:

基本信息修改:将在前缀tb删除:

字段信息根据需求进行修改:

生成信息:根据项目中的模块名,修改其生成模块名和生成包路径,最后设置上传菜单

  • 配置合作商表:

基本信息:

字段信息:

生成信息:根据项目中的模块名,修改其生成模块名和生成包路径,最后设置上传菜单

  • 配置点位表:

基本信息:

字段信息:(记得商圈类型选择商圈类型的字典类型)

生成信息:

(4)生成代码并导入文件中,注意后端的代码是导入manage模块中

2.4 区域管理的改造(自主添加)

需求分析:

在该页面无法查看到每个区域的点位数

需要对区域管理的列表显示进行改造,使其能够显示各列表的点位数

2.4.1 添加RegionVo类(在Region的基础上显示点位数量nodeCount)

@Data
public class RegionVo extends Region {

    //区域点位数量
    private Integer nodeCount;


}

 2.4.2 开启驼峰命名转换字段

记得在domain resources的mybatis-config.xml中打开驼峰命名转换字段,这样Mapper.xml中所写的字段会通过驼峰命名的方式装换类中的字段

2.4.3 修改后端代码:

修改顺序 Mapper => Service => Controller

Mapper:

     /**
     * 
     * @param region
     * @return 区域管理集合和每个区域的点位数量
     */
    public List<RegionVo> selectRegionVoList(Region region);

Mapper.xml:

    <select id="selectRegionVoList" resultType="com.dkd.manage.domain.vo.RegionVo">
        select r.*,count(n.id) as node_count from tb_region r left join tb_node n on r.id = n.region_id
        <where>
            <if test="regionName != null  and regionName != ''"> and region_name like concat('%', #{regionName}, '%')</if>
        </where>
        group by r.id
    </select>

ServiceImpl:

    @Override
    public List<RegionVo> selectRegionVoList(Region region) {
        return regionMapper.selectRegionVoList(region);
    }

因为是将区域管理的列表多显示每个区域的点位数,只需要在Controller层中修改显示区域管理的对应的方法即可:

Controller:

    /**
     * 查询区域管理列表
     */
    @PreAuthorize("@ss.hasPermi('manage:region:list')")
    @GetMapping("/list")
    public TableDataInfo list(Region region)
    {
        startPage();
        List<RegionVo> voList = regionService.selectRegionVoList(region);
        return getDataTable(voList);
    }

2.4.4 修改前端代码:

原有的代码:

修改后的代码:(在原有的代码上添加点位数) 

 2.5 合作商管理的改造

合作商生成的界面:

2.5.1 修改前端代码:

(1)加大搜索合作商名称的标签长度,使其在一条线上,并删除多余的搜索框代码

修改后的效果:

(2) 将合作商ID的label修改为序号,设置type为index和width,移动column的显示顺序

(3)在password的这个column,添加type = "password"这样明文就可以变成密文

修改前:

修改的代码:

修改后:

 

(4)在修改合作商时,设置不需要显示账号和密码

添加 v-if="form.id == null" 即可;因为修改是包含id的所以隐藏账号和密码,而新增不包含id的,所以显示添加账号和密码信息

(5)想在修改表单中显示创建的时间

显示效果:

(5)添加查看详细的操作

添加操作的查看详情的一行

编写查看合作商详情的函数

编写查询合作商详细的对话框

点击后的显示效果:

 (6)给合作商的列表添加点位数(跟刚刚进行区域管理的改造差不多)

显示效果:

(7)添加重置密码的操作,初始的密码值为:123456

因为在后端代码中添加了一个重置密码的请求,所以要修改对应api中js的代码

对应的partner.js:

// 重置合作商管理密码
export function resetPartnerPwd(id) {
  return request({
    url: '/manage/partner/resetPwd/' + id,
    method: 'put'
  })
}

view/partner/index.vue: 

重置密码仿写删除操作的函数 

(8)给操作栏设置宽度,使其在一行上

 显示效果:

2.5.2 修改后端代码:

(1)设置密码以密文的方式保存

通过观察可以发觉password为明文

 修改其添加的代码,使添加合作商的密码都显示为密文

 (2)添加重置密码对应的后端代码:
    @PreAuthorize("@ss.hasPermi('manage:partner:edit')")
    @Log(title = "合作商管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd/{id}")
    public AjaxResult reset(@PathVariable("id") Long id){
        Partner partner = new Partner();
        partner.setId(id);
        partner.setPassword(SecurityUtils.encryptPassword("123456"));
        return toAjax(partnerService.updatePartner(partner));
    }

2.6 点位管理的改造:

2.6.1点位管理的基本改造

(1)改造需求

修改前的页面:

要求改造后的界面显示: 将关联的区域ID调整为所在区域 以及 将关联的合作商ID调整为合作商


开始改造 

(2)对点位管理的中所属区域部分进行修改

改造 将通过node中的区域Id 替换 获取listRegion中的区域名

同时 将所属区域为输入框 替换为 下拉框的方式

在node/index.js 中引入获取 listRegion的列表

在script部分添加

/* 查询所有条件的对象 */
const loadAllParams = reactive({
  pageNum:1,
  pageSize:10000
})

/* 查询区域列表 */
const regionList = ref([])
function getListRegion(){
  listRegion(loadAllParams).then(response=>{
    regionList.value = response.rows
  })
}

getListRegion()

 这时,通过刷新页面可以查看getListRegion()获取的信息

这样方便核对response所返回的列表值

修改搜索框中的 通过输入区域Id获取对应信息 => 通过下拉框的方式选择对应区域信息

(注释部分的代码是修改前的代码)

      <el-form-item label="关联的区域" prop="regionId">
       <!--  <el-input
          v-model="queryParams.regionId"
          placeholder="请输入关联的区域ID"
          clearable
          @keyup.enter="handleQuery"
        /> -->

        <el-select v-model="queryParams.regionId" placeholder="请选择区域" clearable style="width: 100%">
          <el-option
            v-for="item in regionList"
            :key="item.id"
            :label="item.regionName"
            :value="item.id"
          />
        </el-select>
      </el-form-item>

修改新增中的区域的输入框为下拉框 

(注释部分的代码是修改前的代码)

        <el-form-item label="所属区域" prop="regionId">
          <!-- <el-input v-model="form.regionId" placeholder="请输入关联的区域ID" /> -->
          
          <el-select v-model="form.regionId" placeholder="请选择关联的区域">
            <el-option
            v-for="item in regionList"
            :key="item.id"
            :label="item.regionName"
            :value="item.id"
          />
          </el-select>
        </el-form-item>
(3)对点位管理的中合作商部分进行修改

基本上与对点位管理的中所属区域部分进行修改差不多;

对于复用率高的代码,我们可以进行封装,我们将在api下创建page.js

/* 查询所有条件的对象 */
export const loadAllParams = reactive({
  pageNum: 1,
  pageSize: 10000,
});

如果使用的直接进行导入即可:

import {loadAllParams} from '@/api/page'

最终改造后的效果:

(4) 使用...替换详细地址中内容过长的部分,当鼠标移动到上方会显示完整的详细地址

只需要在详细地址这行上加上 show-over-tooltip属性即可

2.6.2 点位管理中的设备相关改造

我们希望能够看到每个点位的设备数,在查看详情中显示当前点位下的所有设备列表

还没有创建设备的数据库表,要根据分析先创建设备的数据库表

关联查询:对于设备数量的统计,需要执行关联查询,在mapper层封装

关联实体:对于区域和合作商的数据,采用Mybatis提供的嵌套查询功能

(1)创建Vo实体类
@Data
public class NodeVo extends Node {

    private Integer vmCount;

    private Region region;

    private Partner partner;
}
(2)mapper:
   public List<NodeVo> selectNodeVoList(Node node);
(3)Mapper.xml:
    <resultMap id="NodeVoResult" type="NodeVo">
        <result property="id"    column="id"    />
        <result property="nodeName"    column="node_name"    />
        <result property="address"    column="address"    />
        <result property="businessAreaType"    column="business_area_type"    />
        <result property="regionId"    column="region_id"    />
        <result property="partnerId"    column="partner_id"    />
        <result property="createTime"    column="create_time"    />
        <result property="updateTime"    column="update_time"    />
        <result property="createBy"    column="create_by"    />
        <result property="updateBy"    column="update_by"    />
        <result property="remark"    column="remark"    />
        <result property="vmCount" column="vm_count" />
        <association property="region" column="region_id" javaType="Region" select="com.dkd.manage.mapper.RegionMapper.selectRegionById"/>
        <association property="partner" column="partner_id" javaType="Partner" select="com.dkd.manage.mapper.PartnerMapper.selectPartnerById"/>
    </resultMap>  

    <select id="selectNodeVoList" resultMap="NodeVoResult">
        SELECT
            n.*,
            COUNT(vm.id) AS vm_count
        FROM
            tb_node n
                LEFT JOIN
            tb_vending_machine vm ON n.id = vm.node_id
        <where>
            <if test="nodeName != null  and nodeName != ''"> and n.node_name like concat('%', #{nodeName}, '%')</if>
            <if test="regionId != null "> and n.region_id = #{regionId}</if>
            <if test="partnerId != null "> and n.partner_id = #{partnerId}</if>
        </where>
        GROUP BY
            n.id;
    </select>
(4)ServiceImpl:
    @Override
    public List<NodeVo> selectNodeVoList(Node node) {
        return nodeMapper.selectNodeVoList(node);
    }
 (5)Controller:
    /**
     * 查询点位管理列表
     */
    @PreAuthorize("@ss.hasPermi('manage:node:list')")
    @GetMapping("/list")
    public TableDataInfo list(Node node)
    {
        startPage();
        List<NodeVo> voList = nodeService.selectNodeVoList(node);
        return getDataTable(voList);
    }

修改前端的代码部分:

最终展示效果:

 2.7 区域管理 通过 查看详细信息 查看 区域信息 和 点位列表

引入listNode,目的是获取相关的点位列表

import {listNode} from '@/api/manage/node'

 编写相关函数 

const nodeList = ref([]);
const regionInfoOpen = ref(false);
/* 查看详情操作按钮*/
function getRegionInfo(row){
  //查看区域信息
  reset();
  const _id = row.id
  getRegion(_id).then(response => {
    form.value = response.data;
  });
  //查看点位列表
  loadAllParams.id = row.id
  listNode(loadAllParams).then(response => {
    nodeList.value = response.rows;
    
  })
  regionInfoOpen.value = true
}

添加修改后的对话框

效果显示:

 

2.8 数据的完整性

 在区域表中进行删除,会导致将区域表下的点位数一并删除(ON DELETE CASCADE)

所以为了保证数据的完整性,我们在删除区域之前如果该区域还有点位数则无法删除。

级联操作

  • 当主表中的行被删除或更新时,可以设置外键约束来自动执行级联操作。
  • ON DELETE CASCADE:当主表的行被删除时,所有依赖于该主键的外键行也将被删除。
  • ON UPDATE CASCADE:当主表的主键值被更新时,所有依赖于该主键的外键值也会相应更新。
  • NO ACTION 或 RESTRICT:如果删除或更新主键值会导致外键违反约束,则操作将被阻止。

将ON DELETE CASCADE 和 ON UPDATE CASCADE 都改为 ON ACTION

在GlobalException中添加处理异常信息的返回 

三、人员管理

需要员工区将设备投放到各个区域

3.1 数据库设计

3.2 使用代码生成器生成代码

(1)创建人员管理的菜单 

(2)添加员工状态的字典(1:启动,0:禁用) 

 导入员工表和角色表

编辑tb_emp中的生成信息 

 

 编辑tb_role 中的生成信息 

最后是生成代码并导入项目中

3.3 人员列表改造

对所显示的主键修改label为序号,同时添加type = "index",width = "50"

将下图的区域id和角色id的输入框都修改为下拉框

角色的下拉框的数据通过获取角色列表来确定,区域框也是如此(获取列表需要考虑分页的情况,所以需要获取 loadAllParams)

import {listRole} from "@/api/manage/role";
import {listRegion} from "@/api/manage/region";
import {loadAllParams}  from "@/api/page"

 将获取到的区域列表存储到regionList,角色列表存储到roleList

const roleList = ref([]);
function getRoleList(){
  listRole(loadAllParams).then(response=>{
    roleList.value = response.rows;
  })
}

const regionList = ref([]);
function getRegionList(){
  listRegion(loadAllParams).then(response=>{
    regionList.value = response.rows;
  })
}

getRegionList()
getRoleList()

将输入框修改为下拉框的代码所示

注意:item的属性命名,要根据F12中所获取的属性字段名相一致

 <el-form-item label="所属区域" prop="regionId">
          <!-- <el-input v-model="form.regionId" placeholder="请输入所属区域Id" /> -->
          <el-select v-model="form.regionId" placeholder="请选择区域" >
            <el-option
              v-for="item in regionList"
              :key="item.id"
              :label="item.regionName"
              :value="item.id"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="角色" prop="roleId">
          <!-- <el-input v-model="form.roleId" placeholder="请输入角色id" /> -->
          <el-select v-model="form.roleId" placeholder="请选择角色">
            <el-option
              v-for="item in roleList"
              :key="item.roleId"
              :label="item.roleName"
              :value="item.roleId"
            ></el-option>
          </el-select>
        </el-form-item>

修改后端代码的添加和修改员工的代码

 

添加启动或禁用

 <el-form-item label="是否启用" prop="status">
          <el-radio-group v-model="form.status">
            <el-radio :label="0">禁用</el-radio>
            <el-radio :label="1">启用</el-radio>
          </el-radio-group>
        </el-form-item>

 

改造后的效果:

 

3.4 列表改造实现同步存储

当修改区域名称时,在人员信息所对应的区域名称没有同步发生改变

在emp的mapper中添加updateByRegionId方法

    @Update("update tb_emp set region_name = #{regionName} where region_id = #{regionId}")
    public int updateByRegionId(@Param("regionName") String regionName, @Param("regionId") Long regionId);

这样只需要在修改region的名称时进行调用empMapper.updateByRegionId方法实现数据一致

加上@Transcational保证原子性

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertRegion(Region region)
    {
        region.setCreateTime(DateUtils.getNowDate());
        int result = regionMapper.insertRegion(region);
        empMapper.updateByRegionId(region.getRegionName(), region.getId());
        return result;
    }

四、阿里云OSS存储文件

(1)设置 AK 和 SK

  • AK(Access Key):访问密钥是公开的标识符,它唯一地标识了用户账户。它可以被认为是一个用户名,用于在请求时识别调用者。

  • SK(Secret Key):密钥是私密的,不应该公开分享或泄露。它类似于密码,用于验证发送请求的用户是否是访问密钥的合法持有者。在发送API请求时,SK通常用于生成签名,以确保请求的完整性和真实性。

以管理员的身份打开CMD命令行

配置系统变量:

set OSS_ACCESS_KEY_ID = 您的AK

set OSS_ACCESS_KEY_SECRET = 您的SK

(2)执行下面命令使其更改生效

setx OSS_ACCESS_KEY_ID = "%OSS_ACCESS_KEY_ID%"

set OSS_ACCESS_KEY_SECRET = "%OSS_ACCESS_KEY_SECRET%"

(3)执行下面命令,验证变量是否生效

echo "%OSS_ACCESS_KEY_ID%"

echo "%OSS_ACCESS_KEY_SECRET%"

(4)引入阿里云OSS的依赖并参考示例使用

五、X-File-Storage

优势:

        X-File-Storage的设计目标之一就是为了简化不同存储平台之间的迁移和集成工作。通过使用X-File-Storage,您可以在其统一的抽象层上操作文件,而不必直接与每个特定存储平台的API打交道。

        这意味着,一旦您熟悉了X-File-Storage的API和使用方式,当您需要切换或添加新的存储平台时,您只需进行一些配置上的更改,而不需要重写大量代码来适应新的存储平台。X-File-Storage已经为您处理了与各种存储平台交互的复杂性。

使用步骤:

  • X-File-Storage只需要导入自身的依赖和所使用云存储平台的依赖;
  • 填写根据X-File-Storage所提供的appllication.yml中的信息;
  • 最后通过X-File-Storage提供的代码方式实现文件上传;
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值