《白云区慢性病地理信息系统》项目研发总结
作者: 林继郁
撰写日期: 2019/1/19
本次任务完成时间: 2018年3月13日~2018年4月20日
开发工具与关键技术: SuperMap、Visual Sutdio、SQL Server、C#、.NET MVC、GIS
所完成的相关模块: 客户端、用户管理、角色管理
项目说明: 本项目仅供个人学习使用,不用于商业与工程
一、项目概要
本项目主要是以C/S模式的白云区慢性病地理信息系统,可以有效的解决信息流通不及时、人员浪费、数据统计等各种问题,保证了操作数据的高效与便捷,使用户拥有更好的体验。
该系统包括客户端、用户管理、角色管理、日志管理和数据管理,如图1所示。客户端主要包括对GIS数据的处理,如测距、测面积、查询搜索以及对各种图层的操作;用户管理对操作用户进行相关的管理;角色管理是对操作用户的相关权限进行管理;日志管理显示所记录的用户操作与登录日志;数据管理进行数据的导入与基础数据的管理。
图1:
二、相关模块功能实现
(1)前台操作:
- 前台操作主要包括前台显示(图2)、测距、测面积、查询搜索、预警排除、区域查询、路径查询、周边分析和各种图层的操作。
图2:
测距和测面积如图3所示,用于进行测量距离和面积。
图3:
查询搜索分为形状查询、区域定位,条件查询搜索。形状查询分为方框查询、圆型查询、自定义查询如图4所示,是用于查询该区域的医院、杜康、药店的位置信息,点击标签可以查看详细信息,可以在详细信息中以该点进行周边查询;区域定位如图8所示,显示白云区的各个区域进行划区域;条件查询搜索如图9所示,可以对住宅小区、公司企业、病例门诊号、卡片编号、项目登记号根据名称进行查询。
图4:
图8:
图9:
预警排除是对所显示的预警信息进行预警的排除如图5所示,点击疫情详细查看疫情的详细信息,点击排除预警输入门诊号、诊断状态、确诊时间等进行疫情的排除如图6所示。
图5:
图6:
图层的操作如图7所示,主要是显示医疗、医院、药店、病例分布、病例热力分布等图层,多个图层会进行叠加。
图7:
路径查询是对病例的活动路径与病原的活动路径进行查询如图10所示,路径查询的查询条件分为时间(时间可以分为年、月、周、天)、登记号、年龄、性别、户籍和疾病。
图10:
周边分析在地图中选择一个中心点,对其进行周边的查询如图11所示,选择中心点,输入查询的半径(最大半径为2000米),再选择所需要查询的目标,就可以查询出该范围内的查询目标。点击所查询出来的目标标签可以以该处进行周边查询,替换原来所选择的中心点。
图11:
修改操作员信息,点击图1中的用户名显示出用户的资料设置,可以进行手机号码、邮箱号码和登录密码进行修改如图12所示。
图12:
- 该模块的相关业务表
图13:
- 经典代码
3.1、创建地图控件、各种图层与加载显示图层
//创建地图控件
function init() {
//新建线矢量图层
lineLayer = new SuperMap.Layer.Vector("距离图层");
//对线图层应用样式style(前面有定义)
lineLayer.style = style;
//创建画线控制,图层是lineLayer;这里DrawFeature(图层,类型,属性);multi:true在将要素放入图层之前是否现将其放入几何图层中
drawLine = new SuperMap.Control.DrawFeature(lineLayer, SuperMap.Handler.Path, { multi: true });
//注册featureadded事件,触发drawCompleted()方法,例如注册"loadstart"事件的单独监听,events.on({ "loadstart": loadStartListener });
drawLine.events.on({ "featureadded": drawCompleted });
//新建面矢量图层
polygonLayer = new SuperMap.Layer.Vector("面积图层");
//对面图层应用样式style(前面有定义)
polygonLayer.style = style;
//创建画面控制,图层是polygonLayer
drawPolygon = new SuperMap.Control.DrawFeature(polygonLayer, SuperMap.Handler.Polygon);
drawPolygon.events.on({ "featureadded": drawCompleted });
markerLayer = new SuperMap.Layer.Markers("图标");
vectorLayer = new SuperMap.Layer.Vector("区域查询图层");
MedicalLayer = new SuperMap.Layer.Markers("医疗分布图层");
//MedicalLayer.setVisibility(false);
HospitalLayer = new SuperMap.Layer.Markers("医院分布图层");
DuKangLayer = new SuperMap.Layer.Markers("杜康分布图层");
DrugstoreLayer = new SuperMap.Layer.Markers("药店分布图层");
CaseLayer = new SuperMap.Layer.Markers("病例分布散点图层");
ThermalLayer = new SuperMap.Layer.HeatMapLayer("病例热力分布图层", { "radius": 45 });
PathogenicGeneLayer = new SuperMap.Layer.Markers("病原基因分布图层");
PatientRouteGridGraph = new SuperMap.Layer.HeatGridLayer("病人路径网格图");
EarlyWarningLayer = new SuperMap.Layer.Markers("预警图层");
//方框查询
BoxQuery = new SuperMap.Control.DrawFeature(vectorLayer, SuperMap.Handler.Box);
BoxQuery.events.on({ "featureadded": BoxQuerys });
//圆形查询
CircularQuery = new SuperMap.Control.DrawFeature(vectorLayer, SuperMap.Handler.RegularPolygon, { handlerOptions: { sides: 50 } });
CircularQuery.events.on({ "featureadded": CircularQuerys });
//自定义查询
CustomQuery = new SuperMap.Control.DrawFeature(vectorLayer, SuperMap.Handler.Polygon);
CustomQuery.events.on({ "featureadded": CircularQuerys });
//周边查询
PeripheralQueryLayer = new SuperMap.Layer.Vector("定点");
PeripheralQuery = new SuperMap.Control.DrawFeature(PeripheralQueryLayer, SuperMap.Handler.Point, { multi: true });
PeripheralQuery.events.on({ "featureadded": drawPointCompleted });
map = new SuperMap.Map("map", {
controls: [
//new SuperMap.Control.LayerSwitcher(),//LayerSwitcher:图层显示控件
new SuperMap.Control.ScaleLine(),//ScaleLine: 地图距离显示控件
//new SuperMap.Control.OverviewMap(),//鹰眼图
//new SuperMap.Control.PanZoomBar(),
new SuperMap.Control.Zoom(),
new SuperMap.Control.MousePosition(),//坐标
new SuperMap.Control.Navigation({//Navigation:地图坐标显示控件
dragPanOptions: {
enableKinetic: true
}
}), drawLine, drawPolygon, BoxQuery, CircularQuery, CustomQuery, PeripheralQuery//点击距离量算,测面积
], units: "m",//地图的单位
});
//创建分块动态REST图层,该图层显示iserver 8C 服务发布的地图,
//其中"world"为图层名称,url图层的服务地址,{transparent: true}设置到url的可选参数
layer1 = new SuperMap.Layer.TiledDynamicRESTLayer("白云区图层", url,
{ transparent: true, cacheEnabled: true }, { maxResolution: "auto" });
layer1.events.on({ "layerInitialized": addLayer });
changeFrameHeight();//计算嵌套标签的高度
showOrFence();//左侧栏
showAreaPoint();//显示区域点名称
dragAndDrop1();//图层控制器窗体拖动
PackUpTime();//收起周边分析中的查询目标
DisplayPatientForms();//显示病人窗体拖动
$("#ActivityBingLi").attr("checked", "checked");//病例活动路径
}
function addLayer() {
//将Layer图层加载到Map对象上
map.addLayers([layer1, EarlyWarningLayer, PathogenicGeneLayer, ThermalLayer, CaseLayer, DrugstoreLayer, DuKangLayer,
HospitalLayer, MedicalLayer, vectorLayer, polygonLayer, lineLayer, markerLayer,
PatientRouteGridGraph]);//,PeripheralQueryLayer
//出图,map.setCenter函数显示地图
map.setCenter(new SuperMap.LonLat(113.22, 23.29), 8);// 113.32, 23.29
}
3.2、定位查询,根据不同的图层进行查询,如图9所示
//定位查询
function InquireAbout() {
$("#tabAddress tr").remove();
setTimeout(function () {
$('.toolLi').removeClass('active');
}, 100);
var addressName = $('#txtDZ').val();
var queryParams = [], queryBySQLParams, queryBySQLService;
var Administer = "false";
if ($("#seleQualification").val() == "住宅小区") {
queryParams.push(new SuperMap.REST.FilterParameter({ name: "P19住宅小区_point_1@BaiyunSQL_Data#1", attributeFilter: "NAME like '%" + addressName + "%' or ADDRESS like '%" + addressName + "%'" }));//获取最新的楼栋ID
Administer = "true";
} else if ($("#seleQualification").val() == "公司企业") {
queryParams.push(new SuperMap.REST.FilterParameter({ name: "P11商业大厦_point_1@BaiyunSQL_Data#1", attributeFilter: "NAME like '%" + addressName + "%' or ADDRESS like '%" + addressName + "%'" }));//获取最新的楼栋ID
Administer = "true";
} else if ($("#seleQualification").val() == "病例门诊号") {
CaseClinicNumber()
} else if ($("#seleQualification").val() == "卡片编号") {
CardNumberLocation()
} else if ($("#seleQualification").val() == "项目登记号") {
RegistrationMark()
}
if (Administer == "true") {
queryBySQLParams = new SuperMap.REST.QueryBySQLParameters({
expectCount: 50,
queryParams: queryParams//查询过滤条件参数数组
});
queryBySQLService = new SuperMap.REST.QueryBySQLService(url2, {
eventListeners: { "processCompleted": processCompleted_selectAddress, "processFailed": processFailed }
});
queryBySQLService.processAsync(queryBySQLParams);
}
};
3.3、周边分析,如图11所示
//周边分析,查询按钮
function functionSelect() {
var center = $("#CentrePoint").val();
var banjing = $("#SelectOp").val();
if (center != "") {
if (banjing != "") {
if (Astrict <= 6) {
remove_drop();
markerLayer.clearMarkers();
ISchecked();
var onet = center.split(",");
var centerPoint = new SuperMap.Geometry.Point(onet[0], onet[1]);//中心点
var Range = $("#SelectOp").val() / 100000;// 半径
var polygon = SuperMap.Geometry.Polygon.createRegularPolygon(centerPoint, Range, 360, 360);//创建有规律的多边形(圆)
var circleVector = new SuperMap.Feature.Vector(polygon);//创建矢量样式
circleVector.style = {
strokeColor: "#DE5145",
fillColor: "#EA7454",
strokeWidth: 2,
fillOpacity: 0.3,
strokeOpacity: 0.5
};
centerPoint = new SuperMap.Geometry.Point(onet[0], onet[1]);//获取中心点坐标
PeripheralQuery.deactivate();/////终止在地图上选点
var size = new SuperMap.Size(32, 35),//指定图标的大小
offset = new SuperMap.Pixel(-(size.w / 2), -size.h);//指定图标的偏移量
var icon;
icon = new SuperMap.Icon("/content/images/markerbig_select.png", size, offset);//图标类,表示显示在屏幕上的图标
Callthepolicemarker = new SuperMap.Marker(SuperMap.LonLat.fromString(onet[0] + "," + onet[1]), icon);
markerLayer.addMarker(Callthepolicemarker);//添加覆盖物到标记图层
vectorLayer.addFeatures(circleVector);//创建矢量图层(将polygon加进去)
map.setCenter(new SuperMap.LonLat(onet[0], onet[1]), 14);//放大倍数
zhoubian(centerPoint);//方法
} else {
confirm("最多只能选择6个查询目标");
}
}
else {
alert("请输入查询的半径!", { icon: 1, title: '提示' });
}
} else {
alert("请在地图上选择中心点!", { icon: 1, title: '提示' });
}
}
(2)后台管理:
- 后台管理主要包括用户管理、角色管理、日志管理和角色管理。
用户管理对用户进行增删查改的操作如图17所示,用户的新增与修改界面如图18所示,用户的修改不能进行用户的登录名修改与用户的密码修改,密码的修改需要在前台操作处修改如图12所示。
图17:
图18:
角色管理是用户的权限管理如图19所示。角色管理分为系统角色、数据权限、功能权限和资源权限。系统角色是对对应的科室下的系统角色进行操作,而功能权限的选择会弹出对应的资源权限,对资源权限选择只读或编辑的权限。图中的保存分配按钮是保存角色的数据权限、功能权限和资源权限。
图19:
- 该模块的相关业务表
图20:
3. 经典代码
3.1、天气的显示,判断是否已经连接网络,天气接口是由NowAPI所提供的接口–天气预报(免费调用、每60分钟200次配额)。
$(function () {
if (navigator.onLine) {
var p = new Ping();
p.ping("http://api.map.baidu.com", function(err, data) {
if (err) {
$("#one_weather").html("暂无网络服务,无法显示当前天气信息");
} else {
$.getScript('http://pv.sohu.com/cityjson', function (_result) {//搜狐接口
if (returnCitySN.cip != '') {
var cityName = returnCitySN.cip;
QueryWeather(cityName);
} else {
layer.msg("网络出错,无法定位到当前城市", {icon:5,time:1000});
}
});
}
});
} else {
layer.msg("暂无网络服务", {icon:5,time:1000});
}
//时间-定时器
window.setInterval(CurrentTime, 1000);
});
////NowAPI--提供的接口,查询实时天气
function QueryWeather(cityName) {
var paramUrl = "http://api.k780.com/?app=weather.today&weaid=" + cityName + "&appkey=32310&sign=50e918b9ba97cbb7cc4c7cb2c96d7980&format=json";
$.ajax({
url: paramUrl,
type: "get",
dataType: "jsonp",
jsonp: 'jsoncallback',
async: false,
data: "",
// success: eval(funback) 封装成方法时,这里是回调参数名称
success: function (data) {
if (data.success == '1') {
var is = data.result.weather_icon;//http://api.k780.com/upload/weather/d/0.gif
var substr = is.split(/weather\/d/);
var jpg = "";
if (substr.length == 2) {
jpg = "<img style='width:28px;height:20px; margin-top: -2px;' src='${ctx}/Content/static/weather/d" + substr[1] + "' />";
} else {
jpg = "<img style='width:28px;height:20px; margin-top: -2px;' src='" + is + "' />";
}
CurrentTime();
$("#one_weather").html(data.result.week + " " + jpg + " " + data.result.citynm + " " + data.result.temperature_curr);
if (data.result.weather == data.result.weather_curr || data.result.weather.indexOf("转") != -1) {
$("#two_weather").html(data.result.weather + " " + data.result.temperature);
} else {
$("#two_weather").html(data.result.weather + "转" + data.result.weather_curr + " " + data.result.temperature);
}
$("#three_weather").html("湿度:" + data.result.humidity + " " + data.result.wind + " " + data.result.winp);
} else {
layer.msg("暂无网络服务", {icon:5,time:1000});
}
},
error: function () {
layer.msg("获取天气失败", {icon:5,time:1000});
}
});
}
三、开发总结
历时一个月的项目研发,对我帮助最大的是学会了如何合理地安排时间完成整个项目。把项目规划成项目计划书,细化化,依次罗列出来,更加清晰地认清每一个模块的难易程度、以及每个模块所需要多少时间,这将大大促进了整个项目的完成速度。而且当所做的项目中出现了重大的错误与难以跨越的坑时,可以更好地根据计划书中的安排进行查看空余的时间段,以达到安排所遗留的模块赶上进度的目的。
曾在学习的时候就觉得它与以往所做的项目并不太相似,也或者说还没有对它投入太多的时间去理解、去学习,导致对项目的前台是如何开始运行、如何书写都还不是太了解。正是因为对前台的功能还不太熟悉,所以在设计项目计划书时把过多的时间都安排在了前台上面,而后台正是所熟悉的部分,尽可能地减少了所安排的时间。在制作项目所需要用到的地图时,因对地图的比例尺和所要在地图上需要显示什么图标、字段之类的没有过多的深究。到了在前台进行距离与面积测量时,才发现所花大量时间制作出一份图标显示过多、数据缺少、比例尺不正确的地图,最后只能重新开始制作一份。从而对计划中的时间重新进行了调整,所以要先对项目有所理解,不能太过于盲目操作。在查找资料时,无意中看到了官方的开发指南时,它以及其简短的代码介绍了地图的显示、各类的功能以及它的代码结构,极大程度地帮助项目开发流程的了解,同时加深了对GIS项目制作的印象。
所做GIS的操作前台并不难,因为所做的项目并不会让你无中生有,而是官方已经把大部分的功能介绍到网站上面,只需要找到相对应的功能,然后根据项目中的数据加以改造,排除错误,最后就会得到你所想要的结果。所书写的代码要有层次感,该缩进的缩进,不能到处都有空行,每个不同部分的代码要进行分开,保持一个良好的习惯。