Day109.尚医通:集成Nacos、翻译字段、医院列表分页条件、下拉列表查询、医院状态、医院详情

目录

一、搭建Nacos服务

二、医院需求分析

三、医院列表功能(接口)

1、医院列表接口初步实现

2、cmn模块 实现翻译字段接口服务

3、实现跨模块远程调用

4、在 hosp 实现跨模块调用

四、实现根据字典编码查询子数据 (下拉列选)

1、后端接口实现

2、医院列表查询 (前端)

五、更新医院上线状态

1、后端接口实现

2、前端页面实现

六、医院详情查询

1、医院详情接口

2、前端页面实现


一、搭建Nacos服务

项目需求 需要翻译字段,模块间的调用

1. 启动Nacos

startup.cmd -m standalone

nacos1.4.0 之后的启动方式默认时cluster集群模式,如果没有进行集群配置,直接启动会报错。
可以用命令行startup.cmd -m standalone就能以单体方式启动服务。
如果觉得每次启动都是单体模式,就可以在startup.cmd中的配置信息set MODE="cluster"修改为set MODE=“standalone”,
于是每次启动就默认单体模式。

2. 确认项目依赖

        <!-- 服务调用feign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--服务注册-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

3. 添加配置

# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

4. 启动类添加注解

@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"}) //扫描到其他项目的类
@EnableDiscoveryClient  //注册中心
public class ServiceHospApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceHospApplication.class, args);
    }

}

5. 测试

二、医院需求分析

  • 一、下拉列表
    • 实现二级联动下拉选择框
    • 实现分页条件医院列表查询 (跨模块到 cmn 翻译字段)
    • 更新上线状态

  • 二、医院详情
    • 根据医院编码查询医院基本信息、预约信息
    • 跨模块到cmn翻译字段

三、医院列表功能(接口)

1、医院列表接口初步实现

1. 分析接口

参数:page、limit、HospitalQueryVo

返回值:R(page)  (MongoDB用springData,mysql用苞米豆)

2. 实现 controller

@Api(description = "医院接口")
@RestController
@RequestMapping("/admin/hosp/hospital")
@CrossOrigin
public class HospitalController {

    @Autowired
    private HospitalService hospitalService;

    @ApiOperation(value = "获取分页列表")
    @GetMapping("{page}/{limit}")
    public R index(@PathVariable Integer page,
                   @PathVariable Integer limit,
                   HospitalQueryVo hospitalQueryVo) {

        Page<Hospital> pageModel = hospitalService.selectPage(page,limit,hospitalQueryVo);
        return R.ok().data("pageModel",pageModel);
    }
}

3. 实现 Service (暂时略过翻译字段)

    //带条件带分页获取医院列表
    @Override
    public Page<Hospital> selectPage(Integer page, Integer limit, HospitalQueryVo hospitalQueryVo) {
        //(1).创建分页对象
        //1.1创建排序对象
        Sort sort = Sort.by(Sort.Direction.DESC,"createTime");
        //1.2创建分页对象
        Pageable pageable = PageRequest.of(page-1,limit,sort);
        //(2).创建查询条件模板
        //2.1封装查询条件
        Hospital hospital = new Hospital();
        BeanUtils.copyProperties(hospitalQueryVo,hospital);
        //2.2创建模板构造器
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //模糊查询
                .withIgnoreCase(true); //不区分大小写
        //2.3创建模板
        Example<Hospital> example = Example.of(hospital,matcher);

        //(3).实现条件分页查询
        Page<Hospital> pageModel = hospitalRepository.findAll(example, pageable);

        //4. TODO 跨模块cmn 翻译字段(重要)

        return pageModel;
    }

2、cmn模块 实现翻译字段接口服务

1. 需求分析,需要有两个接口

* 国标数据接口
参数:value
返回值:name

* 自定义数据接口
参数:value、dictCode
返回值:name

2. 实现 controller

    @ApiOperation(value = "获取数据字典名称(自定义)")
    @GetMapping(value = "/getName/{parentDictCode}/{value}")
    public String getName(
            @PathVariable("parentDictCode") String parentDictCode,
            @PathVariable("value") String value) {
        String name = dictService.getName(parentDictCode,value);
        return name;
    }

    @ApiOperation(value = "获取数据字典名称(国标)")
    @GetMapping(value = "/getName/{value}")
    public String getName(
            @PathVariable("value") String value) {
        String name = dictService.getName("",value);
        return name;
    }

