| New file |
| | |
| | | package com.zy.asrs.controller; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.core.annotations.ManagerAuth; |
| | | import com.core.common.BaseRes; |
| | | import com.core.common.Cools; |
| | | import com.core.common.DateUtils; |
| | | import com.core.common.R; |
| | | import com.zy.asrs.entity.BasStationErrLog; |
| | | import com.zy.asrs.service.BasStationErrLogService; |
| | | import com.zy.common.web.BaseController; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | @RestController |
| | | public class BasStationErrLogController extends BaseController { |
| | | |
| | | @Autowired |
| | | private BasStationErrLogService basStationErrLogService; |
| | | |
| | | @RequestMapping(value = "/basStationErrLog/{id}/auth") |
| | | @ManagerAuth |
| | | public R get(@PathVariable("id") String id) { |
| | | return R.ok(basStationErrLogService.getById(String.valueOf(id))); |
| | | } |
| | | |
| | | @RequestMapping(value = "/basStationErrLog/list/auth") |
| | | @ManagerAuth |
| | | public R list(@RequestParam(defaultValue = "1") Integer curr, |
| | | @RequestParam(defaultValue = "10") Integer limit, |
| | | @RequestParam(required = false) String orderByField, |
| | | @RequestParam(required = false) String orderByType, |
| | | @RequestParam(required = false) String condition, |
| | | @RequestParam Map<String, Object> param) { |
| | | QueryWrapper<BasStationErrLog> wrapper = new QueryWrapper<>(); |
| | | excludeTrash(param); |
| | | convert(param, wrapper); |
| | | allLike(BasStationErrLog.class, param.keySet(), wrapper, condition); |
| | | if (!Cools.isEmpty(orderByField)) { |
| | | wrapper.orderBy(true, "asc".equals(orderByType), humpToLine(orderByField)); |
| | | } |
| | | return R.ok(basStationErrLogService.page(new Page<>(curr, limit), wrapper)); |
| | | } |
| | | |
| | | private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper) { |
| | | for (Map.Entry<String, Object> entry : map.entrySet()) { |
| | | String val = String.valueOf(entry.getValue()); |
| | | String column = humpToLine(entry.getKey()); |
| | | if (val.contains(RANGE_TIME_LINK)) { |
| | | String[] dates = val.split(RANGE_TIME_LINK); |
| | | wrapper.ge(column, DateUtils.convert(dates[0])); |
| | | wrapper.le(column, DateUtils.convert(dates[1])); |
| | | } else { |
| | | wrapper.like(column, val); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @RequestMapping(value = "/basStationErrLog/add/auth") |
| | | @ManagerAuth |
| | | public R add(BasStationErrLog basStationErrLog) { |
| | | basStationErrLogService.save(basStationErrLog); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @RequestMapping(value = "/basStationErrLog/update/auth") |
| | | @ManagerAuth |
| | | public R update(BasStationErrLog basStationErrLog) { |
| | | if (Cools.isEmpty(basStationErrLog) || basStationErrLog.getId() == null) { |
| | | return R.error(); |
| | | } |
| | | basStationErrLogService.updateById(basStationErrLog); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @RequestMapping(value = "/basStationErrLog/delete/auth") |
| | | @ManagerAuth |
| | | public R delete(@RequestParam(value = "ids[]") Integer[] ids) { |
| | | for (Integer id : ids) { |
| | | basStationErrLogService.removeById(id); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | @RequestMapping(value = "/basStationErrLog/export/auth") |
| | | @ManagerAuth |
| | | public R export(@RequestBody JSONObject param) { |
| | | QueryWrapper<BasStationErrLog> wrapper = new QueryWrapper<>(); |
| | | List<String> fields = JSONObject.parseArray(param.getJSONArray("fields").toJSONString(), String.class); |
| | | Map<String, Object> map = excludeTrash(param.getJSONObject("basStationErrLog")); |
| | | convert(map, wrapper); |
| | | List<BasStationErrLog> list = basStationErrLogService.list(wrapper); |
| | | return R.ok(exportSupport(list, fields)); |
| | | } |
| | | |
| | | @RequestMapping(value = "/basStationErrLogQuery/auth") |
| | | @ManagerAuth |
| | | public R query(String condition) { |
| | | QueryWrapper<BasStationErrLog> wrapper = new QueryWrapper<>(); |
| | | wrapper.like("id", condition); |
| | | Page<BasStationErrLog> page = basStationErrLogService.page(new Page<>(0, 10), wrapper); |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (BasStationErrLog basStationErrLog : page.getRecords()) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("id", basStationErrLog.getId()); |
| | | map.put("value", basStationErrLog.getId()); |
| | | result.add(map); |
| | | } |
| | | return R.ok(result); |
| | | } |
| | | |
| | | @RequestMapping(value = "/basStationErrLog/check/column/auth") |
| | | @ManagerAuth |
| | | public R query(@RequestBody JSONObject param) { |
| | | QueryWrapper<BasStationErrLog> wrapper = new QueryWrapper<BasStationErrLog>() |
| | | .eq(humpToLine(String.valueOf(param.get("key"))), param.get("val")); |
| | | if (null != basStationErrLogService.getOne(wrapper)) { |
| | | return R.parse(BaseRes.REPEAT).add(getComment(BasStationErrLog.class, String.valueOf(param.get("key")))); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | } |
| | |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.HashSet; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | @RestController |
| | | public class WrkMastLogController extends BaseController { |
| | | |
| | | private static final Set<String> EXACT_SEARCH_COLUMNS = new HashSet<>(Arrays.asList( |
| | | "wrk_sts", |
| | | "io_type", |
| | | "sta_no", |
| | | "source_sta_no" |
| | | )); |
| | | |
| | | @Autowired |
| | | private WrkMastLogService wrkMastLogService; |
| | |
| | | wrapper.ge(column, DateUtils.convert(dates[0])); |
| | | wrapper.le(column, DateUtils.convert(dates[1])); |
| | | } else { |
| | | if ("manu_type".equals(column)) { |
| | | wrapper.like(column, val); |
| | | } else { |
| | | if (EXACT_SEARCH_COLUMNS.contains(column)) { |
| | | wrapper.eq(column, val); |
| | | } else { |
| | | wrapper.like(column, val); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | package com.zy.asrs.entity; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.IdType; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableId; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import com.core.common.Cools; |
| | | import com.core.common.SpringUtils; |
| | | import com.zy.asrs.service.BasStationService; |
| | | import com.zy.asrs.service.BasWrkIotypeService; |
| | | import com.zy.asrs.service.BasWrkStatusService; |
| | | import com.zy.system.entity.User; |
| | | import com.zy.system.service.UserService; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.io.Serializable; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | |
| | | @Data |
| | | @TableName("asr_bas_station_err_log") |
| | | public class BasStationErrLog implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @ApiModelProperty(value = "编号") |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | @ApiModelProperty(value = "工作号") |
| | | @TableField("wrk_no") |
| | | private Integer wrkNo; |
| | | |
| | | @ApiModelProperty(value = "发生时间") |
| | | @TableField("start_time") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date startTime; |
| | | |
| | | @ApiModelProperty(value = "结束时间") |
| | | @TableField("end_time") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date endTime; |
| | | |
| | | @ApiModelProperty(value = "工作状态") |
| | | @TableField("wrk_sts") |
| | | private Long wrkSts; |
| | | |
| | | @ApiModelProperty(value = "入出库类型") |
| | | @TableField("io_type") |
| | | private Integer ioType; |
| | | |
| | | @ApiModelProperty(value = "站点号") |
| | | @TableField("station_id") |
| | | private Integer stationId; |
| | | |
| | | @ApiModelProperty(value = "目标库位") |
| | | @TableField("loc_no") |
| | | private String locNo; |
| | | |
| | | @ApiModelProperty(value = "目标站") |
| | | @TableField("sta_no") |
| | | private Integer staNo; |
| | | |
| | | @ApiModelProperty(value = "源站") |
| | | @TableField("source_sta_no") |
| | | private Integer sourceStaNo; |
| | | |
| | | @ApiModelProperty(value = "源库位") |
| | | @TableField("source_loc_no") |
| | | private String sourceLocNo; |
| | | |
| | | @ApiModelProperty(value = "条码") |
| | | private String barcode; |
| | | |
| | | @ApiModelProperty(value = "异常码") |
| | | @TableField("err_code") |
| | | private Integer errCode; |
| | | |
| | | @ApiModelProperty(value = "异常") |
| | | private String error; |
| | | |
| | | @ApiModelProperty(value = "异常情况 1: 未处理 2: 已修复") |
| | | private Integer status; |
| | | |
| | | @ApiModelProperty(value = "添加时间") |
| | | @TableField("create_time") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date createTime; |
| | | |
| | | @ApiModelProperty(value = "添加人员") |
| | | @TableField("create_by") |
| | | private Long createBy; |
| | | |
| | | @ApiModelProperty(value = "修改时间") |
| | | @TableField("update_time") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date updateTime; |
| | | |
| | | @ApiModelProperty(value = "修改人员") |
| | | @TableField("update_by") |
| | | private Long updateBy; |
| | | |
| | | @ApiModelProperty(value = "备注") |
| | | private String memo; |
| | | |
| | | @ApiModelProperty(value = "系统状态数据") |
| | | @TableField("system_status") |
| | | private String systemStatus; |
| | | |
| | | public String getStartTime$() { |
| | | return formatDate(startTime); |
| | | } |
| | | |
| | | public String getEndTime$() { |
| | | return formatDate(endTime); |
| | | } |
| | | |
| | | public String getWrkSts$() { |
| | | if (wrkSts == null) { |
| | | return null; |
| | | } |
| | | BasWrkStatusService service = SpringUtils.getBean(BasWrkStatusService.class); |
| | | if (service == null) { |
| | | return String.valueOf(wrkSts); |
| | | } |
| | | BasWrkStatus basWrkStatus = service.getById(wrkSts); |
| | | return basWrkStatus == null ? String.valueOf(wrkSts) : basWrkStatus.getWrkDesc(); |
| | | } |
| | | |
| | | public String getIoType$() { |
| | | if (ioType == null) { |
| | | return null; |
| | | } |
| | | BasWrkIotypeService service = SpringUtils.getBean(BasWrkIotypeService.class); |
| | | if (service == null) { |
| | | return String.valueOf(ioType); |
| | | } |
| | | BasWrkIotype basWrkIotype = service.getById(ioType); |
| | | return basWrkIotype == null ? String.valueOf(ioType) : basWrkIotype.getIoDesc(); |
| | | } |
| | | |
| | | public String getStationLabel$() { |
| | | if (stationId == null) { |
| | | return null; |
| | | } |
| | | BasStationService service = SpringUtils.getBean(BasStationService.class); |
| | | if (service == null) { |
| | | return String.valueOf(stationId); |
| | | } |
| | | BasStation basStation = service.getById(stationId); |
| | | if (basStation == null || Cools.isEmpty(basStation.getStationAlias())) { |
| | | return String.valueOf(stationId); |
| | | } |
| | | return stationId + " - " + basStation.getStationAlias(); |
| | | } |
| | | |
| | | public String getStatus$() { |
| | | if (status == null) { |
| | | return null; |
| | | } |
| | | switch (status) { |
| | | case 1: |
| | | return "未处理"; |
| | | case 2: |
| | | return "已修复"; |
| | | default: |
| | | return String.valueOf(status); |
| | | } |
| | | } |
| | | |
| | | public String getCreateTime$() { |
| | | return formatDate(createTime); |
| | | } |
| | | |
| | | public String getCreateBy$() { |
| | | if (createBy == null) { |
| | | return null; |
| | | } |
| | | UserService service = SpringUtils.getBean(UserService.class); |
| | | if (service == null) { |
| | | return String.valueOf(createBy); |
| | | } |
| | | User user = service.getById(createBy); |
| | | return user == null ? String.valueOf(createBy) : String.valueOf(user.getId()); |
| | | } |
| | | |
| | | public String getUpdateTime$() { |
| | | return formatDate(updateTime); |
| | | } |
| | | |
| | | public String getUpdateBy$() { |
| | | if (updateBy == null) { |
| | | return null; |
| | | } |
| | | UserService service = SpringUtils.getBean(UserService.class); |
| | | if (service == null) { |
| | | return String.valueOf(updateBy); |
| | | } |
| | | User user = service.getById(updateBy); |
| | | return user == null ? String.valueOf(updateBy) : String.valueOf(user.getId()); |
| | | } |
| | | |
| | | private String formatDate(Date value) { |
| | | if (Cools.isEmpty(value)) { |
| | | return ""; |
| | | } |
| | | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(value); |
| | | } |
| | | } |
| | |
| | | @TableField("rgv_fault_duration_ms") |
| | | private Long rgvFaultDurationMs; |
| | | |
| | | @ApiModelProperty(value = "输送站点故障次数") |
| | | @TableField("station_fault_count") |
| | | private Integer stationFaultCount; |
| | | |
| | | @ApiModelProperty(value = "输送站点故障耗时毫秒") |
| | | @TableField("station_fault_duration_ms") |
| | | private Long stationFaultDurationMs; |
| | | |
| | | @ApiModelProperty(value = "数据完整性") |
| | | @TableField("metric_completeness") |
| | | private String metricCompleteness; |
| New file |
| | |
| | | package com.zy.asrs.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.zy.asrs.entity.BasStationErrLog; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | @Mapper |
| | | public interface BasStationErrLogMapper extends BaseMapper<BasStationErrLog> { |
| | | } |
| New file |
| | |
| | | package com.zy.asrs.service; |
| | | |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import com.zy.asrs.entity.BasStationErrLog; |
| | | |
| | | public interface BasStationErrLogService extends IService<BasStationErrLog> { |
| | | } |
| New file |
| | |
| | | package com.zy.asrs.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.zy.asrs.entity.BasStationErrLog; |
| | | import com.zy.asrs.mapper.BasStationErrLogMapper; |
| | | import com.zy.asrs.service.BasStationErrLogService; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | @Service("basStationErrLogService") |
| | | public class BasStationErrLogServiceImpl extends ServiceImpl<BasStationErrLogMapper, BasStationErrLog> implements BasStationErrLogService { |
| | | } |
| | |
| | | private final BasCrnpErrLogService basCrnpErrLogService; |
| | | private final BasDualCrnpErrLogService basDualCrnpErrLogService; |
| | | private final BasRgvErrLogService basRgvErrLogService; |
| | | private final BasStationErrLogService basStationErrLogService; |
| | | private final BasStationService basStationService; |
| | | private final BasWrkStatusService basWrkStatusService; |
| | | private final WrkMastService wrkMastService; |
| | |
| | | BasCrnpErrLogService basCrnpErrLogService, |
| | | BasDualCrnpErrLogService basDualCrnpErrLogService, |
| | | BasRgvErrLogService basRgvErrLogService, |
| | | BasStationErrLogService basStationErrLogService, |
| | | BasStationService basStationService, |
| | | BasWrkStatusService basWrkStatusService, |
| | | WrkMastService wrkMastService) { |
| | |
| | | this.basCrnpErrLogService = basCrnpErrLogService; |
| | | this.basDualCrnpErrLogService = basDualCrnpErrLogService; |
| | | this.basRgvErrLogService = basRgvErrLogService; |
| | | this.basStationErrLogService = basStationErrLogService; |
| | | this.basStationService = basStationService; |
| | | this.basWrkStatusService = basWrkStatusService; |
| | | this.wrkMastService = wrkMastService; |
| | |
| | | entity.setDualCrnFaultDurationMs(defaultLong(entity.getDualCrnFaultDurationMs())); |
| | | entity.setRgvFaultCount(defaultInt(entity.getRgvFaultCount())); |
| | | entity.setRgvFaultDurationMs(defaultLong(entity.getRgvFaultDurationMs())); |
| | | entity.setStationFaultCount(defaultInt(entity.getStationFaultCount())); |
| | | entity.setStationFaultDurationMs(defaultLong(entity.getStationFaultDurationMs())); |
| | | entity.setMetricCompleteness(METRIC_PARTIAL); |
| | | entity.setUpdateTime(now); |
| | | this.saveOrUpdate(entity); |
| | |
| | | entity.setDualCrnFaultDurationMs(faultSummary.dualDurationMs); |
| | | entity.setRgvFaultCount(faultSummary.rgvCount); |
| | | entity.setRgvFaultDurationMs(faultSummary.rgvDurationMs); |
| | | entity.setStationFaultCount(faultSummary.stationCount); |
| | | entity.setStationFaultDurationMs(faultSummary.stationDurationMs); |
| | | entity.setMetricCompleteness(resolveMetricCompleteness(wrkMast, entity)); |
| | | entity.setUpdateTime(time); |
| | | this.saveOrUpdate(entity); |
| | |
| | | addDeviceFaultDuration(durationMap, "单堆垛机", item.getCrnNo(), item.getCrnFaultDurationMs()); |
| | | addDeviceFaultDuration(durationMap, "双工位堆垛机", item.getDualCrnNo(), item.getDualCrnFaultDurationMs()); |
| | | addDeviceFaultDuration(durationMap, "RGV", item.getRgvNo(), item.getRgvFaultDurationMs()); |
| | | addDeviceFaultDuration(durationMap, "输送站点", null, item.getStationFaultDurationMs()); |
| | | } |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | durationMap.forEach((name, durationMs) -> result.add(slice(name, durationMs))); |
| | |
| | | target.put("crnFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getCrnFaultDurationMs())); |
| | | target.put("dualCrnFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getDualCrnFaultDurationMs())); |
| | | target.put("rgvFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getRgvFaultDurationMs())); |
| | | target.put("stationFaultDurationMs", analysis == null ? 0L : defaultLong(analysis.getStationFaultDurationMs())); |
| | | target.put("metricCompleteness", analysis == null ? METRIC_PARTIAL : analysis.getMetricCompleteness()); |
| | | } |
| | | |
| | |
| | | List<BasCrnpErrLog> crnList = basCrnpErrLogService.list(new QueryWrapper<BasCrnpErrLog>().eq("wrk_no", wrkNo)); |
| | | List<BasDualCrnpErrLog> dualList = basDualCrnpErrLogService.list(new QueryWrapper<BasDualCrnpErrLog>().eq("wrk_no", wrkNo)); |
| | | List<BasRgvErrLog> rgvList = basRgvErrLogService.list(new QueryWrapper<BasRgvErrLog>().eq("task_no", wrkNo)); |
| | | List<BasStationErrLog> stationList = basStationErrLogService.list(new QueryWrapper<BasStationErrLog>().eq("wrk_no", wrkNo)); |
| | | summary.crnCount = crnList.size(); |
| | | summary.crnDurationMs = durationMs(crnList, finishTime); |
| | | summary.dualCount = dualList.size(); |
| | | summary.dualDurationMs = durationMs(dualList, finishTime); |
| | | summary.rgvCount = rgvList.size(); |
| | | summary.rgvDurationMs = durationMs(rgvList, finishTime); |
| | | summary.totalCount = summary.crnCount + summary.dualCount + summary.rgvCount; |
| | | summary.totalDurationMs = summary.crnDurationMs + summary.dualDurationMs + summary.rgvDurationMs; |
| | | summary.stationCount = stationList.size(); |
| | | summary.stationDurationMs = durationMs(stationList, finishTime); |
| | | summary.totalCount = summary.crnCount + summary.dualCount + summary.rgvCount + summary.stationCount; |
| | | summary.totalDurationMs = summary.crnDurationMs + summary.dualDurationMs + summary.rgvDurationMs + summary.stationDurationMs; |
| | | summary.hasFault = summary.totalCount > 0 ? 1 : 0; |
| | | return summary; |
| | | } |
| | |
| | | } else if (item instanceof BasRgvErrLog) { |
| | | startTime = ((BasRgvErrLog) item).getStartTime(); |
| | | endTime = ((BasRgvErrLog) item).getEndTime(); |
| | | } else if (item instanceof BasStationErrLog) { |
| | | startTime = ((BasStationErrLog) item).getStartTime(); |
| | | endTime = ((BasStationErrLog) item).getEndTime(); |
| | | } |
| | | if (startTime == null) { |
| | | continue; |
| | |
| | | private long dualDurationMs; |
| | | private int rgvCount; |
| | | private long rgvDurationMs; |
| | | private int stationCount; |
| | | private long stationDurationMs; |
| | | } |
| | | |
| | | private static class BucketAccumulator { |
| | |
| | | DEVICE_ERR_ACTIVE_RGV("device_err_active_rgv_"), |
| | | DEVICE_ERR_ACTIVE_CRN("device_err_active_crn_"), |
| | | DEVICE_ERR_ACTIVE_DUAL_CRN("device_err_active_dual_crn_"), |
| | | DEVICE_ERR_ACTIVE_STATION("device_err_active_station_"), |
| | | DEVICE_STATION_MOVE_RESET("device_station_move_reset_"), |
| | | |
| | | CRN_SEND_COMMAND_LOCK("crn_send_command_lock_"), |
| | |
| | | import com.zy.core.network.DeviceConnectPool; |
| | | import com.zy.core.thread.StationThread; |
| | | import com.zy.core.thread.support.RecentStationArrivalTracker; |
| | | import com.zy.core.thread.support.StationErrLogSupport; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.core.common.DateUtils; |
| | | import com.core.common.SpringUtils; |
| | |
| | | } |
| | | |
| | | OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); |
| | | StationErrLogSupport.sync(deviceConfig, redisUtil, statusList); |
| | | |
| | | if (System.currentTimeMillis() - deviceDataLogTime > deviceLogCollectTime) { |
| | | //保存数据记录 |
| | |
| | | import com.zy.core.network.ZyStationConnectDriver; |
| | | import com.zy.core.network.entity.ZyStationStatusEntity; |
| | | import com.zy.core.thread.support.RecentStationArrivalTracker; |
| | | import com.zy.core.thread.support.StationErrLogSupport; |
| | | import com.zy.core.utils.DeviceLogRedisKeyBuilder; |
| | | import lombok.Data; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | } |
| | | |
| | | OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功", DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); |
| | | StationErrLogSupport.sync(deviceConfig, redisUtil, statusList); |
| | | |
| | | if (System.currentTimeMillis() - deviceDataLogTime > deviceLogCollectTime) { |
| | | DeviceDataLog deviceDataLog = new DeviceDataLog(); |
| | |
| | | import com.zy.core.network.entity.ZyStationStatusEntity; |
| | | import com.zy.core.thread.impl.v5.StationMoveSegmentExecutor; |
| | | import com.zy.core.thread.support.RecentStationArrivalTracker; |
| | | import com.zy.core.thread.support.StationErrLogSupport; |
| | | import com.zy.core.utils.DeviceLogRedisKeyBuilder; |
| | | import com.zy.system.entity.Config; |
| | | import com.zy.system.service.ConfigService; |
| | |
| | | } |
| | | |
| | | OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功", DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); |
| | | StationErrLogSupport.sync(deviceConfig, redisUtil, statusList); |
| | | |
| | | if (System.currentTimeMillis() - deviceDataLogTime > deviceLogCollectTime) { |
| | | DeviceDataLog deviceDataLog = new DeviceDataLog(); |
| | |
| | | import com.zy.core.network.ZyStationConnectDriver; |
| | | import com.zy.core.network.entity.ZyStationStatusEntity; |
| | | import com.zy.core.thread.support.RecentStationArrivalTracker; |
| | | import com.zy.core.thread.support.StationErrLogSupport; |
| | | import com.zy.core.utils.DeviceLogRedisKeyBuilder; |
| | | |
| | | import java.text.MessageFormat; |
| | |
| | | |
| | | OutputQueue.DEVP.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功", |
| | | DateUtils.convert(new Date()), deviceConfig.getDeviceNo())); |
| | | StationErrLogSupport.sync(deviceConfig, redisUtil, statusList); |
| | | |
| | | if (System.currentTimeMillis() - deviceDataLogTime > deviceLogCollectTime) { |
| | | DeviceDataLog deviceDataLog = new DeviceDataLog(); |
| New file |
| | |
| | | package com.zy.core.thread.support; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.core.common.Cools; |
| | | import com.core.common.SpringUtils; |
| | | import com.zy.asrs.entity.BasStationErrLog; |
| | | import com.zy.asrs.entity.DeviceConfig; |
| | | import com.zy.asrs.entity.WrkMast; |
| | | import com.zy.asrs.service.BasStationErrLogService; |
| | | import com.zy.asrs.service.WrkMastService; |
| | | import com.zy.common.utils.RedisUtil; |
| | | import com.zy.core.enums.RedisKeyType; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | public final class StationErrLogSupport { |
| | | |
| | | private StationErrLogSupport() { |
| | | } |
| | | |
| | | public static void sync(DeviceConfig deviceConfig, RedisUtil redisUtil, List<StationProtocol> statusList) { |
| | | if (redisUtil == null || statusList == null || statusList.isEmpty()) { |
| | | return; |
| | | } |
| | | try { |
| | | BasStationErrLogService errLogService = SpringUtils.getBean(BasStationErrLogService.class); |
| | | if (errLogService == null) { |
| | | return; |
| | | } |
| | | WrkMastService wrkMastService = null; |
| | | try { |
| | | wrkMastService = SpringUtils.getBean(WrkMastService.class); |
| | | } catch (Exception ignore) { |
| | | } |
| | | for (StationProtocol stationProtocol : statusList) { |
| | | syncOne(deviceConfig, redisUtil, errLogService, wrkMastService, stationProtocol); |
| | | } |
| | | } catch (Exception ignore) { |
| | | } |
| | | } |
| | | |
| | | private static void syncOne(DeviceConfig deviceConfig, |
| | | RedisUtil redisUtil, |
| | | BasStationErrLogService errLogService, |
| | | WrkMastService wrkMastService, |
| | | StationProtocol stationProtocol) { |
| | | if (stationProtocol == null || stationProtocol.getStationId() == null) { |
| | | return; |
| | | } |
| | | String errFlagKey = RedisKeyType.DEVICE_ERR_ACTIVE_STATION.key + stationProtocol.getStationId(); |
| | | Object active = redisUtil.get(errFlagKey); |
| | | Date now = new Date(); |
| | | if (hasError(stationProtocol)) { |
| | | if (active != null) { |
| | | return; |
| | | } |
| | | BasStationErrLog log = new BasStationErrLog(); |
| | | Integer wrkNo = stationProtocol.getTaskNo(); |
| | | if (wrkNo != null && wrkNo > 0) { |
| | | log.setWrkNo(wrkNo); |
| | | } |
| | | log.setStartTime(now); |
| | | log.setStationId(stationProtocol.getStationId()); |
| | | log.setStaNo(stationProtocol.getTargetStaNo()); |
| | | log.setBarcode(stationProtocol.getBarcode()); |
| | | log.setErrCode(normalizeErrCode(stationProtocol.getError())); |
| | | log.setError(resolveError(stationProtocol)); |
| | | log.setStatus(1); |
| | | log.setCreateTime(now); |
| | | log.setSystemStatus(buildSystemStatus(deviceConfig, stationProtocol)); |
| | | fillWorkContext(log, wrkMastService, wrkNo); |
| | | errLogService.save(log); |
| | | if (log.getId() != null) { |
| | | redisUtil.set(errFlagKey, log.getId(), 60 * 60 * 24); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | if (active == null) { |
| | | return; |
| | | } |
| | | BasStationErrLog update = new BasStationErrLog(); |
| | | update.setId(Long.valueOf(String.valueOf(active))); |
| | | update.setEndTime(now); |
| | | update.setStatus(2); |
| | | update.setUpdateTime(now); |
| | | errLogService.updateById(update); |
| | | redisUtil.del(errFlagKey); |
| | | } |
| | | |
| | | private static void fillWorkContext(BasStationErrLog log, WrkMastService wrkMastService, Integer wrkNo) { |
| | | if (wrkMastService == null || wrkNo == null || wrkNo <= 0) { |
| | | return; |
| | | } |
| | | WrkMast wrkMast = wrkMastService.selectByWorkNo(wrkNo); |
| | | if (wrkMast == null) { |
| | | return; |
| | | } |
| | | log.setWrkSts(wrkMast.getWrkSts()); |
| | | log.setIoType(wrkMast.getIoType()); |
| | | log.setLocNo(wrkMast.getLocNo()); |
| | | log.setSourceStaNo(wrkMast.getSourceStaNo()); |
| | | log.setSourceLocNo(wrkMast.getSourceLocNo()); |
| | | if (log.getStaNo() == null) { |
| | | log.setStaNo(wrkMast.getStaNo()); |
| | | } |
| | | if (Cools.isEmpty(log.getBarcode())) { |
| | | log.setBarcode(wrkMast.getBarcode()); |
| | | } |
| | | } |
| | | |
| | | private static boolean hasError(StationProtocol stationProtocol) { |
| | | return normalizeErrCode(stationProtocol.getError()) != null || !Cools.isEmpty(stationProtocol.getErrorMsg()); |
| | | } |
| | | |
| | | private static Integer normalizeErrCode(Integer errCode) { |
| | | return errCode != null && errCode > 0 ? errCode : null; |
| | | } |
| | | |
| | | private static String resolveError(StationProtocol stationProtocol) { |
| | | if (!Cools.isEmpty(stationProtocol.getErrorMsg())) { |
| | | return stationProtocol.getErrorMsg(); |
| | | } |
| | | Integer errCode = normalizeErrCode(stationProtocol.getError()); |
| | | return errCode == null ? null : "站点报警"; |
| | | } |
| | | |
| | | private static String buildSystemStatus(DeviceConfig deviceConfig, StationProtocol stationProtocol) { |
| | | JSONObject snapshot = new JSONObject(); |
| | | if (deviceConfig != null) { |
| | | snapshot.put("deviceNo", deviceConfig.getDeviceNo()); |
| | | } |
| | | snapshot.put("stationProtocol", stationProtocol); |
| | | return snapshot.toJSONString(); |
| | | } |
| | | } |
| | |
| | | 双工位堆垛机异常日志=Dual-station Crane Error Log |
| | | RGV命令日志=RGV Command Log |
| | | RGV异常日志=RGV Error Log |
| | | 输送站点异常日志=Conveyor Station Error Log |
| | | 输送站点命令日志=Conveyor Station Command Log |
| | | 系统配置=System Configuration |
| | | 新增三方接口统计=Add Third-party API Statistics |
| | |
| | | 修改RGV命令日志=Edit RGV Command Log |
| | | 新增RGV异常日志=Add RGV Error Log |
| | | 修改RGV异常日志=Edit RGV Error Log |
| | | 新增输送站点异常日志=Add Conveyor Station Error Log |
| | | 修改输送站点异常日志=Edit Conveyor Station Error Log |
| | | 新增输送站点命令日志=Add Conveyor Station Command Log |
| | | 修改输送站点命令日志=Edit Conveyor Station Command Log |
| | | 新增系统配置=Add System Configuration |
| | |
| | | 双工位堆垛机异常日志=双工位堆垛机异常日志 |
| | | RGV命令日志=RGV命令日志 |
| | | RGV异常日志=RGV异常日志 |
| | | 输送站点异常日志=输送站点异常日志 |
| | | 输送站点命令日志=输送站点命令日志 |
| | | 系统配置=系统配置 |
| | | 新增三方接口统计=新增三方接口统计 |
| | |
| | | 修改RGV命令日志=修改RGV命令日志 |
| | | 新增RGV异常日志=新增RGV异常日志 |
| | | 修改RGV异常日志=修改RGV异常日志 |
| | | 新增输送站点异常日志=新增输送站点异常日志 |
| | | 修改输送站点异常日志=修改输送站点异常日志 |
| | | 新增输送站点命令日志=新增输送站点命令日志 |
| | | 修改输送站点命令日志=修改输送站点命令日志 |
| | | 新增系统配置=新增系统配置 |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.zy.asrs.mapper.BasStationErrLogMapper"> |
| | | |
| | | <resultMap id="BaseResultMap" type="com.zy.asrs.entity.BasStationErrLog"> |
| | | <id column="id" property="id" /> |
| | | <result column="wrk_no" property="wrkNo" /> |
| | | <result column="start_time" property="startTime" /> |
| | | <result column="end_time" property="endTime" /> |
| | | <result column="wrk_sts" property="wrkSts" /> |
| | | <result column="io_type" property="ioType" /> |
| | | <result column="station_id" property="stationId" /> |
| | | <result column="loc_no" property="locNo" /> |
| | | <result column="sta_no" property="staNo" /> |
| | | <result column="source_sta_no" property="sourceStaNo" /> |
| | | <result column="source_loc_no" property="sourceLocNo" /> |
| | | <result column="barcode" property="barcode" /> |
| | | <result column="err_code" property="errCode" /> |
| | | <result column="error" property="error" /> |
| | | <result column="status" property="status" /> |
| | | <result column="create_time" property="createTime" /> |
| | | <result column="create_by" property="createBy" /> |
| | | <result column="update_time" property="updateTime" /> |
| | | <result column="update_by" property="updateBy" /> |
| | | <result column="memo" property="memo" /> |
| | | <result column="system_status" property="systemStatus" /> |
| | | </resultMap> |
| | | |
| | | </mapper> |
| New file |
| | |
| | | CREATE TABLE IF NOT EXISTS `asr_bas_station_err_log` ( |
| | | `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', |
| | | `wrk_no` int DEFAULT NULL COMMENT '工作号', |
| | | `start_time` datetime DEFAULT NULL COMMENT '发生时间', |
| | | `end_time` datetime DEFAULT NULL COMMENT '结束时间', |
| | | `wrk_sts` bigint DEFAULT NULL COMMENT '工作状态', |
| | | `io_type` int DEFAULT NULL COMMENT '入出库类型', |
| | | `station_id` int DEFAULT NULL COMMENT '站点号', |
| | | `loc_no` varchar(64) DEFAULT NULL COMMENT '目标库位', |
| | | `sta_no` int DEFAULT NULL COMMENT '目标站', |
| | | `source_sta_no` int DEFAULT NULL COMMENT '源站', |
| | | `source_loc_no` varchar(64) DEFAULT NULL COMMENT '源库位', |
| | | `barcode` varchar(128) DEFAULT NULL COMMENT '条码', |
| | | `err_code` int DEFAULT NULL COMMENT '异常码', |
| | | `error` text COMMENT '异常描述', |
| | | `status` int DEFAULT NULL COMMENT '异常情况 1未处理 2已修复', |
| | | `create_time` datetime DEFAULT NULL COMMENT '创建时间', |
| | | `create_by` bigint DEFAULT NULL COMMENT '创建人', |
| | | `update_time` datetime DEFAULT NULL COMMENT '更新时间', |
| | | `update_by` bigint DEFAULT NULL COMMENT '更新人', |
| | | `memo` varchar(255) DEFAULT NULL COMMENT '备注', |
| | | `system_status` longtext COMMENT '系统状态快照', |
| | | PRIMARY KEY (`id`), |
| | | KEY `idx_station_err_log_wrk_no` (`wrk_no`), |
| | | KEY `idx_station_err_log_station_id` (`station_id`), |
| | | KEY `idx_station_err_log_status` (`status`), |
| | | KEY `idx_station_err_log_start_time` (`start_time`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='输送站点异常日志'; |
| | | |
| | | SET @wrk_analysis_table_exists := ( |
| | | SELECT COUNT(*) |
| | | FROM `information_schema`.`TABLES` |
| | | WHERE `TABLE_SCHEMA` = DATABASE() |
| | | AND `TABLE_NAME` = 'asr_wrk_analysis' |
| | | ); |
| | | |
| | | SET @station_fault_count_exists := ( |
| | | SELECT COUNT(*) |
| | | FROM `information_schema`.`COLUMNS` |
| | | WHERE `TABLE_SCHEMA` = DATABASE() |
| | | AND `TABLE_NAME` = 'asr_wrk_analysis' |
| | | AND `COLUMN_NAME` = 'station_fault_count' |
| | | ); |
| | | |
| | | SET @station_fault_duration_exists := ( |
| | | SELECT COUNT(*) |
| | | FROM `information_schema`.`COLUMNS` |
| | | WHERE `TABLE_SCHEMA` = DATABASE() |
| | | AND `TABLE_NAME` = 'asr_wrk_analysis' |
| | | AND `COLUMN_NAME` = 'station_fault_duration_ms' |
| | | ); |
| | | |
| | | SET @sql_station_fault_count := IF( |
| | | @wrk_analysis_table_exists = 1 AND @station_fault_count_exists = 0, |
| | | 'ALTER TABLE `asr_wrk_analysis` ADD COLUMN `station_fault_count` int DEFAULT 0 COMMENT ''输送站点故障次数'' AFTER `rgv_fault_duration_ms`', |
| | | 'SELECT 1' |
| | | ); |
| | | PREPARE stmt_station_fault_count FROM @sql_station_fault_count; |
| | | EXECUTE stmt_station_fault_count; |
| | | DEALLOCATE PREPARE stmt_station_fault_count; |
| | | |
| | | SET @sql_station_fault_duration := IF( |
| | | @wrk_analysis_table_exists = 1 AND @station_fault_duration_exists = 0, |
| | | 'ALTER TABLE `asr_wrk_analysis` ADD COLUMN `station_fault_duration_ms` bigint DEFAULT 0 COMMENT ''输送站点故障耗时毫秒'' AFTER `station_fault_count`', |
| | | 'SELECT 1' |
| | | ); |
| | | PREPARE stmt_station_fault_duration FROM @sql_station_fault_duration; |
| | | EXECUTE stmt_station_fault_duration; |
| | | DEALLOCATE PREPARE stmt_station_fault_duration; |
| | | |
| | | UPDATE `asr_wrk_analysis` a |
| | | LEFT JOIN ( |
| | | SELECT |
| | | e.`wrk_no`, |
| | | COUNT(*) AS `fault_count`, |
| | | SUM( |
| | | CASE |
| | | WHEN e.`start_time` IS NULL THEN 0 |
| | | ELSE GREATEST( |
| | | TIMESTAMPDIFF( |
| | | MICROSECOND, |
| | | e.`start_time`, |
| | | COALESCE(e.`end_time`, wl.`modi_time`, wl.`io_time`, wl.`appe_time`, e.`start_time`) |
| | | ), |
| | | 0 |
| | | ) DIV 1000 |
| | | END |
| | | ) AS `fault_duration_ms` |
| | | FROM `asr_bas_station_err_log` e |
| | | LEFT JOIN `asr_wrk_mast_log` wl ON wl.`wrk_no` = e.`wrk_no` |
| | | GROUP BY e.`wrk_no` |
| | | ) s ON s.`wrk_no` = a.`wrk_no` |
| | | SET a.`station_fault_count` = COALESCE(s.`fault_count`, 0), |
| | | a.`station_fault_duration_ms` = COALESCE(s.`fault_duration_ms`, 0), |
| | | a.`fault_count` = COALESCE(a.`crn_fault_count`, 0) |
| | | + COALESCE(a.`dual_crn_fault_count`, 0) |
| | | + COALESCE(a.`rgv_fault_count`, 0) |
| | | + COALESCE(s.`fault_count`, 0), |
| | | a.`fault_duration_ms` = COALESCE(a.`crn_fault_duration_ms`, 0) |
| | | + COALESCE(a.`dual_crn_fault_duration_ms`, 0) |
| | | + COALESCE(a.`rgv_fault_duration_ms`, 0) |
| | | + COALESCE(s.`fault_duration_ms`, 0), |
| | | a.`has_fault` = CASE |
| | | WHEN COALESCE(a.`crn_fault_count`, 0) |
| | | + COALESCE(a.`dual_crn_fault_count`, 0) |
| | | + COALESCE(a.`rgv_fault_count`, 0) |
| | | + COALESCE(s.`fault_count`, 0) > 0 THEN 1 |
| | | ELSE 0 |
| | | END, |
| | | a.`update_time` = NOW() |
| | | WHERE @wrk_analysis_table_exists = 1; |
| | | |
| | | SET @station_err_log_parent_id := COALESCE( |
| | | ( |
| | | SELECT `id` |
| | | FROM `sys_resource` |
| | | WHERE `code` = 'logReport' AND `level` = 1 |
| | | ORDER BY `id` |
| | | LIMIT 1 |
| | | ), |
| | | ( |
| | | SELECT `id` |
| | | FROM `sys_resource` |
| | | WHERE `code` = 'develop' AND `level` = 1 |
| | | ORDER BY `id` |
| | | LIMIT 1 |
| | | ) |
| | | ); |
| | | |
| | | INSERT INTO `sys_resource`(`code`, `name`, `resource_id`, `level`, `sort`, `status`) |
| | | SELECT 'basStationErrLog/basStationErrLog.html', '输送站点异常日志', @station_err_log_parent_id, 2, 995, 1 |
| | | FROM dual |
| | | WHERE @station_err_log_parent_id IS NOT NULL |
| | | AND NOT EXISTS ( |
| | | SELECT 1 |
| | | FROM `sys_resource` |
| | | WHERE `code` = 'basStationErrLog/basStationErrLog.html' AND `level` = 2 |
| | | ); |
| | | |
| | | UPDATE `sys_resource` |
| | | SET `name` = '输送站点异常日志', |
| | | `resource_id` = @station_err_log_parent_id, |
| | | `level` = 2, |
| | | `sort` = 995, |
| | | `status` = 1 |
| | | WHERE `code` = 'basStationErrLog/basStationErrLog.html' AND `level` = 2; |
| | | |
| | | SET @station_err_log_id := ( |
| | | SELECT `id` |
| | | FROM `sys_resource` |
| | | WHERE `code` = 'basStationErrLog/basStationErrLog.html' AND `level` = 2 |
| | | ORDER BY `id` |
| | | LIMIT 1 |
| | | ); |
| | | |
| | | INSERT INTO `sys_resource`(`code`, `name`, `resource_id`, `level`, `sort`, `status`) |
| | | SELECT 'basStationErrLog/basStationErrLog.html#view', '查看', @station_err_log_id, 3, 1, 1 |
| | | FROM dual |
| | | WHERE @station_err_log_id IS NOT NULL |
| | | AND NOT EXISTS ( |
| | | SELECT 1 |
| | | FROM `sys_resource` |
| | | WHERE `code` = 'basStationErrLog/basStationErrLog.html#view' AND `level` = 3 |
| | | ); |
| | | |
| | | UPDATE `sys_resource` |
| | | SET `name` = '查看', |
| | | `resource_id` = @station_err_log_id, |
| | | `level` = 3, |
| | | `sort` = 1, |
| | | `status` = 1 |
| | | WHERE `code` = 'basStationErrLog/basStationErrLog.html#view' AND `level` = 3; |
| New file |
| | |
| | | (function () { |
| | | var simpleEntityName = 'basStationErrLog'; |
| | | var entityName = 'BasStationErrLog'; |
| | | var primaryKeyField = 'id'; |
| | | var fieldMeta = dedupeFieldMeta([ |
| | | { |
| | | field: 'id', |
| | | columnName: 'id', |
| | | label: '编 号', |
| | | tableProp: 'id', |
| | | exportField: 'id', |
| | | kind: 'text', |
| | | valueType: 'number', |
| | | required: true, |
| | | primaryKey: true, |
| | | sortable: true, |
| | | textarea: false, |
| | | minWidth: 90, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'wrkNo', |
| | | columnName: 'wrk_no', |
| | | label: '工 作 号', |
| | | tableProp: 'wrkNo', |
| | | exportField: 'wrkNo', |
| | | kind: 'text', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 116, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'startTime', |
| | | columnName: 'start_time', |
| | | label: '发生时间', |
| | | tableProp: 'startTime$', |
| | | exportField: 'startTime$', |
| | | kind: 'date', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 168, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'endTime', |
| | | columnName: 'end_time', |
| | | label: '结束时间', |
| | | tableProp: 'endTime$', |
| | | exportField: 'endTime$', |
| | | kind: 'date', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 168, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'wrkSts', |
| | | columnName: 'wrk_sts', |
| | | label: '工作状态', |
| | | tableProp: 'wrkSts$', |
| | | exportField: 'wrkSts$', |
| | | kind: 'foreign', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: 'basWrkStatus', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'ioType', |
| | | columnName: 'io_type', |
| | | label: '入出库类型', |
| | | tableProp: 'ioType$', |
| | | exportField: 'ioType$', |
| | | kind: 'foreign', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 116, |
| | | enumOptions: [], |
| | | foreignQuery: 'basWrkIotype', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'stationId', |
| | | columnName: 'station_id', |
| | | label: '输送站点', |
| | | tableProp: 'stationLabel$', |
| | | exportField: 'stationLabel$', |
| | | kind: 'foreign', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 130, |
| | | enumOptions: [], |
| | | foreignQuery: 'basStation', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'locNo', |
| | | columnName: 'loc_no', |
| | | label: '目标库位', |
| | | tableProp: 'locNo', |
| | | exportField: 'locNo', |
| | | kind: 'text', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'staNo', |
| | | columnName: 'sta_no', |
| | | label: '目 标 站', |
| | | tableProp: 'staNo', |
| | | exportField: 'staNo', |
| | | kind: 'text', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 116, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'sourceStaNo', |
| | | columnName: 'source_sta_no', |
| | | label: '源 站', |
| | | tableProp: 'sourceStaNo', |
| | | exportField: 'sourceStaNo', |
| | | kind: 'text', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'sourceLocNo', |
| | | columnName: 'source_loc_no', |
| | | label: '源 库 位', |
| | | tableProp: 'sourceLocNo', |
| | | exportField: 'sourceLocNo', |
| | | kind: 'text', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 116, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'barcode', |
| | | columnName: 'barcode', |
| | | label: '条 码', |
| | | tableProp: 'barcode', |
| | | exportField: 'barcode', |
| | | kind: 'text', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'errCode', |
| | | columnName: 'err_code', |
| | | label: '异 常 码', |
| | | tableProp: 'errCode', |
| | | exportField: 'errCode', |
| | | kind: 'text', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 116, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'error', |
| | | columnName: 'error', |
| | | label: '异 常', |
| | | tableProp: 'error', |
| | | exportField: 'error', |
| | | kind: 'text', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'status', |
| | | columnName: 'status', |
| | | label: '异常情况', |
| | | tableProp: 'status$', |
| | | exportField: 'status$', |
| | | kind: 'enum', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 120, |
| | | enumOptions: [{ rawValue: '1', label: '未处理' }, { rawValue: '2', label: '已修复' }], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | columnName: 'create_time', |
| | | label: '添加时间', |
| | | tableProp: 'createTime$', |
| | | exportField: 'createTime$', |
| | | kind: 'date', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 168, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'createBy', |
| | | columnName: 'create_by', |
| | | label: '添加人员', |
| | | tableProp: 'createBy$', |
| | | exportField: 'createBy$', |
| | | kind: 'foreign', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: 'user', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'updateTime', |
| | | columnName: 'update_time', |
| | | label: '修改时间', |
| | | tableProp: 'updateTime$', |
| | | exportField: 'updateTime$', |
| | | kind: 'date', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 168, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'updateBy', |
| | | columnName: 'update_by', |
| | | label: '修改人员', |
| | | tableProp: 'updateBy$', |
| | | exportField: 'updateBy$', |
| | | kind: 'foreign', |
| | | valueType: 'number', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 110, |
| | | enumOptions: [], |
| | | foreignQuery: 'user', |
| | | checkboxActiveRaw: '1', |
| | | checkboxInactiveRaw: '0' |
| | | }, |
| | | { |
| | | field: 'memo', |
| | | columnName: 'memo', |
| | | label: '备 注', |
| | | tableProp: 'memo', |
| | | exportField: 'memo', |
| | | kind: 'text', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: true, |
| | | minWidth: 180, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | }, |
| | | { |
| | | field: 'systemStatus', |
| | | columnName: 'system_status', |
| | | label: '系统状态数据', |
| | | tableProp: 'systemStatus', |
| | | exportField: 'systemStatus', |
| | | kind: 'text', |
| | | valueType: 'string', |
| | | required: false, |
| | | primaryKey: false, |
| | | sortable: false, |
| | | textarea: false, |
| | | minWidth: 134, |
| | | enumOptions: [], |
| | | foreignQuery: '', |
| | | checkboxActiveRaw: 'Y', |
| | | checkboxInactiveRaw: 'N' |
| | | } |
| | | |
| | | ]); |
| | | |
| | | function formatFieldLabel(field) { |
| | | var raw = field && field.label ? String(field.label).trim() : ''; |
| | | if (raw) { |
| | | return raw; |
| | | } |
| | | raw = field && field.columnName ? field.columnName : (field && field.field ? field.field : ''); |
| | | if (!raw) { |
| | | return ''; |
| | | } |
| | | raw = String(raw) |
| | | .replace(/\$/g, '') |
| | | .replace(/([a-z0-9])([A-Z])/g, '$1_$2') |
| | | .replace(/_/g, ' ') |
| | | .replace(/\s+/g, ' ') |
| | | .trim(); |
| | | return raw.replace(/\b[a-z]/g, function (letter) { |
| | | return letter.toUpperCase(); |
| | | }); |
| | | } |
| | | |
| | | function dedupeFieldMeta(list) { |
| | | var result = []; |
| | | var seen = {}; |
| | | (list || []).forEach(function (field) { |
| | | if (!field || !field.field || seen[field.field]) { |
| | | return; |
| | | } |
| | | field.label = formatFieldLabel(field); |
| | | seen[field.field] = true; |
| | | result.push(field); |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | function isEmptyValue(value) { |
| | | return value === null || value === undefined || value === ''; |
| | | } |
| | | |
| | | function stringValue(value) { |
| | | return isEmptyValue(value) ? '' : String(value); |
| | | } |
| | | |
| | | function valueOrDash(value) { |
| | | return isEmptyValue(value) ? '--' : value; |
| | | } |
| | | |
| | | function normalizeOptionValue(field, rawValue) { |
| | | if (rawValue === null || rawValue === undefined) { |
| | | return null; |
| | | } |
| | | if (rawValue === '') { |
| | | return ''; |
| | | } |
| | | if (field && field.valueType === 'number') { |
| | | var numberVal = Number(rawValue); |
| | | return isNaN(numberVal) ? rawValue : numberVal; |
| | | } |
| | | return String(rawValue); |
| | | } |
| | | |
| | | function isSearchableField(field) { |
| | | return !!field && field.kind !== 'image' && !field.textarea; |
| | | } |
| | | |
| | | function isSortableField(field) { |
| | | if (!field) { |
| | | return false; |
| | | } |
| | | if (field.primaryKey) { |
| | | return true; |
| | | } |
| | | return field.kind !== 'image' && !field.textarea && field.kind !== 'foreign'; |
| | | } |
| | | |
| | | function defaultFieldValue(field) { |
| | | if (field.primaryKey) { |
| | | return null; |
| | | } |
| | | if (field.kind === 'checkbox') { |
| | | return normalizeOptionValue(field, field.checkboxInactiveRaw); |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | function defaultSearchFieldValue(field) { |
| | | if (field.kind === 'date') { |
| | | return []; |
| | | } |
| | | if (field.kind === 'enum' || field.kind === 'checkbox') { |
| | | return null; |
| | | } |
| | | return ''; |
| | | } |
| | | |
| | | function createSearchDefaults() { |
| | | var result = { |
| | | condition: '' |
| | | }; |
| | | fieldMeta.forEach(function (field) { |
| | | if (!isSearchableField(field)) { |
| | | return; |
| | | } |
| | | result[field.field] = defaultSearchFieldValue(field); |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | function createSearchDisplayDefaults() { |
| | | var result = {}; |
| | | fieldMeta.forEach(function (field) { |
| | | if (field.kind === 'foreign' && isSearchableField(field)) { |
| | | result[field.field] = ''; |
| | | } |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | function createDefaultVisibleColumnKeys() { |
| | | return fieldMeta.map(function (field) { |
| | | return field.field; |
| | | }); |
| | | } |
| | | |
| | | function createFormDefaults() { |
| | | var result = {}; |
| | | fieldMeta.forEach(function (field) { |
| | | result[field.field] = defaultFieldValue(field); |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | function createDisplayDefaults() { |
| | | var result = {}; |
| | | fieldMeta.forEach(function (field) { |
| | | if (field.kind === 'foreign') { |
| | | result[field.field] = ''; |
| | | } |
| | | }); |
| | | return result; |
| | | } |
| | | |
| | | function createFormRules() { |
| | | var rules = {}; |
| | | fieldMeta.forEach(function (field) { |
| | | if (field.primaryKey || !field.required) { |
| | | return; |
| | | } |
| | | rules[field.field] = [{ |
| | | required: true, |
| | | message: (field.kind === 'date' || field.kind === 'enum' ? '请选择' : '请输入') + field.label, |
| | | trigger: (field.kind === 'date' || field.kind === 'enum') ? 'change' : 'blur' |
| | | }]; |
| | | }); |
| | | return rules; |
| | | } |
| | | |
| | | function getTableValue(row, field) { |
| | | var prop = field.tableProp || field.field; |
| | | if (row && !isEmptyValue(row[prop])) { |
| | | return row[prop]; |
| | | } |
| | | return row ? row[field.field] : ''; |
| | | } |
| | | |
| | | function isCheckboxChecked(row, field) { |
| | | var value = row ? row[field.field] : null; |
| | | var activeValue = normalizeOptionValue(field, field.checkboxActiveRaw); |
| | | return String(value) === String(activeValue); |
| | | } |
| | | |
| | | function exportCell(value) { |
| | | return stringValue(value).replace(/\t/g, ' ').replace(/\r?\n/g, ' '); |
| | | } |
| | | |
| | | function escapeHtml(value) { |
| | | return exportCell(value) |
| | | .replace(/&/g, '&') |
| | | .replace(/</g, '<') |
| | | .replace(/>/g, '>') |
| | | .replace(/"/g, '"') |
| | | .replace(/'/g, '''); |
| | | } |
| | | |
| | | function buildPayload(form) { |
| | | var payload = {}; |
| | | fieldMeta.forEach(function (field) { |
| | | var value = form[field.field]; |
| | | if (field.primaryKey) { |
| | | if (!isEmptyValue(value)) { |
| | | payload[field.field] = value; |
| | | } |
| | | return; |
| | | } |
| | | if (field.kind === 'foreign' && isEmptyValue(value)) { |
| | | value = null; |
| | | } |
| | | if (field.kind === 'enum' && value === '') { |
| | | value = null; |
| | | } |
| | | if (field.kind === 'checkbox' && isEmptyValue(value)) { |
| | | value = normalizeOptionValue(field, field.checkboxInactiveRaw); |
| | | } |
| | | if (field.valueType === 'number' && !isEmptyValue(value)) { |
| | | value = Number(value); |
| | | } |
| | | if (field.valueType === 'number' && value === '') { |
| | | value = null; |
| | | } |
| | | payload[field.field] = value; |
| | | }); |
| | | return payload; |
| | | } |
| | | |
| | | function fillFormFromRow(row, form, display) { |
| | | fieldMeta.forEach(function (field) { |
| | | if (field.primaryKey) { |
| | | form[field.field] = row[field.field]; |
| | | return; |
| | | } |
| | | if (field.kind === 'date') { |
| | | form[field.field] = row[field.tableProp] || row[field.field] || ''; |
| | | return; |
| | | } |
| | | if (field.kind === 'foreign') { |
| | | form[field.field] = isEmptyValue(row[field.field]) ? '' : normalizeOptionValue(field, row[field.field]); |
| | | if (display) { |
| | | display[field.field] = row[field.tableProp] || (isEmptyValue(row[field.field]) ? '' : String(row[field.field])); |
| | | } |
| | | return; |
| | | } |
| | | if (field.kind === 'enum') { |
| | | form[field.field] = isEmptyValue(row[field.field]) ? '' : normalizeOptionValue(field, row[field.field]); |
| | | return; |
| | | } |
| | | if (field.kind === 'checkbox') { |
| | | form[field.field] = isEmptyValue(row[field.field]) |
| | | ? normalizeOptionValue(field, field.checkboxInactiveRaw) |
| | | : normalizeOptionValue(field, row[field.field]); |
| | | return; |
| | | } |
| | | form[field.field] = isEmptyValue(row[field.field]) |
| | | ? '' |
| | | : (field.valueType === 'number' ? String(row[field.field]) : row[field.field]); |
| | | }); |
| | | } |
| | | |
| | | function resolveSearchParam(field) { |
| | | if (field.kind === 'date' && field.columnName) { |
| | | return field.columnName; |
| | | } |
| | | return field.field; |
| | | } |
| | | |
| | | function createDownloadFile(filename, titles, rows) { |
| | | var html = [ |
| | | '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">', |
| | | '<head><meta charset="UTF-8"></head><body><table border="1"><thead><tr>', |
| | | titles.map(function (title) { |
| | | return '<th>' + escapeHtml(title) + '</th>'; |
| | | }).join(''), |
| | | '</tr></thead><tbody>', |
| | | (rows || []).map(function (row) { |
| | | return '<tr>' + (row || []).map(function (value) { |
| | | return '<td style="mso-number-format:\\@;">' + escapeHtml(value) + '</td>'; |
| | | }).join('') + '</tr>'; |
| | | }).join(''), |
| | | '</tbody></table></body></html>' |
| | | ].join(''); |
| | | var blob = new Blob(['\ufeff' + html], { |
| | | type: 'application/vnd.ms-excel;charset=utf-8;' |
| | | }); |
| | | var anchor = document.createElement('a'); |
| | | anchor.href = URL.createObjectURL(blob); |
| | | anchor.download = filename; |
| | | document.body.appendChild(anchor); |
| | | anchor.click(); |
| | | setTimeout(function () { |
| | | URL.revokeObjectURL(anchor.href); |
| | | document.body.removeChild(anchor); |
| | | }, 0); |
| | | } |
| | | |
| | | function buildTimestamp() { |
| | | var now = new Date(); |
| | | var pad = function (num) { |
| | | return num < 10 ? '0' + num : String(num); |
| | | }; |
| | | return now.getFullYear() |
| | | + pad(now.getMonth() + 1) |
| | | + pad(now.getDate()) |
| | | + '_' |
| | | + pad(now.getHours()) |
| | | + pad(now.getMinutes()) |
| | | + pad(now.getSeconds()); |
| | | } |
| | | |
| | | function authHeaders() { |
| | | return { |
| | | token: localStorage.getItem('token') |
| | | }; |
| | | } |
| | | |
| | | function handleForbidden(res) { |
| | | if (res && res.code === 403) { |
| | | top.location.href = baseUrl + '/'; |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | var sharedMethods = { |
| | | authHeaders: authHeaders, |
| | | handleForbidden: handleForbidden, |
| | | valueOrDash: valueOrDash, |
| | | stringValue: stringValue, |
| | | getTableValue: getTableValue, |
| | | isCheckboxChecked: isCheckboxChecked, |
| | | normalizeOptionValue: normalizeOptionValue, |
| | | isSortableField: isSortableField, |
| | | getSuggestionFetcher: function (field) { |
| | | var self = this; |
| | | return function (queryString, callback) { |
| | | self.fetchForeignSuggestions(field, queryString, callback); |
| | | }; |
| | | }, |
| | | fetchForeignSuggestions: function (field, queryString, callback) { |
| | | if (!field.foreignQuery || !queryString) { |
| | | callback([]); |
| | | return; |
| | | } |
| | | var self = this; |
| | | $.ajax({ |
| | | url: baseUrl + '/' + field.foreignQuery + 'Query/auth', |
| | | method: 'GET', |
| | | headers: self.authHeaders(), |
| | | data: { condition: queryString }, |
| | | success: function (res) { |
| | | if (self.handleForbidden(res)) { |
| | | return; |
| | | } |
| | | if (!res || res.code !== 200 || !Array.isArray(res.data)) { |
| | | callback([]); |
| | | return; |
| | | } |
| | | callback(res.data.map(function (item) { |
| | | return { |
| | | id: item.id, |
| | | value: item.value |
| | | }; |
| | | })); |
| | | }, |
| | | error: function () { |
| | | callback([]); |
| | | } |
| | | }); |
| | | }, |
| | | handleForeignSelect: function (field, item) { |
| | | this.$set(this.displayTarget, field.field, item && item.value ? item.value : ''); |
| | | this.$set(this.formTarget, field.field, item && item.id !== undefined ? normalizeOptionValue(field, item.id) : ''); |
| | | }, |
| | | handleForeignInput: function (field) { |
| | | if (!this.displayTarget || !this.formTarget) { |
| | | return; |
| | | } |
| | | if (this.displayTarget[field.field]) { |
| | | return; |
| | | } |
| | | this.$set(this.formTarget, field.field, ''); |
| | | } |
| | | }; |
| | | |
| | | if (document.getElementById('app')) { |
| | | new Vue({ |
| | | el: '#app', |
| | | data: function () { |
| | | return { |
| | | fieldMeta: fieldMeta, |
| | | primaryKeyField: primaryKeyField, |
| | | loading: false, |
| | | exporting: false, |
| | | tableData: [], |
| | | selection: [], |
| | | advancedFiltersVisible: false, |
| | | allColumns: fieldMeta.slice(), |
| | | visibleColumnKeys: createDefaultVisibleColumnKeys(), |
| | | searchForm: createSearchDefaults(), |
| | | searchDisplay: createSearchDisplayDefaults(), |
| | | page: { |
| | | curr: 1, |
| | | limit: 15, |
| | | total: 0 |
| | | }, |
| | | sortState: { |
| | | prop: '', |
| | | order: '' |
| | | }, |
| | | dialog: { |
| | | visible: false, |
| | | mode: 'create', |
| | | submitting: false |
| | | }, |
| | | layoutTimer: null, |
| | | tableResizeHandler: null, |
| | | dialogForm: createFormDefaults(), |
| | | dialogDisplay: createDisplayDefaults(), |
| | | dialogRules: createFormRules() |
| | | }; |
| | | }, |
| | | computed: { |
| | | searchableFields: function () { |
| | | return this.fieldMeta.filter(function (field) { |
| | | return isSearchableField(field); |
| | | }); |
| | | }, |
| | | quickSearchableFields: function () { |
| | | var result = []; |
| | | this.searchableFields.forEach(function (field) { |
| | | if (result.length >= 3 || field.kind === 'date') { |
| | | return; |
| | | } |
| | | result.push(field); |
| | | }); |
| | | return result; |
| | | }, |
| | | advancedSearchableFields: function () { |
| | | var quickKeys = this.quickSearchableFields.map(function (field) { |
| | | return field.field; |
| | | }); |
| | | return this.searchableFields.filter(function (field) { |
| | | return quickKeys.indexOf(field.field) === -1; |
| | | }); |
| | | }, |
| | | hasAdvancedFilters: function () { |
| | | return this.advancedSearchableFields.length > 0; |
| | | }, |
| | | visibleColumns: function () { |
| | | var keys = this.visibleColumnKeys; |
| | | return this.allColumns.filter(function (field) { |
| | | return keys.indexOf(field.field) !== -1; |
| | | }); |
| | | }, |
| | | editableFields: function () { |
| | | return this.fieldMeta.filter(function (field) { |
| | | return !field.primaryKey; |
| | | }); |
| | | }, |
| | | exportColumns: function () { |
| | | return this.visibleColumns.map(function (field) { |
| | | return { |
| | | field: field.exportField || field.tableProp || field.field, |
| | | label: field.label |
| | | }; |
| | | }); |
| | | }, |
| | | tableHeight: function () { |
| | | return this.advancedFiltersVisible && this.hasAdvancedFilters |
| | | ? 'calc(100vh - 390px)' |
| | | : 'calc(100vh - 300px)'; |
| | | }, |
| | | formTarget: function () { |
| | | return this.dialogForm; |
| | | }, |
| | | displayTarget: function () { |
| | | return this.dialogDisplay; |
| | | } |
| | | }, |
| | | created: function () { |
| | | this.loadTable(); |
| | | }, |
| | | mounted: function () { |
| | | var self = this; |
| | | self.requestTableLayout(80); |
| | | self.tableResizeHandler = function () { |
| | | self.requestTableLayout(80); |
| | | }; |
| | | window.addEventListener('resize', self.tableResizeHandler); |
| | | }, |
| | | beforeDestroy: function () { |
| | | if (this.layoutTimer) { |
| | | clearTimeout(this.layoutTimer); |
| | | this.layoutTimer = null; |
| | | } |
| | | if (this.tableResizeHandler) { |
| | | window.removeEventListener('resize', this.tableResizeHandler); |
| | | this.tableResizeHandler = null; |
| | | } |
| | | }, |
| | | methods: $.extend({}, sharedMethods, { |
| | | requestTableLayout: function (delay) { |
| | | var self = this; |
| | | if (self.layoutTimer) { |
| | | clearTimeout(self.layoutTimer); |
| | | } |
| | | self.$nextTick(function () { |
| | | self.layoutTimer = setTimeout(function () { |
| | | var table = self.$refs.dataTable; |
| | | if (table && typeof table.doLayout === 'function') { |
| | | table.doLayout(); |
| | | } |
| | | }, delay || 40); |
| | | }); |
| | | }, |
| | | isColumnVisible: function (fieldName) { |
| | | return this.visibleColumnKeys.indexOf(fieldName) !== -1; |
| | | }, |
| | | toggleColumn: function (fieldName, visible) { |
| | | if (visible) { |
| | | if (this.visibleColumnKeys.indexOf(fieldName) === -1) { |
| | | this.visibleColumnKeys.push(fieldName); |
| | | } |
| | | this.requestTableLayout(80); |
| | | return; |
| | | } |
| | | if (this.visibleColumnKeys.length === 1) { |
| | | this.$message.warning('至少保留一列'); |
| | | return; |
| | | } |
| | | this.visibleColumnKeys = this.visibleColumnKeys.filter(function (item) { |
| | | return item !== fieldName; |
| | | }); |
| | | this.requestTableLayout(80); |
| | | }, |
| | | selectAllColumns: function () { |
| | | this.visibleColumnKeys = createDefaultVisibleColumnKeys(); |
| | | this.requestTableLayout(80); |
| | | }, |
| | | resetColumns: function () { |
| | | this.visibleColumnKeys = createDefaultVisibleColumnKeys(); |
| | | this.requestTableLayout(80); |
| | | }, |
| | | toggleAdvancedFilters: function () { |
| | | this.advancedFiltersVisible = !this.advancedFiltersVisible; |
| | | this.requestTableLayout(260); |
| | | }, |
| | | handleSearchForeignSelect: function (field, item) { |
| | | this.$set(this.searchDisplay, field.field, item && item.value ? item.value : ''); |
| | | this.$set(this.searchForm, field.field, item && item.id !== undefined ? normalizeOptionValue(field, item.id) : ''); |
| | | }, |
| | | handleSearchForeignInput: function (field) { |
| | | if (this.searchDisplay[field.field]) { |
| | | return; |
| | | } |
| | | this.$set(this.searchForm, field.field, ''); |
| | | }, |
| | | buildQueryParams: function () { |
| | | var self = this; |
| | | var params = { |
| | | curr: self.page.curr, |
| | | limit: self.page.limit |
| | | }; |
| | | if (self.searchForm.condition) { |
| | | params.condition = self.searchForm.condition; |
| | | } |
| | | self.searchableFields.forEach(function (field) { |
| | | var value = self.searchForm[field.field]; |
| | | if (field.kind === 'date') { |
| | | if (value && value.length === 2) { |
| | | params[resolveSearchParam(field)] = value[0] + ' - ' + value[1]; |
| | | } |
| | | return; |
| | | } |
| | | if (!isEmptyValue(value)) { |
| | | params[resolveSearchParam(field)] = value; |
| | | } |
| | | }); |
| | | if (self.sortState.prop && self.sortState.order) { |
| | | params.orderByField = self.sortState.prop; |
| | | params.orderByType = self.sortState.order === 'ascending' ? 'asc' : 'desc'; |
| | | } |
| | | return params; |
| | | }, |
| | | loadTable: function () { |
| | | var self = this; |
| | | self.loading = true; |
| | | $.ajax({ |
| | | url: baseUrl + '/' + simpleEntityName + '/list/auth', |
| | | method: 'GET', |
| | | headers: self.authHeaders(), |
| | | data: self.buildQueryParams(), |
| | | success: function (res) { |
| | | self.loading = false; |
| | | if (self.handleForbidden(res)) { |
| | | return; |
| | | } |
| | | if (!res || res.code !== 200) { |
| | | self.$message.error((res && res.msg) ? res.msg : '加载失败'); |
| | | return; |
| | | } |
| | | var payload = res.data || {}; |
| | | self.tableData = Array.isArray(payload.records) ? payload.records : []; |
| | | self.page.total = payload.total || 0; |
| | | self.requestTableLayout(80); |
| | | }, |
| | | error: function () { |
| | | self.loading = false; |
| | | self.requestTableLayout(80); |
| | | self.$message.error('加载失败'); |
| | | } |
| | | }); |
| | | }, |
| | | handleSearch: function () { |
| | | this.page.curr = 1; |
| | | this.loadTable(); |
| | | }, |
| | | handleReset: function () { |
| | | this.searchForm = createSearchDefaults(); |
| | | this.searchDisplay = createSearchDisplayDefaults(); |
| | | this.advancedFiltersVisible = false; |
| | | this.page.curr = 1; |
| | | this.sortState = { |
| | | prop: '', |
| | | order: '' |
| | | }; |
| | | this.loadTable(); |
| | | }, |
| | | handleSelectionChange: function (rows) { |
| | | this.selection = rows || []; |
| | | }, |
| | | handleSortChange: function (payload) { |
| | | this.sortState = { |
| | | prop: payload && payload.prop ? payload.prop : '', |
| | | order: payload && payload.order ? payload.order : '' |
| | | }; |
| | | this.page.curr = 1; |
| | | this.loadTable(); |
| | | }, |
| | | handleCurrentChange: function (curr) { |
| | | this.page.curr = curr; |
| | | this.loadTable(); |
| | | }, |
| | | handleSizeChange: function (limit) { |
| | | this.page.limit = limit; |
| | | this.page.curr = 1; |
| | | this.loadTable(); |
| | | }, |
| | | resetDialogState: function () { |
| | | this.dialogForm = createFormDefaults(); |
| | | this.dialogDisplay = createDisplayDefaults(); |
| | | if (this.$refs.dialogForm) { |
| | | this.$refs.dialogForm.clearValidate(); |
| | | } |
| | | }, |
| | | openCreateDialog: function () { |
| | | this.dialog.mode = 'create'; |
| | | this.dialog.visible = true; |
| | | this.$nextTick(this.resetDialogState); |
| | | }, |
| | | openEditDialog: function (row) { |
| | | var self = this; |
| | | self.dialog.mode = 'edit'; |
| | | self.dialog.visible = true; |
| | | self.$nextTick(function () { |
| | | self.resetDialogState(); |
| | | fillFormFromRow(row, self.dialogForm, self.dialogDisplay); |
| | | if (self.$refs.dialogForm) { |
| | | self.$refs.dialogForm.clearValidate(); |
| | | } |
| | | }); |
| | | }, |
| | | submitDialog: function () { |
| | | var self = this; |
| | | if (!self.$refs.dialogForm) { |
| | | return; |
| | | } |
| | | self.$refs.dialogForm.validate(function (valid) { |
| | | if (!valid) { |
| | | return false; |
| | | } |
| | | self.dialog.submitting = true; |
| | | $.ajax({ |
| | | url: baseUrl + '/' + simpleEntityName + '/' + (self.dialog.mode === 'create' ? 'add' : 'update') + '/auth', |
| | | method: 'POST', |
| | | headers: self.authHeaders(), |
| | | data: buildPayload(self.dialogForm), |
| | | success: function (res) { |
| | | self.dialog.submitting = false; |
| | | if (self.handleForbidden(res)) { |
| | | return; |
| | | } |
| | | if (!res || res.code !== 200) { |
| | | self.$message.error((res && res.msg) ? res.msg : '保存失败'); |
| | | return; |
| | | } |
| | | self.$message.success(res.msg || '保存成功'); |
| | | self.dialog.visible = false; |
| | | self.loadTable(); |
| | | }, |
| | | error: function () { |
| | | self.dialog.submitting = false; |
| | | self.$message.error('保存失败'); |
| | | } |
| | | }); |
| | | return true; |
| | | }); |
| | | }, |
| | | removeSelection: function () { |
| | | var self = this; |
| | | var ids = self.selection.map(function (row) { |
| | | return row[self.primaryKeyField]; |
| | | }); |
| | | self.removeRows(ids); |
| | | }, |
| | | removeRows: function (ids) { |
| | | var self = this; |
| | | if (!ids || ids.length === 0) { |
| | | self.$message.warning('请选择要删除的数据'); |
| | | return; |
| | | } |
| | | self.$confirm('确定删除选中的记录吗?', '提示', { type: 'warning' }).then(function () { |
| | | $.ajax({ |
| | | url: baseUrl + '/' + simpleEntityName + '/delete/auth', |
| | | method: 'POST', |
| | | headers: self.authHeaders(), |
| | | traditional: true, |
| | | data: { 'ids[]': ids }, |
| | | success: function (res) { |
| | | if (self.handleForbidden(res)) { |
| | | return; |
| | | } |
| | | if (!res || res.code !== 200) { |
| | | self.$message.error((res && res.msg) ? res.msg : '删除失败'); |
| | | return; |
| | | } |
| | | self.$message.success(res.msg || '删除成功'); |
| | | self.selection = []; |
| | | if (self.tableData.length === ids.length && self.page.curr > 1) { |
| | | self.page.curr = self.page.curr - 1; |
| | | } |
| | | self.loadTable(); |
| | | }, |
| | | error: function () { |
| | | self.$message.error('删除失败'); |
| | | } |
| | | }); |
| | | }).catch(function () {}); |
| | | }, |
| | | exportRows: function () { |
| | | var self = this; |
| | | self.exporting = true; |
| | | var requestBody = { |
| | | fields: self.exportColumns.map(function (item) { |
| | | return item.field; |
| | | }) |
| | | }; |
| | | requestBody[simpleEntityName] = self.buildQueryParams(); |
| | | $.ajax({ |
| | | url: baseUrl + '/' + simpleEntityName + '/export/auth', |
| | | method: 'POST', |
| | | headers: $.extend({ 'Content-Type': 'application/json;charset=UTF-8' }, self.authHeaders()), |
| | | data: JSON.stringify(requestBody), |
| | | success: function (res) { |
| | | self.exporting = false; |
| | | if (self.handleForbidden(res)) { |
| | | return; |
| | | } |
| | | if (!res || res.code !== 200) { |
| | | self.$message.error((res && res.msg) ? res.msg : '导出失败'); |
| | | return; |
| | | } |
| | | createDownloadFile( |
| | | simpleEntityName + '_' + buildTimestamp() + '.xls', |
| | | self.exportColumns.map(function (item) { |
| | | return item.label; |
| | | }), |
| | | Array.isArray(res.data) ? res.data : [] |
| | | ); |
| | | self.$message.success('导出成功'); |
| | | }, |
| | | error: function () { |
| | | self.exporting = false; |
| | | self.$message.error('导出失败'); |
| | | } |
| | | }); |
| | | } |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | })(); |
| | |
| | | }, |
| | | wrkSts: { |
| | | label: '工作状态', |
| | | kind: 'foreign', |
| | | kind: 'enum', |
| | | tableProp: 'wrkSts$', |
| | | exportField: 'wrkSts$', |
| | | foreignQuery: 'basWrkStatus', |
| | | enumOptions: [], |
| | | searchable: true, |
| | | quickSearch: true, |
| | | minWidth: 160 |
| | | }, |
| | | ioType: { |
| | | label: '入出库类型', |
| | | kind: 'foreign', |
| | | kind: 'enum', |
| | | tableProp: 'ioType$', |
| | | exportField: 'ioType$', |
| | | foreignQuery: 'basWrkIotype', |
| | | enumOptions: [], |
| | | searchable: true, |
| | | quickSearch: true, |
| | | minWidth: 160 |
| | |
| | | minWidth: 90 |
| | | }, |
| | | sourceStaNo: { |
| | | label: '源站' |
| | | label: '源站', |
| | | kind: 'enum', |
| | | enumOptions: [], |
| | | searchable: true, |
| | | minWidth: 120 |
| | | }, |
| | | staNo: { |
| | | label: '目标站' |
| | | label: '目标站', |
| | | kind: 'enum', |
| | | enumOptions: [], |
| | | searchable: true, |
| | | minWidth: 120 |
| | | }, |
| | | sourceLocNo: { |
| | | label: '源库位', |
| | |
| | | }, |
| | | barcode: { |
| | | label: '条码', |
| | | searchable: true, |
| | | minWidth: 140 |
| | | }, |
| | | modiUser: { |
| | |
| | | }; |
| | | } |
| | | |
| | | function getFieldByName(fieldName) { |
| | | for (var i = 0; i < fieldMeta.length; i += 1) { |
| | | if (fieldMeta[i] && fieldMeta[i].field === fieldName) { |
| | | return fieldMeta[i]; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | function buildEnumOptions(records, valueField, labelField) { |
| | | var options = []; |
| | | var seen = {}; |
| | | (records || []).forEach(function (item) { |
| | | if (!item) { |
| | | return; |
| | | } |
| | | var rawValue = item[valueField]; |
| | | if (isEmptyValue(rawValue)) { |
| | | return; |
| | | } |
| | | var key = String(rawValue); |
| | | if (seen[key]) { |
| | | return; |
| | | } |
| | | seen[key] = true; |
| | | options.push({ |
| | | rawValue: key, |
| | | label: isEmptyValue(item[labelField]) ? key : String(item[labelField]) |
| | | }); |
| | | }); |
| | | return options; |
| | | } |
| | | |
| | | function handleForbidden(res) { |
| | | if (res && res.code === 403) { |
| | | top.location.href = baseUrl + '/'; |
| | |
| | | } |
| | | }, |
| | | created: function () { |
| | | this.loadSearchEnumOptions(); |
| | | this.loadTable(); |
| | | }, |
| | | mounted: function () { |
| | |
| | | } |
| | | this.$set(this.searchForm, field.field, ''); |
| | | }, |
| | | loadSearchEnumOptions: function () { |
| | | var self = this; |
| | | [ |
| | | { |
| | | field: 'wrkSts', |
| | | url: baseUrl + '/basWrkStatus/list/auth', |
| | | valueField: 'wrkSts', |
| | | labelField: 'wrkDesc', |
| | | limit: 200 |
| | | }, |
| | | { |
| | | field: 'ioType', |
| | | url: baseUrl + '/basWrkIotype/list/auth', |
| | | valueField: 'ioType', |
| | | labelField: 'ioDesc', |
| | | limit: 200 |
| | | }, |
| | | { |
| | | field: 'staNo', |
| | | url: baseUrl + '/basStation/list/auth', |
| | | valueField: 'stationId', |
| | | labelField: 'stationId', |
| | | limit: 500 |
| | | }, |
| | | { |
| | | field: 'sourceStaNo', |
| | | url: baseUrl + '/basStation/list/auth', |
| | | valueField: 'stationId', |
| | | labelField: 'stationId', |
| | | limit: 500 |
| | | } |
| | | ].forEach(function (config) { |
| | | $.ajax({ |
| | | url: config.url, |
| | | method: 'GET', |
| | | headers: self.authHeaders(), |
| | | data: { |
| | | curr: 1, |
| | | limit: config.limit |
| | | }, |
| | | success: function (res) { |
| | | if (self.handleForbidden(res)) { |
| | | return; |
| | | } |
| | | if (!res || res.code !== 200) { |
| | | return; |
| | | } |
| | | var payload = res.data || {}; |
| | | var field = getFieldByName(config.field); |
| | | if (!field) { |
| | | return; |
| | | } |
| | | self.$set(field, 'enumOptions', buildEnumOptions(payload.records, config.valueField, config.labelField)); |
| | | } |
| | | }); |
| | | }); |
| | | }, |
| | | buildQueryParams: function () { |
| | | var self = this; |
| | | var params = { |
| New file |
| | |
| | | <!DOCTYPE html> |
| | | <html lang="zh-CN"> |
| | | <head> |
| | | <meta charset="utf-8"> |
| | | <title>BasStationErrLog 管理</title> |
| | | <meta name="renderer" content="webkit"> |
| | | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> |
| | | <link rel="stylesheet" href="../../static/vue/element/element.css"> |
| | | <link rel="stylesheet" href="../../static/css/cool.css"> |
| | | <style> |
| | | :root { |
| | | --card-bg: rgba(255, 255, 255, 0.94); |
| | | --card-border: rgba(216, 226, 238, 0.95); |
| | | --text-main: #243447; |
| | | } |
| | | |
| | | [v-cloak] { |
| | | display: none; |
| | | } |
| | | |
| | | html, |
| | | body { |
| | | margin: 0; |
| | | min-height: 100%; |
| | | color: var(--text-main); |
| | | font-family: "Avenir Next", "PingFang SC", "Microsoft YaHei", sans-serif; |
| | | background: |
| | | radial-gradient(1000px 420px at 0% -10%, rgba(44, 107, 193, 0.12), transparent 56%), |
| | | radial-gradient(900px 400px at 100% 0%, rgba(28, 150, 126, 0.10), transparent 58%), |
| | | linear-gradient(180deg, #f2f6fb 0%, #f8fafc 100%); |
| | | } |
| | | |
| | | .page-shell { |
| | | max-width: 1700px; |
| | | margin: 0 auto; |
| | | padding: 14px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .card-shell { |
| | | position: relative; |
| | | border-radius: 24px; |
| | | border: 1px solid var(--card-border); |
| | | background: |
| | | radial-gradient(760px 220px at -8% 0%, rgba(43, 117, 196, 0.05), transparent 55%), |
| | | radial-gradient(680px 200px at 108% 10%, rgba(24, 150, 129, 0.05), transparent 58%), |
| | | var(--card-bg); |
| | | box-shadow: 0 16px 32px rgba(44, 67, 96, 0.08); |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .card-body { |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | |
| | | .list-toolbar { |
| | | padding: 12px 16px 10px; |
| | | border-bottom: 1px solid rgba(222, 230, 239, 0.92); |
| | | } |
| | | |
| | | .toolbar-main { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .toolbar-left { |
| | | flex: 1 1 960px; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .toolbar-search { |
| | | flex: 1 1 auto; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .toolbar-search-item { |
| | | flex: 0 0 152px; |
| | | min-width: 152px; |
| | | } |
| | | |
| | | .toolbar-search-item.keyword { |
| | | flex: 0 0 220px; |
| | | min-width: 220px; |
| | | } |
| | | |
| | | .toolbar-query-actions, |
| | | .toolbar-ops { |
| | | display: flex; |
| | | gap: 8px; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .toolbar-ops { |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .list-toolbar .el-input__inner, |
| | | .list-toolbar .el-range-editor.el-input__inner, |
| | | .advanced-panel .el-input__inner, |
| | | .advanced-panel .el-range-editor.el-input__inner { |
| | | height: 32px; |
| | | line-height: 32px; |
| | | } |
| | | |
| | | .list-toolbar .el-range-editor.el-input__inner, |
| | | .advanced-panel .el-range-editor.el-input__inner { |
| | | align-items: center; |
| | | } |
| | | |
| | | .list-toolbar .el-input__icon, |
| | | .advanced-panel .el-input__icon { |
| | | line-height: 32px; |
| | | } |
| | | |
| | | .list-toolbar .el-range-editor .el-range__icon, |
| | | .list-toolbar .el-range-editor .el-range-separator, |
| | | .list-toolbar .el-range-editor .el-range__close-icon, |
| | | .advanced-panel .el-range-editor .el-range__icon, |
| | | .advanced-panel .el-range-editor .el-range-separator, |
| | | .advanced-panel .el-range-editor .el-range__close-icon { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | height: 100%; |
| | | line-height: 1; |
| | | } |
| | | |
| | | .list-toolbar .el-button, |
| | | .advanced-panel .el-button { |
| | | padding: 8px 12px; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .advanced-panel { |
| | | padding: 10px 16px 12px; |
| | | border-bottom: 1px solid rgba(222, 230, 239, 0.92); |
| | | background: rgba(248, 251, 254, 0.78); |
| | | } |
| | | |
| | | .advanced-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(6, minmax(0, 1fr)); |
| | | gap: 8px; |
| | | } |
| | | |
| | | .advanced-item { |
| | | min-width: 0; |
| | | } |
| | | |
| | | .advanced-item.span-2 { |
| | | grid-column: span 2; |
| | | } |
| | | |
| | | .table-wrap { |
| | | padding: 10px 16px; |
| | | } |
| | | |
| | | .table-shell { |
| | | border-radius: 20px; |
| | | overflow: hidden; |
| | | border: 1px solid rgba(217, 227, 238, 0.98); |
| | | background: rgba(255, 255, 255, 0.95); |
| | | } |
| | | |
| | | .table-shell .el-table { |
| | | border-radius: 20px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .table-shell .el-table th { |
| | | background: #f7fafc; |
| | | color: #53677d; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .payload-cell { |
| | | display: inline-block; |
| | | max-width: 280px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .mono { |
| | | font-family: Menlo, Monaco, Consolas, "Liberation Mono", monospace; |
| | | } |
| | | |
| | | .pager-bar { |
| | | padding: 0 16px 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .column-popover { |
| | | max-width: 320px; |
| | | } |
| | | |
| | | .column-popover-head { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 12px; |
| | | margin-bottom: 10px; |
| | | font-size: 13px; |
| | | font-weight: 700; |
| | | color: var(--text-main); |
| | | } |
| | | |
| | | .column-list { |
| | | display: grid; |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | gap: 8px 10px; |
| | | max-height: 280px; |
| | | overflow: auto; |
| | | padding-right: 4px; |
| | | } |
| | | |
| | | .dialog-panel .el-dialog { |
| | | border-radius: 24px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .dialog-panel .el-dialog__header { |
| | | padding: 22px 24px 12px; |
| | | background: linear-gradient(180deg, #f8fbff 0%, #f3f7fb 100%); |
| | | border-bottom: 1px solid rgba(224, 232, 241, 0.92); |
| | | } |
| | | |
| | | .dialog-panel .el-dialog__title { |
| | | font-weight: 700; |
| | | color: var(--text-main); |
| | | } |
| | | |
| | | .dialog-panel .el-dialog__body { |
| | | padding: 18px 24px 8px; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 10px; |
| | | } |
| | | |
| | | @media (max-width: 1520px) { |
| | | .advanced-grid { |
| | | grid-template-columns: repeat(5, minmax(0, 1fr)); |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 1280px) { |
| | | .advanced-grid { |
| | | grid-template-columns: repeat(4, minmax(0, 1fr)); |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 960px) { |
| | | .toolbar-left { |
| | | flex-basis: 100%; |
| | | } |
| | | |
| | | .advanced-grid { |
| | | grid-template-columns: repeat(3, minmax(0, 1fr)); |
| | | } |
| | | |
| | | .advanced-item.span-2 { |
| | | grid-column: span 2; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 720px) { |
| | | .page-shell { |
| | | padding: 12px; |
| | | } |
| | | |
| | | .toolbar-search-item, |
| | | .toolbar-search-item.keyword { |
| | | min-width: 100%; |
| | | flex-basis: 100%; |
| | | } |
| | | |
| | | .toolbar-query-actions, |
| | | .toolbar-ops { |
| | | width: 100%; |
| | | } |
| | | |
| | | .advanced-grid { |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | } |
| | | |
| | | .advanced-item.span-2 { |
| | | grid-column: span 2; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 560px) { |
| | | .advanced-grid { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .advanced-item.span-2 { |
| | | grid-column: auto; |
| | | } |
| | | |
| | | .list-toolbar, |
| | | .advanced-panel, |
| | | .table-wrap, |
| | | .pager-bar { |
| | | padding-left: 14px; |
| | | padding-right: 14px; |
| | | } |
| | | |
| | | .column-list { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <div id="app" class="page-shell" v-cloak> |
| | | <section class="card-shell list-card"> |
| | | <div class="card-body"> |
| | | <div class="list-toolbar"> |
| | | <div class="toolbar-main"> |
| | | <div class="toolbar-left"> |
| | | <div class="toolbar-search"> |
| | | <div class="toolbar-search-item keyword"> |
| | | <el-input |
| | | v-model.trim="searchForm.condition" |
| | | size="small" |
| | | clearable |
| | | placeholder="请输入" |
| | | @keyup.enter.native="handleSearch"> |
| | | </el-input> |
| | | </div> |
| | | <div |
| | | v-for="field in quickSearchableFields" |
| | | :key="'quick-' + field.field" |
| | | class="toolbar-search-item"> |
| | | <el-select |
| | | v-if="field.kind === 'enum'" |
| | | v-model="searchForm[field.field]" |
| | | size="small" |
| | | clearable |
| | | :placeholder="field.label" |
| | | style="width: 100%;"> |
| | | <el-option |
| | | v-for="option in field.enumOptions" |
| | | :key="'quick-' + field.field + '-' + option.rawValue" |
| | | :label="option.label" |
| | | :value="normalizeOptionValue(field, option.rawValue)"> |
| | | </el-option> |
| | | </el-select> |
| | | <el-autocomplete |
| | | v-else-if="field.kind === 'foreign'" |
| | | v-model="searchDisplay[field.field]" |
| | | size="small" |
| | | :fetch-suggestions="getSuggestionFetcher(field)" |
| | | :placeholder="field.label" |
| | | style="width: 100%;" |
| | | @select="handleSearchForeignSelect(field, $event)" |
| | | @input="handleSearchForeignInput(field)"> |
| | | <template slot-scope="{ item }"> |
| | | <div class="mono">{{ item.value }}</div> |
| | | <div style="font-size:12px;color:#8a98ac;">ID: {{ item.id }}</div> |
| | | </template> |
| | | </el-autocomplete> |
| | | <el-select |
| | | v-else-if="field.kind === 'checkbox'" |
| | | v-model="searchForm[field.field]" |
| | | size="small" |
| | | clearable |
| | | :placeholder="field.label" |
| | | style="width: 100%;"> |
| | | <el-option label="是" :value="normalizeOptionValue(field, field.checkboxActiveRaw)"></el-option> |
| | | <el-option label="否" :value="normalizeOptionValue(field, field.checkboxInactiveRaw)"></el-option> |
| | | </el-select> |
| | | <el-input |
| | | v-else |
| | | v-model.trim="searchForm[field.field]" |
| | | size="small" |
| | | clearable |
| | | :placeholder="field.label" |
| | | @keyup.enter.native="handleSearch"> |
| | | </el-input> |
| | | </div> |
| | | </div> |
| | | <div class="toolbar-query-actions"> |
| | | <el-button size="small" type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button> |
| | | <el-button size="small" icon="el-icon-refresh-left" @click="handleReset">重置</el-button> |
| | | <el-button |
| | | v-if="hasAdvancedFilters" |
| | | size="small" |
| | | plain |
| | | :icon="advancedFiltersVisible ? 'el-icon-arrow-up' : 'el-icon-arrow-down'" |
| | | @click="toggleAdvancedFilters"> |
| | | {{ advancedFiltersVisible ? '收起' : '筛选' }} |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <div class="toolbar-ops"> |
| | | <el-button size="small" type="primary" plain icon="el-icon-plus" @click="openCreateDialog">新增</el-button> |
| | | <el-button size="small" type="danger" plain icon="el-icon-delete" :disabled="selection.length === 0" @click="removeSelection">删除</el-button> |
| | | <el-popover |
| | | placement="bottom" |
| | | width="320" |
| | | trigger="click" |
| | | popper-class="column-popover"> |
| | | <div class="column-popover-head"> |
| | | <span>列设置</span> |
| | | <div> |
| | | <el-button type="text" @click="selectAllColumns">全选</el-button> |
| | | <el-button type="text" @click="resetColumns">重置</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="column-list"> |
| | | <el-checkbox |
| | | v-for="field in allColumns" |
| | | :key="'column-' + field.field" |
| | | :value="isColumnVisible(field.field)" |
| | | @change="toggleColumn(field.field, $event)"> |
| | | {{ field.label }} |
| | | </el-checkbox> |
| | | </div> |
| | | <el-button slot="reference" size="small" plain icon="el-icon-setting">列设置</el-button> |
| | | </el-popover> |
| | | <el-button size="small" plain icon="el-icon-download" :loading="exporting" @click="exportRows">导出</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-collapse-transition> |
| | | <div v-show="advancedFiltersVisible && hasAdvancedFilters" class="advanced-panel"> |
| | | <div class="advanced-grid"> |
| | | <div |
| | | v-for="field in advancedSearchableFields" |
| | | :key="'advanced-' + field.field" |
| | | :class="['advanced-item', field.kind === 'date' ? 'span-2' : '']"> |
| | | <el-date-picker |
| | | v-if="field.kind === 'date'" |
| | | v-model="searchForm[field.field]" |
| | | size="small" |
| | | type="datetimerange" |
| | | unlink-panels |
| | | range-separator="至" |
| | | :start-placeholder="field.label + '开始'" |
| | | :end-placeholder="field.label + '结束'" |
| | | value-format="yyyy-MM-dd HH:mm:ss" |
| | | style="width: 100%;"> |
| | | </el-date-picker> |
| | | <el-select |
| | | v-else-if="field.kind === 'enum'" |
| | | v-model="searchForm[field.field]" |
| | | size="small" |
| | | clearable |
| | | :placeholder="field.label" |
| | | style="width: 100%;"> |
| | | <el-option |
| | | v-for="option in field.enumOptions" |
| | | :key="'advanced-' + field.field + '-' + option.rawValue" |
| | | :label="option.label" |
| | | :value="normalizeOptionValue(field, option.rawValue)"> |
| | | </el-option> |
| | | </el-select> |
| | | <el-autocomplete |
| | | v-else-if="field.kind === 'foreign'" |
| | | v-model="searchDisplay[field.field]" |
| | | size="small" |
| | | :fetch-suggestions="getSuggestionFetcher(field)" |
| | | :placeholder="field.label" |
| | | style="width: 100%;" |
| | | @select="handleSearchForeignSelect(field, $event)" |
| | | @input="handleSearchForeignInput(field)"> |
| | | <template slot-scope="{ item }"> |
| | | <div class="mono">{{ item.value }}</div> |
| | | <div style="font-size:12px;color:#8a98ac;">ID: {{ item.id }}</div> |
| | | </template> |
| | | </el-autocomplete> |
| | | <el-select |
| | | v-else-if="field.kind === 'checkbox'" |
| | | v-model="searchForm[field.field]" |
| | | size="small" |
| | | clearable |
| | | :placeholder="field.label" |
| | | style="width: 100%;"> |
| | | <el-option label="是" :value="normalizeOptionValue(field, field.checkboxActiveRaw)"></el-option> |
| | | <el-option label="否" :value="normalizeOptionValue(field, field.checkboxInactiveRaw)"></el-option> |
| | | </el-select> |
| | | <el-input |
| | | v-else |
| | | v-model.trim="searchForm[field.field]" |
| | | size="small" |
| | | clearable |
| | | :placeholder="field.label" |
| | | @keyup.enter.native="handleSearch"> |
| | | </el-input> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-collapse-transition> |
| | | |
| | | <div class="table-wrap"> |
| | | <div class="table-shell"> |
| | | <el-table |
| | | ref="dataTable" |
| | | :key="'table-' + visibleColumnKeys.join('|')" |
| | | v-loading="loading" |
| | | :data="tableData" |
| | | border |
| | | stripe |
| | | :height="tableHeight" |
| | | @selection-change="handleSelectionChange" |
| | | @sort-change="handleSortChange"> |
| | | <el-table-column type="selection" width="52" align="center"></el-table-column> |
| | | <el-table-column |
| | | v-for="field in visibleColumns" |
| | | :key="field.field" |
| | | :prop="field.field" |
| | | :label="field.label" |
| | | :width="field.primaryKey ? 90 : null" |
| | | :min-width="field.primaryKey ? null : field.minWidth" |
| | | :sortable="isSortableField(field) ? 'custom' : false" |
| | | :show-overflow-tooltip="field.kind !== 'image'" |
| | | align="center"> |
| | | <template slot-scope="scope"> |
| | | <el-image |
| | | v-if="field.kind === 'image' && getTableValue(scope.row, field)" |
| | | :src="getTableValue(scope.row, field)" |
| | | fit="cover" |
| | | style="width: 48px; height: 48px; border-radius: 10px;"> |
| | | </el-image> |
| | | <el-tag v-else-if="field.kind === 'enum'" size="mini" type="success"> |
| | | {{ valueOrDash(getTableValue(scope.row, field)) }} |
| | | </el-tag> |
| | | <el-tag v-else-if="field.kind === 'checkbox'" size="mini" :type="isCheckboxChecked(scope.row, field) ? 'success' : 'info'"> |
| | | {{ isCheckboxChecked(scope.row, field) ? '是' : '否' }} |
| | | </el-tag> |
| | | <span v-else-if="field.textarea" class="payload-cell mono" :title="stringValue(getTableValue(scope.row, field))"> |
| | | {{ valueOrDash(getTableValue(scope.row, field)) }} |
| | | </span> |
| | | <span v-else>{{ valueOrDash(getTableValue(scope.row, field)) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="160" fixed="right" align="center"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="text" @click="openEditDialog(scope.row)">修改</el-button> |
| | | <el-button type="text" style="color:#f56c6c;" @click="removeRows([scope.row[primaryKeyField]])">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="pager-bar"> |
| | | <el-pagination |
| | | small |
| | | background |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :current-page="page.curr" |
| | | :page-size="page.limit" |
| | | :page-sizes="[15, 30, 50, 100, 200, 500]" |
| | | :total="page.total" |
| | | @current-change="handleCurrentChange" |
| | | @size-change="handleSizeChange"> |
| | | </el-pagination> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <el-dialog |
| | | class="dialog-panel" |
| | | :title="dialog.mode === 'create' ? '新增输送站点异常日志' : '修改输送站点异常日志'" |
| | | :visible.sync="dialog.visible" |
| | | width="760px" |
| | | :close-on-click-modal="false"> |
| | | <el-form |
| | | ref="dialogForm" |
| | | :model="dialogForm" |
| | | :rules="dialogRules" |
| | | label-width="110px" |
| | | size="small"> |
| | | <el-row :gutter="16"> |
| | | <el-col |
| | | v-for="field in editableFields" |
| | | :key="'dialog-' + field.field" |
| | | :span="field.textarea || field.kind === 'image' ? 24 : 12"> |
| | | <el-form-item :label="field.label" :prop="field.field"> |
| | | <el-date-picker |
| | | v-if="field.kind === 'date'" |
| | | v-model="dialogForm[field.field]" |
| | | type="datetime" |
| | | value-format="yyyy-MM-dd HH:mm:ss" |
| | | :placeholder="'请选择' + field.label" |
| | | style="width: 100%;"> |
| | | </el-date-picker> |
| | | <el-select |
| | | v-else-if="field.kind === 'enum'" |
| | | v-model="dialogForm[field.field]" |
| | | clearable |
| | | :placeholder="'请选择' + field.label" |
| | | style="width: 100%;"> |
| | | <el-option |
| | | v-for="option in field.enumOptions" |
| | | :key="'dialog-' + field.field + '-' + option.rawValue" |
| | | :label="option.label" |
| | | :value="normalizeOptionValue(field, option.rawValue)"> |
| | | </el-option> |
| | | </el-select> |
| | | <el-autocomplete |
| | | v-else-if="field.kind === 'foreign'" |
| | | v-model="dialogDisplay[field.field]" |
| | | :fetch-suggestions="getSuggestionFetcher(field)" |
| | | :placeholder="'请输入' + field.label" |
| | | style="width: 100%;" |
| | | @select="handleForeignSelect(field, $event)" |
| | | @input="handleForeignInput(field)"> |
| | | <template slot-scope="{ item }"> |
| | | <div class="mono">{{ item.value }}</div> |
| | | <div style="font-size:12px;color:#8a98ac;">ID: {{ item.id }}</div> |
| | | </template> |
| | | </el-autocomplete> |
| | | <el-switch |
| | | v-else-if="field.kind === 'checkbox'" |
| | | v-model="dialogForm[field.field]" |
| | | :active-value="normalizeOptionValue(field, field.checkboxActiveRaw)" |
| | | :inactive-value="normalizeOptionValue(field, field.checkboxInactiveRaw)" |
| | | active-color="#13ce66" |
| | | inactive-color="#c0c4cc"> |
| | | </el-switch> |
| | | <el-input |
| | | v-else-if="field.textarea" |
| | | v-model.trim="dialogForm[field.field]" |
| | | type="textarea" |
| | | :rows="3" |
| | | :placeholder="'请输入' + field.label"> |
| | | </el-input> |
| | | <el-input |
| | | v-else |
| | | v-model.trim="dialogForm[field.field]" |
| | | :placeholder="'请输入' + field.label"> |
| | | </el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div slot="footer" class="dialog-footer"> |
| | | <el-button @click="dialog.visible = false">取消</el-button> |
| | | <el-button type="primary" :loading="dialog.submitting" @click="submitDialog">保存</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | |
| | | <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/vue/js/vue.min.js"></script> |
| | | <script type="text/javascript" src="../../static/vue/element/element.js"></script> |
| | | <script type="text/javascript" src="../../static/js/basStationErrLog/basStationErrLog.js?v=20260331" charset="utf-8"></script> |
| | | </body> |
| | | </html> |