Compare commits

..

9 Commits

Author SHA1 Message Date
曹鹏飞 995dbf3369 Merge branch 'feature/bug-1372' into feature/quotation
# Conflicts:
#	nflg-mobilebroken-common/src/main/java/com/nflg/mobilebroken/common/constant/Constant.java
2026-03-27 14:54:07 +08:00
曹鹏飞 f715b9c1a1 feat: bug-1372 工单问题类型从字典获取 2026-03-27 14:52:59 +08:00
曹鹏飞 62101a7e91 Merge branch 'feature/bug-1334' 2026-03-23 11:47:02 +08:00
曹鹏飞 960f0f79cb Merge branch 'feature/bug-1334' into prod/20260317 2026-03-17 18:17:17 +08:00
曹鹏飞 5e533f4d39 Merge branch 'feature/bug-1344' into prod/20260317 2026-03-17 18:16:20 +08:00
曹鹏飞 26084b1e1b Merge remote-tracking branch '南方路机/master' into prod/20260317
# Conflicts:
#	nflg-mobilebroken-admin/src/main/java/com/nflg/mobilebroken/admin/controller/TicketController.java
2026-03-17 18:15:42 +08:00
曹鹏飞 5e38841aae Merge branch 'feature/bug-1369' into prod/20260316 2026-03-16 09:21:52 +08:00
10001392 8302a7e8cf 禅道优化
1、移动破和工服管理的工单管理中,工单标题的翻译列,可否展示到工单列表上,或者增加个备注列?
2026-03-13 13:50:55 +08:00
10001392 736978c29f 禅道优化
1、工服模块工单管理列表增加事故等级展示;派工管理列表中增加是否按时完成字段
2、移动破和工服管理的工单管理中,工单标题的翻译列,可否展示到工单列表上,或者增加个备注列?
3、工服管理的派工管理,增加设备编号筛选字段
4、派工中,要求增加导出功能,在有选中数据的情况下,导出所选数据列表。在未选中数据的情况下,默认导出所有派工数据
2026-03-12 08:57:08 +08:00
16 changed files with 388 additions and 13 deletions

View File

