模版下载接口

This commit is contained in:
fl 2025-04-29 18:22:27 +08:00
parent f9d3ac8aa2
commit 857b6c9bee
11 changed files with 381 additions and 18 deletions

View File

@ -11,6 +11,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
@ -122,12 +124,11 @@ public class EpcController extends BaseController {
@ApiOperation(value = "EPC模版下载")
// @PreAuthorize("@ss.hasPermi('key:people:add')")
@PostMapping("/downloadEpcTemp")
public AjaxResult downloadEpcTemp(@RequestBody TbGwModelDto o) {
public void downloadEpcTemp(HttpServletRequest request, HttpServletResponse response, @RequestBody TbGwModelDto o) {
try {
return service.downloadEpcTemp(o);
service.downloadEpcTemp(request, response, o);
}catch (Exception e){
log.info("国网模版修改失败{}",e.getMessage());
return error(e.getMessage());
log.info("EPC模版下载失败{}",e.getMessage());
}
}

View File

@ -12,6 +12,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
@ -123,12 +125,11 @@ public class SouthController extends BaseController {
@ApiOperation(value = "南网模版下载")
// @PreAuthorize("@ss.hasPermi('key:people:add')")
@PostMapping("/downloadEpcTemp")
public AjaxResult downloadSouthTemp(@RequestBody TbGwModelDto o) {
public void downloadSouthTemp(HttpServletRequest request, HttpServletResponse response, @RequestBody TbGwModelDto o) {
try {
return service.downloadSouthTemp(o);
service.downloadSouthTemp(request, response, o);
}catch (Exception e){
log.info("国网模版修改失败{}",e.getMessage());
return error(e.getMessage());
log.info("南网模版下载失败{}",e.getMessage());
}
}

View File

@ -43,6 +43,22 @@ public class ComCorePersonBean extends PersonFileBean{
private String title;
/**
* 等级
*/
private String level;
/**
* 专业
*/
private String major;
/**
* 保险
*/
private Integer isNormal;
/**
* 资格证书
*/
@ -58,6 +74,18 @@ public class ComCorePersonBean extends PersonFileBean{
*/
private String education;
/**
* 年龄
*/
private String age;
/**
* 毕业院校
*/
private String almaMater;
/**
* 在本施工队伍中的职责分工
*/

View File

@ -62,4 +62,10 @@ public class ComOtherPersonBean extends PersonFileBean{
*/
private String level;
/**
* 保险
*/
private Integer isNormal;
}

View File

@ -4,6 +4,8 @@ import com.bonus.common.core.domain.AjaxResult;
import com.bonus.tool.dto.TbGwModelDto;
import com.bonus.tool.dto.TbGwModelVo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface EpcService {
@ -47,5 +49,5 @@ public interface EpcService {
* @param
* @return
*/
AjaxResult downloadEpcTemp(TbGwModelDto o);
void downloadEpcTemp(HttpServletRequest request, HttpServletResponse response, TbGwModelDto o);
}

View File

@ -4,6 +4,8 @@ import com.bonus.common.core.domain.AjaxResult;
import com.bonus.tool.dto.TbGwModelDto;
import com.bonus.tool.dto.TbGwModelVo;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public interface SouthService {
@ -47,5 +49,5 @@ public interface SouthService {
* @param o
* @return
*/
AjaxResult downloadSouthTemp(TbGwModelDto o);
void downloadSouthTemp(HttpServletRequest request, HttpServletResponse response, TbGwModelDto o);
}

View File

@ -3,17 +3,23 @@ package com.bonus.tool.service.impl;
import com.bonus.common.core.domain.AjaxResult;
import com.bonus.common.enums.TableType;
import com.bonus.common.utils.SecurityUtils;
import com.bonus.common.utils.StringUtils;
import com.bonus.tool.dto.*;
import com.bonus.tool.mapper.EpcMapper;
import com.bonus.tool.mapper.StateGridMapper;
import com.bonus.tool.mapper.TbCompanyPerfMapper;
import com.bonus.tool.service.EpcService;
import com.bonus.tool.template.util.FreeMarkerUtil;
import com.bonus.tool.template.util.WordUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* @author fly
@ -26,6 +32,9 @@ public class EpcServiceImpl implements EpcService {
@Resource
private EpcMapper mapper;
@Resource
private TbCompanyPerfMapper tbCompanyPerfMapper;
@Resource
private StateGridMapper stateGridMapper;
@ -153,7 +162,7 @@ public class EpcServiceImpl implements EpcService {
}
@Override
public AjaxResult downloadEpcTemp(TbGwModelDto o) {
public void downloadEpcTemp(HttpServletRequest request, HttpServletResponse response, TbGwModelDto o) {
AjaxResult ajaxResult = getEpcTempById(o);
if (ajaxResult.isSuccess()) {
TbGwModelVo data = (TbGwModelVo) ajaxResult.get("data");
@ -163,6 +172,16 @@ public class EpcServiceImpl implements EpcService {
//获取附件信息
List<TbFileSourceVo> comCoreList = stateGridMapper.getFileSourceList(item.getId(),TableType.TB_KEY_PEOPLE.getCode());
personFileGroup(item, comCoreList);
//获取人员业绩
TbCompanyPerfVo tbCompanyPerfVo = new TbCompanyPerfVo();
tbCompanyPerfVo.setPersonId(item.getUserId());
String perfId = item.getPerfId();
if(StringUtils.isNotEmpty(perfId)){
String[] split = perfId.split(",");
tbCompanyPerfVo.setPerfIds(Arrays.asList(split));
List<TbCompanyPerfVo> personPerfList = tbCompanyPerfMapper.getTbCompanyPerfListByPersonId(tbCompanyPerfVo);
item.setPeoplePerfList(personPerfList);
}
});
//1.3公司其他人员文件
data.getComOtherList().forEach(item -> {
@ -178,8 +197,275 @@ public class EpcServiceImpl implements EpcService {
personFileGroup(item, comOtherList);
});
//将数据转换为模版数据
dealWithWordData(request,response,data);
}
}
@Value("file.domain")
private String prefixPath;
@Value("file.prefix")
private String mappingPath;
/**
* 将数据转换为模版数据
* @param request
* @param response
* @param tbData
*/
private void dealWithWordData(HttpServletRequest request, HttpServletResponse response,TbGwModelVo tbData) {
try {
Map<String, Object> data = new HashMap<>(16);
List<Map<String, Object>> list = new ArrayList<>();
List<Map<String, Object>> list2 = new ArrayList<>();
// 设置标题和简介
data.put("title", tbData.getName() != null ? tbData.getName() : "EPC总承包项目投标技术文件");
data.put("Introduction", "项目经理、设计负责人、采购负责人、施工负责人、商务负责人等主要负责人");
int personNum = 1;
// 处理项目核心人员信息
if (tbData.getComCoreList() != null && !tbData.getComCoreList().isEmpty()) {
for (int i = 0; i < tbData.getComCoreList().size(); i++) {
ComCorePersonBean item = tbData.getComCoreList().get(i);
Map<String, Object> map = new HashMap<>();
map.put("i", personNum++);
map.put("zw", item.getPostName() != null ? item.getPostName() : "");
map.put("name", item.getUserName() != null ? item.getUserName() : "");
map.put("zc", item.getTitle() != null ? item.getTitle() : "");
map.put("zsmc", item.getDiploma() != null ? item.getDiploma() : "");
map.put("level", item.getLevel() != null ? item.getLevel() : "");
map.put("zh", item.getDiplomaNum() != null ? item.getDiplomaNum() : "");
map.put("zy", item.getMajor() != null ? item.getMajor() : "");
map.put("ylbx", item.getIsNormal() != null ? (item.getIsNormal() == 1 ? "异常" : "正常") : "异常");
map.put("bz", "");
list.add(map);
}
}
// 处理公司其他人员信息
if (tbData.getComOtherList() != null && !tbData.getComOtherList().isEmpty()) {
for (int i = 0; i < tbData.getComOtherList().size(); i++) {
ComOtherPersonBean item = tbData.getComOtherList().get(i);
Map<String, Object> map = new HashMap<>();
map.put("i", personNum++);
map.put("zw", item.getPostName() != null ? item.getPostName() : "");
map.put("name", item.getUserName() != null ? item.getUserName() : "");
map.put("zc", item.getTitle() != null ? item.getTitle() : "");
map.put("zsmc", item.getDiploma() != null ? item.getDiploma() : "");
map.put("level", item.getLevel() != null ? item.getLevel() : "");
map.put("zh", item.getDiplomaNum() != null ? item.getDiplomaNum() : "");
map.put("zy", item.getMajor() != null ? item.getMajor() : "");
map.put("ylbx", item.getIsNormal() != null ? (item.getIsNormal() == 1 ? "异常" : "正常") : "异常");
map.put("bz", "");
list.add(map);
}
}
// 处理分包人员信息
if (tbData.getSubPersonList() != null && !tbData.getSubPersonList().isEmpty()) {
for (int i = 0; i < tbData.getSubPersonList().size(); i++) {
ComOtherPersonBean item = tbData.getSubPersonList().get(i);
Map<String, Object> map = new HashMap<>();
map.put("i", personNum++);
map.put("zw", item.getPostName() != null ? item.getPostName() : "");
map.put("name", item.getUserName() != null ? item.getUserName() : "");
map.put("zc", item.getTitle() != null ? item.getTitle() : "");
map.put("zsmc", item.getDiploma() != null ? item.getDiploma() : "");
map.put("level", item.getLevel() != null ? item.getLevel() : "");
map.put("zh", item.getDiplomaNum() != null ? item.getDiplomaNum() : "");
map.put("zy", item.getMajor() != null ? item.getMajor() : "");
map.put("ylbx", item.getIsNormal() != null ? (item.getIsNormal() == 1 ? "异常" : "正常") : "异常");
map.put("bz", "");
list.add(map);
}
}
// 处理公司核心人员简历信息
if (tbData.getComCoreList() != null && !tbData.getComCoreList().isEmpty()) {
for (int i = 0; i < tbData.getComCoreList().size(); i++) {
ComCorePersonBean item = tbData.getComCoreList().get(i);
Map<String, Object> map = new HashMap<>();
map.put("hasJj", true);
map.put("zy", item.getPostName() != null ? item.getPostName() + "简介" : "项目经理简介");
map.put("name", item.getUserName() != null ? item.getUserName() : "");
map.put("age", item.getAge() != null ? item.getAge() : "");
map.put("xl", item.getEducation() != null ? item.getEducation() : "");
map.put("zc", item.getTitle() != null ? item.getTitle() : "");
map.put("zw", item.getPostName() != null ? item.getPostName() : "");
map.put("rz", item.getPostName() != null ? item.getPostName() : "");
map.put("byxx", item.getAlmaMater() != null ? item.getAlmaMater() : "");
map.put("Introduction", item.getPostName() != null ? item.getPostName() + "简历表" : "项目经理简历表");
// 处理工作经历
List<Map<String, Object>> infoList = new ArrayList<>();
if (item.getPeoplePerfList() != null && !item.getPeoplePerfList().isEmpty()) {
for (int j = 0; j < item.getPeoplePerfList().size(); j++) {
TbCompanyPerfVo tbCompanyPerfVo = item.getPeoplePerfList().get(i);
Map<String, Object> expMap = new HashMap<>();
expMap.put("time", tbCompanyPerfVo.getStartTime()+""+tbCompanyPerfVo.getEndTime());
expMap.put("xm", tbCompanyPerfVo.getProName());
expMap.put("zy", item.getPostName() != null ? item.getPostName() : "");
expMap.put("lxr", tbCompanyPerfVo.getOwnerUnit()+tbCompanyPerfVo.getOwnerPhone());
infoList.add(expMap);
}
}
// 处理证件图片
List<Map<String, Object>> imgList = new ArrayList<>();
int imgIndex = 1;
// 处理身份证图片
if (item.getIdCardFileList() != null) {
for (TbFileSourceVo file : item.getIdCardFileList()) {
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("width", "4959860");
imgMap.put("height", "3492375");
imgMap.put("index", (100 * (i + 1)) + imgIndex++);
imgMap.put("base64Url", file.getFilePath() != null ?
FreeMarkerUtil.getImageBase(prefixPath + mappingPath + file.getFilePath()) : "");
imgList.add(imgMap);
}
}
// 处理学历证书图片
if (item.getDiplomaFileList() != null) {
for (TbFileSourceVo file : item.getDiplomaFileList()) {
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("width", "5325745");
imgMap.put("height", "7534910");
imgMap.put("index", (100 * (i + 1)) + imgIndex++);
imgMap.put("base64Url", file.getFilePath() != null ?
FreeMarkerUtil.getImageBase(prefixPath + mappingPath + file.getFilePath()) : "");
imgList.add(imgMap);
}
}
// 处理其他资质图片
if (item.getOtherFileList() != null) {
for (TbFileSourceVo file : item.getOtherFileList()) {
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("width", "5325745");
imgMap.put("height", "7534910");
imgMap.put("index", (100 * (i + 1)) + imgIndex++);
imgMap.put("base64Url", file.getFilePath() != null ?
FreeMarkerUtil.getImageBase(prefixPath + mappingPath + file.getFilePath()) : "");
imgList.add(imgMap);
}
}
// 处理业绩信息
map.put("yjTitle", item.getPostName() != null ? item.getPostName() + "业绩" : "项目经理业绩");
List<Map<String, Object>> yjList = new ArrayList<>();
if (item.getProPerf() != null && !item.getProPerf().isEmpty()) {
String[] perfList = item.getProPerf().split(",");
for (int j = 0; j < perfList.length; j++) {
Map<String, Object> yjMap = new HashMap<>();
yjMap.put("yj", "业绩" + (j + 1) + "" + perfList[j]);
// 业绩相关图片 - 如果没有特定的业绩图片可以复用证书图片或者不添加
List<Map<String, Object>> imgList2 = new ArrayList<>();
if (item.getOtherFileList() != null) {
for (int k = 0; k < item.getOtherFileList().size(); k++) {
TbFileSourceVo file = item.getOtherFileList().get(k);
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("index", (10000 * (j + 1)) + (k + 1));
imgMap.put("width", "5325745");
imgMap.put("height", "7534910");
imgMap.put("base64Url", file.getFilePath() != null ?
FreeMarkerUtil.getImageBase(prefixPath + mappingPath + file.getFilePath()) : "");
imgList2.add(imgMap);
}
}
yjMap.put("imgList", imgList2);
yjList.add(yjMap);
}
}
map.put("infoList", infoList);
map.put("imgList", imgList);
map.put("yjList", yjList);
list2.add(map);
}
}
// 处理公司其他人员简历信息和分包人信息
List<ComOtherPersonBean> comOtherList = tbData.getComOtherList();
List<ComOtherPersonBean> subPersonList = tbData.getSubPersonList();
comOtherList.addAll(subPersonList);
if (comOtherList.isEmpty()) {
for (int i = 0; i < comOtherList.size(); i++) {
ComOtherPersonBean item = comOtherList.get(i);
Map<String, Object> map = new HashMap<>();
map.put("hasJj", false);
// 处理工作经历
List<Map<String, Object>> infoList = new ArrayList<>();
// 处理证件图片
List<Map<String, Object>> imgList = new ArrayList<>();
int imgIndex = 1;
// 处理身份证图片
if (item.getIdCardFileList() != null) {
for (TbFileSourceVo file : item.getIdCardFileList()) {
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("width", "4959860");
imgMap.put("height", "3492375");
imgMap.put("index", (100 * (i + 1)) + imgIndex++);
imgMap.put("base64Url", file.getFilePath() != null ?
FreeMarkerUtil.getImageBase(prefixPath + mappingPath + file.getFilePath()) : "");
imgList.add(imgMap);
}
}
// 处理学历证书图片
if (item.getDiplomaFileList() != null) {
for (TbFileSourceVo file : item.getDiplomaFileList()) {
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("width", "5325745");
imgMap.put("height", "7534910");
imgMap.put("index", (100 * (i + 1)) + imgIndex++);
imgMap.put("base64Url", file.getFilePath() != null ?
FreeMarkerUtil.getImageBase(prefixPath + mappingPath + file.getFilePath()) : "");
imgList.add(imgMap);
}
}
// 处理其他资质图片
if (item.getOtherFileList() != null) {
for (TbFileSourceVo file : item.getOtherFileList()) {
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("width", "5325745");
imgMap.put("height", "7534910");
imgMap.put("index", (100 * (i + 1)) + imgIndex++);
imgMap.put("base64Url", file.getFilePath() != null ?
FreeMarkerUtil.getImageBase(prefixPath + mappingPath + file.getFilePath()) : "");
imgList.add(imgMap);
}
}
// 处理业绩信息
map.put("yjTitle", "");
List<Map<String, Object>> yjList = new ArrayList<>();
Map<String, Object> yjMap = new HashMap<>();
yjMap.put("yj", "业绩");
// 业绩相关图片 - 如果没有特定的业绩图片可以复用证书图片或者不添加
List<Map<String, Object>> imgList2 = new ArrayList<>();
Map<String, Object> imgMap = new HashMap<>();
imgMap.put("index", 10000) ;
imgMap.put("width", "5325745");
imgMap.put("height", "7534910");
imgMap.put("base64Url", "");
imgList2.add(imgMap);
yjMap.put("imgList", imgList2);
yjList.add(yjMap);
map.put("infoList", infoList);
map.put("imgList", imgList);
map.put("yjList", yjList);
list2.add(map);
}
}
data.put("list", list);
data.put("list2", list2);
data.put("tbr", tbData.getCreateUser() != null ? tbData.getCreateUser() : "");
// 导出Word文档
WordUtils.exportMillCertificateWord(request, response, data, tbData.getName(), "EPC.ftl");
} catch (Exception e) {
log.error("处理EPC模版下载数据失败", e);
}
return AjaxResult.success();
}
/**

View File

@ -3,16 +3,22 @@ package com.bonus.tool.service.impl;
import com.bonus.common.core.domain.AjaxResult;
import com.bonus.common.enums.TableType;
import com.bonus.common.utils.SecurityUtils;
import com.bonus.common.utils.StringUtils;
import com.bonus.tool.dto.*;
import com.bonus.tool.mapper.EpcMapper;
import com.bonus.tool.mapper.SouthMapper;
import com.bonus.tool.mapper.StateGridMapper;
import com.bonus.tool.mapper.TbCompanyPerfMapper;
import com.bonus.tool.service.SouthService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -26,6 +32,12 @@ public class SouthServiceImpl implements SouthService {
@Resource
private SouthMapper mapper;
@Resource
private EpcServiceImpl epcServiceImpl;
@Resource
private TbCompanyPerfMapper tbCompanyPerfMapper;
@Resource
private StateGridMapper stateGridMapper;
@ -153,7 +165,7 @@ public class SouthServiceImpl implements SouthService {
}
@Override
public AjaxResult downloadSouthTemp(TbGwModelDto o) {
public void downloadSouthTemp(HttpServletRequest request, HttpServletResponse response, TbGwModelDto o) {
AjaxResult ajaxResult = getSouthTempById(o);
if (ajaxResult.isSuccess()) {
TbGwModelVo data = (TbGwModelVo) ajaxResult.get("data");
@ -163,6 +175,16 @@ public class SouthServiceImpl implements SouthService {
//获取附件信息
List<TbFileSourceVo> comCoreList = stateGridMapper.getFileSourceList(item.getId(), TableType.TB_KEY_PEOPLE.getCode());
personFileGroup(item, comCoreList);
//获取人员业绩
TbCompanyPerfVo tbCompanyPerfVo = new TbCompanyPerfVo();
tbCompanyPerfVo.setPersonId(item.getUserId());
String perfId = item.getPerfId();
if(StringUtils.isNotEmpty(perfId)){
String[] split = perfId.split(",");
tbCompanyPerfVo.setPerfIds(Arrays.asList(split));
List<TbCompanyPerfVo> personPerfList = tbCompanyPerfMapper.getTbCompanyPerfListByPersonId(tbCompanyPerfVo);
item.setPeoplePerfList(personPerfList);
}
});
//1.3公司其他人员文件
data.getComOtherList().forEach(item -> {
@ -177,9 +199,8 @@ public class SouthServiceImpl implements SouthService {
List<TbFileSourceVo> comOtherList = stateGridMapper.getFileSourceList(item.getId(),TableType.TB_SUB_PEOPLE.getCode());
personFileGroup(item, comOtherList);
});
epcServiceImpl.downloadEpcTemp(request, response, o);
}
return AjaxResult.success();
}
/**

View File

@ -217,7 +217,7 @@ public class StateGridServiceImpl implements StateGridService {
//获取附件信息
List<TbFileSourceVo> comCoreList = getFileSourceList(item.getId(),TableType.TB_KEY_PEOPLE.getCode());
personFileGroup(item, comCoreList);
//获取附件信息
//获取人员业绩
TbCompanyPerfVo tbCompanyPerfVo = new TbCompanyPerfVo();
tbCompanyPerfVo.setPersonId(item.getUserId());
String perfId = item.getPerfId();

View File

@ -15,6 +15,7 @@
epc_id,
key_id,
position,
perf_id,
pro_perf
)values
<foreach collection="list" item="item" separator=",">
@ -22,6 +23,7 @@
#{item.parentId},
#{item.id},
#{item.postName},
#{item.perfId},
#{item.proPerf}
)
</foreach>
@ -128,9 +130,14 @@
tkp.id_card,
tkp.title,
tkp.diploma,
tkp.diploma_num,
tkp.age,
tkp.education,
tkp.alma_mater,
tgku.position as post_name,
tkp.major,
tkp.`level`,
tgku.perf_id,
tgku.pro_perf
FROM tb_epc_company_user tgku
LEFT JOIN tb_key_people tkp ON tgku.key_id = tkp.id
@ -147,6 +154,7 @@
tkp.diploma_num,
tkp.major,
tkp.`level`,
tkp.`is_normal`,
tgou.position as post_name
FROM tb_epc_other_user tgou
LEFT JOIN tb_other_people tkp ON tgou.other_id = tkp.id

View File

@ -15,6 +15,7 @@
south_id,
key_id,
position,
perf_id,
pro_perf
)values
<foreach collection="list" item="item" separator=",">
@ -22,6 +23,7 @@
#{item.parentId},
#{item.id},
#{item.postName},
#{item.perfId},
#{item.proPerf}
)
</foreach>
@ -128,9 +130,14 @@
tkp.id_card,
tkp.title,
tkp.diploma,
tkp.diploma_num,
tkp.age,
tkp.education,
tkp.alma_mater,
tgku.position as post_name,
tkp.major,
tkp.`level`,
tgku.perf_id,
tgku.pro_perf
FROM tb_south_company_user tgku
LEFT JOIN tb_key_people tkp ON tgku.key_id = tkp.id
@ -147,6 +154,7 @@
tkp.diploma_num,
tkp.major,
tkp.`level`,
tkp.`is_normal`,
tgou.position as post_name
FROM tb_south_other_user tgou
LEFT JOIN tb_other_people tkp ON tgou.other_id = tkp.id