目录
- 一、医院管理模块需求分析
- 1、医院列表
- 2、医院详情
- 二、医院列表功能(接口)
- 1、添加service分页接口与实现
- 2、添加controller方法
- 3、service_cmn模块提供接口
- 3.1 添加service接口与实现
- 3.2 添加controller
- 4、封装Feign服务调用
- 4.1 搭建service_client父模块
- 4.2 在service_client模块引入依赖
- 4.3 搭建service_cmn_client模块
- 4.4 添加Feign接口类
- 5、医院接口远程调用数据字典
- 5.1 在service-hosp添加依赖
- 5.2 service_hosp模块启动类添加注解
- 5.3 调整service方法
- 6、添加数据字典显示接口
- 6.1 根据dictcode查询下层节点
- 三、医院列表功能(前端)
- 四、更新医院上线状态功能(接口)
- 1、添加service方法和实现
- 2、添加controller
- 五、更新医院上线状态功能(前端)
- 1、封装api请求
- 2、修改/views/hosp/list.vue组件
- 六、医院详情(接口)
- 1、添加service方法和实现
- 2、添加controller方法
- 七、医院详情(前端)
- 1、添加隐藏路由
- 2、创建医院详情页面
一、医院管理模块需求分析
目前我们把医院、科室和排班都上传到了平台,那么管理平台就应该把他们管理起来,在我们的管理平台能够直观的查看这些信息
1、医院列表
2、医院详情
二、医院列表功能(接口)
1、添加service分页接口与实现
(1)在HospitalService定义医院列表方法
Page<Hospital> getHospitalPage(Integer pageNum, Integer pageSize, HospitalQueryVo hospitalQueryVo);
(2)在HospitalServiceImpl添加医院列表实现的方法
@Override
public Page<Hospital> getHospitalPage(Integer pageNum, Integer pageSize, HospitalQueryVo hospitalQueryVo) {
Hospital hospital = new Hospital();
// if (!StringUtils.isEmpty(hospitalQueryVo.getHosname())){
// hospital.setHosname(hospitalQueryVo.getHosname());
// }
// if (!StringUtils.isEmpty(hospitalQueryVo.getHoscode())){
// hospital.setHoscode(hospitalQueryVo.getHoscode());
// }
// if (!StringUtils.isEmpty(hospitalQueryVo.getCityCode())){
// hospital.setCityCode(hospitalQueryVo.getCityCode());
// }
BeanUtils.copyProperties(hospitalQueryVo, hospital);
//0为第一页
Pageable pageable = PageRequest.of(pageNum-1, pageSize);
//创建匹配器,即如何使用查询条件
ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
// .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式:模糊查询
.withMatcher("hosname",ExampleMatcher.GenericPropertyMatchers.contains())
.withIgnoreCase(true); //改变默认大小写忽略方式:忽略大小写
Example<Hospital> hospitalExample = Example.of(hospital, matcher);
Page<Hospital> pages = hospitalRepository.findAll(hospitalExample, pageable);
return pages;
}
2、添加controller方法
在HospitalController添加医院列表方法
@RestController
@RequestMapping("/admin/hospital")
public class HospitalController {
@Autowired
private HospitalService hospitalService;
@GetMapping("/{pageNum}/{pageSize}")
public R getHospitalPage(@PathVariable Integer pageNum, @PathVariable Integer pageSize, HospitalQueryVo hospitalQueryVo){
Page<Hospital> hospitalPage = hospitalService.getHospitalPage(pageNum,pageSize,hospitalQueryVo);
return R.ok().data("total",hospitalPage.getTotalPages()).data("list",hospitalPage.getTotalElements());
}
}
3、service_cmn模块提供接口
3.1 添加service接口与实现
在DictService添加查询数据字典方法
String getNameByValue(Long value);
String getNameByDictCodeAndValue(String dictCode, Long value);
在DictServiceImpl实现查询数据字典方法
@Override
public String getNameByValue(Long value) {
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("value",value);
Dict dict = baseMapper.selectOne(wrapper);
if (dict != null){
return dict.getName();
}
return null;
}
@Override
public String getNameByDictCodeAndValue(String dictCode, Long value) {
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("dict_code",dictCode);
Dict dict = baseMapper.selectOne(wrapper);
QueryWrapper<Dict> wrapper1 = new QueryWrapper<>();
wrapper1.eq("parent_id",dict.getId());
wrapper1.eq("value",value);
Dict dict2 = baseMapper.selectOne(wrapper1);
return dict2.getName();
}
3.2 添加controller
在DictController添加方法
提供两个api接口,如省市区不需要上级编码,医院等级需要上级编码
//根据医院所属的省市区编号获取省市区文字
//远程调用@PathVariable指定value属性值
@GetMapping("/{value}")
public String getNameByValue(@PathVariable("value") Long value){
return dictService.getNameByValue(value);
}
//根据医院的等级编号获取医院等级信息
@GetMapping("/{dictCode}/{value}")
public String getNameByDictCodeAndValue(@PathVariable("dictCode") String dictCode,
@PathVariable("value") Long value){
return dictService.getNameByDictCodeAndValue(dictCode,value);
}
4、封装Feign服务调用
openfeign4步骤
1.导入openfeign依赖
2.自定义一个feign客户端接口,@FeignClient(value="调用方在注册中心上的应用名称“),方法和被调用方的controller层方法完全一致
3.在启动类上加@EnableFeignClient(basePackages=“com.donglin.yygh”)注解
4.在远程调用的地方直接注入自定义feign接口的代理对象,即可远程调用
思考如果多个模块调用同一个微服务?
service
service_cmn
service_hosp:4步依赖service-cmn-client
3.在启动类上加@EnableFeignClient(basePackages="com.donglin.yygh")注解
4.在远程调用的地方直接注入自定义feign接口的代理对象,即可远程调用
service-client:
service-cmn-client
1.导入openfeign依赖
2.自定义一个feign客户端接口,@FeignClient(value="调用方在注册中心上的应用名称“),方法和被调用方的controller层方法完全一致
4.1 搭建service_client父模块
4.2 在service_client模块引入依赖
<dependencies>
<dependency>
<groupId>com.donglin</groupId>
<artifactId>model</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>provided </scope>
</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>
4.3 搭建service_cmn_client模块
4.4 添加Feign接口类
@FeignClient(value = "service-cmn") //被调用方 在application.properties去查看服务名称 spring.application.name=service-cmn
public interface DictFeignClient {
//根据医院所属的省市区编号获取省市区文字
//远程调用@PathVariable指定value属性值
@GetMapping("/admin/cmn/{value}")
public String getNameByValue(@PathVariable("value") Long value);
//根据医院的等级编号获取医院等级信息
@GetMapping("/admin/cmn/{dictCode}/{value}")
public String getNameByDictCodeAndValue(@PathVariable("dictCode") String dictCode,
@PathVariable("value") Long value);
}
5、医院接口远程调用数据字典
5.1 在service-hosp添加依赖
<dependency>
<groupId>com.donglin</groupId>
<artifactId>service_cmn_client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
5.2 service_hosp模块启动类添加注解
@SpringBootApplication
@ComponentScan(basePackages = {"com.donglin"})
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.donglin.yygh")
public class ServiceHospApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHospApplication.class,args);
}
}
5.3 调整service方法
修改HospitalServiceImpl类实现分页
@Autowired
private DictFeignClient dictFeignClient;
@Override
public Page<Hospital> getHospitalPage(Integer pageNum, Integer pageSize, HospitalQueryVo hospitalQueryVo) {
Hospital hospital = new Hospital();
BeanUtils.copyProperties(hospitalQueryVo, hospital);
//0为第一页
Pageable pageable = PageRequest.of(pageNum-1, pageSize);
//创建匹配器,即如何使用查询条件
ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
// .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //改变默认字符串匹配方式:模糊查询
.withMatcher("hosname",ExampleMatcher.GenericPropertyMatchers.contains())
.withIgnoreCase(true); //改变默认大小写忽略方式:忽略大小写
Example<Hospital> hospitalExample = Example.of(hospital, matcher);
Page<Hospital> pages = hospitalRepository.findAll(hospitalExample, pageable);
pages.getContent().stream().forEach(item->{
this.packageHospital(item);
});
return pages;
}
private void packageHospital(Hospital item) {
String hostype = item.getHostype();
String provinceCode = item.getProvinceCode();
String cityCode = item.getCityCode();
String districtCode = item.getDistrictCode();
String provinceAddress = dictFeignClient.getNameByValue(Long.parseLong(provinceCode));
String cityAddress = dictFeignClient.getNameByValue(Long.parseLong(cityCode));
String districtAddress = dictFeignClient.getNameByValue(Long.parseLong(districtCode));
String level = dictFeignClient.getNameByDictCodeAndValue(DictEnum.HOSTYPE.getDictCode(), Long.parseLong(hostype));
item.getParam().put("hostypeString",level);
item.getParam().put("fullAddress",provinceAddress+cityAddress+districtAddress+ item.getAddress());
}
5.4 启动service_cmn和service_hosp服务,访问service_hosp的swagger-ui界面测试
6、添加数据字典显示接口
用于页面条件查询,多级联动
直接用之前的
6.1 根据dictcode查询下层节点
(1)添加controller
@ApiOperation(value = "根据数据id查询子数据列表")
@GetMapping("/childList/{pid}")
@Cacheable(value = "dict", key = "'selectIndexList'+#pid")
public R getchildListById(@PathVariable Long pid){
List<Dict> list = dictService.getchildListById(pid);
return R.ok().data("items",list);
}
(2)编写service
定义方法
List<Dict> getchildListById(Long pid);
实现方法
@Override
public List<Dict> getchildListById(Long pid) {
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id",pid);
List<Dict> dictList = baseMapper.selectList(wrapper);
//向list集合每个dict对象中设置hasChildren
for (Dict dict : dictList) {
Long dictId = dict.getId();
boolean isChild = this.isChildren(dictId);
dict.setHasChildren(isChild);
}
return dictList;
}
三、医院列表功能(前端)
(1)在router/index.js添加
{
path: '/yygh/hosp',
component: Layout,
redirect: '/yygh/hosp/list',
name: '医院管理',
alwaysShow: true,
meta: { title: '医院管理', icon: 'el-icon-s-help' },
children: [
{
path: 'list',
name: '医院列表',
component: () => import('@/views/yygh/hosp/list'),
meta: { title: '医院列表', icon: 'table' }
}
]
},
(2)封装api请求
在api/yygh目录下创建hosp.js文件
import request from '@/utils/request'
export default {
//医院列表
getPageList(pageNum,pageSize,searchObj) {
return request ({
url: `/admin/hospital/${pageNum}/${pageSize}`,
method: 'get',
params: searchObj
})
},
//查询dictCode查询下级数据字典
getChildList(pid) {
return request({
url: `/admin/cmn/childList/${pid}`,
method: 'get'
})
},
}
创建hosp/list.vue页面
(3)编写页面内容
在hosp/list.vue添加内容
<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>
<script>
import hospApi from '@/api/hosp.js'
export default {
data() {
return {
listLoading: true, // 数据是否正在加载
list: null, // 医院列表数据集合
total: 0, // 数据库中的总记录数
page: 1, // 默认页码
limit: 10, // 每页记录数
searchObj: {
provinceCode:'',
cityCode:''
}, // 查询表单对象
provinceList: [], //所有省集合
cityList: [] //所有市集合
}
},
created() {
//调用医院列表
this.fetchData()
//调用查询所有省的方法
hospApi.getChildList(86).then(response => {
this.provinceList = response.data.items
})
},
methods: {
//医院列表
fetchData(page=1) {
this.page = page
hospApi.getPageList(this.page,this.limit,this.searchObj)
.then(response => {
//每页数据集合
this.list = response.data.list
//总记录数
this.total = response.data.total
//加载图表不显示
this.listLoading = false
})
},
//查询所有省
findAllProvince() {
hospApi.getChildList(86).then(response => {
this.provinceList = response.data.items
})
},
//点击某个省,显示里面市(联动)
provinceChanged() {
//初始化值
this.cityList = []
this.searchObj.cityCode = ''
//调用方法,根据省id,查询下面子节点
hospApi.getChildList(this.searchObj.provinceCode)
.then(response => {
//console.log(response.data.dictList)
this.cityList = response.data.items
})
},
//分页,页码变化
changeSize() {
this.limit = size
this.fetchData(1)
},
//医院列表
fetchData(page=1) {
this.page = page
hospApi.getPageList(this.page,this.limit,this.searchObj)
.then(response => {
//每页数据集合
this.list = response.data.list
//总记录数
this.total = response.data.total
//加载图表不显示
this.listLoading = false
})
},
//查询所有省
findAllProvince() {
hospApi.getChildList(86).then(response => {
this.provinceList = response.data.items
})
},
//点击某个省,显示里面市(联动)
provinceChanged() {
//初始化值
this.cityList = []
this.searchObj.cityCode = ''
//调用方法,根据省id,查询下面子节点
hospApi.getChildList(this.searchObj.provinceCode)
.then(response => {
//console.log(response.data.dictList)
this.cityList = response.data.items
})
},
//分页,页码变化
changeSize() {
this.limit = size
this.fetchData(1)
},
resetData(){
this.searchObj={},
this.fetchData()
}
}
}
</script>
四、更新医院上线状态功能(接口)
1、添加service方法和实现
(1)在HospService定义方法
void updateStatus(String id, Integer status);
(2)在HospServiceImpl实现方法
@Override
public void updateStatus(String id, Integer status) {
if (status == 0 || status == 1){
Hospital hospital = hospitalRepository.findById(id).get();
hospital.setStatus(status);
hospital.setUpdateTime(new Date());
hospitalRepository.save(hospital);
}
}
2、添加controller
在HospController添加方法
@ApiOperation(value = "更新上线状态")
@PutMapping("/{id}/{status}")
public R updateStatus(@PathVariable String id,@PathVariable Integer status){
hospitalService.updateStatus(id,status);
return R.ok();
}
五、更新医院上线状态功能(前端)
1、封装api请求
在api/yygh/hosp.js添加
//更新上线状态
updateStatus(id,status){
return request({
url: `/admin/hospital/${id}/${status}`,
method: 'put'
})
},
2、修改/views/hosp/list.vue组件
<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>
添加调用方法
updateStatus(id,status){
this.$confirm('您是否要修改医院状态, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
hospApi.updateStatus(id,status).then(res=>{
this.fetchData(this.page)
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消修改'
});
});
},
六、医院详情(接口)
1、添加service方法和实现
(1)在HospService定义方法
/**
* 医院详情
* @param id
* @return
*/
Hospital detail(String id);
(2)在HospServiceImpl定义方法
@Override
public Hospital detail(String id) {
Hospital hospital = hospitalRepository.findById(id).get();
this.packageHospital(hospital);
return hospital;
}
2、添加controller方法
@ApiOperation(value = "获取医院详情")
@GetMapping("/detail/{id}")
public R detail(@PathVariable String id){
Hospital hospital = hospitalService.detail(id);
return R.ok().data("hospital",hospital);
}
七、医院详情(前端)
1、添加隐藏路由
在router/index.js添加
{
path: 'detail/:id',
name: '查看详情',
component: () => import('@/views/yygh/hosp/detail'),
meta: { title: '查看详情', noCache: true },
hidden: true
}
2、创建医院详情页面
(1)添加查看按钮
list.vue
<router-link :to="'/yygh/hosp/detail/'+scope.row.id">
<el-button type="primary" size="mini">查看</el-button>
</router-link>
(2)封装api请求
//查看医院详情
getHospById(id){
return request({
url: `/admin/hospital/detail/${id}`,
method: 'put'
})
},
(3)修改显示页面组件
<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>
<script>
import hospApi from '@/api/yygh/hosp'
export default {
data() {
return {
hospital: null, //医院信息
bookingRule: null //预约信息
}
},
created() {
//获取路由id
const id = this.$route.params.id
//调用方法,根据id查询医院详情
this.fetachHospDetail(id)
},
methods:{
//根据id查询医院详情
fetachHospDetail(id) {
hospApi.getHospById(id)
.then(response => {
this.hospital = response.data.hospital.hospital
this.bookingRule = response.data.hospital.bookingRule
})
},
//返回医院列表
back() {
this.$router.push({ path: '/hospSet/hosp/list' })
}
}
}
</script>
(4)引入样式
第一、将show.css文件复制到src/styles目录
第二、在src/main.js文件添加引用
import '@/styles/show.css'