3. 实现 service

    //获取数据字典名称
    @Override
    public String getName(String parentDictCode, String value) {
        //1.判断parentDictCode是否为空 (国标还是自定义数据)
        if(StringUtils.isEmpty(parentDictCode)){
            //国标数据查询
            Dict dict = baseMapper.selectOne(new QueryWrapper<Dict>()
                    .eq("value", value));
            if(dict!=null){
                return dict.getName();
            }
        }else {
            //自定义数据查询
            Dict parentDict = this.getDictByDictCode(parentDictCode);

            Dict dict = baseMapper.selectOne(new QueryWrapper<Dict>()
                    .eq("parent_id",parentDict.getId())
                    .eq("value", value));
            if(dict!=null){
                return dict.getName();
            }
        }
        return "";
    }
    //根据字典编码查询父级别数据
    private Dict getDictByDictCode(String parentDictCode) {
        QueryWrapper<Dict> wrapper = new QueryWrapper<>();
        wrapper.eq("dict_code",parentDictCode);
        Dict dict = baseMapper.selectOne(wrapper);
        return dict;
    }

3、实现跨模块远程调用

1. 搭建service-client 父模块 (提取服务接口),修改pom.xml

    <artifactId>service-client</artifactId>
    <packaging>pom</packaging>

    <dependencies>
        <dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>model</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>common_utils</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>provided </scope>
        </dependency>
        <!-- 服务调用feign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <scope>provided </scope>
        </dependency>
    </dependencies>

2. 搭建service_cmn_client模块

3. 创建相关服务接口

注意:1.请求路径完整路径    2.远程调用 @PathVariable不能省略

@FeignClient("service-cmn")  //指定调用的服务名
public interface DictFeignClient {
    //注意完整请求路径
    //获取数据字典名称(自定义)
    @GetMapping(value = "/admin/cmn/dict/getName/{parentDictCode}/{value}")
    public String getName(
            @PathVariable("parentDictCode") String parentDictCode,
            @PathVariable("value") String value);

    //获取数据字典名称(国标)
    @GetMapping(value = "/admin/cmn/dict/getName/{value}")
    public String getName(
            @PathVariable("value") String value);

}

4、在 hosp 实现跨模块调用

1. service模块 确认依赖

        <!-- 服务调用feign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2. hosp模块 导入依赖

        <!--服务接口-->
        <dependency>
            <groupId>com.atguigu</groupId>
            <artifactId>service_cmn_client</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

3. 启动类添加注解   @EnableFeignClients(basePackages="")

@SpringBootApplication
@ComponentScan(basePackages = {"com.atguigu"}) //扫描到其他项目的类
@EnableDiscoveryClient  //声明注册中心客户端
@EnableFeignClients(basePackages = "com.atguigu")  //开启Feign,扫描其他项目的接口服务
public class ServiceHospApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceHospApplication.class, args);
    }

}

4. 改造查询接口

    //远程方法调用
    @Autowired
    private DictFeignClient dictFeignClient;


    //带条件带分页获取医院列表
    @Override
    public Page<Hospital> selectPage(Integer page, Integer limit, HospitalQueryVo hospitalQueryVo) {
        //(1).创建分页对象
        //1.1创建排序对象
        Sort sort = Sort.by(Sort.Direction.DESC,"createTime");
        //1.2创建分页对象
        Pageable pageable = PageRequest.of(page-1,limit,sort);
        //(2).创建查询条件模板
        //2.1封装查询条件
        Hospital hospital = new Hospital();
        BeanUtils.copyProperties(hospitalQueryVo,hospital);
        //2.2创建模板构造器
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //模糊查询
                .withIgnoreCase(true); //不区分大小写
        //2.3创建模板
        Example<Hospital> example = Example.of(hospital,matcher);

        //(3).实现条件分页查询
        Page<Hospital> pageModel = hospitalRepository.findAll(example, pageable);

        //4.TOD 跨模块cmn 翻译字段(重要)
        pageModel.getContent().stream().forEach(item ->{
            this.packHospital(item);
        });

        return pageModel;
    }
    //医院信息字段翻译
    private Hospital packHospital(Hospital hospital) {
        //DictEnum.HOSTYPE 枚举类
        String hostypeString = dictFeignClient.getName(
                DictEnum.HOSTYPE.getDictCode(), hospital.getHostype());

        String provinceString = dictFeignClient.getName(hospital.getProvinceCode());
        String cityString = dictFeignClient.getName(hospital.getCityCode());
        String districtString = dictFeignClient.getName(hospital.getDistrictCode());

        hospital.getParam().put("hostypeString", hostypeString);
        hospital.getParam().put("fullAddress", provinceString + cityString + districtString + hospital.getAddress());
        return hospital;
    }