@ -2,7 +2,9 @@ package com.nflg.mobilebroken.admin.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.pdf.BaseFont;
import com.nflg.mobilebroken.admin.annotation.ApiMark;
@ -21,6 +23,7 @@ import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*;
import com.nflg.mobilebroken.starter.annotation.MethodInfoMark;
import com.nflg.mobilebroken.starter.service.UniPushService;
import com.nflg.mobilebroken.starter.service.impl.DeepSeekTranslate;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
@ -40,6 +43,7 @@ import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
@ -145,6 +149,12 @@ public class TicketController extends ControllerBase {
@Resource
private ITBaseAreaService areaService;
@Resource
private DeepSeekTranslate deepSeekTranslate;
@Resource
private ILanguageService languageService;
/**
* 获取问题类型
* @return 问题类型列表
@ -152,9 +162,14 @@ public class TicketController extends ControllerBase {
@GetMapping("getQuestions")
@ApiMark(moduleName = "工单管理", apiName = "获取问题类型", isPublic = true)
public ApiResult<List<String>> getQuestions() {
return ApiResult.success(Arrays.asList("技术设计问题", "装配工艺问题", "焊接质量问题", "机组装配质量问题", "电控问题"
, "工况方案问题", "客户操作不当", "原材料配件质量问题", "QC检验遗漏/误差", "部件/整机外观", "安装问题", "调试问题"
, "外购件质量问题", "运输问题", "非故障问题/参数咨询"));
// return ApiResult.success(Arrays.asList("技术设计问题", "装配工艺问题", "焊接质量问题", "机组装配质量问题", "电控问题"
// , "工况方案问题", "客户操作不当", "原材料配件质量问题", "QC检验遗漏/误差", "部件/整机外观", "安装问题", "调试问题"
// , "外购件质量问题", "运输问题", "非故障问题/参数咨询"));
return ApiResult.success(dictionaryItemService.getListByDictionaryCodeAndType(Constant.DICTIONARY_TICKET_QUESTION,"移动破")
.stream()
.map(DictionaryItem::getName)
.collect(Collectors.toList())
);
}
/**
@ -279,9 +294,25 @@ public class TicketController extends ControllerBase {
*/
@PostMapping("searchTicket")
@ApiMark(moduleName = "工单管理", apiName = "搜索工单")
public ApiResult<PageData<AdminTicketVO>> searchTicket(@Valid @RequestBody AdminTicketSearchRequest request) {
public ApiResult<PageData<AdminTicketVO>> searchTicket(@Valid @RequestBody AdminTicketSearchRequest request, HttpServletRequest request2) {
// 20260311 工单标题在列表页面把它的翻译列展示出来
String languageCode = request2.getHeader("language");
Language language;
if (StrUtil.isNotBlank(languageCode)) {
language = languageService.lambdaQuery().eq(Language::getCode, languageCode).one();
} else {
language = null;
}
return ApiResult.success(PageUtil.convert(ticketService.searchPage(request), d -> {
d.setEvaluate(getTicketEvaluateForList(Math.toIntExact(d.getId())));
// 标题字符串不含中文才翻译
if (ObjectUtil.isNotEmpty(d.getTitle()) && !Validator.hasChinese(d.getTitle())) {
String text = d.getTitle().replaceAll("<br>", ",");
if (language != null && language.getName() != null) {
String titleTranslate = deepSeekTranslate.translateWord(text, "auto", language.getName(), "text");
d.setTitleTranslate(titleTranslate);
}
}
return d;
}));
}

View File

@ -153,4 +153,6 @@ public class Constant {
* 角色 营销总监
*/
public static final String ROLE_CODE_MARKETING_DIRECTOR = "MarketingDirector";
public static final String DICTIONARY_TICKET_QUESTION = "Question";
}

View File

@ -3,6 +3,7 @@ package com.nflg.mobilebroken.common.pojo.request;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
@Data
public class DispatchSearchRequest extends PageRequest {
@ -51,4 +52,6 @@ public class DispatchSearchRequest extends PageRequest {
* 结束时间
*/
private LocalDate endDate;
private List<Long> ids;
}

View File

@ -28,6 +28,11 @@ public class SaveDictionaryItemRequest {
@NotBlank(message = "属性值不能为空")
private String value;
/**
* 类型分组
*/
private String type;
//多语言翻译
private List<TranslateMap> languages;
}

View File

@ -29,6 +29,9 @@ public class AdminTicketVO {
@ExcelColumn("标题")
private String title;
@ExcelColumn("标题翻译")
private String titleTranslate = "";
//工单状态
@JsonIgnore
@IgnoreExport

View File

@ -24,6 +24,11 @@ public class DictionaryItemVO {
*/
private String value;
/**
* 类型分组
*/
private String type;
/**
* 创建人
*/

View File

@ -1,11 +1,15 @@
package com.nflg.mobilebroken.gongfu.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.mobilebroken.common.constant.MessageSubType;
import com.nflg.mobilebroken.common.constant.MessageType;
import com.nflg.mobilebroken.common.constant.TicketState;
import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.request.*;
@ -15,26 +19,36 @@ import com.nflg.mobilebroken.common.pojo.vo.GongfuFileVO;
import com.nflg.mobilebroken.common.util.AdminUserUtil;
import com.nflg.mobilebroken.common.util.DateTimeUtil;
import com.nflg.mobilebroken.common.util.VUtils;
import com.nflg.mobilebroken.gongfu.annotation.ApiMark;
import com.nflg.mobilebroken.gongfu.pojo.dto.DispatchDTO;
import com.nflg.mobilebroken.gongfu.pojo.vo.ApplyforAuditVO;
import com.nflg.mobilebroken.gongfu.pojo.vo.DispatchApplyforAuditVO;
import com.nflg.mobilebroken.gongfu.publisher.DispatchEventPublisher;
import com.nflg.mobilebroken.repository.entity.AdminMessage;
import com.nflg.mobilebroken.repository.entity.GongfuDispatch;
import com.nflg.mobilebroken.repository.entity.GongfuDispatchApplyfor;
import com.nflg.mobilebroken.repository.entity.GongfuFile;
import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.ttzero.excel.entity.ListSheet;
import org.ttzero.excel.entity.Workbook;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -62,6 +76,8 @@ public class DispatchController extends ControllerBase {
@Resource
private IAdminMessageService adminMessageService;
@Resource
private IDictionaryItemService dictionaryItemService;
/**
* 新增派工单
@ -362,4 +378,60 @@ public class DispatchController extends ControllerBase {
);
return ApiResult.success();
}
/**
* 导出选中的派工
* @param ids 选中的id集合
*/
@PostMapping("exportSelect")
@ApiMark(moduleName = "派工管理", apiName = "导出选中的派工")
public void exportSelect(HttpServletResponse response, @RequestBody @NotEmpty List<Long> ids) throws Exception {
DispatchSearchRequest request = new DispatchSearchRequest();
request.setIds(ids);
handleExportData(response, request);
}
private void handleExportData(HttpServletResponse response, DispatchSearchRequest request) throws IOException {
request.setPage(1);
request.setPageSize(Integer.MAX_VALUE);
IPage<DispatchVO> page = dispatchService.search(request, AdminUserUtil.getUserId());
List<DispatchVO> list = page.getRecords();
Set<Integer> typeSet = list.stream().map(DispatchVO::getType).collect(Collectors.toSet());
List<DictionaryItem> dictionaryItems = dictionaryItemService.listByIds(typeSet);
// List<GongfuDispatchApplyfor> applyforList = dispatchApplyforService.lambdaQuery().in(GongfuDispatchApplyfor::getTicketId, list.stream().map(DispatchVO::getId).collect(Collectors.toList())).list();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
List<DispatchDTO> datas = list.stream().map(d -> {
DispatchDTO data = new DispatchDTO();
BeanUtil.copyProperties(d, data);
TicketState ticketState = TicketState.findByValue(data.getState().byteValue());
if (ObjectUtil.isNotEmpty(ticketState)) {
data.setStateDesc(ticketState.getDescription());
}
Optional<DictionaryItem> itemOptional = dictionaryItems.stream().filter(di -> di.getId().equals(data.getType())).findFirst();
itemOptional.ifPresent(dictionaryItem -> data.setTypeDesc(dictionaryItem.getName()));
data.setIsDelayDesc(data.isDelay() ? "" : "");
// if (CollectionUtil.isNotEmpty(applyforList)) {
// Optional<GongfuDispatchApplyfor> applyforOptional = applyforList.stream().filter(a -> a.getTicketId().equals(data.getId())).findFirst();
// applyforOptional.ifPresent(applyfor -> data.setDelayEndDate(applyfor.getEndDate()));
// }
if (ObjectUtil.isNotEmpty(data.getActualEndDate()) && ObjectUtil.isNotEmpty(data.getPlanEndDate())) {
data.setIsOntime(LocalDate.parse(data.getActualEndDate(), formatter).isAfter(LocalDate.parse(data.getPlanEndDate(), formatter))
? "" : (ObjectUtil.isNotEmpty(data.getActualEndDate()) ? "" : ""));
}
data.setAssetInfo(data.getCustomerName() + "" + data.getDeviceNo() + "");
return data;
}).collect(Collectors.toList());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("派工导出.xlsx", StandardCharsets.UTF_8));
new Workbook().addSheet(new ListSheet<>(datas)).writeTo(response.getOutputStream());
}
/**
* 导出派工列表
* @param request
*/
@PostMapping("exportSearch")
public void exportSearch(HttpServletResponse response, @RequestBody DispatchSearchRequest request) throws IOException {
handleExportData(response, request);
}
}

View File

@ -2,6 +2,8 @@ package com.nflg.mobilebroken.gongfu.controller;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.pdf.BaseFont;
import com.nflg.mobilebroken.common.constant.*;
@ -24,6 +26,7 @@ import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*;
import com.nflg.mobilebroken.starter.annotation.MethodInfoMark;
import com.nflg.mobilebroken.starter.service.UniPushService;
import com.nflg.mobilebroken.starter.service.impl.DeepSeekTranslate;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
@ -42,6 +45,7 @@ import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
@ -138,6 +142,11 @@ public class TicketController extends ControllerBase {
@Resource
private ITicketSolutionAuditService ticketSolutionAuditService;
@Resource
private DeepSeekTranslate deepSeekTranslate;
@Resource
private ILanguageService languageService;
/**
* 获取问题类型
* @return 问题类型列表
@ -145,9 +154,14 @@ public class TicketController extends ControllerBase {
@GetMapping("getQuestions")
@ApiMark(moduleName = "工单管理", apiName = "获取问题类型", isPublic = true)
public ApiResult<List<String>> getQuestions() {
return ApiResult.success(Arrays.asList("技术设计问题", "装配工艺问题", "焊接质量问题", "机组装配质量问题", "电控问题"
, "工况方案问题", "客户操作不当", "原材料配件质量问题", "QC检验遗漏/误差", "部件/整机外观", "安装问题", "调试问题"
, "外购件质量问题", "运输问题", "非故障问题/参数咨询"));
// return ApiResult.success(Arrays.asList("技术设计问题", "装配工艺问题", "焊接质量问题", "机组装配质量问题", "电控问题"
// , "工况方案问题", "客户操作不当", "原材料配件质量问题", "QC检验遗漏/误差", "部件/整机外观", "安装问题", "调试问题"
// , "外购件质量问题", "运输问题", "非故障问题/参数咨询"));
return ApiResult.success(dictionaryItemService.getListByDictionaryCodeAndType(Constant.DICTIONARY_TICKET_QUESTION,"工服")
.stream()
.map(DictionaryItem::getName)
.collect(Collectors.toList())
);
}
/**
@ -273,9 +287,25 @@ public class TicketController extends ControllerBase {
*/
@PostMapping("searchTicket")
@ApiMark(moduleName = "工单管理", apiName = "搜索工单")
public ApiResult<PageData<AdminTicketVO>> searchTicket(@Valid @RequestBody AdminTicketSearchRequest request) {
public ApiResult<PageData<AdminTicketVO>> searchTicket(@Valid @RequestBody AdminTicketSearchRequest request, HttpServletRequest request2) {
// 20260311 工单标题在列表页面把它的翻译列展示出来
String languageCode = request2.getHeader("language");
Language language;
if (StrUtil.isNotBlank(languageCode)) {
language = languageService.lambdaQuery().eq(Language::getCode, languageCode).one();
} else {
language = null;
}
return ApiResult.success(PageUtil.convert(ticketService.searchPage(request), d -> {
d.setEvaluate(getTicketEvaluateForList(d.getId()));
// 标题字符串不含中文才翻译
if (ObjectUtil.isNotEmpty(d.getTitle()) && !Validator.hasChinese(d.getTitle())) {
String text = d.getTitle().replaceAll("<br>", ",");
if (language != null && language.getName() != null) {
String titleTranslate = deepSeekTranslate.translateWord(text, "auto", language.getName(), "text");
d.setTitleTranslate(titleTranslate);
}
}
return d;
}));
}

View File

@ -0,0 +1,196 @@
package com.nflg.mobilebroken.gongfu.pojo.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.ttzero.excel.annotation.ExcelColumn;
import java.time.LocalDateTime;
@EqualsAndHashCode(callSuper = false)
@Data
@Accessors(chain = true)
public class DispatchDTO {
/**
* id
*/
// @ExcelColumn("id")
private Long id;
/**
* 派工编号
*/
@ExcelColumn("派工编号")
private String code;
/**
* 派工名称
*/
@ExcelColumn("派工名称")
private String title;
/**
* 状态0待处理1处理中2完成
*/
private Integer state;
/**
* 单据状态
*/
@ExcelColumn("单据状态")
private String stateDesc;
/**
* 类型0工单1定检2培训3个案4回访5安装调试
*/
private Integer type;
/**
* 类型描述
*/
@ExcelColumn("派工类型")
private String typeDesc;
/**
* 设备编号
*/
@ExcelColumn("设备编号")
private String deviceNo;
@ExcelColumn("资产信息")
private String assetInfo;
/**
* 客户名称
*/
@ExcelColumn("客户名称")
private String customerName;
/**
* 地址
*/
@ExcelColumn("派工地址")
private String address;
/**
* 执行人类型1内部用户2外部用户
*/
private Integer handlerUserType;
/**
* 执行人id
*/
private Long handlerUserId;
/**
* 执行人
*/
@ExcelColumn("派工执行人")
private String handlerUserName;
/**
* 描述
*/
@ExcelColumn("派工任务描述")
private String remark;
/**
* 代理商名称
*/
@ExcelColumn("代理商名称")
private String agentName;
/**
* 计划开始日期
*/
@ExcelColumn("计划开始日期")
private String planStartDate;
/**
* 计划完成日期
*/
@ExcelColumn("计划完成日期")
private String planEndDate;
/**
* 实际开始日期
*/
@ExcelColumn("实际开始日期")
private String actualStartDate;
/**
* 实际结束日期
*/
@ExcelColumn("实际结束日期")
private String actualEndDate;
/**
* 是否延期
*/
@JsonProperty("isDelay")
private boolean isDelay;
/**
* 是否延期
*/
@ExcelColumn("是否延期")
private String isDelayDesc;
/**
* 延期结束日期
*/
// @ExcelColumn("延期日期")
private String delayEndDate;
/**
* 完成时间
*/
@ExcelColumn("完结时间")
private LocalDateTime completeDate;
/**
* 计划执行天数
*/
@ExcelColumn("计划执行天数")
private long planNum;
/**
* 是否按时完成
*/
@ExcelColumn("是否按时完成")
private String isOntime = "";
/**
* 延期原因
*/
private String delayReason;
/**
* 实际执行天数
*/
private Long actualNum;
/**
* 创建人id
*/
private Integer createById;
/**
* 创建人
*/
@ExcelColumn("派单人")
private String createBy;
/**
* 创建时间
*/
@ExcelColumn("派单日期")
private LocalDateTime createTime;
/**
* 延期申请id
*/
private Long applyforId;
}

View File

@ -48,6 +48,11 @@ public class DictionaryItem implements Serializable {
*/
private String value;
/**
* 类型分组
*/
private String type;
/**
* 创建人
*/

View File

@ -25,4 +25,6 @@ public interface DictionaryItemMapper extends BaseMapper<DictionaryItem> {
List<DictionaryItem> getListByDictionaryCode(String code,String language);
DictionaryItem getByCode(String dictionaryCode, String dictionaryItemCode);
List<DictionaryItem> getListByDictionaryCodeAndType(String dictionaryCode, String type);
}

View File

@ -29,4 +29,6 @@ public interface IDictionaryItemService extends IService<DictionaryItem> {
List<DictionaryItem> getListByDictionaryCode(String code,String language);
DictionaryItem getByCode(String dictionaryCode, String DictionaryItemCode);
List<DictionaryItem> getListByDictionaryCodeAndType(String dictionaryCode,String type);
}

View File

@ -86,6 +86,7 @@ public class DictionaryItemServiceImpl extends ServiceImpl<DictionaryItemMapper,
.setName(request.getName())
.setCode(request.getCode())
.setValue(request.getValue())
.setType(request.getType())
.setCreateBy(AdminUserUtil.getUserName())
.setCreateTime(LocalDateTime.now());
save(dictionaryItem);
@ -96,6 +97,7 @@ public class DictionaryItemServiceImpl extends ServiceImpl<DictionaryItemMapper,
.setName(request.getName())
.setCode(request.getCode())
.setValue(request.getValue())
.setType(request.getType())
.setUpdateBy(AdminUserUtil.getUserName())
.setUpdateTime(LocalDateTime.now());
updateById(dictionaryItem);
@ -146,4 +148,9 @@ public class DictionaryItemServiceImpl extends ServiceImpl<DictionaryItemMapper,
public DictionaryItem getByCode(String dictionaryCode, String DictionaryItemCode) {
return baseMapper.getByCode(dictionaryCode, DictionaryItemCode);
}
@Override
public List<DictionaryItem> getListByDictionaryCodeAndType(String dictionaryCode, String type) {
return baseMapper.getListByDictionaryCodeAndType(dictionaryCode, type);
}
}

View File

@ -24,4 +24,10 @@
INNER JOIN dictionary_item di ON d.id=di.dictionary_id
WHERE d.`code`= #{dictionaryCode} AND di.`code`= #{dictionaryItemCode}
</select>
<select id="getListByDictionaryCodeAndType" resultType="com.nflg.mobilebroken.repository.entity.DictionaryItem">
SELECT di.*
FROM dictionary d
INNER JOIN dictionary_item di ON d.id=di.dictionary_id
WHERE d.`code`= #{dictionaryCode} AND di.`type`= #{type}
</select>
</mapper>

View File

@ -43,6 +43,12 @@
or dv.customer_name like concat('%',#{request.key},'%')
)
</if>
<if test="request.ids!=null">
AND da.id in
<foreach collection="request.ids" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</if>
</where>
ORDER BY usort DESC,da.state,da.plan_start_date DESC,da.id DESC
</select>

View File

@ -161,7 +161,7 @@
,t.create_time AS 'createTime',t.solve_time AS 'completeTime',di.name AS 'warrantyStatusDesc',d.device_type AS 'deviceType'
,d.model_no AS 'equipmentModel',d.shipment_date AS 'shipmentDate',IF(tf.id IS NULL, false, true) AS 'followed'
,auc.user_name AS 'cqm',t.update_time AS 'closeTime',auh.user_name AS 'currentHandle',dt2.cqm_person_name AS 'cqms'
,t.handle_name AS 'handle',t.description,t.throughput
,t.handle_name AS 'handle',t.description,t.throughput,t.accident_level
FROM gongfu_ticket t
LEFT JOIN app_user u ON t.user_id=u.id
LEFT JOIN admin_user au ON t.user_id=au.id