|
@@ -0,0 +1,327 @@
|
|
|
+package com.jpsoft.proj.rescue.service;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import com.jpsoft.framework.dao.core.SpringJdbcDAO;
|
|
|
+import com.jpsoft.framework.dao.util.PageModel;
|
|
|
+import com.jpsoft.framework.dao.util.UUIDHexGenerator;
|
|
|
+import com.jpsoft.framework.util.DateUtil;
|
|
|
+import com.jpsoft.proj.model.MatchedVolunteer;
|
|
|
+import com.jpsoft.proj.model.RescueAcceptPO;
|
|
|
+import com.jpsoft.proj.model.RescueAcceptVO;
|
|
|
+import com.jpsoft.proj.model.RescueApplyPO;
|
|
|
+import com.jpsoft.proj.model.RescueApplyVO;
|
|
|
+import com.jpsoft.proj.model.RescueFlow;
|
|
|
+import com.jpsoft.proj.utils.RequestParams;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class RescueVolunteerService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private SpringJdbcDAO dao;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RescueFlowService flowService;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 结束志愿者自己的救援
|
|
|
+ * @param rescueId
|
|
|
+ */
|
|
|
+ public void updateForCloseSelfRescue(String volunteerId,String rescueId,String caller){
|
|
|
+ flowService.addFlow(RescueFlow.RESCUING.getCode(),"结束自己的救援",rescueId, caller);
|
|
|
+ dao.getJdbcTemplate().update("update t_rescue_apply_accept set finish_time=now(),note='结束自己的救援' where rescue_id=? and volunteer_id=? and accept_if=1", rescueId,volunteerId);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 接受或忽略求助申请(acceptIf)
|
|
|
+ * @param accept
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String addRescueApplyAccept(RescueAcceptPO accept){
|
|
|
+ UUIDHexGenerator uuid=UUIDHexGenerator.getInstance();
|
|
|
+ accept.setAcceptId(uuid.generate());
|
|
|
+ accept.setAcceptTime(new Date());
|
|
|
+ dao.insertPojo(accept, "t_rescue_apply_accept");
|
|
|
+ return accept.getAcceptId();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void updateRescueApplyAccept(RescueAcceptPO accept){
|
|
|
+ dao.updatePojo(accept, "t_rescue_apply_accept", "accept_id");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加载我能参与的求助信息(按时间倒序,能力匹配,未完结的求助,未忽略的(未参与或正参与))
|
|
|
+ * 当已经有足够志愿者参与时,是否还显示?
|
|
|
+ * @param pageNo
|
|
|
+ * @param pageSize
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public PageModel<RescueApplyVO> loadCanJoinRescueApply(String volunteerId,String longitude,String latitude,int pageNum,int pageSize,String sortField,String sortAction){
|
|
|
+ StringBuilder sql=new StringBuilder();
|
|
|
+ sql.append("select m.real_name publisher_name,m.phone publisher_phone,d.code_name emergency_name,ac.accept_if,rap.*, ");
|
|
|
+ sql.append(" ST_Distance_sphere(point(rap.lon,rap.lat), point(?,?)) distance");
|
|
|
+ sql.append(" from t_rescue_apply rap ");
|
|
|
+ sql.append(" left join t_member m on rap.publisher=m.member_id");
|
|
|
+ sql.append(" left join t_sort_code d on rap.emergency_sort=d.code_id");
|
|
|
+ sql.append(" left join t_rescue_workflow rwf on rap.flow_id=rwf.flow_id");
|
|
|
+ sql.append(" left join t_rescue_apply_accept ac on ac.rescue_id=rap.rescue_id and ac.volunteer_id=?");
|
|
|
+ sql.append(" where rwf.step!=?");
|
|
|
+ sql.append(" and (ac.accept_id is null or (ac.accept_if=1 and ac.finish_time is null))"); //未忽略的(未参与或正参与)
|
|
|
+ //能力匹配
|
|
|
+ sql.append(" and exists(select volunteer_id from t_volunteer vter inner join t_emergency_rescue_mapping erm on instr(vter.rescue_sort,erm.rescue_sort)>0");
|
|
|
+ sql.append(" where erm.emergency_sort=rap.emergency_sort and vter.volunteer_id=?");
|
|
|
+ sql.append(" )");
|
|
|
+
|
|
|
+ if(StringUtils.isNoneBlank(sortField)){
|
|
|
+ sortField=sortField.equalsIgnoreCase("time")?"publish_time":"distance";
|
|
|
+ if(StringUtils.isNoneBlank(sortAction)){
|
|
|
+ sortAction=sortAction.equalsIgnoreCase("desc")?"desc":"asc";
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ sortAction=sortField.equals("publish_time")?"desc":"asc";
|
|
|
+ }
|
|
|
+
|
|
|
+ sql.append(" order by "+sortField+" "+sortAction);
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ sql.append(" order by distance");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return dao.queryForPagedListPojo(sql.toString(), pageNum, pageSize,RescueApplyVO.class,longitude,latitude,volunteerId,RescueFlow.COMPLETE.getCode(),volunteerId);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取单个求助记录(用于志愿者端参与)
|
|
|
+ * @param rescueId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public RescueApplyVO getRescueApplyForJoin(String rescueId,String longitude,String latitude){
|
|
|
+ StringBuilder sql=new StringBuilder(300);
|
|
|
+ sql.append("select m.real_name publisher_name,m.phone publisher_phone,d.code_name emergency_name,r.*, ");
|
|
|
+ sql.append(" wf.step,(select count(1) from t_rescue_apply_accept rac where rac.accept_if=1 and rac.rescue_id=r.rescue_id) accept_count,");
|
|
|
+ sql.append(" ST_Distance_sphere(point(r.lon,r.lat), point(?,?)) distance");
|
|
|
+ sql.append(" from t_rescue_apply r");
|
|
|
+ sql.append(" left join t_member m on r.publisher=m.member_id");
|
|
|
+ sql.append(" left join t_rescue_workflow wf on r.flow_id=wf.flow_id");
|
|
|
+ sql.append(" left join t_sort_code d on r.emergency_sort=d.code_id");
|
|
|
+ //sql.append(" left join (select rescue_id,count(1) accept_count from t_rescue_apply_accept where accept_if=1 group by rescue_id) apt on r.rescue_id=apt.rescue_id");
|
|
|
+ sql.append(" where r.rescue_id=? ");
|
|
|
+ return dao.queryForObject(sql.toString(), RescueApplyVO.class,longitude,latitude,rescueId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询志愿者参与的救援记录(移动端)救援状态以个人参与状态显示
|
|
|
+ * @param volunteerId
|
|
|
+ * @param args
|
|
|
+ * @param pageNo
|
|
|
+ * @param pageSize
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public PageModel<RescueAcceptVO> queryMyJoinedRescues(RequestParams args,int pageNo,int pageSize){
|
|
|
+ List<Object> sqlParams=new ArrayList<Object>();
|
|
|
+ StringBuilder sql=new StringBuilder(100);
|
|
|
+ sql.append("select r.*,ra.volunteer_id,ra.finish_time,ra.accept_time,v.real_name volunteer_name,wf.step,");
|
|
|
+ sql.append(" m.real_name publisher_name,m.phone publisher_phone,d.code_name emergency_name");
|
|
|
+ sql.append(" from t_rescue_apply_accept ra inner join t_rescue_apply r on ra.rescue_id=r.rescue_id");
|
|
|
+ sql.append(" left join t_member m on r.publisher=m.member_id");
|
|
|
+ sql.append(" left join t_volunteer v on ra.volunteer_id=v.volunteer_id");
|
|
|
+ sql.append(" left join t_sort_code d on r.emergency_sort=d.code_id");
|
|
|
+ sql.append(" left join t_rescue_workflow wf on r.flow_id=wf.flow_id");
|
|
|
+ sql.append(" where ra.accept_if=1 ");
|
|
|
+
|
|
|
+
|
|
|
+ //按参与人id
|
|
|
+ if(StringUtils.isNoneBlank(args.get("volunteerId"))){
|
|
|
+ sql.append(" and ra.volunteer_id=? ");
|
|
|
+ sqlParams.add(args.get("volunteerId"));
|
|
|
+ }
|
|
|
+
|
|
|
+ //按参与人名字关键字
|
|
|
+ if(StringUtils.isNoneBlank(args.get("volunteer"))){
|
|
|
+ sql.append(" and (v.real_name like ? or v.phone like ?)");
|
|
|
+ sqlParams.add("%"+args.get("volunteer")+"%");
|
|
|
+ sqlParams.add("%"+args.get("volunteer")+"%");
|
|
|
+ }
|
|
|
+
|
|
|
+ //按发布时间
|
|
|
+ if(StringUtils.isNoneBlank(args.get("publishStart"))){
|
|
|
+ sql.append(" and r.publish_time>=?");
|
|
|
+ sqlParams.add(args.get("publishStart"));
|
|
|
+ }
|
|
|
+ if(StringUtils.isNoneBlank(args.get("publishEnd"))){
|
|
|
+ sql.append(" and r.publish_time<=?");
|
|
|
+ sqlParams.add(args.get("publishEnd"));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //按参加时间
|
|
|
+ if(StringUtils.isNoneBlank(args.get("joinStart"))){
|
|
|
+ sql.append(" and accept_time>=?");
|
|
|
+ sqlParams.add(args.get("joinStart"));
|
|
|
+ }
|
|
|
+ if(StringUtils.isNoneBlank(args.get("joinEnd"))){
|
|
|
+ sql.append(" and accept_time<=?");
|
|
|
+ sqlParams.add(args.get("joinEnd"));
|
|
|
+ }
|
|
|
+ //按救援状态(以个人的状态为准)
|
|
|
+ if(StringUtils.isNoneBlank(args.get("joinStatus"))){
|
|
|
+ if(args.get("joinStatus").equals(RescueFlow.RESCUING.getCode())){
|
|
|
+ sql.append(" and ra.finish_time is null");
|
|
|
+ }
|
|
|
+ else if(args.get("joinStatus").equals(RescueFlow.COMPLETE.getCode())){
|
|
|
+ sql.append(" and ra.finish_time is not null");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ sql.append(" order by accept_time desc");
|
|
|
+ Object[] sqlArgs=sqlParams.size()>0?sqlParams.toArray():null;
|
|
|
+ return dao.queryForPagedListPojo(sql.toString(),pageNo, pageSize,RescueAcceptVO.class,sqlArgs);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统计志愿者 总救援数、本月救援数、漏单数
|
|
|
+ * @param volunteerId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Map<String,Object> getJoinRescueRpt(String volunteerId){
|
|
|
+ String crtMonth=DateUtil.format(new Date(), "yyyy-MM");
|
|
|
+ StringBuilder sql=new StringBuilder(100);
|
|
|
+ sql.append("select count(1) total_rescue,sum((case when DATE_FORMAT(accept_time,'%Y-%m')=? then 1 else 0 end)) month_rescue,");
|
|
|
+ sql.append(" sum((case when finish_time is not null then 1 else 0 end)) finish_rescue");
|
|
|
+ sql.append(" from t_rescue_apply_accept where volunteer_id=? and accept_if=1"); //accept_if=1 接受求助
|
|
|
+
|
|
|
+ Map<String,Object> rpt=dao.queryForSingleMap(sql.toString(), crtMonth,volunteerId);
|
|
|
+
|
|
|
+ sql.setLength(0);
|
|
|
+
|
|
|
+ sql.append("select count(volunteer_id is null) lack_count from t_rescue_apply a ");
|
|
|
+ sql.append(" left join t_rescue_apply_accept ac on a.rescue_id=ac.rescue_id and ac.volunteer_id=? and accept_if=0"); //accept_if=0 忽略的求助单
|
|
|
+ sql.append(" where DATE_FORMAT(publish_time,'%Y-%m')=? ");
|
|
|
+
|
|
|
+ Map<String,Object> rpt2=dao.queryForSingleMap(sql.toString(), volunteerId,crtMonth);
|
|
|
+
|
|
|
+ if(rpt==null){
|
|
|
+ return rpt2;
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ rpt.putAll(rpt2);
|
|
|
+ return rpt;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否正在救援中
|
|
|
+ * @param volunteerId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public boolean isInRescuing(String volunteerId){
|
|
|
+ StringBuilder sql=new StringBuilder(200);
|
|
|
+ sql.append("select ac.volunteer_id ");
|
|
|
+ sql.append(" from t_rescue_apply_accept ac ");
|
|
|
+ sql.append(" where ac.volunteer_id=? and ac.accept_if=1 and ac.finish_time is null ");
|
|
|
+
|
|
|
+ Map<String,Object> rst=dao.queryForSingleMap(sql.toString(), volunteerId);
|
|
|
+ return rst!=null&&rst.size()>0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 指定志愿者指定求助记录的参与状态
|
|
|
+ * @param volunteerId
|
|
|
+ * @param rescueId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public RescueAcceptPO getRescueAcceptInfo(String volunteerId,String rescueId){
|
|
|
+ StringBuilder sql=new StringBuilder(200);
|
|
|
+ sql.append("select ac.* ");
|
|
|
+ sql.append(" from t_rescue_apply_accept ac ");
|
|
|
+ sql.append(" where ac.volunteer_id=? and ac.rescue_id=? ");
|
|
|
+
|
|
|
+ return dao.queryForObject(sql.toString(), RescueAcceptPO.class, volunteerId,rescueId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查找匹配的志愿者短信通知救援
|
|
|
+ * @param rescueApply
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public List<MatchedVolunteer> findMatchedVolunteer(RescueApplyVO rescueApply){
|
|
|
+ StringBuilder sql=new StringBuilder(300);
|
|
|
+ sql.append("select distinct v.phone,v.volunteer_id");
|
|
|
+ sql.append(" from t_rescue_apply rap ");
|
|
|
+ sql.append(" inner join t_emergency_rescue_mapping erm on rap.emergency_sort=erm.emergency_sort ");
|
|
|
+ sql.append(" inner join t_volunteer v on instr(v.rescue_sort,erm.rescue_sort)>0 "); //能力匹配
|
|
|
+ sql.append(" where rap.rescue_id=? ");
|
|
|
+
|
|
|
+ sql.append(" and not exists( "); //无任务
|
|
|
+ sql.append(" select rescue_id from t_rescue_apply_accept ac where ac.volunteer_id=v.volunteer_id and ac.accept_if=1 and ac.finish_time is null ");
|
|
|
+ sql.append(" ) ");
|
|
|
+
|
|
|
+ sql.append(" and not exists( "); //没有忽略该任务
|
|
|
+ sql.append(" select rescue_id from t_rescue_apply_accept ac where ac.volunteer_id=v.volunteer_id and ac.rescue_id=rap.rescue_id and ac.accept_if=0 ");
|
|
|
+ sql.append(" ) ");
|
|
|
+
|
|
|
+ //注册地或最后位置要在事发地50公里范围内,否则排除(由于最后位置可能是很求以前的不可靠,可能会有不该发通知的也发了,不该发的却发了)
|
|
|
+ sql.append(" and ( ifnull(ST_Distance_sphere(point(rap.lon,rap.lat), point(v.reg_lon,v.reg_lat)),1000000)<50000 or ");
|
|
|
+ sql.append(" ifnull(ST_Distance_sphere(point(rap.lon,rap.lat), point(v.last_lon,v.last_lat)),1000000)<50000 ) ");
|
|
|
+
|
|
|
+ sql.append(" limit ?");
|
|
|
+
|
|
|
+ return dao.queryForListPojo(sql.toString(), MatchedVolunteer.class,rescueApply.getRescueId(),rescueApply.getNeedVolunteerCount());
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否已经有足够的志愿者参与
|
|
|
+ * @param rescueId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public boolean hadEnoughVolunteer(String rescueId){
|
|
|
+ StringBuilder sql=new StringBuilder();
|
|
|
+ sql.append("select cast(d.spare2 as signed) req_count, ");
|
|
|
+ sql.append(" (select count(1) from t_rescue_apply_accept raa where raa.rescue_id=ra.rescue_id and raa.accept_if=1) accept_count ");
|
|
|
+ sql.append(" from t_rescue_apply ra ");
|
|
|
+ sql.append(" inner join t_sort_code d on ra.emergency_sort=d.code_id ");
|
|
|
+ sql.append(" where ra.rescue_id=? ");
|
|
|
+
|
|
|
+ Map<String,Object> rst=dao.queryForSingleMap(sql.toString(), rescueId);
|
|
|
+ if(rst==null||rst.get("reqCount")==null||rst.get("acceptCount")==null){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ((Number)rst.get("acceptCount")).doubleValue()>=((Number)rst.get("reqCount")).doubleValue();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void addCallLog(List<MatchedVolunteer> volunteers,RescueApplyPO rescueApply){
|
|
|
+ if(volunteers==null||volunteers.size()==0){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String sql="insert into t_volunteer_call_log(call_id,volunteer_id,seek_time,rescue_id,call_time) values(?,?,?,?,?)";
|
|
|
+ List<Object[]> args=new ArrayList<Object[]>(volunteers.size());
|
|
|
+ UUIDHexGenerator uuid=UUIDHexGenerator.getInstance();
|
|
|
+ for(MatchedVolunteer vol : volunteers){
|
|
|
+ args.add(new Object[]{uuid.generate(),vol.getVolunteerId(),rescueApply.getPublishTime(),rescueApply.getRescueId(),new Date()});
|
|
|
+ }
|
|
|
+ dao.getJdbcTemplate().batchUpdate(sql, args);
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean updateForNeedSound(String volunteerId){
|
|
|
+ String sql="update t_volunteer_call_log set sound_if=1 where sound_if=0 and volunteer_id=? and DATE_FORMAT(call_time,'%Y-%m-%d')>=?";
|
|
|
+ int num=dao.getJdbcTemplate().update(sql, volunteerId,DateUtil.format(new Date(), "yyyy-MM-dd"));
|
|
|
+ return num>0;
|
|
|
+ }
|
|
|
+}
|