测试: 

四、实现根据字典编码查询子数据 (下拉列选)

1、后端接口实现

1. controller

    //根据数据id查询子数据列表
    @ApiOperation(value = "根据dictCode获取下级节点")
    @GetMapping("/findByDictCode/{dictCode}")
    public R findByDictCode(@PathVariable String dictCode){
        List<Dict> list = dictService.findByDictCode(dictCode);
        return R.ok().data("list",list);
    }

2. service 

    //根据数据id查询子数据列表
    @Override
    public List<Dict> findByDictCode(String dictCode) {
        Dict dictByDictCode = this.getDictByDictCode(dictCode);
        List<Dict> dictList = this.findChildData(dictByDictCode.getId());
        return dictList;
    }

2、医院列表查询 (前端)

1. 添加路由,创建页面

      {
        path: 'hospital/list',
      name: '医院列表',
      component: () =>import('@/views/yygh/hosp/list'),
      meta: { title: '医院列表', icon: 'table' }
      } 

2. 创建API方法

新建hosp.js

import request from '@/utils/request'
//提取请求路径
const api_name = '/admin/hosp/hospital'

export default{

    //带条件带分页获取医院列表
    getPageList(page,limit,searchObj){
        return request({
            url: `${api_name}/${page}/${limit}`,//插值表达式
            method: 'get',
            params: searchObj //普通用params json用data
            })
    }
   
}

dict.js 下新增方法

import request from '@/utils/request'
//提取请求路径
const api_name = '/admin/cmn/dict'

export default {

    //根据数据id查询子数据列表
    findChildData(id) {
        return request({
            url: `${api_name}/findChildData/${id}`,//插值表达式
            method: 'get'
        })
    },
    //查询dictCode查询下级数据字典
    findByDictCode(dictCode) {
        return request({
            url: `${api_name}/findByDictCode/${dictCode}`,
            method: 'get'
        })
    },

}

3. 添加页面元素

<template>
    <div class="app-container">
        <el-form :inline="true" class="demo-form-inline">

            <el-form-item>
                <el-select v-model="searchObj.provinceCode" placeholder="请选择省" @change="provinceChanged">
                    <el-option v-for="item in provinceList" :key="item.id" :label="item.name" :value="item.id" />
                </el-select>
            </el-form-item>

            <el-form-item>
                <el-select v-model="searchObj.cityCode" placeholder="请选择市">
                    <el-option v-for="item in cityList" :key="item.id" :label="item.name" :value="item.id" />
                </el-select>
            </el-form-item>

            <el-form-item>
                <el-input v-model="searchObj.hosname" placeholder="医院名称" />
            </el-form-item>

            <el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
            <el-button type="default" @click="resetData()">清空</el-button>
        </el-form>

        <!-- banner列表 -->
        <el-table v-loading="listLoading" :data="list" border fit highlight-current-row>

            <el-table-column label="序号" width="60" align="center">
                <template slot-scope="scope">
                    {{ (page - 1) * limit + scope.$index + 1 }}
                </template>
            </el-table-column>

            <el-table-column label="医院logo">
                <template slot-scope="scope">
                    <img :src="'data:image/jpeg;base64,'+scope.row.logoData" width="80">
                </template>
            </el-table-column>

            <el-table-column prop="hosname" label="医院名称" />
            <el-table-column prop="param.hostypeString" label="等级" width="90" />
            <el-table-column prop="param.fullAddress" label="详情地址" />
            <el-table-column label="状态" width="80">
                <template slot-scope="scope">
                    {{ scope.row.status === 0 ? '未上线' : '已上线' }}
                </template>
            </el-table-column>
            <el-table-column prop="createTime" label="创建时间" />

            <el-table-column label="操作" width="230" align="center">
                <template slot-scope="scope">
                    <router-link :to="'/hospSet/hospital/show/'+scope.row.id">
                        <el-button type="primary" size="mini">查看</el-button>
                    </router-link>
                    <router-link :to="'/hospSet/hospital/schedule/'+scope.row.hoscode">
                        <el-button type="primary" size="mini">排班</el-button>
                    </router-link>

                    <el-button v-if="scope.row.status == 1" type="primary" size="mini"
                        @click="updateStatus(scope.row.id, 0)">下线</el-button>
                    <el-button v-if="scope.row.status == 0" type="danger" size="mini"
                        @click="updateStatus(scope.row.id, 1)">上线</el-button>
                </template>

            </el-table-column>
        </el-table>

        <!-- 分页组件 -->
        <el-pagination :current-page="page" :total="total" :page-size="limit" :page-sizes="[5, 10, 20, 30, 40, 50, 100]"
            style="padding: 30px 0; text-align: center;" layout="sizes, prev, pager, next, jumper, ->, total, slot"
            @current-change="fetchData" @size-change="changeSize" />
    </div>
