处理宿州位置汇聚记录仪下线不正常问题
parent
791b5deeca
commit
6f86f370ca
|
|
@ -4,9 +4,8 @@ import cn.hutool.core.bean.BeanUtil;
|
|||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
|
|
@ -176,14 +175,12 @@ public class GpsServiceImpl implements IGpsService {
|
|||
String deviceCode = originEsGpsInfo.getDeviceCode();
|
||||
String deviceType = originEsGpsInfo.getDeviceType();
|
||||
// DeviceEntityV2 de = deviceService.checkDeviceExists(info);
|
||||
Object o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType+":" + deviceCode);
|
||||
JSONObject o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType+":" + deviceCode);
|
||||
if (Objects.isNull(o)) {
|
||||
logger.error("redis中的Object=null,deviceType={},deviceCode={}",deviceType,deviceCode);
|
||||
logger.error("批量下线设备redis中的Object=null,deviceType={},deviceCode={}",deviceType,deviceCode);
|
||||
continue;
|
||||
}
|
||||
JSONObject o1 = (JSONObject) o;
|
||||
String json = o1.toJSONString();
|
||||
EsGpsInfoVO2 esGpsInfoVO2 = JSON.parseObject(json, EsGpsInfoVO2.class);
|
||||
EsGpsInfoVO2 esGpsInfoVO2 = JSONUtil.toBean(o, EsGpsInfoVO2.class);
|
||||
//更新在线状态和时间,经纬度不变
|
||||
esGpsInfoVO2.setOnline(originEsGpsInfo.getOnline());
|
||||
|
||||
|
|
@ -222,14 +219,13 @@ public class GpsServiceImpl implements IGpsService {
|
|||
String deviceCode = gpsInfoVO2.getDeviceCode();
|
||||
String deviceType = gpsInfoVO2.getDeviceType();
|
||||
// DeviceEntityV2 de = deviceService.checkDeviceExists(info);
|
||||
Object o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType + ":" + deviceCode);
|
||||
JSONObject o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType + ":" + deviceCode);
|
||||
if (Objects.isNull(o)) {
|
||||
logger.error("redis中的Object=null,deviceType={},deviceCode={}", deviceType, deviceCode);
|
||||
logger.error("下线设备redis中的Object=null,deviceType={},deviceCode={}", deviceType, deviceCode);
|
||||
return null;
|
||||
}
|
||||
JSONObject o1 = (JSONObject) o;
|
||||
String json = o1.toJSONString();
|
||||
EsGpsInfoVO2 esGpsInfoVO2 = JSON.parseObject(json, EsGpsInfoVO2.class);
|
||||
|
||||
EsGpsInfoVO2 esGpsInfoVO2 = JSONUtil.toBean(o, EsGpsInfoVO2.class);
|
||||
//更新在线状态和时间,经纬度不变
|
||||
esGpsInfoVO2.setOnline(gpsInfoVO2.getOnline());
|
||||
|
||||
|
|
@ -415,7 +411,19 @@ public class GpsServiceImpl implements IGpsService {
|
|||
}*/
|
||||
deviceEntityV2.setDeviceCode(deviceCode);
|
||||
deviceEntityV2.setDeviceType(deviceType);
|
||||
RemoteDeviceVo deviceEntityV21 = BeanUtil.toBean(RedisUtils.getBucket("deviceInfo:" + deviceType+":"+deviceCode), RemoteDeviceVo.class) ;
|
||||
RemoteDeviceVo deviceEntityV21 = new RemoteDeviceVo();
|
||||
if ("5".equals(deviceType)){
|
||||
deviceEntityV21 = BeanUtil.toBean(RedisUtils.getBucket("deviceInfo:" + deviceType+":"+deviceCode), RemoteDeviceVo.class) ;
|
||||
if (null == deviceEntityV21){
|
||||
deviceEntityV21 = BeanUtil.toBean(RedisUtils.getBucket("deviceInfo:8" +":"+deviceCode), RemoteDeviceVo.class) ;
|
||||
if (null == deviceEntityV21){
|
||||
deviceEntityV21 = BeanUtil.toBean(RedisUtils.getBucket("deviceInfo:7" +":"+deviceCode), RemoteDeviceVo.class) ;
|
||||
|
||||
}
|
||||
}
|
||||
}else {
|
||||
deviceEntityV21 = BeanUtil.toBean(RedisUtils.getBucket("deviceInfo:" + deviceType+":"+deviceCode), RemoteDeviceVo.class) ;
|
||||
}
|
||||
if(Objects.isNull(deviceEntityV21)){
|
||||
logger.error("库里没有这个数据,deviceCode={}",deviceCode);
|
||||
return null;
|
||||
|
|
@ -438,11 +446,10 @@ public class GpsServiceImpl implements IGpsService {
|
|||
//如果定位是0的话 ,则上传最后一次有定位的坐标,如果最后一次是0的话,那就上传0
|
||||
boolean nonLatLng = isNonLatLng(lat, lng);
|
||||
if(nonLatLng){
|
||||
Object o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType + ":" + deviceCode);
|
||||
JSONObject o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType + ":" + deviceCode);
|
||||
if(!Objects.isNull(o)) {
|
||||
com.alibaba.fastjson.JSONObject o1 = (JSONObject) o;
|
||||
String json = o1.toJSONString();
|
||||
EsGpsInfoVO2 esGpsInfoVO3 = JSON.parseObject(json, EsGpsInfoVO2.class);
|
||||
|
||||
EsGpsInfoVO2 esGpsInfoVO3 = JSONUtil.toBean(o, EsGpsInfoVO2.class);
|
||||
String lat1 = esGpsInfoVO3.getLat();
|
||||
String lng1 = esGpsInfoVO3.getLng();
|
||||
esGpsInfoVO2.setLat(lat1);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package org.dromara.system.controller.system;
|
|||
import cn.hutool.core.date.DateUtil;
|
||||
import jdk.dynalink.linker.LinkerServices;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
|
|
@ -24,6 +25,7 @@ import java.util.*;
|
|||
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@Slf4j
|
||||
public class IndexStaticsController extends BaseController {
|
||||
|
||||
private final ISysDeptService deptService;
|
||||
|
|
@ -112,32 +114,27 @@ public class IndexStaticsController extends BaseController {
|
|||
* 各地市总数和在线数
|
||||
* */
|
||||
@PostMapping("/onLineBar")
|
||||
public R onLineBar(){
|
||||
List<SysDeptVo> deptVoList = deptService.getDsList();
|
||||
List<DeviceStaticsVo> staticsVoList = deviceService.countByDs();
|
||||
public R onLineBar(@RequestBody TDeviceBo bo){
|
||||
SysDeptBo deptBo = new SysDeptBo();
|
||||
deptBo.setIsVisible("1");
|
||||
deptBo.setParentId(bo.getZzjgdm());
|
||||
List<SysDeptVo> deptVoList = deptService.selectDeptList(deptBo);
|
||||
log.error("单位集合={}",deptVoList.toString());
|
||||
List<DeviceStaticsVo> list = new ArrayList<>(); //用来接收处理后的统计结果
|
||||
for (SysDeptVo deptVo : deptVoList) {
|
||||
boolean bl = false; //用来统计结果是否有当前这个机构
|
||||
for (DeviceStaticsVo staticsVo : staticsVoList) {
|
||||
String deptId = staticsVo.getZzjgdm()+"00000000";
|
||||
if (deptId.equals(deptVo.getDeptId())){
|
||||
staticsVo.setZzjgdm(deptId);
|
||||
staticsVo.setZzjgmc(deptVo.getDeptName().replaceAll("公安局",""));
|
||||
int onlineCo = RedisUtils.searchKeys("org_code:"+staticsVo.getZzjgdm()+"*");
|
||||
staticsVo.setOnlineCo(onlineCo);
|
||||
list.add(staticsVo);
|
||||
bl = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bl){
|
||||
DeviceStaticsVo staticsVo = new DeviceStaticsVo();
|
||||
staticsVo.setZzjgdm(deptVo.getDeptId());
|
||||
staticsVo.setZzjgmc(deptVo.getDeptName().replaceAll("公安局",""));
|
||||
staticsVo.setCo(0);
|
||||
staticsVo.setOnlineCo(0);
|
||||
list.add(staticsVo);
|
||||
}
|
||||
DeviceStaticsVo staticsVo = new DeviceStaticsVo();
|
||||
TDeviceBo deviceBo = new TDeviceBo();
|
||||
deviceBo.setZzjgdm(deptVo.getDeptId());
|
||||
deviceBo.setValid(1);
|
||||
DeviceRedis redis = new DeviceRedis();
|
||||
redis.setZzjgdm(deptVo.getDeptId());
|
||||
Long co = deviceService.countByCondition(deviceBo);
|
||||
Long online = redisService.countByZzjgdm(redis);
|
||||
staticsVo.setZzjgdm(deptVo.getDeptId());
|
||||
staticsVo.setZzjgmc(deptVo.getShortName());
|
||||
staticsVo.setCo(co);
|
||||
staticsVo.setOnlineCo(online);
|
||||
list.add(staticsVo);
|
||||
}
|
||||
return R.ok(list);
|
||||
}
|
||||
|
|
@ -210,7 +207,7 @@ public class IndexStaticsController extends BaseController {
|
|||
* 终端种类占比
|
||||
* */
|
||||
@PostMapping("/deviceTypePen")
|
||||
public R deviceTypePen(TDeviceBo deviceInfo){
|
||||
public R deviceTypePen(@RequestBody TDeviceBo deviceInfo){
|
||||
List<SysDictDataVo> dataList = dictTypeService.selectDictDataByType("zd_device_type");
|
||||
List<HashMap> list = new ArrayList<>();
|
||||
for (SysDictDataVo data : dataList) {
|
||||
|
|
@ -228,7 +225,7 @@ public class IndexStaticsController extends BaseController {
|
|||
*终端单位分布
|
||||
* */
|
||||
@PostMapping("/deviceBar")
|
||||
public R deviceBar(TDeviceBo deviceInfo){
|
||||
public R deviceBar(@RequestBody TDeviceBo deviceInfo){
|
||||
|
||||
SysDeptBo dept = new SysDeptBo();
|
||||
dept.setParentId(deviceInfo.getZzjgdm());
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ public class DeviceStaticsVo implements Serializable {
|
|||
|
||||
private String zzjgdm;
|
||||
|
||||
private Integer co;
|
||||
private Long co;
|
||||
|
||||
private Integer onlineCo;
|
||||
private Long onlineCo;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
package org.dromara.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.system.domain.DeviceRedis;
|
||||
import org.dromara.system.domain.vo.DeviceRedisVo;
|
||||
|
|
@ -11,4 +14,6 @@ public interface DeviceRedisMapper extends BaseMapperPlus<DeviceRedis,DeviceRedi
|
|||
int insertBatch(List<DeviceRedis> list);
|
||||
|
||||
List<DeviceRedisVo> countByCondition(DeviceRedis redis);
|
||||
|
||||
Long countByzzjgdm(@Param(Constants.WRAPPER) Wrapper<DeviceRedis> queryWrapper);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,4 +69,21 @@ public class DeviceRedisSchedule {
|
|||
RedisUtils.batchInsert(deviceInfoDataMap,-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* 定时处理记录仪基本数据 10天没有更新的设备设置为删除状态
|
||||
* */
|
||||
@Scheduled(cron = "0 0 0/1 * * ?")
|
||||
public void deleteZfjly(){
|
||||
deviceService.deleteZfjly();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 定时删除设备状态为删除的定位信息和在线表
|
||||
* */
|
||||
@Scheduled(cron = "0 0 0/1 * * ?")
|
||||
public void removeRedis(){
|
||||
deviceService.deleteRedis();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ public interface IDeviceRedisService {
|
|||
int insertBatch(List<DeviceRedis> list);
|
||||
|
||||
List<DeviceRedisVo> countByCondition(DeviceRedis redis);
|
||||
|
||||
Long countByZzjgdm(DeviceRedis deviceRedis);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,4 +85,8 @@ public interface ITDeviceService {
|
|||
TDeviceVo queryByDeviceCode(String deviceCode);
|
||||
|
||||
List<TDeviceExportVo> selectDeviceExportList(TDeviceBo bo);
|
||||
|
||||
int deleteZfjly();
|
||||
|
||||
int deleteRedis();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
package org.dromara.system.service.impl;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.dromara.system.api.RemoteDataScopeService;
|
||||
import org.dromara.system.domain.DeviceRedis;
|
||||
import org.dromara.system.domain.TDevice;
|
||||
import org.dromara.system.domain.vo.DeviceRedisVo;
|
||||
import org.dromara.system.mapper.DeviceRedisMapper;
|
||||
import org.dromara.system.service.IDeviceRedisService;
|
||||
import org.dromara.system.service.ISysDeptService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
|
@ -23,6 +28,9 @@ public class DeviceRedisServiceImpl implements IDeviceRedisService {
|
|||
|
||||
private final DeviceRedisMapper baseMapper;
|
||||
|
||||
@DubboReference
|
||||
private RemoteDataScopeService remoteDataScopeService;
|
||||
|
||||
@Autowired
|
||||
SqlSessionFactory sqlSessionFactory;
|
||||
|
||||
|
|
@ -61,4 +69,13 @@ public class DeviceRedisServiceImpl implements IDeviceRedisService {
|
|||
public List<DeviceRedisVo> countByCondition(DeviceRedis redis) {
|
||||
return baseMapper.countByCondition(redis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countByZzjgdm(DeviceRedis deviceRedis) {
|
||||
LambdaQueryWrapper<DeviceRedis> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.ne(DeviceRedis::getDeviceType,"9");
|
||||
String depts = remoteDataScopeService.getDeptAndChild(deviceRedis.getZzjgdm());
|
||||
lqw.inSql(DeviceRedis::getZzjgdm,depts);
|
||||
return baseMapper.countByzzjgdm(lqw);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ public class SysDeptServiceImpl implements ISysDeptService {
|
|||
lqw.eq(StringUtils.isNotBlank(bo.getParentId()), SysDept::getParentId, bo.getParentId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getIsVisible()),SysDept::getIsVisible,bo.getIsVisible());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getFullName()), SysDept::getFullName, bo.getFullName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getIsVisible()),SysDept::getIsVisible,bo.getIsVisible());
|
||||
lqw.orderByAsc(SysDept::getAncestors);
|
||||
lqw.orderByAsc(SysDept::getParentId);
|
||||
lqw.orderByAsc(SysDept::getOrderNum);
|
||||
|
|
@ -105,7 +105,7 @@ public class SysDeptServiceImpl implements ISysDeptService {
|
|||
return TreeBuildUtils.build(depts, (dept, tree) ->
|
||||
tree.setId(dept.getDeptId())
|
||||
.setParentId(dept.getParentId())
|
||||
.setName(dept.getShortName())
|
||||
.setName(dept.getDeptName())
|
||||
.setWeight(dept.getOrderNum()));
|
||||
}
|
||||
|
||||
|
|
@ -290,10 +290,6 @@ public class SysDeptServiceImpl implements ISysDeptService {
|
|||
// 如果该部门是启用状态,则启用该部门的所有上级部门
|
||||
updateParentDeptStatusNormal(dept);
|
||||
}
|
||||
if ("0".equals(dept.getIsVisible())){ //如果隐藏该部门则其子部门全部隐藏
|
||||
updateDeptChildrenVisiable(dept.getDeptId(),"0");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.redis.utils.RedisUtils;
|
||||
import org.dromara.system.api.RemoteDataScopeService;
|
||||
import org.dromara.system.domain.DeviceRedis;
|
||||
import org.dromara.system.domain.vo.DeviceStaticsVo;
|
||||
import org.dromara.system.domain.vo.TDeviceExportVo;
|
||||
import org.dromara.system.mapper.DeviceRedisMapper;
|
||||
import org.dromara.system.service.ISysConfigService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.system.domain.bo.TDeviceBo;
|
||||
import org.dromara.system.domain.vo.TDeviceVo;
|
||||
|
|
@ -43,6 +47,12 @@ public class TDeviceServiceImpl implements ITDeviceService {
|
|||
private final TDeviceMapper baseMapper;
|
||||
|
||||
|
||||
private final ISysConfigService configService;
|
||||
|
||||
private final DeviceRedisMapper redisMapper;
|
||||
|
||||
private String lastRemoveTime;
|
||||
|
||||
@DubboReference
|
||||
private RemoteDataScopeService remoteDataScopeService;
|
||||
|
||||
|
|
@ -120,6 +130,53 @@ public class TDeviceServiceImpl implements ITDeviceService {
|
|||
return baseMapper.selectDeviceExportList(lqw);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 删除长时间未更新的执法记录仪
|
||||
* */
|
||||
@Override
|
||||
public int deleteZfjly() {
|
||||
String day = configService.selectConfigByKey("device.remove.day");
|
||||
LambdaQueryWrapper<TDevice> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.inSql(TDevice::getDeviceType,"'5','7','8'");
|
||||
lqw.eq(TDevice::getValid,"1");
|
||||
lqw.le(TDevice::getUpdateTime,DateUtil.offsetDay(new Date(),Integer.getInteger(day)));
|
||||
List<TDevice> list = baseMapper.selectList(lqw);
|
||||
for (TDevice device : list) {
|
||||
device.setValid(0);
|
||||
device.setUpdateTime(DateUtil.now());
|
||||
baseMapper.updateById(device);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 删除状态为删除的设备定位信息和存在t_device_redis的数据
|
||||
* */
|
||||
|
||||
@Override
|
||||
public int deleteRedis() {
|
||||
LambdaQueryWrapper<TDevice> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.gt(StringUtils.isNotBlank(lastRemoveTime),TDevice::getUpdateTime,lastRemoveTime);
|
||||
lqw.eq(TDevice::getValid,0);
|
||||
lqw.orderByDesc(TDevice::getUpdateTime);
|
||||
List<TDeviceVo> list = baseMapper.selectVoList(lqw);
|
||||
try {
|
||||
if (list.size()>0){
|
||||
lastRemoveTime = list.get(0).getUpdateTime();
|
||||
for (TDeviceVo deviceVo : list) {
|
||||
RedisUtils.del("online_users:"+deviceVo.getDeviceType()+":"+deviceVo.getDeviceCode());
|
||||
LambdaQueryWrapper<DeviceRedis> dqw = new LambdaQueryWrapper<>();
|
||||
dqw.eq(DeviceRedis::getDeviceCode,deviceVo.getDeviceCode());
|
||||
redisMapper.delete(dqw);
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TDeviceVo queryOne(TDeviceBo bo) {
|
||||
LambdaQueryWrapper<TDevice> lqw = buildQueryWrapper(bo);
|
||||
|
|
|
|||
|
|
@ -46,4 +46,9 @@
|
|||
WHERE d.dict_type = 'zd_device_type'
|
||||
</select>
|
||||
|
||||
<select id="countByzzjgdm" resultType="Long">
|
||||
select count(*) from t_device_redis
|
||||
${ew.getCustomSqlSegment}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@
|
|||
#{remark1},#{remark2},#{cardNum},#{createTime},#{updateTime})
|
||||
ON DUPLICATE KEY UPDATE
|
||||
police_no = values(police_no),police_name = values(police_name),phone_num = values(phone_num),
|
||||
car_num = values(car_num),valid = values(valid),remark1 = values(remark1),remark2 = values(remark2),card_num = values(card_num),
|
||||
update_time = now()
|
||||
car_num = values(car_num),valid = '1',remark1 = values(remark1),remark2 = values(remark2),card_num = values(card_num),
|
||||
update_time = values(update_time)
|
||||
</insert>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
Loading…
Reference in New Issue