环境
fisco-bcos 2.8
ubuntu 20
solidity 0.4.25[版本有点老,也可以用0.6的版本 ]
前言
大家可以阅读上篇对于这个系统的部分合约讲解
上一篇 基于fisco-bcos的共享病例智能合约的设计与实现【3】
这篇将介绍如何用RBAC合约结合医生合约,并且还需要介绍医院 和科室合约【因为医生需要和医院和科室进行绑定】。
重新梳理一下医生和医院科室的关系
在现实中,在每个医院里,都有不同的科室,每个科室也有不同的医生,所以医院和科室是一对多关系,科室和医生也是一对多关系。
所以写合约的时候我们需要考虑先后顺序的问题
科室合约
pragma solidity^0.4.25;
// 科室信息智能合约
// 对医院科室的增删改查
contract Department{
string public DepartmentName;
uint256 public Phone;
string public Detail;
address[] public doctorList;
mapping(address=>bool) docktorMapping;
// 医生管理员根据医院实际情况添加科室信息
constructor(string _name,uint256 _phone,string _detail ) public{
DepartmentName = _name;
Phone = _phone;
Detail = _detail;
}
function getDepartmentDetailByD() public view returns(string,uint256,string){
return (DepartmentName,Phone,Detail);
}
function updateByDepartmentByD(string _name,uint256 _phone,string _detail){
if(keccak256(abi.encode(_name)) != keccak256(abi.encode(""))){
DepartmentName = _name;
}
if(_phone !=0){
Phone = _phone;
}
if(keccak256(abi.encode(_detail)) != keccak256(abi.encode(""))){
Detail = _detail;
}
}
function addDoctorByD(address _doctor) public{
doctorList.push(_doctor);
docktorMapping[_doctor] = true;
}
function getDoctorListByD() public view returns(address[]){
return doctorList;
}
function hasDoctorByD(address _doctor) public view returns(bool){
return docktorMapping[_doctor];
}
function removeDoctorByD(address _doctor) public{
docktorMapping[_doctor] = false;
for(uint256 i = 0;i<doctorList.length;i++){
if(_doctor == doctorList[i]){
for(uint256 j = i;j<doctorList.length-1;j++){
doctorList[j] = doctorList[j+1];
}
doctorList.length--;
}
}
}
}
科室合约里的变量里有 科室名,电话和科室简述,另外还有医生List和医生mapping,当医生添加到科室的时候,需要list 保存其医生地址, 至于mapping ,是方便由于验证医生是否在此科室里【如hasDoctorByD
方法】
医院合约
pragma solidity^0.4.25;
// 医院信息管理智能合约
//用于各个医院的信息登记
contract Hospital {
uint256 public HospitalID;
string public HospitalName;
uint256 public Phone;
string public Detail;
address[] public departmentList;
mapping(address=> bool) departmentMapping;
// 初始化医院相关信息,包括医院名称、咨询电话和简介
constructor(uint256 id,string _name,uint256 _phone,string _detail) public{
HospitalID = id;
HospitalName = _name;
Phone = _phone;
Detail = _detail;
}
function getHospitalDetialByH() public view returns(uint256,string,uint256,string){
return (HospitalID,HospitalName,Phone,Detail);
}
function updateByHospitalMsgByH(string _name,uint256 _phone,string _detail) public {
if (keccak256(abi.encode(_name)) != keccak256(abi.encode(""))){
HospitalName = _name;
}
if(_phone != 0){
Phone = _phone;
}
if(keccak256(abi.encode(_detail)) != keccak256(abi.encode(""))){
Detail = _detail;
}
}
function addDepartmentByH(address _department) public {
departmentList.push(_department);
departmentMapping[_department] = true;
}
function getDepartmentListByH() public view returns(address[]){
return departmentList;
}
function hasDepartmentByH(address _department) public view returns(bool){
return departmentMapping[_department];
}
function removeDepartmentByH(address _department) public {
departmentMapping[_department] = false;
for(uint256 i = 0;i<departmentList.length;i++){
if(_department == departmentList[i]){
for(uint256 j = i;j<departmentList.length;j++){
departmentList[j] = departmentList[j+1];
}
departmentList.length--;
}
}
}
}
医院合约里的变量里有 医院id,医院名,医院电话,医院描述 另外还有科室List和科室mapping,当科室添加到医院的时候,需要list 保存其科室地址, 至于mapping ,是方便由于验证科室是否在此医院里【如hasDepartmentByH
方法】
RBAC 合约 【医院部分】
现在看回RBAC 合约,上篇我们讲解了RBAC 合约怎么对病人合约进行操作,现在我们讲解RBAC 合约怎么操作医院
// ----------------------------------医院---------------------------------------------------
address[] public hospitalList;
uint256 public hospitaIdAdd;
mapping(string=>address) hospitalMapping;
mapping(address=>bool) hospitalMappingToBool;
function createHospital(string memory _hName,uint256 _hPhone,string memory _hDetail) public onlyAdmin(msg.sender) returns(bool){
// uint256 id,string _name,uint256 _phone,string _detail
hospitaIdAdd++;
Hospital hospital = new Hospital(hospitaIdAdd,_hName,_hPhone,_hDetail);
hospitalMapping[_hName] = address(hospital);
hospitalList.push(address(hospital));
hospitalMappingToBool[address(hospital)] =true;
return true;
}
function getHospitalList() public view returns(address[]){
return hospitalList;
}
function searchHospital(string memory _hName) public view returns(uint256,string,uint256,string){
address hospitalA = hospitalMapping[_hName] ;
require(hospitalA!=address(0),"该医院不存在");
Hospital hospital = Hospital(hospitalA);
return hospital.getHospitalDetialByH();
}
function getHospitalDetail(uint256 _hNumberByList) public view returns(address,uint256,string,uint256,string){
address hospitalA = hospitalList[_hNumberByList];
require(hospitalA!=address(0),"该医院不存在");
Hospital hospital = Hospital(hospitalA);
uint256 id;
string memory name;
uint256 phone;
string memory detail;
(id,name,phone,detail) = hospital.getHospitalDetialByH();
return (address(hospital),id,name,phone,detail);
}
function hasHospital(address _hospitalA) public view returns(bool){
return hospitalMappingToBool[_hospitalA] ;
}
function updateByHospitalMsg(address _hospitalA,string _name,uint256 _phone,string _detail) public onlyAdmin(msg.sender) returns(bool){
require(hasHospital(_hospitalA),"该医院不存在");
Hospital hospital = Hospital(_hospitalA);
hospital.updateByHospitalMsgByH(_name,_phone,_detail);
return true;
}
modifier onlyAdmin(address amount){
require(amount ==admin,"Access Control:admin only");
_;
}
讲解一下上面代码用到的变量
-
address[] public hospitalList;
用来将系统的医院存储起来 -
uint256 public hospitaIdAdd;
这个是医院的自增id -
mapping(string=>address) hospitalMapping;
这个是医院名字与医院合约地址的映射,此可以作为搜索searchHospital
功能,比如搜索名字可以返回医生信息 -
mapping(address=>bool) hospitalMappingToBool;
这个是医院的状态证明,方便多个方法的 权限校验【需要验证医院是否存在,才能更好的进行操作】,如hasHospital
方法我就不多介绍了,都是增删改查,而onlyAdmin(msg.sender) ,这个msg.sender,就是之前说的部署合约那个人将会是管理员,只有管理员才能新建医院等方法使用。
RBAC合约【科室部分】
// ----------------------------------科室---------------------------------------------------
function addDepartment(address _hospitalA,string _name,uint256 _phone,string _detail) public onlyAdmin(msg.sender) returns(bool){
require(hasHospital(_hospitalA),"该医院不存在");
Hospital hospital = Hospital(_hospitalA);
Department department = new Department(_name,_phone,_detail);
hospital.addDepartmentByH(address(department));
return true;
}
function hasDepartment(address _hospitalA,address _departmentA) public view returns(bool){
require(hasHospital(_hospitalA),"该医院不存在");
Hospital hospital = Hospital(_hospitalA);
return hospital.hasDepartmentByH(_departmentA);
}
function removeDepartment(address _hospitalA,address _departmentA) public onlyAdmin(msg.sender) returns(bool){
require(hasHospital(_hospitalA),"该医院不存在");
require(hasDepartment(_hospitalA,_departmentA),"该部门不存在");
Hospital hospital = Hospital(_hospitalA);
hospital.removeDepartmentByH(_departmentA);
return true;
}
function updateByDepartment(address _hospitalA,address _departmentA,string _name,uint256 _phone,string _detail) public onlyAdmin(msg.sender) returns(bool){
Department department = Department(_departmentA);
department.updateByDepartmentByD(_name,_phone,_detail);
return true;
}
function getDepartmentDetail(address _hospitalA,address _departmentA) public view returns(string,uint256,string){
require(hasDepartment(_hospitalA,_departmentA),"该部门不存在");
Department department = Department(_departmentA);
return department.getDepartmentDetailByD();
}
function getDepartmentList(address _hospitalA) public view returns(address[]){
require(hasHospital(_hospitalA),"该医院不存在");
Hospital hospital =Hospital(_hospitalA);
return hospital.getDepartmentListByH();
}
科室的部分,因为是和医院有一对多的关系,所以在增删改的时候,都会与医院产生关系,并且还需要调用医院的方法,如 hospital.addDepartmentByH(address(department)); 就需要调用医院的addDepartmentByH 方法,将其科室加入其医院中
RBAC合约 【医生部分】
终于到了医生部分,医院科室都有了,接下来就是让医生加入到科室医院里
// ----------------------------------医生---------------------------------------------------
event EventDoctorAdd(address role,address doctorA);
function addDoctor(address _hospitalA,address _departmentA,string _dName,uint256 _phone,string _pTitle)
public returns(bool){
require(hasDepartment(_hospitalA,_departmentA),"该部门或者医院不存在");
Doctor doctor = new Doctor(_dName,_phone,_pTitle);
Department department = Department(_departmentA);
department.addDoctorByD(address(doctor));
addRole(msg.sender,"DO",address(doctor));
emit EventDoctorAdd(msg.sender,address(doctor));
return true;
}
function hasDoctor(address _hospitalA,address _departmentA,address _doctorA) public view returns(bool){
require(hasDepartment(_hospitalA,_departmentA),"该部门或者医院不存在");
Department department = Department(_departmentA);
return department.hasDoctorByD(_doctorA);
}
function removeDoctor(string _role,address _hospitalA,address _departmentA) public onlyDoctor(msg.sender) returns(bool){
require(hasDepartment(_hospitalA,_departmentA),"该部门或者医院不存在");
address _doctorA = roles[_role].getRoleDetail(msg.sender);
Department department = Department(_departmentA);
department.removeDoctorByD(_doctorA);
removeRole(msg.sender,"DO");
return true;
}
// 工具类,获取该医生的合约地址
function getDoctorAddress() public view onlyDoctor(tx.origin) returns(address){
return roles["DO"].getRoleDetail(tx.origin);
}
// 获取医生细节 需要变换
function getDocotrDetail(string _role,address amount ) public onlyDoctor(amount) view returns(string,uint256,string,uint256,uint8,uint256){
address _doctorA = roles[_role].getRoleDetail(amount);
Doctor doctor = Doctor(_doctorA);
return doctor.getDoctorDetailByD();
}
// 获取医生细节 需要变换
function getDocotrDetail2(address amount ) public view returns(string,uint256,string,uint256,uint8,uint256){
Doctor doctor = Doctor(amount);
return doctor.getDoctorDetailByD();
}
// 获取医生列表
function getDoctorList(address _hospitalA,address _departmentA) public view returns(address[]){
require(hasDepartment(_hospitalA,_departmentA),"该部门不存在");
Department department = Department(_departmentA);
return department.getDoctorListByD();
}
// 更新医生数据
function updateDoctorMsg(string _role,string _name,uint256 _phone,string _pTitle,uint256 _age,uint8 _gendor) public onlyDoctor(msg.sender) returns(bool){
address _doctorA = roles[_role].getRoleDetail(msg.sender);
Doctor doctor = Doctor(_doctorA);
doctor.updateDoctorDetailByD(_name,_phone,_pTitle,_age,_gendor);
return true;
}
除了需要将其加入到roles 里面,还需要将其加入到科室医院里
require(hasDepartment(_hospitalA,_departmentA),"该部门或者医院不存在");//判断科室医院是否存在
Doctor doctor = new Doctor(_dName,_phone,_pTitle); //生成医生合约地址
Department department = Department(_departmentA);// 根据地址还原科室对象,
department.addDoctorByD(address(doctor)); //调用添加医院方法
addRole(msg.sender,"DO",address(doctor));// 增加医生到roles 里面,角色标识为 DO
其他方法就不解释了,大家自行阅读
结语
RBAC 合约已经讲解完毕,对于医生,医院,科室和病人的各种操作增删改查,基本体现在RBAC合约,接下来将讲解最后部署的合约 SyStem,它需要集成这个RBAC合约,在SyStem合约,医生和病人可以进行操作预约挂号,接诊,填写病历等操作。