</template>

4. 实现JS

饿了么ui的bug:下拉列选的值要进行初始化

<script>
    import hospApi from '@/api/yygh/hosp'
    import dictApi from '@/api/yygh/dict'
    export default {
        data() {
            return {
                listLoading: true, // 数据是否正在加载
                list: null, // 医院列表数据集合
                total: 0, // 数据库中的总记录数
                page: 1, // 默认页码
                limit: 10, // 每页记录数
                searchObj: {
                    provinceCode: '',
                    cityCode: ''
                }, // 查询表单对象 饿了么ui的bug:下拉列选的值要做初始化
                provinceList: [], //所有省集合
                cityList: []   //所有市集合
            }
        },
        created() {
            //初始化表格数据
            this.fetchData();
            //初始化省信息
            this.getProvinceList();

        },              
        methods: {
            //表格数据查询
            fetchData(page=1){
                this.page = page
                hospApi.getPageList(this.page,this.limit,this.searchObj)
                .then(resopnse=>{
                    this.list = resopnse.data.pageModel.content
                    this.total = resopnse.data.pageModel.totalElements
                    this.listLoading = false
                })
            },
            //查询省信息 下拉列选  传递字典code 
            getProvinceList(){
                dictApi.findByDictCode("Province")
                .then(response=>{
                    this.provinceList = response.data.list
                })
            },
            //二级联动省市信息 下拉列选
            provinceChanged(){
                //清除历史信息
                this.searchObj.cityCode = ""
                this.cityList = []
                dictApi.findChildData(this.searchObj.provinceCode)
                .then(response=>{
                    this.cityList = response.data.list
                })
            },
            //清空
            resetData(){
                this.searchObj = {
                    provinceCode: '',
                    cityCode: ''
                };
                this.fetchData();

            },
            //切换每页记录数
            changeSize(size){
                this.limit = size;
                this.fetchData();
            }
        }
    }
</script>

5. 测试 

五、更新医院上线状态

1、后端接口实现

1. 分析接口

参数:id、status

返回值:R.ok()

2. 实现 controller

    @ApiOperation(value = "更新上线状态")
    @GetMapping("updateStatus/{id}/{status}")
    public R updateStatus(
            @PathVariable("id") String id,
            @PathVariable("status") Integer status){
        hospitalService.updateStatus(id,status);
        return R.ok();
    }

3. 实现 service

    //更新上线状态
    @Override
    public void updateStatus(String id, Integer status) {
        if(status.intValue() == 0 || status.intValue() == 1) {
            //先查询,后更新
            Hospital hospital = hospitalRepository.findById(id).get();
            hospital.setStatus(status);
            hospital.setUpdateTime(new Date());
            hospitalRepository.save(hospital);
        }
    }

2、前端页面实现

1. 确认入口

2. 新建API方法

    //医院状态修改 (上线下限)
    updateStatus(id, status) {
        return request({
            url: `${api_name}/updateStatus/${id}/${status}`,
            method: 'get'
        })
    },

3. JS 实现

            updateStatus(id, status){
                hospApi.updateStatus(id,status)
                .then(response=>{
                    this.fetchData();
                    this.$message({
                        type: "success",
                        message: "操作成功!",
                    });
                })
                
            }

六、医院详情查询

1、医院详情接口

1. 分析接口

