출장등록 진행중 -> 화면 등록 완료
리스트 진행
This commit is contained in:
parent
b4b54de6d2
commit
e572834961
@ -37,6 +37,11 @@ public class RestResponse {
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
@Builder
|
||||
public RestResponse(HttpStatus status, String msg) {
|
||||
this.status = status;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ public class ItnCommuteVO implements Serializable {
|
||||
private Integer commuteGroupId; // 그룹 아이디
|
||||
private String uniqId;
|
||||
private String userName; // 이름
|
||||
private String userRank; // 직위
|
||||
private String rankCd; // 직위
|
||||
private String category; // 구분
|
||||
private String workDt; // 근무일자
|
||||
private String startTime; // 출근시간
|
||||
|
||||
@ -109,7 +109,7 @@ public class CommuteServiceImpl implements CommuteService {
|
||||
|
||||
if( matchedUser != null ){
|
||||
t.setUsrid(matchedUser.getUserName());
|
||||
t.setPstn(matchedUser.getUserRank());
|
||||
t.setPstn(matchedUser.getRankCd());
|
||||
t.setUniqId(matchedUser.getUniqId());
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package com.itn.admin.itn.bizTrip.mapper;
|
||||
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripApprovalVO;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripMemberVO;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface BizTripMapper {
|
||||
void insertBizTrip(BizTripVO trip);
|
||||
|
||||
void insertTripMember(BizTripMemberVO member);
|
||||
|
||||
void insertApprovalLine(BizTripApprovalVO approval);
|
||||
|
||||
List<BizTripVO> selectTripList();
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.itn.admin.itn.bizTrip.mapper.domain;
|
||||
|
||||
import com.itn.admin.cmn.vo.CmnVO;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BizTripApprovalVO extends CmnVO {
|
||||
|
||||
private Integer id;
|
||||
private Integer tripId; // 출장 ID (FK)
|
||||
private String approverId; // 결재자 uniq_id
|
||||
private Integer orderNo; // 결재 순서
|
||||
private String approveStatus; // 결재 상태 (WAIT, APPROVED, REJECTED)
|
||||
private LocalDateTime approveDt; // 결재 일시
|
||||
private String comment; // 결재 의견
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.itn.admin.itn.bizTrip.mapper.domain;
|
||||
|
||||
import com.itn.admin.cmn.vo.CmnVO;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BizTripMemberVO extends CmnVO {
|
||||
|
||||
private Integer id;
|
||||
private Integer tripId; // 출장 ID (FK)
|
||||
private String uniqId; // 유저 고유 ID (FK)
|
||||
private String role; // 역할 (기안자: 0, 동행자: 1 등)
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.itn.admin.itn.bizTrip.mapper.domain;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class BizTripRequestDTO {
|
||||
private BizTripVO tripInfo;
|
||||
private List<BizTripMemberVO> tripMembers;
|
||||
private List<BizTripApprovalVO> approvalLines;
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.itn.admin.itn.bizTrip.mapper.domain;
|
||||
|
||||
import com.itn.admin.cmn.vo.CmnVO;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BizTripVO extends CmnVO {
|
||||
|
||||
private Integer tripId; // 출장 고유 ID
|
||||
private String tripTypeCd; // 출장 구분 (TRIP_TYPE 공통코드)
|
||||
private String locationCd; // 출장지 (TRIP_LOCATION 공통코드)
|
||||
private String locationTxt; // 출장지 (TRIP_LOCATION 공통코드)
|
||||
private String purpose; // 출장 목적
|
||||
private String moveCd; // 이동 수단 (TRIP_MOVE 공통코드)
|
||||
private LocalDate tripDt; // 출장일자
|
||||
private LocalTime startTime; // 출장 시작시간
|
||||
private LocalTime endTime; // 출장 종료시간
|
||||
private String status; // 결재 상태 (ING, DONE 등)
|
||||
|
||||
|
||||
private String latestApproveStatus; // 최신 결재 상태
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.itn.admin.itn.bizTrip.service;
|
||||
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripRequestDTO;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface BizTripService {
|
||||
RestResponse register(BizTripRequestDTO dto);
|
||||
|
||||
List<BizTripVO> selectTripList();
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.itn.admin.itn.bizTrip.service.impl;
|
||||
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.bizTrip.mapper.BizTripMapper;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripApprovalVO;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripMemberVO;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripRequestDTO;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripVO;
|
||||
import com.itn.admin.itn.bizTrip.service.BizTripService;
|
||||
import com.itn.admin.itn.code.mapper.CodeMapper;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeVO;
|
||||
import com.itn.admin.itn.code.server.CodeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class BizTripServiceImpl implements BizTripService {
|
||||
|
||||
@Autowired
|
||||
private BizTripMapper bizTripMapper;
|
||||
|
||||
@Override
|
||||
public RestResponse register(BizTripRequestDTO dto) {
|
||||
// 1. BizTripVO insert (자동 생성된 tripId 얻기)
|
||||
BizTripVO trip = dto.getTripInfo();
|
||||
bizTripMapper.insertBizTrip(trip); // insert 후 trip.tripId에 PK 자동 세팅됨
|
||||
|
||||
Integer tripId = trip.getTripId();
|
||||
|
||||
// 2. 출장 참여 인원 등록
|
||||
List<BizTripMemberVO> memberList = dto.getTripMembers();
|
||||
if (memberList != null && !memberList.isEmpty()) {
|
||||
for (BizTripMemberVO member : memberList) {
|
||||
member.setTripId(tripId);
|
||||
bizTripMapper.insertTripMember(member);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 결재 라인 등록
|
||||
List<BizTripApprovalVO> approvalList = dto.getApprovalLines();
|
||||
if (approvalList != null && !approvalList.isEmpty()) {
|
||||
for (BizTripApprovalVO approval : approvalList) {
|
||||
approval.setTripId(tripId);
|
||||
bizTripMapper.insertApprovalLine(approval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new RestResponse(HttpStatus.OK, "등록되었습니다");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BizTripVO> selectTripList() {
|
||||
return bizTripMapper.selectTripList();
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,42 +1,42 @@
|
||||
package com.itn.admin.itn.trip.web;
|
||||
package com.itn.admin.itn.bizTrip.web;
|
||||
|
||||
import com.itn.admin.cmn.config.CustomUserDetails;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripVO;
|
||||
import com.itn.admin.itn.bizTrip.service.BizTripService;
|
||||
import com.itn.admin.itn.user.mapper.domain.UserVO;
|
||||
import com.itn.admin.itn.user.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class TripController {
|
||||
public class BizTripController {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
private BizTripService bizTripService;
|
||||
|
||||
|
||||
@GetMapping("/itn/trip/reg")
|
||||
public String list(@ModelAttribute("userVO") UserVO userVO
|
||||
,@AuthenticationPrincipal CustomUserDetails loginUser
|
||||
@GetMapping("/itn/bizTrip/reg")
|
||||
public String list(@AuthenticationPrincipal CustomUserDetails loginUser
|
||||
,Model model
|
||||
) {
|
||||
log.info(" + loginUser :: [{}]", loginUser.getUser());
|
||||
|
||||
/*
|
||||
Map<String, Object> resultMap = userService.getList(userVO);
|
||||
|
||||
model.addAttribute("list", resultMap.get("resultList"));
|
||||
*/
|
||||
model.addAttribute("loginUser", loginUser.getUser());
|
||||
|
||||
return "itn/trip/reg";
|
||||
return "itn/bizTrip/reg";
|
||||
}
|
||||
@GetMapping("/itn/bizTrip/list")
|
||||
public String bizTripList(Model model) {
|
||||
List<BizTripVO> list = bizTripService.selectTripList();
|
||||
model.addAttribute("list", list);
|
||||
return "itn/bizTrip/list"; // Thymeleaf HTML 파일 경로
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.itn.admin.itn.bizTrip.web;
|
||||
|
||||
import com.itn.admin.cmn.config.CustomUserDetails;
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.bizTrip.mapper.domain.BizTripRequestDTO;
|
||||
import com.itn.admin.itn.bizTrip.service.BizTripService;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeDetailVO;
|
||||
import com.itn.admin.itn.user.mapper.domain.UserVO;
|
||||
import com.itn.admin.itn.user.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class BizTripRestController {
|
||||
|
||||
@Autowired
|
||||
private BizTripService bizTripService;
|
||||
|
||||
@PostMapping("/api/bizTrip/register")
|
||||
public ResponseEntity<RestResponse> registerBizTrip(@RequestBody BizTripRequestDTO dto
|
||||
, @AuthenticationPrincipal CustomUserDetails loginUser) {
|
||||
dto.getTripInfo().setFrstRegisterId(loginUser.getUser().getUniqId());
|
||||
log.info("dto: [{}]", dto);
|
||||
// bizTripService.register(dto);
|
||||
return ResponseEntity.ok().body(bizTripService.register(dto));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -41,6 +41,10 @@ public interface UserMapper {
|
||||
|
||||
void changepassword(UserVO userVO);
|
||||
|
||||
List<UserVO> selectUsersByNameAndRank(String userName);
|
||||
|
||||
|
||||
@Select("SELECT * FROM users WHERE user_name LIKE CONCAT('%', #{userName}, '%')")
|
||||
List<UserVO> findByUniqUserName(String userName);
|
||||
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ public class UserVO extends CmnVO {
|
||||
private String userId;
|
||||
private String password;
|
||||
private String userName;
|
||||
private String userRank;
|
||||
private String rankCd;
|
||||
private String mobilePhone;
|
||||
private String gwId;
|
||||
private String biostarId;
|
||||
|
||||
@ -26,4 +26,5 @@ public interface UserService {
|
||||
RestResponse changepassword(UserVO userVO);
|
||||
|
||||
RestResponse findByUniqUserName(String userName);
|
||||
RestResponse findByUniqApprovalUser(String userName);
|
||||
}
|
||||
|
||||
@ -107,6 +107,27 @@ public class UserServiceImpl implements UserService {
|
||||
users.forEach(user -> {
|
||||
String deptNm = tCodeUtils.getCodeName("DEPT", user.getDeptCd());
|
||||
user.setDeptNm(deptNm); // UserVO에 deptCdName 필드 있어야 함
|
||||
String rankNm = tCodeUtils.getCodeName("RANK", user.getRankCd());
|
||||
user.setDeptNm(rankNm); // UserVO에 deptCdName 필드 있어야 함
|
||||
});
|
||||
|
||||
|
||||
return RestResponse.builder()
|
||||
.status(HttpStatus.OK) // 200 성공
|
||||
.data(users)
|
||||
// .msg("수정되었습니다.")
|
||||
.build();
|
||||
|
||||
} @Override
|
||||
public RestResponse findByUniqApprovalUser(String userName) {
|
||||
|
||||
List<UserVO> users = userMapper.selectUsersByNameAndRank(userName);
|
||||
// 코드 이름을 붙여주는 처리 (가공)
|
||||
users.forEach(user -> {
|
||||
String deptNm = tCodeUtils.getCodeName("DEPT", user.getDeptCd());
|
||||
user.setDeptNm(deptNm); // UserVO에 deptCdName 필드 있어야 함
|
||||
String rankNm = tCodeUtils.getCodeName("RANK", user.getRankCd());
|
||||
user.setDeptNm(rankNm); // UserVO에 deptCdName 필드 있어야 함
|
||||
});
|
||||
|
||||
return RestResponse.builder()
|
||||
|
||||
@ -49,6 +49,11 @@ public class UserRestController {
|
||||
log.info("userName: {}", userName);
|
||||
return ResponseEntity.ok(userService.findByUniqUserName(userName));
|
||||
}
|
||||
@GetMapping("/api/admin/approval/search/name")
|
||||
public ResponseEntity<?> findByUniqApprovalUser(@RequestParam String userName) {
|
||||
log.info("userName: {}", userName);
|
||||
return ResponseEntity.ok(userService.findByUniqApprovalUser(userName));
|
||||
}
|
||||
|
||||
// 코드 그룹 수정 메서드
|
||||
@PutMapping("/api/admin/user/{uniqId}")
|
||||
|
||||
104
src/main/resources/mapper/itn/bizTrip/BizTripMapper.xml
Normal file
104
src/main/resources/mapper/itn/bizTrip/BizTripMapper.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?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.itn.admin.itn.bizTrip.mapper.BizTripMapper">
|
||||
|
||||
<insert id="insertBizTrip" useGeneratedKeys="true" keyProperty="tripId">
|
||||
INSERT INTO biz_trip (
|
||||
trip_type_cd, location_cd, location_txt, purpose,
|
||||
move_cd, trip_dt, start_time, end_time, status,
|
||||
frst_register_id
|
||||
) VALUES (
|
||||
#{tripTypeCd}, #{locationCd}, #{locationTxt}, #{purpose},
|
||||
#{moveCd}, #{tripDt}, #{startTime}, #{endTime}, #{status},
|
||||
#{frstRegisterId}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertTripMember">
|
||||
INSERT INTO biz_trip_member (trip_id, uniq_id, role)
|
||||
VALUES (#{tripId}, #{uniqId}, #{role})
|
||||
</insert>
|
||||
|
||||
<insert id="insertApprovalLine">
|
||||
INSERT INTO biz_trip_approval (trip_id, approver_id, order_no, approve_status)
|
||||
VALUES (#{tripId}, #{approverId}, #{orderNo}, #{approveStatus})
|
||||
</insert>
|
||||
|
||||
<select id="selectTripList" resultType="bizTripVO">
|
||||
SELECT
|
||||
bt.trip_id,
|
||||
bt.trip_type_cd,
|
||||
bt.location_cd,
|
||||
bt.location_txt,
|
||||
bt.purpose,
|
||||
bt.move_cd,
|
||||
bt.trip_dt,
|
||||
bt.start_time,
|
||||
bt.end_time,
|
||||
bt.frst_register_id,
|
||||
|
||||
-- 상태 계산 로직
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM biz_trip_approval a
|
||||
WHERE a.trip_id = bt.trip_id
|
||||
AND a.approve_status = '40'
|
||||
) THEN '40' -- 반려
|
||||
|
||||
WHEN NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM biz_trip_approval a
|
||||
WHERE a.trip_id = bt.trip_id
|
||||
AND a.approve_status <> '30'
|
||||
) THEN '30' -- 전체 승인
|
||||
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM biz_trip_approval a
|
||||
WHERE a.trip_id = bt.trip_id
|
||||
AND a.approve_status <> '10'
|
||||
) THEN '20' -- 일부 결재함 (진행 중)
|
||||
|
||||
ELSE '10' -- 전부 대기
|
||||
END AS status
|
||||
|
||||
FROM biz_trip bt
|
||||
ORDER BY bt.trip_dt DESC
|
||||
</select>
|
||||
|
||||
<!--
|
||||
<!– 모든 코드 그룹을 조회하는 쿼리 –>
|
||||
<select id="findAll" resultType="codeVO">
|
||||
SELECT * FROM common_code
|
||||
</select>
|
||||
|
||||
<!– 특정 코드 그룹을 ID로 조회하는 쿼리 –>
|
||||
<select id="findById" parameterType="String" resultType="codeVO">
|
||||
SELECT * FROM common_code WHERE code_group_id = #{codeGroupId}
|
||||
</select>
|
||||
|
||||
<!– 코드 그룹을 추가하는 쿼리 –>
|
||||
<insert id="insert" parameterType="codeVO">
|
||||
INSERT INTO common_code (code_group_id, code_group_name, description, frst_register_id, frst_regist_pnttm, last_updusr_id, last_updt_pnttm)
|
||||
VALUES (#{codeGroupId}, #{codeGroupName}, #{description}, #{frstRegisterId}, #{frstRegistPnttm}, #{lastUpdusrId}, #{lastUpdtPnttm})
|
||||
</insert>
|
||||
|
||||
<!– 코드 그룹을 수정하는 쿼리 –>
|
||||
<update id="update" parameterType="codeVO">
|
||||
UPDATE common_code
|
||||
SET code_group_name = #{codeGroupName},
|
||||
description = #{description},
|
||||
last_updusr_id = #{lastUpdusrId},
|
||||
last_updt_pnttm = #{lastUpdtPnttm}
|
||||
WHERE code_group_id = #{codeGroupId}
|
||||
</update>
|
||||
|
||||
<!– 코드 그룹을 삭제하는 쿼리 –>
|
||||
<delete id="delete" parameterType="String">
|
||||
DELETE FROM common_code WHERE code_group_id = #{codeGroupId}
|
||||
</delete>-->
|
||||
</mapper>
|
||||
@ -12,7 +12,7 @@
|
||||
, user_id
|
||||
, user_pw as password
|
||||
, user_name
|
||||
, user_rank
|
||||
, rank_cd
|
||||
, role
|
||||
, gw_id
|
||||
, biostar_id
|
||||
@ -33,7 +33,7 @@
|
||||
, user_id
|
||||
, user_pw AS password
|
||||
, user_name
|
||||
, user_rank
|
||||
, rank_cd
|
||||
, mobile_phone
|
||||
, dept_cd
|
||||
, role
|
||||
@ -57,8 +57,8 @@
|
||||
|
||||
<update id="updateUserInfo" parameterType="userVO">
|
||||
UPDATE users SET
|
||||
user_name = #{username}
|
||||
, user_rank = #{userRank}
|
||||
user_name = #{userName}
|
||||
, rank_cd = #{rankCd}
|
||||
, dept_cd = #{deptCd}
|
||||
<if test="role != null and role != ''">
|
||||
,role = #{role}
|
||||
@ -66,6 +66,9 @@
|
||||
<if test="gwId != null and gwId != ''">
|
||||
,gw_id = #{gwId}
|
||||
</if>
|
||||
<if test="mobilePhone != null and mobilePhone != ''">
|
||||
,mobile_phone = #{mobilePhone}
|
||||
</if>
|
||||
<if test="biostarId != null and biostarId != ''">
|
||||
,biostar_id = #{biostarId}
|
||||
</if>
|
||||
@ -83,4 +86,20 @@
|
||||
WHERE uniq_id = #{uniqId}
|
||||
</update>
|
||||
|
||||
<select id="selectUsersByNameAndRank" resultType="userVO">
|
||||
SELECT u.*
|
||||
FROM users u
|
||||
JOIN common_code_detail ccd
|
||||
on u.rank_cd = ccd.code_id
|
||||
WHERE ccd.code_group_id = 'RANK'
|
||||
AND ccd.sort_order <= (
|
||||
SELECT sort_order
|
||||
FROM common_code_detail
|
||||
WHERE code_group_id = 'RANK'
|
||||
AND code_name = '차장'
|
||||
)
|
||||
AND u.user_name LIKE CONCAT('%', #{userName}, '%')
|
||||
AND u.active_yn = 'Y'
|
||||
|
||||
</select>
|
||||
</mapper>
|
||||
@ -25,6 +25,10 @@
|
||||
|
||||
<typeAlias type="com.itn.admin.itn.commute.mapper.domain.ItnCommuteBackVO" alias="itnCommuteBackVO"/>
|
||||
|
||||
<typeAlias type="com.itn.admin.itn.bizTrip.mapper.domain.BizTripVO" alias="bizTripVO"/>
|
||||
<typeAlias type="com.itn.admin.itn.bizTrip.mapper.domain.BizTripMemberVO" alias="bizTripMemberVO"/>
|
||||
<typeAlias type="com.itn.admin.itn.bizTrip.mapper.domain.BizTripApprovalVO" alias="bizTripApprovalVO"/>
|
||||
|
||||
<typeAlias type="com.itn.admin.gw.holiday.mapper.domain.HolidayVO" alias="holidayVO"/>
|
||||
</typeAliases>
|
||||
|
||||
|
||||
@ -1,177 +0,0 @@
|
||||
|
||||
$(function () {
|
||||
|
||||
$(".slider").each(function () {
|
||||
var $slider = $(this); // 현재 슬라이더 요소
|
||||
var $input = $slider.closest('.input-group').find('.sliderValue'); // 해당 슬라이더의 input 요소
|
||||
|
||||
// 슬라이더 초기화
|
||||
$slider.slider({
|
||||
range: "max",
|
||||
min: 1,
|
||||
max: 1000000,
|
||||
value: 1,
|
||||
slide: function (event, ui) {
|
||||
$input.val(ui.value); // 슬라이더 이동 시 input 값 업데이트
|
||||
}
|
||||
});
|
||||
|
||||
// 슬라이더의 초기 값을 input에 설정
|
||||
$input.val($slider.slider("value"));
|
||||
|
||||
// input 변경 시 슬라이더 값 업데이트 (실시간)
|
||||
$input.on("input", function () {
|
||||
var value = $(this).val();
|
||||
// 숫자 범위 확인 후 슬라이더 값 업데이트
|
||||
if ($.isNumeric(value) && value >= 1 && value <= 1000000) {
|
||||
$slider.slider("value", value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("form").on("reset", function () {
|
||||
setTimeout(function () {
|
||||
$("#divTwoSms #sendCnt").val(1); // 건수 필드 값을 1로 설정
|
||||
$("#divTwoSms #slider").slider("value", 1); // 슬라이더 값도 1로 설정
|
||||
}, 0); // setTimeout 사용 이유: reset 이벤트 후에 값 설정
|
||||
});
|
||||
|
||||
/*
|
||||
* 예시 버튼
|
||||
* */
|
||||
$(".examBtn").on("click", function () {
|
||||
|
||||
var tagId = getParentsId($(this));
|
||||
var $recvPhone = $(tagId + ' .recvPhone');
|
||||
var $sendPhone = $(tagId + ' .sendPhone');
|
||||
var $msgType = $(tagId + ' .msgType');
|
||||
var $message = $(tagId + ' .message');
|
||||
var $subject = $(tagId + ' .subject');
|
||||
|
||||
// 기본 전화번호 설정
|
||||
$recvPhone.val('01083584250');
|
||||
$sendPhone.val('01083584250');
|
||||
|
||||
// 메시지 타입에 따른 메시지 설정
|
||||
var msgType = $msgType.val();
|
||||
var msg = generateMessage(msgType);
|
||||
|
||||
// 내용
|
||||
$message.val(msg);
|
||||
updateByteCount($message);
|
||||
|
||||
if (msgType === 'L'
|
||||
||msgType === 'M'
|
||||
||msgType === 'A'
|
||||
||msgType === 'F'
|
||||
) {
|
||||
$subject.val('ITN SUBJECT');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function generateMessage(msgType) {
|
||||
var messages = {
|
||||
'S': 'ITN SMS test ',
|
||||
'L': 'ITN LMS test ',
|
||||
'M': 'ITN MMS message test ',
|
||||
'A': 'ITN ',
|
||||
'F': 'ITN '
|
||||
};
|
||||
// 타입이 위 값들고 같이 않으면 null 반환
|
||||
return (messages[msgType] || '') + getNowDate();
|
||||
}
|
||||
$('.msgType').on('change', function() {
|
||||
|
||||
var msgType = $(this).val();
|
||||
var tagId = getParentsId($(this));
|
||||
|
||||
// 제목
|
||||
$(tagId+' .subject').closest('.form-group').hide();
|
||||
|
||||
// 파일 그룹
|
||||
$(tagId+' .fileUploadGroup').hide();
|
||||
$(tagId+' .fileUploadGroup input[type="file"]').val("");
|
||||
|
||||
if(msgType === 'L'
|
||||
||msgType === 'A'
|
||||
||msgType === 'F'
|
||||
) {
|
||||
$(tagId+' .subject').closest('.form-group').show();
|
||||
}else if(msgType === 'M'){
|
||||
$(tagId+' .subject').closest('.form-group').show();
|
||||
$(tagId+' .fileUploadGroup').show();
|
||||
}
|
||||
|
||||
var $message = $(tagId + ' .message');
|
||||
$message.val(generateMessage(msgType));
|
||||
|
||||
});
|
||||
|
||||
|
||||
$('.toggle-info-btn').on('click', function() {
|
||||
var $card = $(this).closest('.card'); // 클릭한 버튼의 가장 가까운 부모 .card 요소 찾기
|
||||
var $hiddenInfo = $card.find('.hidden-info'); // 해당 카드 내에서 .hidden-info 요소 찾기
|
||||
|
||||
$hiddenInfo.slideToggle(); // 애니메이션 효과를 추가하여 더 부드럽게 보이도록 함
|
||||
var icon = $(this).find('i');
|
||||
if ($hiddenInfo.is(':visible')) {
|
||||
icon.removeClass('fa-info-circle').addClass('fa-times-circle');
|
||||
} else {
|
||||
icon.removeClass('fa-times-circle').addClass('fa-info-circle');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('textarea').on('input', function() {
|
||||
updateByteCount(this);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// function updateByteCount(textarea) {
|
||||
// console.log('textarea : ', textarea);
|
||||
// var text = $(textarea).val();
|
||||
// var byteLength = new TextEncoder().encode(text).length;
|
||||
// $(textarea).closest('.form-group').find('.byte-count').text(byteLength + ' bytes');
|
||||
// }
|
||||
function updateByteCount(textarea) {
|
||||
var text = $(textarea).val();
|
||||
var byteLength = calculateByteLength(text);
|
||||
$(textarea).closest('.form-group').find('.byte-count').text(byteLength + ' bytes');
|
||||
}
|
||||
|
||||
function calculateByteLength(text) {
|
||||
var byteLength = 0;
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
var charCode = text.charCodeAt(i);
|
||||
if (charCode <= 0x007F) {
|
||||
byteLength += 1; // 1 byte for ASCII characters
|
||||
} else if (charCode <= 0x07FF) {
|
||||
byteLength += 2; // 2 bytes for characters from U+0080 to U+07FF
|
||||
} else {
|
||||
byteLength += 2; // 2 bytes for characters from U+0800 and above (including Hangul)
|
||||
}
|
||||
}
|
||||
return byteLength;
|
||||
}
|
||||
function getParentsId($obj){
|
||||
|
||||
var $col = $obj.closest('.col-md-6'); // 클릭한 버튼의 가장 가까운 부모 .card 요소 찾기
|
||||
// 해당 카드 내에서 .hidden-info 요소 찾기
|
||||
return '#' + $col.attr('id');
|
||||
}
|
||||
|
||||
function getNowDate(){
|
||||
|
||||
// 현재 날짜와 시간을 가져와서 포맷팅
|
||||
var now = new Date();
|
||||
var year = String(now.getFullYear()).substring(2); // 년도 마지막 두 자리
|
||||
var month = ('0' + (now.getMonth() + 1)).slice(-2); // 월 (0부터 시작하므로 +1 필요)
|
||||
var day = ('0' + now.getDate()).slice(-2); // 일
|
||||
var hours = ('0' + now.getHours()).slice(-2); // 시
|
||||
var minutes = ('0' + now.getMinutes()).slice(-2); // 분
|
||||
|
||||
return year + month + day + '|' + hours + ':' + minutes;
|
||||
}
|
||||
@ -1,272 +0,0 @@
|
||||
|
||||
// 타이머 ID 저장을 위한 변수
|
||||
let oneInsertCntIntervalId;
|
||||
let oneTransferCntIntervalId;
|
||||
let oneReporingCntIntervalId;
|
||||
// insert 타이머
|
||||
let oneIntervalId_insertSeconds;
|
||||
// 이관 타이머
|
||||
let oneIntervalId_transferSeconds;
|
||||
// 이관 타이머
|
||||
let oneIntervalId_reporingSeconds;
|
||||
|
||||
|
||||
|
||||
function fn_oneInsertScriptStart(){
|
||||
// 건수를 현황확인으로 이동
|
||||
$('#divOneSmsCard .sendCntTxt').text('('+$('#divOneSms .sliderValue').val()+'건)');
|
||||
oneStartInsertTimer(); // insert 타임어택 시작
|
||||
}
|
||||
|
||||
|
||||
// LOG 테이블에
|
||||
function fn_oneReportScriptStart(){
|
||||
oneStartReportTimer(); // report 타임어택 시작
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function oneStartInsertTimer() {
|
||||
console.log(' :: startInsertTimer :: ');
|
||||
let startTime = Date.now();
|
||||
oneStartInsertCntTimer();
|
||||
oneIntervalId_insertSeconds = setInterval(function() {
|
||||
let currentTime = Date.now();
|
||||
let elapsedTime = (currentTime - startTime) / 1000; // 밀리초를 초 단위로 변환
|
||||
// 분과 초로 변환
|
||||
let minutes = Math.floor(elapsedTime / 60); // 분 계산
|
||||
let seconds = (elapsedTime % 60).toFixed(3); // 나머지 초 계산
|
||||
|
||||
document.querySelector('#divOneSmsCard .insertSeconds').innerText = minutes + ' 분 ' + seconds + ' 초';
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function oneStartInsertCntTimer() {
|
||||
console.log('oneStartInsertCntTimer ::');
|
||||
// 1초마다 fn_insertCntAndTime 함수를 호출
|
||||
oneInsertCntIntervalId = setInterval(fn_oneInsertCntAndTime, 1000);
|
||||
}
|
||||
|
||||
function oneStopInsertTimer() {
|
||||
clearInterval(oneIntervalId_insertSeconds);
|
||||
clearInterval(oneInsertCntIntervalId);
|
||||
console.log("insert 타이머가 멈췄습니다.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function fn_oneInsertCntAndTime(){
|
||||
|
||||
console.log('fn_oneInsertCntAndTime ::');
|
||||
// 폼 데이터를 수집
|
||||
var formData = new FormData($("#divOneSms .sendForm")[0]);
|
||||
|
||||
var jsonObject = {};
|
||||
formData.forEach((value, key) => {
|
||||
if (!(value instanceof File)) {
|
||||
jsonObject[key] = value;
|
||||
}
|
||||
});
|
||||
console.log('url : /agent/one/findByInsertCnt');
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/agent/one/findByInsertCnt",
|
||||
data: JSON.stringify(jsonObject), // JSON 문자열로 변환된 데이터를 전송
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
// async: true,
|
||||
success: function (data) {
|
||||
console.log(' one findByInsertCnt data : ', data);
|
||||
|
||||
if (data.status === 'OK') {
|
||||
var cnt = data.data;
|
||||
|
||||
$('#divOneSmsCard .insertCnt').text(cnt);
|
||||
let text = $('#divOneSmsCard .sendCntTxt').text();
|
||||
let numberOnly = text.match(/\d+/)[0];
|
||||
console.log(' one numberOnly :', numberOnly);
|
||||
console.log(' one cnt >= numberOnly :', cnt >= numberOnly);
|
||||
if(cnt >= numberOnly){
|
||||
oneStopInsertTimer();
|
||||
// oneStartTransferTimer($('#oneUserId').val()); // 이관 카운트
|
||||
// fn_oneReportScriptStart();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("오류 알림 : :: "+data.msg);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
alert(" findByInsertCnt 조회에 실패하였습니다.");
|
||||
oneStopInsertTimer();
|
||||
console.log("ERROR : " + JSON.stringify(e));
|
||||
},
|
||||
beforeSend : function(xmlHttpRequest) {
|
||||
},
|
||||
complete : function(xhr, textStatus) {
|
||||
//로딩창 hide
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 이관 타이머 start
|
||||
function oneStartTransferTimer(userId) {
|
||||
console.log(' :: one startTransferTimer :: ');
|
||||
let startTime = Date.now();
|
||||
oneStartTransferCntTimer(userId)
|
||||
oneIntervalId_transferSeconds = setInterval(function() {
|
||||
let currentTime = Date.now();
|
||||
let elapsedTime = (currentTime - startTime) / 1000; // 밀리초를 초 단위로 변환
|
||||
document.querySelector('#divOneSmsCard .transferSeconds').innerText = elapsedTime.toFixed(3) + ' 초';
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function oneStartTransferCntTimer(userId) {
|
||||
// 1초마다 fn_tranferCntAndTime 함수를 호출
|
||||
oneTransferCntIntervalId = setInterval(function() {
|
||||
fn_oneTranferCntAndTime(userId);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
||||
function oneStopTransferTimer() {
|
||||
clearInterval(oneIntervalId_transferSeconds);
|
||||
clearInterval(oneTransferCntIntervalId);
|
||||
console.log("이관 타이머가 멈췄습니다.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
function fn_oneTranferCntAndTime(userId){
|
||||
|
||||
// 폼 데이터를 수집
|
||||
var formData = new FormData($("#divOneSms .sendForm")[0]);
|
||||
|
||||
var jsonObject = {};
|
||||
formData.forEach((value, key) => {
|
||||
jsonObject[key] = value;
|
||||
});
|
||||
jsonObject['userId'] = userId;
|
||||
console.log('jsonObject : ', jsonObject);
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/agent/server/findByTransferCnt",
|
||||
data: JSON.stringify(jsonObject), // JSON 문자열로 변환된 데이터를 전송
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
// async: true,
|
||||
success: function (data) {
|
||||
console.log('tranfer data : ', data);
|
||||
|
||||
if (data.status == 'OK') {
|
||||
var cnt = data.data;
|
||||
|
||||
$('#divOneSmsCard .transferCnt').text(cnt);
|
||||
let text = $('#divOneSmsCard .insertCnt').text();
|
||||
let numberOnly = text.match(/\d+/)[0];
|
||||
if(cnt >= Number(numberOnly)){
|
||||
oneStopTransferTimer();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("오류 알림 : :: "+data.msg);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
alert("이관 조회에 실패하였습니다.");
|
||||
console.log("ERROR : " + JSON.stringify(e));
|
||||
},
|
||||
beforeSend : function(xmlHttpRequest) {
|
||||
},
|
||||
complete : function(xhr, textStatus) {
|
||||
//로딩창 hide
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 리포트 영역
|
||||
// 리포트 영역
|
||||
// 리포트 영역
|
||||
function oneStartReportTimer(userId) {
|
||||
console.log(' :: startReportTimer :: ');
|
||||
let startTime = Date.now();
|
||||
oneStartReporingCntTimer();
|
||||
oneIntervalId_reporingSeconds = setInterval(function() {
|
||||
let currentTime = Date.now();
|
||||
let elapsedTime = (currentTime - startTime) / 1000; // 밀리초를 초 단위로 변환
|
||||
document.querySelector('#divOneSmsCard .reportSeconds').innerText = elapsedTime.toFixed(3) + ' 초';
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function oneStartReporingCntTimer() {
|
||||
// 1초마다 fn_twoReportCntAndTime 함수를 호출
|
||||
oneReporingCntIntervalId = setInterval(function() {
|
||||
fn_oneReportCntAndTime();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function oneStopReporingTimer() {
|
||||
clearInterval(oneIntervalId_reporingSeconds);
|
||||
clearInterval(oneReporingCntIntervalId);
|
||||
console.log("report 타이머가 멈췄습니다.");
|
||||
}
|
||||
|
||||
|
||||
function fn_oneReportCntAndTime(userId){
|
||||
|
||||
// 폼 데이터를 수집
|
||||
var formData = new FormData($("#divOneSms .sendForm")[0]);
|
||||
|
||||
var jsonObject = {};
|
||||
formData.forEach((value, key) => {
|
||||
if (!(value instanceof File)) {
|
||||
jsonObject[key] = value;
|
||||
}
|
||||
});
|
||||
jsonObject['userId'] = userId;
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/agent/one/findByLogMoveCntWhereMessage",
|
||||
data: JSON.stringify(jsonObject), // JSON 문자열로 변환된 데이터를 전송
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
// async: true,
|
||||
success: function (data) {
|
||||
console.log('findByLogMoveCntWhereMessage data : ', data);
|
||||
|
||||
if (data.status == 'OK') {
|
||||
var cnt = data.data;
|
||||
$('#divOneSmsCard .reportStartCnt').text(cnt);
|
||||
|
||||
var transferCnt = $('#divOneSmsCard .insertCnt').text();
|
||||
|
||||
|
||||
console.log('cnt : ', cnt);
|
||||
console.log('reportStartCnt : ', transferCnt);
|
||||
console.log('');
|
||||
if(cnt >= Number(transferCnt)){
|
||||
oneStopReporingTimer();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("오류 알림 : :: "+data.msg);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
alert("report 조회에 실패하였습니다.");
|
||||
console.log("ERROR : " + JSON.stringify(e));
|
||||
},
|
||||
beforeSend : function(xmlHttpRequest) {
|
||||
|
||||
},
|
||||
complete : function(xhr, textStatus) {
|
||||
//로딩창 hide
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1,273 +0,0 @@
|
||||
|
||||
// 타이머 ID 저장을 위한 변수
|
||||
let twoInsertCntIntervalId;
|
||||
let twoTransferCntIntervalId;
|
||||
let twoReporingCntIntervalId;
|
||||
// insert 타이머
|
||||
let twoIntervalId_insertSeconds;
|
||||
// 이관 타이머
|
||||
let twoIntervalId_transferSeconds;
|
||||
// 리포트 타이머
|
||||
let twoIntervalId_reporingSeconds;
|
||||
|
||||
|
||||
|
||||
function fn_twoInsertScriptStart(){
|
||||
// 건수를 현황확인으로 이동
|
||||
$('#divTwoSmsCard .sendCntTxt').text('('+$('#divTwoSms .sliderValue').val()+'건)');
|
||||
twoStartInsertTimer(); // insert 타임어택 시작
|
||||
}
|
||||
|
||||
|
||||
function fn_twoReportScriptStart(){
|
||||
twoStartReportTimer(); // report 타임어택 시작
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function twoStartInsertTimer() {
|
||||
console.log(' :: startInsertTimer :: ');
|
||||
let startTime = Date.now();
|
||||
twoStartInsertCntTimer();
|
||||
twoIntervalId_insertSeconds = setInterval(function() {
|
||||
let currentTime = Date.now();
|
||||
let elapsedTime = (currentTime - startTime) / 1000; // 밀리초를 초 단위로 변환
|
||||
// 분과 초로 변환
|
||||
let minutes = Math.floor(elapsedTime / 60); // 분 계산
|
||||
let seconds = (elapsedTime % 60).toFixed(3); // 나머지 초 계산
|
||||
|
||||
document.querySelector('#divTwoSmsCard .insertSeconds').innerText = minutes + ' 분 ' + seconds + ' 초';
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function twoStartInsertCntTimer() {
|
||||
// 1초마다 fn_insertCntAndTime 함수를 호출
|
||||
twoInsertCntIntervalId = setInterval(fn_twoInsertCntAndTime, 1000);
|
||||
}
|
||||
|
||||
function twoStopInsertTimer() {
|
||||
clearInterval(twoIntervalId_insertSeconds);
|
||||
clearInterval(twoInsertCntIntervalId);
|
||||
console.log("insert 타이머가 멈췄습니다.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function fn_twoInsertCntAndTime(){
|
||||
|
||||
// 폼 데이터를 수집
|
||||
var formData = new FormData($("#divTwoSms .sendForm")[0]);
|
||||
|
||||
var jsonObject = {};
|
||||
formData.forEach((value, key) => {
|
||||
if (!(value instanceof File)) {
|
||||
jsonObject[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
console.log('fn_twoInsertCntAndTime : [{}]',jsonObject);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/agent/two/findByInsertCnt",
|
||||
data: JSON.stringify(jsonObject), // JSON 문자열로 변환된 데이터를 전송
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
// async: true,
|
||||
success: function (data) {
|
||||
// console.log('insert data : ', data);
|
||||
|
||||
if (data.status == 'OK') {
|
||||
var cnt = data.data;
|
||||
|
||||
$('#divTwoSmsCard .insertCnt').text(cnt);
|
||||
let text = $('#divTwoSmsCard .sendCntTxt').text();
|
||||
let numberOnly = text.match(/\d+/)[0];
|
||||
// console.log('numberOnly :', numberOnly);
|
||||
// console.log('cnt >= numberOnly :', cnt >= numberOnly);
|
||||
if(cnt >= numberOnly){
|
||||
twoStopInsertTimer();
|
||||
// twoStartTransferTimer($('#twoUserId').val()); // 이관 카운트
|
||||
// fn_twoReportScriptStart();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("오류 알림 : :: "+data.msg);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
alert("조회에 실패하였습니다.");
|
||||
console.log("ERROR : " + JSON.stringify(e));
|
||||
},
|
||||
beforeSend : function(xmlHttpRequest) {
|
||||
},
|
||||
complete : function(xhr, textStatus) {
|
||||
//로딩창 hide
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 이관 타이머 start
|
||||
function twoStartTransferTimer(userId) {
|
||||
console.log(' :: two startTransferTimer :: ');
|
||||
let startTime = Date.now();
|
||||
twoStartTransferCntTimer(userId)
|
||||
twoIntervalId_transferSeconds = setInterval(function() {
|
||||
let currentTime = Date.now();
|
||||
let elapsedTime = (currentTime - startTime) / 1000; // 밀리초를 초 단위로 변환
|
||||
// console.log('elapsedTime : ', elapsedTime);
|
||||
document.querySelector('#divTwoSmsCard .transferSeconds').innerText = elapsedTime.toFixed(3) + ' 초';
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function twoStartTransferCntTimer(userId) {
|
||||
// 1초마다 fn_tranferCntAndTime 함수를 호출
|
||||
twoTransferCntIntervalId = setInterval(function() {
|
||||
fn_twoTranferCntAndTime(userId);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
||||
function twoStopTransferTimer() {
|
||||
clearInterval(twoIntervalId_transferSeconds);
|
||||
clearInterval(twoTransferCntIntervalId);
|
||||
console.log("이관 타이머가 멈췄습니다.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
function fn_twoTranferCntAndTime(userId){
|
||||
|
||||
// 폼 데이터를 수집
|
||||
var formData = new FormData($("#divTwoSms .sendForm")[0]);
|
||||
|
||||
// console.log('? :: ', formData);
|
||||
var jsonObject = {};
|
||||
formData.forEach((value, key) => {
|
||||
jsonObject[key] = value;
|
||||
});
|
||||
jsonObject['userId'] = userId;
|
||||
// console.log('jsonObject : ', jsonObject);
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/agent/server/findByTransferCnt",
|
||||
data: JSON.stringify(jsonObject), // JSON 문자열로 변환된 데이터를 전송
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
// async: true,
|
||||
success: function (data) {
|
||||
console.log('tranfer data : ', data);
|
||||
|
||||
if (data.status == 'OK') {
|
||||
var cnt = data.data;
|
||||
|
||||
$('#divTwoSmsCard .transferCnt').text(cnt);
|
||||
let text = $('#divTwoSmsCard .insertCnt').text();
|
||||
let numberOnly = text.match(/\d+/)[0];
|
||||
if(cnt >= Number(numberOnly)){
|
||||
twoStopTransferTimer();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("오류 알림 : :: "+data.msg);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
alert("이관 조회에 실패하였습니다.");
|
||||
console.log("ERROR : " + JSON.stringify(e));
|
||||
},
|
||||
beforeSend : function(xmlHttpRequest) {
|
||||
},
|
||||
complete : function(xhr, textStatus) {
|
||||
//로딩창 hide
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 리포트 영역
|
||||
// 리포트 영역
|
||||
// 리포트 영역
|
||||
function twoStartReportTimer() {
|
||||
// console.log(' :: startReportTimer :: ');
|
||||
let startTime = Date.now();
|
||||
twoStartReporingCntTimer();
|
||||
twoIntervalId_reporingSeconds = setInterval(function() {
|
||||
let currentTime = Date.now();
|
||||
let elapsedTime = (currentTime - startTime) / 1000; // 밀리초를 초 단위로 변환
|
||||
document.querySelector('#divTwoSmsCard .reportSeconds').innerText = elapsedTime.toFixed(3) + ' 초';
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function twoStartReporingCntTimer() {
|
||||
// 1초마다 fn_twoReportCntAndTime 함수를 호출
|
||||
twoReporingCntIntervalId = setInterval(function() {
|
||||
fn_twoReportCntAndTime();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function twoStopReporingTimer() {
|
||||
clearInterval(twoIntervalId_reporingSeconds);
|
||||
clearInterval(twoReporingCntIntervalId);
|
||||
console.log("report 타이머가 멈췄습니다.");
|
||||
}
|
||||
|
||||
|
||||
function fn_twoReportCntAndTime(userId){
|
||||
|
||||
// 폼 데이터를 수집
|
||||
var formData = new FormData($("#divTwoSms .sendForm")[0]);
|
||||
|
||||
var jsonObject = {};
|
||||
formData.forEach((value, key) => {
|
||||
if (!(value instanceof File)) {
|
||||
jsonObject[key] = value;
|
||||
}
|
||||
});
|
||||
jsonObject['userId'] = userId;
|
||||
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/agent/two/findByLogMoveCntWhereMessage",
|
||||
data: JSON.stringify(jsonObject), // JSON 문자열로 변환된 데이터를 전송
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
// async: true,
|
||||
success: function (data) {
|
||||
console.log('findByLogMoveCntWhereMessage data : ', data);
|
||||
|
||||
if (data.status == 'OK') {
|
||||
var cnt = data.data;
|
||||
|
||||
console.log('cnt : ', cnt);
|
||||
// 리포트 영역에 cnt 추가
|
||||
$('#divTwoSmsCard .reportStartCnt').text(cnt);
|
||||
// server DB에 update한 건수와 cnt비교
|
||||
var transferCnt = $('#divTwoSmsCard .insertCnt').text();
|
||||
|
||||
console.log('cnt : ', cnt);
|
||||
console.log('reportStartCnt : ', transferCnt);
|
||||
console.log('');
|
||||
if(cnt >= Number(transferCnt)){
|
||||
twoStopReporingTimer();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("오류 알림 : :: "+data.msg);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
alert("report 조회에 실패하였습니다.");
|
||||
console.log("ERROR : " + JSON.stringify(e));
|
||||
},
|
||||
beforeSend : function(xmlHttpRequest) {
|
||||
|
||||
},
|
||||
complete : function(xhr, textStatus) {
|
||||
//로딩창 hide
|
||||
}
|
||||
});
|
||||
}
|
||||
247
src/main/resources/static/cmn/js/bizTrip/event.js
Normal file
247
src/main/resources/static/cmn/js/bizTrip/event.js
Normal file
@ -0,0 +1,247 @@
|
||||
/**
|
||||
* 페이지 로드 완료 후 실행되는 초기화 함수 (비워둠)
|
||||
* @function
|
||||
*/
|
||||
$(function () {
|
||||
// 초기화 코드 필요 시 여기에 작성
|
||||
});
|
||||
|
||||
/**
|
||||
* Enter 키 입력 시 사용자 검색 수행
|
||||
* @event keydown
|
||||
* @param {KeyboardEvent} e
|
||||
*/
|
||||
document.getElementById("userSearchKeyword").addEventListener("keydown", function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
searchUser();
|
||||
}
|
||||
});
|
||||
document.getElementById("approvalSearchKeyword").addEventListener("keydown", function (e) {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
searchApproval();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 모달이 열릴 때 사용자 목록을 불러오고 포커스를 맞춤
|
||||
* @event shown.bs.modal
|
||||
*/
|
||||
$('#userSearchModal').on('shown.bs.modal', function () {
|
||||
loadUserList();
|
||||
$('#userSearchKeyword').trigger('focus');
|
||||
});
|
||||
$('#approvalSearchModal').on('shown.bs.modal', function () {
|
||||
loadApprovalList();
|
||||
$('#approvalSearchKeyword').trigger('focus');
|
||||
});
|
||||
|
||||
/**
|
||||
* 날짜 입력 필드 클릭 시 브라우저 기본 날짜 선택기 표시
|
||||
* @event click
|
||||
*/
|
||||
document.querySelector('input[id="tripDate"]').addEventListener('click', function () {
|
||||
this.showPicker && this.showPicker();
|
||||
});
|
||||
|
||||
/**
|
||||
* 사용자 목록을 불러오는 Ajax 요청 함수
|
||||
* @function
|
||||
* @param {string} [keyword=""] - 검색 키워드
|
||||
* @returns {void}
|
||||
*/
|
||||
function loadUserList(keyword = "") {
|
||||
$.ajax({
|
||||
url: '/api/admin/user/search/name',
|
||||
type: 'GET',
|
||||
data: { userName: keyword },
|
||||
success: function (result) {
|
||||
const tbody = document.getElementById("userSearchResult");
|
||||
tbody.innerHTML = "";
|
||||
|
||||
const data = result.data;
|
||||
if (data && data.length > 0) {
|
||||
data.forEach(user => {
|
||||
const row = document.createElement("tr");
|
||||
row.innerHTML = `
|
||||
<td>${user.userName}</td>
|
||||
<td>${user.deptNm || "-"}</td>
|
||||
<td>${user.rankCd || "-"}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-success"
|
||||
onclick="selectUser('${user.userName}', '${user.deptNm}', '${user.mobilePhone}', '${user.uniqId}')">
|
||||
<i class="fas fa-user-plus"></i> 추가
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
} else {
|
||||
tbody.innerHTML = `<tr><td colspan="5" class="text-center text-muted">검색 결과가 없습니다.</td></tr>`;
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("사용자 목록을 불러오는 데 실패했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadApprovalList(keyword = "") {
|
||||
$.ajax({
|
||||
url: '/api/admin/approval/search/name',
|
||||
type: 'GET',
|
||||
data: { userName: keyword },
|
||||
success: function (result) {
|
||||
const tbody = document.getElementById("approvalSearchResult");
|
||||
const data = result.data;
|
||||
|
||||
tbody.innerHTML = "";
|
||||
if (data && data.length > 0) {
|
||||
data.forEach(user => {
|
||||
const row = document.createElement("tr");
|
||||
row.innerHTML = `
|
||||
<td>${user.userName}</td>
|
||||
<td>${user.deptNm || "-"}</td>
|
||||
<td>${user.rankCd || "-"}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-success"
|
||||
onclick="selectApproval('${user.userName}', '${user.deptNm}', '${user.mobilePhone}', '${user.uniqId}')">
|
||||
<i class="fas fa-user-plus"></i> 추가
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
} else {
|
||||
tbody.innerHTML = `<tr><td colspan="5" class="text-center text-muted">검색 결과가 없습니다.</td></tr>`;
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("사용자 목록을 불러오는 데 실패했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자를 선택하여 출장 인원 또는 결재라인에 추가
|
||||
* @function
|
||||
* @param {string} name - 사용자 이름
|
||||
* @param {string} dept - 부서명
|
||||
* @param {string} phone - 전화번호
|
||||
* @param {string} uniqId - 사용자 고유 ID
|
||||
* @returns {void}
|
||||
*/
|
||||
function selectUser(name, dept, phone, uniqId) {
|
||||
|
||||
const tbody = document.getElementById("tripMemberTbody");
|
||||
const newRow = document.createElement("tr");
|
||||
newRow.setAttribute("data-uniqid", uniqId);
|
||||
newRow.innerHTML = `
|
||||
<td>${name}</td>
|
||||
<td>${dept}</td>
|
||||
<td>${phone}</td>
|
||||
<td class="text-center">
|
||||
<a href="#" class="btn btn-danger btn-sm" onclick="removeMemberRow(this)">
|
||||
<i class="fas fa-user-minus"></i> 삭제
|
||||
</a>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(newRow);
|
||||
$('#userSearchModal').modal('hide');
|
||||
}
|
||||
|
||||
|
||||
function selectApproval(name, dept, phone, uniqId) {
|
||||
const stageId = $('#approvalSearchModal').data('stageId');
|
||||
|
||||
const rowMap = {
|
||||
approval1: { index: 0, inputId: "approver1" },
|
||||
approval2: { index: 1, inputId: "approver2" },
|
||||
approval3: { index: 2, inputId: "approver3" }
|
||||
};
|
||||
|
||||
const { index, inputId } = rowMap[stageId];
|
||||
const tbody = document.getElementById("approvalLineTbody");
|
||||
const targetRow = tbody.rows[index];
|
||||
if (!targetRow) return;
|
||||
|
||||
targetRow.innerHTML = `
|
||||
<td class="text-center align-middle">${targetRow.cells[0].textContent}</td>
|
||||
<td>${name}</td>
|
||||
<td>${dept}</td>
|
||||
<td>${phone}</td>
|
||||
<td class="text-center">
|
||||
<a href="#" class="btn btn-danger btn-sm" onclick="resetApproval('${stageId}')">
|
||||
<i class="fas fa-user-minus"></i> 삭제
|
||||
</a>
|
||||
</td>
|
||||
`;
|
||||
|
||||
// hidden input에 uniqId 저장
|
||||
document.getElementById(inputId).value = uniqId;
|
||||
|
||||
$('#approvalSearchModal').modal('hide');
|
||||
$('#approvalSearchModal').data('stageId', null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 검색창 버튼 클릭 시 사용자 검색 실행
|
||||
* @function
|
||||
*/
|
||||
function searchUser() {
|
||||
const keyword = document.getElementById("userSearchKeyword").value.trim();
|
||||
loadUserList(keyword);
|
||||
}
|
||||
function searchApproval() {
|
||||
const keyword = document.getElementById("userSearchKeyword").value.trim();
|
||||
loadApprovalList(keyword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 출장 인원 행 삭제
|
||||
* @function
|
||||
* @param {HTMLElement} el - 삭제 버튼 요소
|
||||
*/
|
||||
function removeMemberRow(el) {
|
||||
if (confirm("정말 삭제하시겠습니까?")) {
|
||||
const row = el.closest("tr");
|
||||
if (row) row.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 결재자 지정 모달 열기
|
||||
* @function
|
||||
* @param {string} stageId - 결재 단계 ID (approval1, approval2, approval3)
|
||||
*/
|
||||
function openApprovalModal(stageId) {
|
||||
$('#approvalSearchModal').data('stageId', stageId).modal('show');
|
||||
}
|
||||
|
||||
/**
|
||||
* 결재자 삭제 및 단계 초기화
|
||||
* @function
|
||||
* @param {string} stageId - 결재 단계 ID
|
||||
*/
|
||||
function resetApproval(stageId) {
|
||||
const rowIndex = {
|
||||
approval1: 0,
|
||||
approval2: 1,
|
||||
approval3: 2
|
||||
}[stageId];
|
||||
|
||||
const tbody = document.getElementById("approvalLineTbody");
|
||||
const label = ['검토 1', '검토 2', '결제'][rowIndex];
|
||||
|
||||
tbody.rows[rowIndex].innerHTML = `
|
||||
<td class="text-center align-middle">${label}</td>
|
||||
<td colspan="4">
|
||||
<button type="button" class="btn btn-outline-info btn-sm" onclick="openApprovalModal('${stageId}')">
|
||||
<i class="fas fa-user-plus"></i> 사용자 지정
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
}
|
||||
26
src/main/resources/static/cmn/js/bizTrip/init.js
Normal file
26
src/main/resources/static/cmn/js/bizTrip/init.js
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
$(function () {
|
||||
|
||||
/**
|
||||
* 시작 시간 선택기 초기화
|
||||
* @function
|
||||
*/
|
||||
$('#startTimePicker').datetimepicker({
|
||||
format: 'HH:mm',
|
||||
stepping: 10
|
||||
});
|
||||
|
||||
/**
|
||||
* 종료 시간 선택기 초기화
|
||||
* @function
|
||||
*/
|
||||
$('#endTimePicker').datetimepicker({
|
||||
format: 'HH:mm',
|
||||
stepping: 10,
|
||||
icons: {
|
||||
time: 'far fa-clock',
|
||||
up: 'fas fa-chevron-up',
|
||||
down: 'fas fa-chevron-down'
|
||||
}
|
||||
});
|
||||
});
|
||||
52
src/main/resources/static/cmn/js/bizTrip/service.js
Normal file
52
src/main/resources/static/cmn/js/bizTrip/service.js
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 출장 등록 전송 함수 (값 생성 + 전송 담당)
|
||||
*/
|
||||
function collectAndSubmitTripData() {
|
||||
if (!validateTripForm()) return;
|
||||
|
||||
// 값 생성
|
||||
const tripInfo = {
|
||||
tripTypeCd: $('#tripType').val(),
|
||||
locationCd: $('#tripLocation').val(),
|
||||
locationTxt: $('#locationTxt').val(),
|
||||
purpose: $('#purpose').val(),
|
||||
moveCd: $('#tripMove').val(),
|
||||
tripDt: $('#tripDate').val(),
|
||||
startTime: $('#startTimePicker input').val(),
|
||||
endTime: $('#endTimePicker input').val(),
|
||||
status: '10'
|
||||
};
|
||||
|
||||
const tripMembers = [];
|
||||
$('#tripMemberTbody tr').each(function () {
|
||||
const uniqId = $(this).data('uniqid');
|
||||
if (!uniqId) return;
|
||||
const role = $(this).find('td').eq(3).text().trim() === '기안자' ? '0' : '1';
|
||||
tripMembers.push({ uniqId, role });
|
||||
});
|
||||
|
||||
const approvalLines = [];
|
||||
['approver1', 'approver2', 'approver3'].forEach((id, idx) => {
|
||||
const uniqId = $(`#${id}`).val();
|
||||
if (uniqId) {
|
||||
approvalLines.push({
|
||||
approverId: uniqId,
|
||||
orderNo: idx + 1,
|
||||
approveStatus: '10'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const payload = { tripInfo, tripMembers, approvalLines };
|
||||
console.log("payload:", payload);
|
||||
|
||||
// Ajax 전송
|
||||
$.ajax({
|
||||
url: '/api/bizTrip/register',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(payload),
|
||||
success: () => fn_successAlert("등록 성공", "출장 정보가 저장되었습니다."),
|
||||
error: () => fn_failedAlert("등록 실패", "오류가 발생했습니다.")
|
||||
});
|
||||
}
|
||||
65
src/main/resources/static/cmn/js/bizTrip/validation.js
Normal file
65
src/main/resources/static/cmn/js/bizTrip/validation.js
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 출장 등록 입력값 유효성 검사 함수
|
||||
* - 필수 항목 누락 여부 확인
|
||||
* - 출장일자가 오늘 이전인지 확인
|
||||
* - 시작 시간이 종료 시간보다 늦은지 확인
|
||||
*
|
||||
* @returns {boolean} 유효하면 true, 유효하지 않으면 false
|
||||
*/
|
||||
function validateTripForm() {
|
||||
// ===== [1] 입력값 가져오기 =====
|
||||
const tripType = $('#tripType');
|
||||
const location = $('#tripLocation');
|
||||
const locationTxt = $('#locationTxt');
|
||||
const purpose = $('#purpose');
|
||||
const move = $('#tripMove');
|
||||
const date = $('#tripDate');
|
||||
const start = $('#startTimePicker input');
|
||||
const end = $('#endTimePicker input');
|
||||
const approver = $('#approver3');
|
||||
|
||||
const tripTypeCd = tripType.val();
|
||||
const locationCd = location.val();
|
||||
const locationTxtVal = locationTxt.val();
|
||||
const purposeVal = purpose.val();
|
||||
const moveCd = move.val();
|
||||
const tripDt = date.val();
|
||||
const startTime = start.val();
|
||||
const endTime = end.val();
|
||||
const approver3 = approver.val();
|
||||
|
||||
// ===== [2] 필수값 체크 + focus =====
|
||||
if (!tripTypeCd) return fn_failedAlert("입력 오류", "출장 구분을 선택해주세요.", 1000), tripType.focus(), false;
|
||||
if (!locationCd) return fn_failedAlert("입력 오류", "출장지를 선택해주세요.", 1000), location.focus(), false;
|
||||
if (!locationTxtVal || locationTxtVal.trim() === "") return fn_failedAlert("입력 오류", "목적지를 입력해주세요.", 1000), locationTxt.focus(), false;
|
||||
if (!purposeVal || purposeVal.trim() === "") return fn_failedAlert("입력 오류", "출장 목적을 입력해주세요.", 1000), purpose.focus(), false;
|
||||
if (!moveCd) return fn_failedAlert("입력 오류", "이동 수단을 선택해주세요.", 1000), move.focus(), false;
|
||||
if (!tripDt) return fn_failedAlert("입력 오류", "출장일자를 선택해주세요.", 1000), date.focus(), false;
|
||||
if (!startTime || !endTime) return fn_failedAlert("입력 오류", "시작/종료 시간을 입력해주세요.", 1000), start.focus(), false;
|
||||
if (!approver3) return fn_failedAlert("입력 오류", "최종 결재자를 지정해주세요.", 1000), approver.focus(), false;
|
||||
|
||||
// ===== [3] 출장일자가 오늘보다 과거일 경우 =====
|
||||
const today = new Date();
|
||||
const inputDate = new Date(tripDt);
|
||||
today.setHours(0, 0, 0, 0);
|
||||
inputDate.setHours(0, 0, 0, 0);
|
||||
if (inputDate < today) {
|
||||
fn_failedAlert("입력 오류", "출장일자는 오늘보다 빠를 수 없습니다.");
|
||||
date.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// ===== [4] 시간 순서 확인 (종료 > 시작) =====
|
||||
const [sH, sM] = startTime.split(':').map(Number);
|
||||
const [eH, eM] = endTime.split(':').map(Number);
|
||||
const startDate = new Date(); startDate.setHours(sH, sM, 0, 0);
|
||||
const endDate = new Date(); endDate.setHours(eH, eM, 0, 0);
|
||||
if (endDate <= startDate) {
|
||||
fn_failedAlert("입력 오류", "종료 시간은 시작 시간보다 이후여야 합니다.");
|
||||
end.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// ===== [5] 유효성 통과 =====
|
||||
return true;
|
||||
}
|
||||
@ -37,7 +37,7 @@
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" th:href="@{/plugins/toastr/toastr.min.css}">
|
||||
|
||||
<!-- CSS -->
|
||||
|
||||
|
||||
<!-- jQuery -->
|
||||
@ -121,6 +121,16 @@
|
||||
body: msg
|
||||
})
|
||||
}
|
||||
function fn_failedAlert(title, msg, delay){
|
||||
$(document).Toasts('create', {
|
||||
class: 'bg-danger',
|
||||
title: title,
|
||||
subtitle: '',
|
||||
autohide : true,
|
||||
delay: delay,
|
||||
body: msg
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
@ -92,7 +92,7 @@
|
||||
</a>
|
||||
<ul class="nav nav-treeview">
|
||||
<li class="nav-item">
|
||||
<a th:href="@{/itn/trip/reg}" class="nav-link">
|
||||
<a th:href="@{/itn/bizTrip/reg}" class="nav-link">
|
||||
<!-- <i class="far fa-circle nav-icon"></i>-->
|
||||
<!-- <i class="far fa-clock nav-icon"></i>-->
|
||||
<i class="nav-icon fas fa-calendar-check"></i>
|
||||
|
||||
220
src/main/resources/templates/itn/bizTrip/list.html
Normal file
220
src/main/resources/templates/itn/bizTrip/list.html
Normal file
@ -0,0 +1,220 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- 관련 Namespace 선언 및 layout:decorate 추가 -->
|
||||
<html lang="en"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="layout">
|
||||
<head>
|
||||
<!-- layout.html 에 들어간 head 부분을 제외하고 개별 파일에만 적용되는 head 부분 추가 -->
|
||||
<title>사용자 관리</title>
|
||||
|
||||
<!-- 필요하다면 개별 파일에 사용될 css/js 선언 -->
|
||||
|
||||
<link rel="stylesheet" th:href="@{/plugins/datatables-bs4/css/dataTables.bootstrap4.min.css}">
|
||||
<link rel="stylesheet" th:href="@{/plugins/datatables-responsive/css/responsive.bootstrap4.min.css}">
|
||||
<link rel="stylesheet" th:href="@{/plugins/datatables-buttons/css/buttons.bootstrap4.min.css}">
|
||||
|
||||
<style>
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
.cursor-pointer:hover {
|
||||
text-decoration: underline;
|
||||
color: #007bff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body layout:fragment="body">
|
||||
|
||||
<div class="wrapper">
|
||||
<div th:replace="~{fragments/top_nav :: topFragment}"/>
|
||||
|
||||
<!-- Main Sidebar Container -->
|
||||
<aside class="main-sidebar sidebar-dark-primary elevation-4"
|
||||
th:insert="~{fragments/mainsidebar :: sidebarFragment}">
|
||||
</aside>
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<div class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1 class="m-0">사용자 관리</h1>
|
||||
</div><!-- /.col -->
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item"><a href="#">Home</a></li>
|
||||
<li class="breadcrumb-item active">출퇴근 관리</li>
|
||||
</ol>
|
||||
</div><!-- /.col -->
|
||||
</div><!-- /.row -->
|
||||
</div><!-- /.container-fluid -->
|
||||
</div>
|
||||
<!-- /.content-header -->
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<!-- /.card -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">목록</h3>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body">
|
||||
<table id="tripTb" class="table table-bordered table-striped" style="width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>출장ID</th>
|
||||
<th>출장일</th>
|
||||
<th>시간</th>
|
||||
<th>출장구분</th>
|
||||
<th>지역</th>
|
||||
<th>목적지</th>
|
||||
<th>목적</th>
|
||||
<th>이동수단</th>
|
||||
<th>상태</th>
|
||||
<th>결재상태</th>
|
||||
<th>작성자</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="row, stat : ${list}">
|
||||
<td th:text="${stat.count}"/>
|
||||
<td th:text="${row.tripId}"/>
|
||||
<td th:text="${#temporals.format(row.tripDt, 'yyyy-MM-dd')}"/>
|
||||
<td th:text="${row.startTime + ' ~ ' + row.endTime}"/>
|
||||
<td th:text="${@TCodeUtils.getCodeName('TRIP_TYPE', row.tripTypeCd)}"/>
|
||||
<td th:text="${@TCodeUtils.getCodeName('TRIP_LOCATION', row.locationCd)}"/>
|
||||
<td th:text="${row.locationTxt}"/>
|
||||
<td th:text="${row.purpose}"/>
|
||||
<td th:text="${@TCodeUtils.getCodeName('TRIP_MOVE', row.moveCd)}"/>
|
||||
<td>
|
||||
<span th:switch="${row.status}">
|
||||
<span th:case="'10'" class="badge badge-warning">대기</span>
|
||||
<span th:case="'20'" class="badge badge-primary">진행</span>
|
||||
<span th:case="'30'" class="badge badge-success">승인</span>
|
||||
<span th:case="'40'" class="badge badge-danger">반려</span>
|
||||
<span th:case="*">-</span>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span th:switch="${row.latestApproveStatus}">
|
||||
<span th:case="'10'" class="badge badge-warning">대기</span>
|
||||
<span th:case="'20'" class="badge badge-primary">진행</span>
|
||||
<span th:case="'30'" class="badge badge-success">승인</span>
|
||||
<span th:case="'40'" class="badge badge-danger">반려</span>
|
||||
<span th:case="*">-</span>
|
||||
</span>
|
||||
</td>
|
||||
<td th:text="${row.frstRegisterId}"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
</div>
|
||||
<!-- /.card -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
<!-- /.container-fluid -->
|
||||
</section>
|
||||
<!-- /Main content -->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- /.content-wrapper -->
|
||||
<footer class="main-footer"
|
||||
th:insert="~{fragments/footer :: footerFragment}">
|
||||
</footer>
|
||||
|
||||
<!-- Control Sidebar -->
|
||||
<aside class="control-sidebar control-sidebar-dark">
|
||||
<!-- Control sidebar content goes here -->
|
||||
</aside>
|
||||
<!-- /.control-sidebar -->
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
|
||||
<!-- DataTables & Plugins -->
|
||||
<script th:src="@{/plugins/datatables/jquery.dataTables.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-bs4/js/dataTables.bootstrap4.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-responsive/js/dataTables.responsive.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-responsive/js/responsive.bootstrap4.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/dataTables.buttons.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.bootstrap4.min.js}"></script>
|
||||
<script th:src="@{/plugins/jszip/jszip.min.js}"></script>
|
||||
<script th:src="@{/plugins/pdfmake/pdfmake.min.js}"></script>
|
||||
<script th:src="@{/plugins/pdfmake/vfs_fonts.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.html5.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.print.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.colVis.min.js}"></script>
|
||||
<script>
|
||||
|
||||
const commonExportOptions = {
|
||||
columns: ':visible',
|
||||
format: {
|
||||
body: function (data, row, column, node) {
|
||||
if ($(node).find('select').length) {
|
||||
return $(node).find('select option:selected').text();
|
||||
}
|
||||
// 태그 제거: 보이는 텍스트만 반환
|
||||
return $(node).text();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$("#tripTb").DataTable({
|
||||
"responsive": true
|
||||
, "lengthChange": false
|
||||
, "autoWidth": false
|
||||
, "pageLength": 20
|
||||
, "buttons": [
|
||||
{
|
||||
extend: 'copy',
|
||||
charset: 'UTF-8',
|
||||
exportOptions: commonExportOptions
|
||||
},
|
||||
{
|
||||
extend: 'csv',
|
||||
charset: 'UTF-8',
|
||||
bom: true,
|
||||
exportOptions: commonExportOptions
|
||||
},
|
||||
{
|
||||
extend: 'excel',
|
||||
charset: 'UTF-8',
|
||||
exportOptions: commonExportOptions
|
||||
},
|
||||
{
|
||||
extend: 'pdf',
|
||||
charset: 'UTF-8',
|
||||
exportOptions: commonExportOptions
|
||||
},
|
||||
{
|
||||
extend: 'print',
|
||||
charset: 'UTF-8',
|
||||
exportOptions: commonExportOptions
|
||||
},
|
||||
"colvis"]
|
||||
}).buttons().container().appendTo('#commuteTb_wrapper .col-md-6:eq(0)');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
|
||||
</html>
|
||||
@ -6,7 +6,7 @@
|
||||
layout:decorate="layout">
|
||||
<head>
|
||||
<!-- layout.html 에 들어간 head 부분을 제외하고 개별 파일에만 적용되는 head 부분 추가 -->
|
||||
<title>사용자 관리</title>
|
||||
<title>출장 등록</title>
|
||||
|
||||
<!-- 필요하다면 개별 파일에 사용될 css/js 선언 -->
|
||||
|
||||
@ -33,14 +33,6 @@
|
||||
border-top: 2px solid #009fe3;
|
||||
}
|
||||
|
||||
.btn-custom {
|
||||
border: 1px solid #dcdcdc;
|
||||
background-color: #ffffff;
|
||||
color: #009fe3;
|
||||
font-weight: bold;
|
||||
padding: 6px 18px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@ -81,7 +73,7 @@
|
||||
<!-- 출장신청 영역 -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
출장신청
|
||||
출장정보
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-bordered table-form" style="table-layout: fixed;">
|
||||
@ -100,19 +92,19 @@
|
||||
<th>출장지</th>
|
||||
<td>
|
||||
<select class="form-control d-inline" style="width: 20%;" id="tripLocation" name="tripLocation">
|
||||
<option value="" th:selected>-- 선택 --</option>
|
||||
<option value="" th:selected>-- 지역 --</option>
|
||||
<option th:each="code : ${@TCodeUtils.getCodeList('TRIP_LOCATION')}"
|
||||
th:value="${code.codeId}"
|
||||
th:text="${code.codeName}">
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<input type="text" class="form-control d-inline" style="width: 70%;">
|
||||
<input type="text" id="locationTxt" class="form-control d-inline" style="width: 70%;" placeholder="목적지">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>출장목적</th>
|
||||
<td><input type="text" class="form-control"></td>
|
||||
<td><input type="text" id="purpose" class="form-control"></td>
|
||||
<th>이동사항</th>
|
||||
<td>
|
||||
<select class="form-control" id="tripMove" name="tripMove">
|
||||
@ -131,12 +123,30 @@
|
||||
</td>
|
||||
<th>시간</th>
|
||||
<td>
|
||||
<div class="d-flex gap-2">
|
||||
<input type="time" id="startTime" class="form-control" style="margin-right: 4px;">
|
||||
<span class="align-self-center">~</span>
|
||||
<input type="time" id="endTime" class="form-control" style="margin-left: 4px;">
|
||||
<div class="d-flex">
|
||||
<!-- 시작 시간 -->
|
||||
<div class="input-group date" id="startTimePicker" data-target-input="nearest" style="margin-right: 5px;">
|
||||
<input type="text"
|
||||
class="form-control datetimepicker-input"
|
||||
data-target="#startTimePicker"
|
||||
data-toggle="datetimepicker" />
|
||||
<div class="input-group-append" data-target="#startTimePicker" data-toggle="datetimepicker">
|
||||
<div class="input-group-text"><i class="far fa-clock"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="align-self-center mx-2">~</span>
|
||||
<!-- 종료 시간 -->
|
||||
<div class="input-group date" id="endTimePicker" data-target-input="nearest">
|
||||
<input type="text"
|
||||
class="form-control datetimepicker-input"
|
||||
data-target="#endTimePicker"
|
||||
data-toggle="datetimepicker" />
|
||||
<div class="input-group-append" data-target="#endTimePicker" data-toggle="datetimepicker">
|
||||
<div class="input-group-text"><i class="far fa-clock"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -163,9 +173,8 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tripMemberTbody">
|
||||
<tr>
|
||||
<tr th:data-uniqid="${loginUser.getUniqId()}">
|
||||
<td th:text="${loginUser.getUserName()}"/>
|
||||
|
||||
<td th:text="${@TCodeUtils.getCodeName('DEPT', loginUser.getDeptCd())}"/>
|
||||
<td th:text="${loginUser.getMobilePhone()}"/>
|
||||
<td class="text-center">기안자</td>
|
||||
@ -175,9 +184,57 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 결제 라인 영역 -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
결제라인
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-bordered table-form mb-0">
|
||||
<thead>
|
||||
<tr class="text-center bg-light">
|
||||
<th style="width: 20%;">결재 단계</th>
|
||||
<th style="width: 20%;">이름</th>
|
||||
<th style="width: 25%;">부서명</th>
|
||||
<th style="width: 25%;">연락처</th>
|
||||
<th style="width: 10%;" class="text-center">관리</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="approvalLineTbody">
|
||||
<tr>
|
||||
<td class="text-center align-middle">검토 1</td>
|
||||
<td colspan="4">
|
||||
<button type="button" class="btn btn-outline-info btn-sm" onclick="openApprovalModal('approval1')">
|
||||
<i class="fas fa-user-plus"></i> 사용자 지정
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center align-middle">검토 2</td>
|
||||
<td colspan="4">
|
||||
<button type="button" class="btn btn-outline-info btn-sm" onclick="openApprovalModal('approval2')">
|
||||
<i class="fas fa-user-plus"></i> 사용자 지정
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center align-middle">결제</td>
|
||||
<td colspan="4">
|
||||
<button type="button" class="btn btn-outline-info btn-sm" onclick="openApprovalModal('approval3')">
|
||||
<i class="fas fa-user-plus"></i> 사용자 지정
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<input type="hidden" id="approver1" name="approver1">
|
||||
<input type="hidden" id="approver2" name="approver2">
|
||||
<input type="hidden" id="approver3" name="approver3">
|
||||
</div>
|
||||
<div class="text-right mt-2">
|
||||
<!-- 등록 버튼 -->
|
||||
<button type="submit" class="btn btn-primary btn-sm">
|
||||
<button type="submit" class="btn btn-primary btn-sm" onclick="collectAndSubmitTripData()">
|
||||
<i class="fas fa-save"></i> 등록
|
||||
</button>
|
||||
</div>
|
||||
@ -191,6 +248,52 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 사용자 검색 모달 -->
|
||||
<div class="modal fade" id="approvalSearchModal" tabindex="-1" role="dialog" aria-labelledby="userSearchModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info">
|
||||
<h5 class="modal-title text-white" id="approvalSearchModalLabel">사용자 검색</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<!-- 검색 영역 -->
|
||||
<div class="form-inline mb-3">
|
||||
<label class="mr-2">이름 검색</label>
|
||||
<input type="text" class="form-control mr-2" auto id="approvalSearchKeyword" placeholder="검색어 입력" autocomplete="off">
|
||||
<button type="button" class="btn btn-info btn-sm" onclick="searchUser()">검색</button>
|
||||
</div>
|
||||
|
||||
<!-- 결과 테이블 -->
|
||||
<div class="table-responsive" style="max-height: 500px; overflow-y: auto;">
|
||||
<table class="table table-hover table-bordered table-sm text-center">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>이름</th>
|
||||
<th>부서</th>
|
||||
<th>직급</th>
|
||||
<th>추가</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="approvalSearchResult">
|
||||
<!-- 검색 결과 동적 렌더링 -->
|
||||
<!-- 예시 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">닫기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 사용자 검색 모달 -->
|
||||
<div class="modal fade" id="userSearchModal" tabindex="-1" role="dialog" aria-labelledby="userSearchModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
@ -206,7 +309,7 @@
|
||||
<!-- 검색 영역 -->
|
||||
<div class="form-inline mb-3">
|
||||
<label class="mr-2">이름 검색</label>
|
||||
<input type="text" class="form-control mr-2" id="userSearchKeyword" placeholder="검색어 입력">
|
||||
<input type="text" class="form-control mr-2" auto id="userSearchKeyword" placeholder="검색어 입력" autocomplete="off">
|
||||
<button type="button" class="btn btn-info btn-sm" onclick="searchUser()">검색</button>
|
||||
</div>
|
||||
|
||||
@ -249,127 +352,10 @@
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
|
||||
<!-- DataTables & Plugins -->
|
||||
<script th:src="@{/plugins/datatables/jquery.dataTables.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-bs4/js/dataTables.bootstrap4.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-responsive/js/dataTables.responsive.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-responsive/js/responsive.bootstrap4.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/dataTables.buttons.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.bootstrap4.min.js}"></script>
|
||||
<script th:src="@{/plugins/jszip/jszip.min.js}"></script>
|
||||
<script th:src="@{/plugins/pdfmake/pdfmake.min.js}"></script>
|
||||
<script th:src="@{/plugins/pdfmake/vfs_fonts.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.html5.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.print.min.js}"></script>
|
||||
<script th:src="@{/plugins/datatables-buttons/js/buttons.colVis.min.js}"></script>
|
||||
<script>
|
||||
document.querySelector('input[id="startTime"]').addEventListener('click', function() {
|
||||
this.showPicker && this.showPicker(); // 일부 브라우저에서 시간 선택기 강제 실행
|
||||
});
|
||||
|
||||
document.querySelector('input[id="endTime"]').addEventListener('click', function() {
|
||||
this.showPicker && this.showPicker(); // 일부 브라우저에서 시간 선택기 강제 실행
|
||||
});
|
||||
document.querySelector('input[id="tripDate"]').addEventListener('click', function() {
|
||||
this.showPicker && this.showPicker(); // 일부 브라우저에서 시간 선택기 강제 실행
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// 사용자 목록 로딩 (검색 포함)
|
||||
function loadUserList(keyword = "") {
|
||||
$.ajax({
|
||||
url: '/api/admin/user/search/name'
|
||||
,type: 'GET'
|
||||
,data: { userName: keyword }
|
||||
,success: function (resutl) {
|
||||
console.log(' + loadUserList resutl : ', resutl);
|
||||
const tbody = document.getElementById("userSearchResult");
|
||||
tbody.innerHTML = ""; // 초기화
|
||||
|
||||
var data = resutl.data;
|
||||
if (data && data.length > 0) {
|
||||
data.forEach(user => {
|
||||
const row = document.createElement("tr");
|
||||
row.innerHTML = `
|
||||
<td>${user.userName}</td>
|
||||
<td>${user.deptNm || "-"}</td>
|
||||
<td>${user.userRank || "-"}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-success" onclick="selectUser('${user.userName}', '${user.deptNm}', '${user.mobilePhone}')">
|
||||
<i class="fas fa-user-plus"></i> 추가
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
} else {
|
||||
tbody.innerHTML = `<tr><td colspan="5" class="text-center text-muted">검색 결과가 없습니다.</td></tr>`;
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("사용자 목록을 불러오는 데 실패했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 모달 열릴 때 사용자 목록 자동 로드
|
||||
$('#userSearchModal').on('shown.bs.modal', function () {
|
||||
loadUserList(); // 최초 전체 목록 로드
|
||||
});
|
||||
|
||||
|
||||
function selectUser(name, dept, phone) {
|
||||
console.log('phone: ', phone);
|
||||
// 원하는 방식으로 테이블에 사용자 추가
|
||||
const tbody = document.getElementById("tripMemberTbody");
|
||||
|
||||
const newRow = document.createElement("tr");
|
||||
newRow.innerHTML = `
|
||||
<td>${name}</td>
|
||||
<td>${dept}</td>
|
||||
<td>${phone}</td>
|
||||
<td class="text-center">
|
||||
<a href="#" class="btn btn-danger btn-sm" onclick="removeMemberRow(this)">
|
||||
<i class="fas fa-user-minus"></i> 삭제
|
||||
</a>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(newRow);
|
||||
|
||||
// 모달 닫기
|
||||
$('#userSearchModal').modal('hide');
|
||||
}
|
||||
|
||||
// 검색 버튼 클릭 시
|
||||
function searchUser() {
|
||||
const keyword = document.getElementById("userSearchKeyword").value.trim();
|
||||
loadUserList(keyword);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 출장 인원 행 삭제 함수
|
||||
function removeMemberRow(el) {
|
||||
if (confirm("정말 삭제하시겠습니까?")) {
|
||||
const row = el.closest("tr");
|
||||
if (row) {
|
||||
row.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script th:src="@{/cmn/js/bizTrip/init.js}"></script>
|
||||
<script th:src="@{/cmn/js/bizTrip/event.js}"></script>
|
||||
<script th:src="@{/cmn/js/bizTrip/service.js}"></script>
|
||||
<script th:src="@{/cmn/js/bizTrip/validation.js}"></script>
|
||||
</body>
|
||||
|
||||
|
||||
@ -161,13 +161,23 @@
|
||||
<label for="userId">ID</label>
|
||||
<input type="text" class="form-control" id="userId" name="userId" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mobilePhone">핸드폰번호</label>
|
||||
<input type="text" class="form-control" id="mobilePhone" name="mobilePhone">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="userName">이름</label>
|
||||
<input type="text" class="form-control" id="userName" name="userName">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="userRank">직급</label>
|
||||
<input type="text" class="form-control" id="userRank" name="userRank" placeholder="직급을 입력해 주세요.">
|
||||
<label for="rankCd">직급</label>
|
||||
<select class="form-control" id="rankCd" name="rankCd">
|
||||
<option value="" th:selected>-- 선택 --</option>
|
||||
<option th:each="code : ${@TCodeUtils.getCodeList('RANK')}"
|
||||
th:value="${code.codeId}"
|
||||
th:text="${code.codeName}">
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="deptCd">부서명</label>
|
||||
@ -328,8 +338,9 @@
|
||||
var modalId = '#editUserInfoModal';
|
||||
$(modalId+' #uniqId').val(dataInfo.uniqId);
|
||||
$(modalId+' #userId').val(dataInfo.userId);
|
||||
$(modalId+' #userName').val(dataInfo.username);
|
||||
$(modalId+' #userRank').val(dataInfo.userRank);
|
||||
$(modalId+' #userName').val(dataInfo.userName);
|
||||
$(modalId+' #mobilePhone').val(dataInfo.mobilePhone);
|
||||
$(modalId+' #rankCd').val(dataInfo.rankCd);
|
||||
$(modalId+' #deptCd').val(dataInfo.deptCd);
|
||||
$(modalId+' #hireDate').val(dataInfo.hireDate);
|
||||
$(modalId+' #resignDate').val(dataInfo.resignDate);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user