参数:id

返回值:R.(map(医院基本信息、预约规则))

2. 实现 controller

    @ApiOperation(value = "获取医院详情")
    @GetMapping("show/{id}")
    public R show(
            @PathVariable String id) {
        Map<String,Object> map = hospitalService.getHospitalById(id);
        return R.ok().data(map);
    }

3. 实现service

    //获取医院详情
    @Override
    public Map<String, Object> getHospitalById(String id) {
        //1.根据id查询医院信息,
        Hospital hospital = hospitalRepository.findById(id).get();

        //2.信息字段翻译
        hospital = this.packHospital(hospital);

        //3.判断后取出预约规则,封装返回
        BookingRule bookingRule = hospital.getBookingRule();
        hospital.setBookingRule(null); //节省内存空间

        Map<String,Object> map = new HashMap<>();
        map.put("hospital",hospital);
        map.put("bookingRule",bookingRule);
        return map;
    }

4. 测试

2、前端页面实现

1. 确认入口

需要创建隐藏路由 (注意修改地址!)

 

2. 添加隐藏路由,创建页面

      {
        path: 'hospital/show/:id',
        name: '查看医院详情',
        component: () => import('@/views/yygh/hosp/show'),
        meta: { title: '查看', noCache: true },
        hidden: true
      }

3. 创建API接口方法

    //查看医院详情
    getHospById(id) {
        return request({
            url: `${api_name}/show/${id}`,
            method: 'get'
        })
    }

4. 添加页面元素

<template>
    <div class="app-container">
        <h4>基本信息</h4>
        <table class="table table-striped table-condenseda table-bordered" width="100%">
            <tbody>
                <tr>
                    <th width="15%">医院名称</th>
                    <td width="35%"><b style="font-size: 14px">{{ hospital.hosname }}</b>
                        | {{ hospital.param.hostypeString }}</td>
                    <th width="15%">医院logo</th>
                    <td width="35%">
                        <img :src="'data:image/jpeg;base64,'+hospital.logoData" width="80">
                    </td>
                </tr>
                <tr>
                    <th>医院编码</th>
                    <td>{{ hospital.hoscode }}</td>
                    <th>地址</th>
                    <td>{{ hospital.param.fullAddress }}</td>
                </tr>
                <tr>
                    <th>坐车路线</th>
                    <td colspan="3">{{ hospital.route }}</td>
                </tr>
                <tr>
                    <th>医院简介</th>
                    <td colspan="3">{{ hospital.intro }}</td>
                </tr>
            </tbody>
        </table>

        <h4>预约规则信息</h4>
        <table class="table table-striped table-condenseda table-bordered" width="100%">
            <tbody>
                <tr>
                    <th width="15%">预约周期</th>
                    <td width="35%">{{ bookingRule.cycle }}天</td>
                    <th width="15%">放号时间</th>
                    <td width="35%">{{ bookingRule.releaseTime }}</td>
                </tr>
                <tr>
                    <th>停挂时间</th>
                    <td>{{ bookingRule.stopTime }}</td>
                    <th>退号时间</th>
                    <td>{{ bookingRule.quitDay == -1 ? '就诊前一工作日' : '就诊当日' }}{{ bookingRule.quitTime }} 前取消</td>
                </tr>
                <tr>
                    <th>预约规则</th>
                    <td colspan="3">
                        <ol>
                            <li v-for="item in bookingRule.rule" :key="item">{{ item }}</li>
                        </ol>
                    </td>
                </tr>
                <br>
                <el-row>
                    <el-button @click="back">返回</el-button>
                </el-row>
            </tbody>
        </table>
    </div>
</template>

5. JS实现

<script>
    import hospApi from '@/api/yygh/hosp'
    import dictApi from '@/api/yygh/dict'
    export default {
        data() {
            return {
                hospital: {},
                bookingRule: {}
            }
        },
        created() {
            //获取元素用route,页面跳转用router
            let id = this.$route.params.id
            this.getData(id)
        },
        methods: {
            getData(id) {
                hospApi.getHospById(id).then(response => {
                    this.hospital = response.data.hospital
                    this.bookingRule = response.data.bookingRule
                })
            },
            //页面跳转
            back(){
                this.$router.push({path:"/yygh/hospset/hospital/list"})
            }
        }
    }
</script>

6. 添加样式

 

7. 测试 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值