Merge branch 'master' of http://192.168.0.25:9001/r/owl-kisa
Conflicts:
src/main/webapp/scripts/app/issue/issueDetail.controller.js
26개 파일 변경됨
16개 파일 추가됨
1개 파일 삭제됨
| | |
| | | |
| | | <!-- Logging --> |
| | | <slf4j.version>1.7.28</slf4j.version> |
| | | <log4j.version>2.12.1</log4j.version> |
| | | <log4j.version>2.17.1</log4j.version> |
| | | |
| | | <!-- Spring Session Redis --> |
| | | <spring.session.version>2.1.8.RELEASE</spring.session.version> |
| | |
| | | |
| | | <!-- Elastic Search --> |
| | | <elastic.search.version>7.3.0</elastic.search.version> |
| | | |
| | | <!-- jsoup --> |
| | | <jsoup.version>1.8.3</jsoup.version> |
| | | |
| | | <!-- Util --> |
| | | <jackson.version>2.9.9</jackson.version> |
| | |
| | | <version>${java.mail.version}</version> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>javax.interceptor</groupId> |
| | | <artifactId>javax.interceptor-api</artifactId> |
| | | <version>1.2</version> |
| | | </dependency> |
| | | <!-- Excel import --> |
| | | <dependency> |
| | | <groupId>org.apache.poi</groupId> |
| | |
| | | <artifactId>commons-validator</artifactId> |
| | | <version>${common.validator.version}</version> |
| | | </dependency> |
| | | |
| | | <!-- jsoup --> |
| | | <dependency> |
| | | <groupId>org.jsoup</groupId> |
| | | <artifactId>jsoup</artifactId> |
| | | <version>${jsoup.version}</version> |
| | | </dependency> |
| | | |
| | | |
| | | <!-- spring --> |
| | | <dependency> |
| | |
| | | <version>0.9.1</version> |
| | | </dependency> |
| | | |
| | | <!-- Swagger(api 문서화) --> |
| | | <dependency> |
| | | <groupId>io.springfox</groupId> |
| | | <artifactId>springfox-swagger2</artifactId> |
| | | <version>2.9.2</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>io.springfox</groupId> |
| | | <artifactId>springfox-swagger-ui</artifactId> |
| | | <version>2.9.2</version> |
| | | </dependency> |
| | | </dependencies> |
| | | |
| | | <repositories> |
| | |
| | | <url>https://maven.java.net/content/repositories/public/</url> |
| | | </repository> |
| | | |
| | | <repository> |
| | | <id>JBoss repository</id> |
| | | <url>http://repository.jboss.org/nexus/content/groups/public/</url> |
| | | </repository> |
| | | </repositories> |
| | | |
| | | <build> |
| | |
| | | .antMatchers("/language/change").permitAll() |
| | | .antMatchers("/security/*").permitAll() |
| | | .antMatchers("/api/issue").permitAll() |
| | | .antMatchers("/api/issue/*").permitAll() |
| | | .antMatchers("/**/*").authenticated(); |
| | | |
| | | // http.addFilter(new CustomAuthenticationFilter()); |
| | | // http.addFilterBefore(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); |
| | | |
New file |
| | |
| | | package kr.wisestone.owl.config; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | import springfox.documentation.builders.ApiInfoBuilder; |
| | | import springfox.documentation.builders.PathSelectors; |
| | | import springfox.documentation.builders.RequestHandlerSelectors; |
| | | import springfox.documentation.service.ApiInfo; |
| | | import springfox.documentation.service.Parameter; |
| | | import springfox.documentation.spi.DocumentationType; |
| | | import springfox.documentation.spring.web.plugins.Docket; |
| | | import springfox.documentation.swagger2.annotations.EnableSwagger2; |
| | | |
| | | /** |
| | | * API 문서 제작 패키지 Swagger 설정 클래스 |
| | | */ |
| | | @Configuration |
| | | @EnableSwagger2 |
| | | public class SwaggerConfig { |
| | | |
| | | private static final String API_NAME = "OWL API"; |
| | | private static final String API_VERSION = "1.0.0"; |
| | | private static final String API_DESCRIPTION = "OWL API 명세서"; |
| | | |
| | | |
| | | /** |
| | | * API 설정 |
| | | * @return docket class |
| | | */ |
| | | @Bean |
| | | public Docket api() { |
| | | // Parameter parameterBuilder = new ParameterBuilder() |
| | | // .name(HttpHeaders.AUTHORIZATION) |
| | | // .description("Access Tocken") |
| | | // .modelRef(new ModelRef("string")) |
| | | // .parameterType("header") |
| | | // .required(false) |
| | | // .build(); |
| | | |
| | | List<Parameter> globalParameters = new ArrayList<>(); |
| | | // globalParameters.add(parameterBuilder); |
| | | |
| | | return new Docket(DocumentationType.SWAGGER_2) |
| | | .globalOperationParameters(globalParameters) |
| | | .consumes(getConsumeContentTypes()) |
| | | .produces(getProduceContentTypes()) |
| | | .apiInfo(apiInfo()) |
| | | .select() |
| | | .apis(RequestHandlerSelectors.basePackage("kr.wisestone.owl.web.controller.Api")) |
| | | .paths(PathSelectors.any()) |
| | | .build(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * API 문서 타이틀/버전/설명 설정 |
| | | * @return ApiInfo 클래스 |
| | | */ |
| | | public ApiInfo apiInfo() { |
| | | return new ApiInfoBuilder() |
| | | .title(API_NAME) |
| | | .version(API_VERSION) |
| | | .description(API_DESCRIPTION) |
| | | .build(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * API 문서 테스트 Request Content-Type 설정 추가 |
| | | * @return consumes content-type 목록 |
| | | */ |
| | | private Set<String> getConsumeContentTypes() { |
| | | Set<String> consumes = new HashSet<>(); |
| | | consumes.add("application/json;charset=UTF-8"); |
| | | consumes.add("application/x-www-form-urlencoded"); |
| | | return consumes; |
| | | } |
| | | |
| | | /** |
| | | * API 문서 테스트 Response content-type 설정 추가 |
| | | * @return produce content-type 목록 |
| | | */ |
| | | private Set<String> getProduceContentTypes() { |
| | | Set<String> produces = new HashSet<>(); |
| | | produces.add("application/json;charset=UTF-8"); |
| | | return produces; |
| | | } |
| | | } |
| | |
| | | package kr.wisestone.owl.constant; |
| | | |
| | | /** |
| | | * exception 용 메세지 클래스 |
| | | * Created by jeong on 2017-08-02. |
| | | */ |
| | | public class MsgConstants { |
| | |
| | | |
| | | public static final String EMAIL_TEMPLATE_NOT_EXIST = "EMAIL_TEMPLATE_NOT_EXIST"; // 이메일 템플릿을 찾을수 없습니다. |
| | | |
| | | public static final String API_PARAMETER_ISSUE_TYPE_ERROR = "API_PARAMETER_ISSUE_TYPE_ERROR"; // api 파라미터 오류(이슈타입) |
| | | public static final String API_PARAMETER_PROJECT_ERROR = "API_PARAMETER_PROJECT_ERROR"; // api 파라미터 오류(프로젝트) |
| | | public static final String API_PARAMETER_ERROR = "API_PARAMETER_ERROR"; // api 파라미터 오류 |
| | | public static final String API_USER_ERROR = "API_USER_ERROR"; // api 사용자 오류 |
| | | public static final String API_OVERLAP_ERROR = "API_OVERLAP_ERROR"; // API 중복된 상위 이슈가 여러개일 경우 |
| | | public static final String API_OVERLAP_SETTING_NOT_EXIST = "API_OVERLAP_SETTING_NOT_EXIST"; // API 중복된 설정이 안되어 있을 경우 |
| | | public static final String API_ISSUE_NOT_EXIST = "API_ISSUE_NOT_EXIST"; // 수정할 이슈를 찾을수 없습니다. |
| | | public static final String API_COMPLETE_ISSUE_STATUS_NOT_EXIST = "API_COMPLETE_ISSUE_STATUS_NOT_EXIST"; // 자동 종료 처리할 상태가 설정되지 않았습니다. |
| | | public static final String API_ISSUE_STATUS_NOT_EXIST = "API_ISSUE_STATUS_NOT_EXIST"; // 이슈 상태를 찾을수 없습니다 |
| | | public static final String API_ISSUE_STATUS_IS_NULL = "API_ISSUE_STATUS_IS_NULL"; // 이슈 상태 값이 없습니다. |
| | | public static final String API_CUSTOM_FIELD_NOT_EXIST = "API_CUSTOM_FIELD_NOT_EXIST"; // 사용자 정의 필드를 존재하지 않습니다. |
| | | public static final String API_ISSUE_STATUS_NOT_IN_WORKFLOW = "API_ISSUE_STATUS_NOT_IN_WORKFLOW"; // 이슈 상태가 워크플로우에 포함되어 있지 않습니다 |
| | | /** |
| | | * api 파라미터 오류(이슈타입) |
| | | */ |
| | | public static final String API_PARAMETER_ISSUE_TYPE_ERROR = "API_PARAMETER_ISSUE_TYPE_ERROR"; |
| | | /** |
| | | * api 파라미터 오류(프로젝트) |
| | | */ |
| | | public static final String API_PARAMETER_PROJECT_ERROR = "API_PARAMETER_PROJECT_ERROR"; |
| | | /** |
| | | * api 파라미터 오류 |
| | | */ |
| | | public static final String API_PARAMETER_ERROR = "API_PARAMETER_ERROR"; |
| | | /** |
| | | * api 사용자 오류 |
| | | */ |
| | | public static final String API_USER_ERROR = "API_USER_ERROR"; |
| | | /** |
| | | * API 중복된 상위 이슈가 여러개일 경우 |
| | | */ |
| | | public static final String API_OVERLAP_ERROR = "API_OVERLAP_ERROR"; |
| | | /** |
| | | * API 중복된 설정이 안되어 있을 경우 |
| | | */ |
| | | public static final String API_OVERLAP_SETTING_NOT_EXIST = "API_OVERLAP_SETTING_NOT_EXIST"; |
| | | /** |
| | | * 수정할 이슈를 찾을수 없습니다. |
| | | */ |
| | | public static final String API_ISSUE_NOT_EXIST = "API_ISSUE_NOT_EXIST"; |
| | | /** |
| | | * 자동 종료 처리할 상태가 설정되지 않았습니다. |
| | | */ |
| | | public static final String API_COMPLETE_ISSUE_STATUS_NOT_EXIST = "API_COMPLETE_ISSUE_STATUS_NOT_EXIST"; |
| | | /** |
| | | * 이슈 상태를 찾을수 없습니다 |
| | | */ |
| | | public static final String API_ISSUE_STATUS_NOT_EXIST = "API_ISSUE_STATUS_NOT_EXIST"; |
| | | /** |
| | | * 이슈 상태 값이 없습니다. |
| | | */ |
| | | public static final String API_ISSUE_STATUS_IS_NULL = "API_ISSUE_STATUS_IS_NULL"; |
| | | /** |
| | | * 사용자 정의 필드를 존재하지 않습니다. |
| | | */ |
| | | public static final String API_CUSTOM_FIELD_NOT_EXIST = "API_CUSTOM_FIELD_NOT_EXIST"; |
| | | /** |
| | | * 이슈 상태가 워크플로우에 포함되어 있지 않습니다 |
| | | */ |
| | | public static final String API_ISSUE_STATUS_NOT_IN_WORKFLOW = "API_ISSUE_STATUS_NOT_IN_WORKFLOW"; |
| | | } |
| | |
| | | import kr.wisestone.owl.web.condition.DepartmentCondition; |
| | | import kr.wisestone.owl.web.condition.IssueCondition; |
| | | import kr.wisestone.owl.web.condition.ProjectCondition; |
| | | import kr.wisestone.owl.web.form.EmailCommonForm; |
| | | import kr.wisestone.owl.web.form.EmailTemplateForm; |
| | | import kr.wisestone.owl.web.form.IssueApiForm; |
| | | import kr.wisestone.owl.web.form.IssueForm; |
| | |
| | | void setCountDownIssues(List<IssueVo> issueVos); |
| | | |
| | | void makeIssueMapToIssue(Issue issue, Map<String, Object> issueMap); |
| | | |
| | | void sendCommonEmail(EmailCommonForm make); |
| | | } |
| | |
| | | issueApiForm.addUseIssueCustomFieldId(customFieldApiOverlap.getCustomField().getId()); |
| | | } |
| | | |
| | | // 중복된 이슈검색 |
| | | // 종료상태가 아닌 중복된 상위 이슈검색 |
| | | List<Issue> issues = this.findIssue(issueApiForm, customFieldApiOverlaps, user.getId()); |
| | | int size = issues.size(); |
| | | if (size > 0) { |
| | |
| | | issueCustomFieldValueCondition.setUseValue(concatUseValue); |
| | | issueCustomFieldValueCondition.setUseValues(userValues); |
| | | issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId()); |
| | | issueCustomFieldValueCondition.setIssueStatusType("CLOSE"); |
| | | List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition); |
| | | if (results != null && results.size() > 0) { |
| | | for (Map<String, Object> result : results) { |
| | |
| | | this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.SEND, sb.toString()); |
| | | } |
| | | |
| | | @Override |
| | | public void sendCommonEmail(EmailCommonForm emailCommonForm) { |
| | | if (emailCommonForm.getSendEmails().size() < 1) { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_SEND_USER)); |
| | | } else if (emailCommonForm.getIssueId() == null) { |
| | | throw new OwlRuntimeException( |
| | | this.messageAccessor.getMessage(MsgConstants.ISSUE_NOT_EXIST)); |
| | | } |
| | | |
| | | Issue issue = this.getIssue(emailCommonForm.getIssueId()); |
| | | |
| | | // 발신자 표시 |
| | | User user = this.webAppUtil.getLoginUserObject(); |
| | | UserVo toUser = this.webAppUtil.getLoginUser(); |
| | | |
| | | // 사용자 시스템 기능 사용 정보 수집 |
| | | log.info(ElasticSearchUtil.makeUserActiveHistoryMessage(this.webAppUtil.getLoginUser(), ElasticSearchConstants.ISSUE_ANOTHER_USER_SEND_EMAIL)); |
| | | StringBuilder sb = new StringBuilder(); |
| | | |
| | | Locale locale = CommonUtil.getUserLanguage(user.getLanguage()); |
| | | String[] sendMails = ConvertUtil.ToArray(emailCommonForm.getSendEmails()); |
| | | for(int i=0; i < sendMails.length; i++) { |
| | | sendMails[i] = CommonUtil.decryptAES128(sendMails[i]); |
| | | } |
| | | this.systemEmailService.sendEmail(emailCommonForm.getTitle(), emailCommonForm.getDescription(), sendMails, null); |
| | | |
| | | this.issueHistoryService.detectSendIssueMail(IssueHistoryType.SEND, emailCommonForm.getSendEmails(), sb); |
| | | this.issueHistoryService.addIssueHistory(issue, IssueHistoryType.SEND, sb.toString()); |
| | | } |
| | | |
| | | // 예약 발생 이슈를 실행한다 |
| | | @Override |
| | | @Transactional |
| | |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 이슈 사용자 정의 필드 값 검색 조건 클래스 |
| | | * Created by wisestone on 2018-06-07. |
| | | */ |
| | | public class IssueCustomFieldValueCondition { |
| | |
| | | private Long workspaceId; |
| | | private Long customFieldId; |
| | | private String customFieldType; |
| | | private List<String> useValues = Lists.newArrayList(); // 단일, 다중 일때 검색 값 |
| | | private String useValue; // 텍스트 필드일 때 검색 값 |
| | | /** |
| | | * 사용자 정의 필드 사용 값 |
| | | */ |
| | | private List<String> useValues = Lists.newArrayList(); |
| | | /** |
| | | * 텍스트 필드일 때 검색 값 |
| | | */ |
| | | private String useValue; |
| | | private boolean useParentIssueId = true; |
| | | /** |
| | | * 이슈 상태 유형(READY / OPEN / CLOSE) |
| | | */ |
| | | private String issueStatusType; |
| | | |
| | | public IssueCustomFieldValueCondition(){} |
| | | |
| | |
| | | return condition; |
| | | } |
| | | |
| | | public String getIssueStatusType() { |
| | | return issueStatusType; |
| | | } |
| | | |
| | | public void setIssueStatusType(String issueStatusType) { |
| | | this.issueStatusType = issueStatusType; |
| | | } |
| | | |
| | | public Long getIssueTypeId() { |
| | | return issueTypeId; |
| | | } |
New file |
| | |
| | | package kr.wisestone.owl.web.controller.Api; |
| | | |
| | | import io.swagger.annotations.ApiImplicitParam; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import kr.wisestone.owl.constant.MsgConstants; |
| | | import kr.wisestone.owl.domain.Issue; |
| | | import kr.wisestone.owl.exception.OwlRuntimeException; |
| | | import kr.wisestone.owl.service.IssueService; |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | | import kr.wisestone.owl.web.controller.BaseController; |
| | | import kr.wisestone.owl.web.form.ApiIssueAddForm; |
| | | import kr.wisestone.owl.web.form.ApiIssueModifyForm; |
| | | import kr.wisestone.owl.web.form.IssueApiForm; |
| | | import org.json.simple.parser.ParseException; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * OWL-API 컨트롤러 |
| | | */ |
| | | @Controller |
| | | @RequestMapping("/api") |
| | | public class ApiController extends BaseController { |
| | | |
| | | @Autowired |
| | | private IssueService issueService; |
| | | |
| | | |
| | | /** |
| | | * 이슈 추가 |
| | | * @param apiIssueAddForm 입력 폼 데이터 |
| | | * @param files 파일 |
| | | * @return JSON |
| | | * @throws OwlRuntimeException 파라미터 오류시 발생 |
| | | * @throws CloneNotSupportedException 이슈 복사 시에 발생 |
| | | */ |
| | | @PostMapping(value = "/issue") |
| | | @ApiOperation(value = "이슈 추가", notes = "새로운 이슈를 추가한다.") |
| | | @ApiImplicitParam(name = "files", required = false, dataType = "file") |
| | | public |
| | | @ResponseBody |
| | | Map<String, Object> addIssue(ApiIssueAddForm apiIssueAddForm, @RequestParam("files") List<MultipartFile> files) throws OwlRuntimeException, CloneNotSupportedException, ParseException { |
| | | Map<String, Object> resJsonData = new HashMap<>(); |
| | | |
| | | IssueApiForm issueApiForm = ConvertUtil.copyProperties(apiIssueAddForm, IssueApiForm.class); |
| | | // String str = request.getParameter(Constants.REQ_KEY_CONTENT); |
| | | issueApiForm.setMultipartFiles(files); |
| | | issueApiForm.parseCustomFields(apiIssueAddForm.getCustomFields()); |
| | | issueApiForm.setApiType(IssueApiForm.ApiType.add); |
| | | // 사용자 정의 필드가 없을 경우 검색을 할 수 없기 때문에 예외처리 |
| | | if (issueApiForm.getCustomFieldValues() == null || issueApiForm.getCustomFieldValues().size() == 0) { |
| | | throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_CUSTOM_FIELD_NOT_EXIST)); |
| | | } |
| | | |
| | | List<Issue> issues = this.issueService.addApiIssue(issueApiForm); |
| | | // 버전 생성 |
| | | for (Issue issue : issues) { |
| | | this.issueService.addIssueVersion(issue.getId(), issue.getRegisterId()); |
| | | } |
| | | |
| | | return this.setSuccessMessage(resJsonData); |
| | | } |
| | | |
| | | /** |
| | | * 이슈 상태 수정 |
| | | * @param apiIssueModifyForm 수정 폼 데이터 |
| | | * @return JSON |
| | | * @throws OwlRuntimeException 파라미터 오류시 발생 |
| | | * @throws CloneNotSupportedException 이슈 복사 시에 발생 |
| | | */ |
| | | @PostMapping(value = "/issue/1") |
| | | @ApiOperation(value = "이슈 상태 수정", notes = "사용자 정의 필드가 동일한 기존 이슈를 변경한다.") |
| | | public |
| | | @ResponseBody |
| | | Map<String, Object> modifyIssue(ApiIssueModifyForm apiIssueModifyForm) throws OwlRuntimeException, CloneNotSupportedException, ParseException { |
| | | Map<String, Object> resJsonData = new HashMap<>(); |
| | | |
| | | IssueApiForm issueApiForm = ConvertUtil.copyProperties(apiIssueModifyForm, IssueApiForm.class); |
| | | issueApiForm.parseCustomFields(apiIssueModifyForm.getCustomFields()); |
| | | issueApiForm.setApiType(IssueApiForm.ApiType.add); |
| | | // 사용자 정의 필드가 없을 경우 검색을 할 수 없기 때문에 예외처리 |
| | | if (issueApiForm.getCustomFieldValues() == null || issueApiForm.getCustomFieldValues().size() == 0) { |
| | | throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_CUSTOM_FIELD_NOT_EXIST)); |
| | | } |
| | | |
| | | this.issueService.modifyIssue(issueApiForm, new ArrayList<>()); |
| | | |
| | | return this.setSuccessMessage(resJsonData); |
| | | } |
| | | } |
| | | |
| | |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | | import kr.wisestone.owl.vo.ApiTokenVo; |
| | | import kr.wisestone.owl.web.condition.ApiTokenCondition; |
| | | import kr.wisestone.owl.web.controller.BaseController; |
| | | import kr.wisestone.owl.web.form.ApiTokenForm; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.domain.Pageable; |
| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * API 토큰 컨트롤러 클래스 |
| | | */ |
| | | @Controller |
| | | public class ApiTokenController extends BaseController { |
| | | |
| | | @Autowired |
| | | private ApiTokenService apiTokenService; |
| | | |
| | | // 토큰 생성 |
| | | /** |
| | | * 토큰 생성 |
| | | * @param params 토큰 생성에 필요한 파라미터 |
| | | * @return 생성 결과 Map<String, Object> |
| | | */ |
| | | @RequestMapping(value = "/apiToken/add", produces = MediaType.APPLICATION_JSON_VALUE) |
| | | public |
| | | @ResponseBody |
| | |
| | | return this.setSuccessMessage(resJsonData); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 토큰 조회 |
| | | * @param params 토큰 조회에 필요한 파라미터 |
| | | * @return 조회 결과, Map<String, ApiTokenVo> |
| | | */ |
| | | // 토큰 조회 |
| | | @RequestMapping(value = "/apiToken/find", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) |
| | | public |
| | |
| | | return this.setSuccessMessage(resJsonData); |
| | | } |
| | | |
| | | /** |
| | | * 토큰 삭제 |
| | | * @param params 토큰 삭제에 필요한 파라미터 |
| | | * @return 삭제 결과, Map<String, Object> |
| | | */ |
| | | // 토큰 삭제 |
| | | @RequestMapping(value = "/apiToken/remove", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) |
| | | public |
| | |
| | | import kr.wisestone.owl.web.condition.ApiMonitorCondition; |
| | | import kr.wisestone.owl.web.condition.DepartmentCondition; |
| | | import kr.wisestone.owl.web.condition.IssueCondition; |
| | | import kr.wisestone.owl.web.form.EmailCommonForm; |
| | | import kr.wisestone.owl.web.form.EmailTemplateForm; |
| | | import kr.wisestone.owl.web.form.IssueForm; |
| | | import org.slf4j.Logger; |
| | |
| | | } |
| | | |
| | | |
| | | // 일반 메일 발송 (사용자 직접 작성) |
| | | @RequestMapping(value = "/issue/sendCommonEmail", produces = MediaType.APPLICATION_JSON_VALUE) |
| | | public |
| | | @ResponseBody |
| | | Map<String, Object> sendCommonEmail(@RequestBody Map<String, Map<String, Object>> params) { |
| | | Map<String, Object> resJsonData = new HashMap<>(); |
| | | this.issueService.sendCommonEmail(EmailCommonForm.make(params.get(Constants.REQ_KEY_CONTENT))); |
| | | return this.setSuccessMessage(resJsonData); |
| | | } |
| | | |
| | | |
| | | // api 기록 조회 |
| | | @RequestMapping(value = "/api/findHistory", produces = MediaType.APPLICATION_JSON_VALUE) |
| | | public |
New file |
| | |
| | | package kr.wisestone.owl.web.form; |
| | | |
| | | import io.swagger.annotations.ApiParam; |
| | | |
| | | |
| | | /** |
| | | * API 이슈 추가용 Form class |
| | | */ |
| | | public class ApiIssueAddForm { |
| | | @ApiParam(value = "사용자 토큰", required = true) |
| | | private String token; |
| | | @ApiParam(value = "이슈 제목") |
| | | private String title; |
| | | @ApiParam(value = "이슈 타입 ID", required = true) |
| | | private Long issueTypeId; |
| | | @ApiParam(value = "사용자 정의 필드", required = true) |
| | | private String customFields; |
| | | |
| | | public ApiIssueAddForm() { |
| | | } |
| | | |
| | | public String getCustomFields() { |
| | | return customFields; |
| | | } |
| | | |
| | | public void setCustomFields(String customFields) { |
| | | this.customFields = customFields; |
| | | } |
| | | |
| | | public String getToken() { |
| | | return token; |
| | | } |
| | | |
| | | public void setToken(String token) { |
| | | this.token = token; |
| | | } |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public void setTitle(String title) { |
| | | this.title = title; |
| | | } |
| | | |
| | | public Long getIssueTypeId() { |
| | | return issueTypeId; |
| | | } |
| | | |
| | | public void setIssueTypeId(Long issueTypeId) { |
| | | this.issueTypeId = issueTypeId; |
| | | } |
| | | } |
New file |
| | |
| | | package kr.wisestone.owl.web.form; |
| | | |
| | | import io.swagger.annotations.ApiParam; |
| | | |
| | | |
| | | /** |
| | | * API 이슈 상태 수정용 Form class |
| | | */ |
| | | public class ApiIssueModifyForm { |
| | | @ApiParam(value = "사용자 토큰", required = true) |
| | | private String token; |
| | | @ApiParam(value = "이슈 타입 ID", required = true) |
| | | private Long issueTypeId; |
| | | @ApiParam(value = "이슈 상태 ID", required = true) |
| | | private Long issueStatusId; |
| | | @ApiParam(value = "댓글", required = true) |
| | | private String comment; |
| | | @ApiParam(value = "사용자 정의 필드", required = true) |
| | | private String customFields; |
| | | |
| | | public ApiIssueModifyForm() { |
| | | } |
| | | |
| | | public Long getIssueTypeId() { |
| | | return issueTypeId; |
| | | } |
| | | |
| | | public void setIssueTypeId(Long issueTypeId) { |
| | | this.issueTypeId = issueTypeId; |
| | | } |
| | | |
| | | public Long getIssueStatusId() { |
| | | return issueStatusId; |
| | | } |
| | | |
| | | public void setIssueStatusId(Long issueStatusId) { |
| | | this.issueStatusId = issueStatusId; |
| | | } |
| | | |
| | | public String getToken() { |
| | | return token; |
| | | } |
| | | |
| | | public void setToken(String token) { |
| | | this.token = token; |
| | | } |
| | | |
| | | public String getComment() { |
| | | return comment; |
| | | } |
| | | |
| | | public void setComment(String comment) { |
| | | this.comment = comment; |
| | | } |
| | | |
| | | public String getCustomFields() { |
| | | return customFields; |
| | | } |
| | | |
| | | public void setCustomFields(String customFields) { |
| | | this.customFields = customFields; |
| | | } |
| | | } |
| | |
| | | package kr.wisestone.owl.web.form; |
| | | |
| | | import com.google.common.collect.Lists; |
| | | import kr.wisestone.owl.domain.User; |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | | import kr.wisestone.owl.util.MapUtil; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * API 토큰 Form class |
| | | */ |
| | | public class ApiTokenForm { |
| | | private Long id; |
| | | private User user; |
New file |
| | |
| | | package kr.wisestone.owl.web.form; |
| | | |
| | | import com.google.common.collect.Lists; |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | | import kr.wisestone.owl.util.MapUtil; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | public class EmailCommonForm { |
| | | private List<String> sendEmails = Lists.newArrayList(); |
| | | private String title; |
| | | private String description; |
| | | private Long issueId; |
| | | |
| | | public static EmailCommonForm make(Map<String, Object> params) { |
| | | EmailCommonForm emailCommonForm = ConvertUtil.convertMapToClass(params, EmailCommonForm.class); |
| | | if (MapUtil.getStrings(params, "sendEmails") != null) { |
| | | emailCommonForm.setSendEmails(MapUtil.getStrings(params, "sendEmails")); |
| | | } |
| | | return emailCommonForm; |
| | | } |
| | | |
| | | public List<String> getSendEmails() { |
| | | return sendEmails; |
| | | } |
| | | |
| | | public void setSendEmails(List<String> sendEmails) { |
| | | this.sendEmails = sendEmails; |
| | | } |
| | | |
| | | public String getTitle() { |
| | | return title; |
| | | } |
| | | |
| | | public void setTitle(String title) { |
| | | this.title = title; |
| | | } |
| | | |
| | | public String getDescription() { |
| | | return description; |
| | | } |
| | | |
| | | public void setDescription(String description) { |
| | | this.description = description; |
| | | } |
| | | |
| | | public Long getIssueId() { |
| | | return issueId; |
| | | } |
| | | |
| | | public void setIssueId(Long issueId) { |
| | | this.issueId = issueId; |
| | | } |
| | | } |
| | |
| | | import kr.wisestone.owl.util.ConvertUtil; |
| | | import kr.wisestone.owl.util.MapUtil; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.io.Serializable; |
| | | import java.util.*; |
| | | |
| | | public class IssueApiForm { |
| | | /** |
| | | * API 이슈 추가 / 수정용 form class |
| | | */ |
| | | public class IssueApiForm implements Serializable { |
| | | |
| | | public enum ApiType { |
| | | add, |
| | |
| | | public IssueApiForm() { |
| | | } |
| | | |
| | | public static IssueApiForm make(Map<String, Object> content, List<MultipartFile> files) { |
| | | IssueApiForm form = ConvertUtil.convertMapToClass(content, IssueApiForm.class); |
| | | form.setMultipartFiles(files); |
| | | |
| | | // api 타입 |
| | | if (MapUtil.getString(content, "apiType") != null) { |
| | | try { |
| | | form.setApiType(ApiType.valueOf(MapUtil.getString(content, "apiType"))); |
| | | } catch (Exception ex) { |
| | | return null; |
| | | } |
| | | } |
| | | /** |
| | | * 사용자 정의 필드 변환 |
| | | * @param customFieldJson 사용자 정의 필드 json |
| | | */ |
| | | public void parseCustomFields(String customFieldJson) { |
| | | |
| | | // 사용자 필드 정보 |
| | | if (MapUtil.getObject(content, "customFields") != null){ |
| | | List<Map<String, Object>> customFields = (List)MapUtil.getObject(content, "customFields"); |
| | | Map<String, Object> json = ConvertUtil.convertJsonToMap(customFieldJson); |
| | | List<Map<String, Object>> customFields = (List) MapUtil.getObject(json, "customFields"); |
| | | for (Map<String, Object> customField : customFields) { |
| | | IssueCustomFieldValueForm issueCustomFieldValueForm = ConvertUtil.convertMapToClass(customField, IssueCustomFieldValueForm.class); |
| | | form.addIssueCustomFieldValue(issueCustomFieldValueForm); |
| | | this.addIssueCustomFieldValue(issueCustomFieldValueForm); |
| | | |
| | | Map<String, Object> customFieldVo = new HashMap<>(); |
| | | customFieldVo.put("id", issueCustomFieldValueForm.getCustomFieldId()); |
| | |
| | | useValues.add(issueCustomFieldValueForm.getUseValue()); |
| | | customField.put("useValues", useValues); |
| | | |
| | | form.addCustomFieldValue(customField); |
| | | this.addCustomFieldValue(customField); |
| | | } |
| | | } |
| | | |
| | | // 첨부 파일 |
| | | // if (MapUtil.getObject(content, "files") != null){ |
| | | // form.setFiles((List)MapUtil.getObject(content, "files")); |
| | | // } |
| | | return form; |
| | | } |
| | | |
| | | public String getToken() { |
New file |
| | |
| | | /** |
| | | * OWL-ITS |
| | | */ |
| | | package kr.wisestone.owl; |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <Configuration status="warn" name="owl-its" monitorInterval="600"> |
| | | <Configuration status="ERROR" name="owl-its" monitorInterval="600"> |
| | | <Properties> |
| | | <Property name="LOG_FORMAT">%d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n</Property> |
| | | <Property name="BASE_DIR">/owl-enterprise-logs</Property> |
| | |
| | | <AppenderRef ref="File"/> |
| | | </Logger> |
| | | |
| | | <!-- Crawling Logger --> |
| | | <Logger name="kr.wisestone.owl.crawling" level="debug" additivity="false"> |
| | | <AppenderRef ref="Console"/> |
| | | <AppenderRef ref="File"/> |
| | | </Logger> |
| | | |
| | | <!-- Root Loggers --> |
| | | <Root level="warn"> |
| | | <AppenderRef ref="Console"/> |
| | |
| | | </when> |
| | | </choose> |
| | | ) customFieldValue ON customFieldValue.issueId = issue.id |
| | | WHERE issStatus.issue_status_type != 'CLOSE' |
| | | AND issue.issue_type_id = #{issueTypeId} |
| | | WHERE issue.issue_type_id = #{issueTypeId} |
| | | <choose> |
| | | <when test="issueStatusType != null"> |
| | | AND issStatus.issue_status_type != #{issueStatusType} |
| | | </when> |
| | | </choose> |
| | | GROUP BY issue.id |
| | | HAVING concatUseValue LIKE CONCAT('%', #{useValue}, '%') |
| | | </select> |
| | |
| | | font-size: 0.79rem; |
| | | } |
| | | |
| | | .select3-selection__email__remove { |
| | | color: #0066ff; |
| | | margin-left: 8px; |
| | | margin-top: 7px; |
| | | cursor: pointer; |
| | | font-size: 0.79rem; |
| | | } |
| | | |
| | | .select4-selection__choice { |
| | | font-size: 0.66rem; |
| | | letter-spacing: -0.01em; |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | define(['app', 'angular'], |
| | | function (app, angular) { |
| | | app.provider("$downProvider", function () { |
| | | return { |
| | | $get : function ($log) { |
| | | return { |
| | | config : function () { |
| | | var tableConfig = { |
| | | hName : "", // 헤더 이름 |
| | | hWidth : "", // 칼럼 길이 |
| | | hChecked : false, // 체크 박스 선택 여부 |
| | | hAlign : "text-center", // 헤더 정렬 기준 |
| | | hSort : true, // 정렬 가능 여부 |
| | | dName : "", // 데이터 이름 |
| | | dAlign : "text-left", // 데이터 정렬 기준 |
| | | dRenderer : "", // 렌더러 여부 |
| | | dVisible : "", // bootstrap 반응형 컬럼 표시 여부 |
| | | dType : "none", // 태그 타입 |
| | | dDateFormat : "", // 날짜 형식 |
| | | rowSpan : 0, // rowspan 을 지원한다. |
| | | colSpan : 0, // colspan 을 지원한다. |
| | | subHead : false, // 만약 rowspan, colspan 을 사용하게 되면 true 로 셋팅. |
| | | columnHint : "", // 컬럼 정보를 추출하기 위한 힌트 정보를 준다 - downColumnGenerator 의 사용자 정의 필드 부분에서 사용 |
| | | columnTooltip : "", // hover 시 툴팁 보여주기 |
| | | setHName : function (hName) { |
| | | this.hName = hName; |
| | | return this; |
| | | }, |
| | | setHWidth : function (hWidth) { |
| | | this.hWidth = hWidth; |
| | | return this; |
| | | }, |
| | | setHChecked : function (hChecked) { |
| | | this.hChecked = hChecked; |
| | | return this; |
| | | }, |
| | | setHAlign : function (hAlign) { |
| | | this.hAlign = hAlign; |
| | | return this; |
| | | }, |
| | | setHSort : function (hSort) { |
| | | this.hSort = hSort; |
| | | return this; |
| | | }, |
| | | setDName : function (dName) { |
| | | this.dName = dName; |
| | | return this; |
| | | }, |
| | | setDAlign : function (dAlign) { |
| | | this.dAlign = dAlign; |
| | | return this; |
| | | }, |
| | | setDRenderer : function (dRenderer) { |
| | | this.dRenderer = dRenderer; |
| | | return this; |
| | | }, |
| | | setDVisible : function (dVisible) { |
| | | this.dVisible = dVisible; |
| | | return this; |
| | | }, |
| | | setDType : function (dType) { |
| | | this.dType = dType; |
| | | return this; |
| | | }, |
| | | setDDateFormat : function (dDateFormat) { |
| | | this.dDateFormat = dDateFormat; |
| | | return this; |
| | | }, |
| | | setRowSpan : function (dRowSpan) { |
| | | this.rowSpan = dRowSpan; |
| | | return this; |
| | | }, |
| | | setColSpan : function (dColSpan) { |
| | | this.colSpan = dColSpan; |
| | | return this; |
| | | }, |
| | | setSubHead : function (dSubHead) { |
| | | this.subHead = dSubHead; |
| | | return this; |
| | | }, |
| | | setColumnHint : function (dColumnHint) { |
| | | this.columnHint = dColumnHint; |
| | | return this; |
| | | }, |
| | | setColumnTooltip : function (hTooltip) { |
| | | this.columnTooltip = hTooltip; |
| | | return this; |
| | | } |
| | | }; |
| | | |
| | | return tableConfig; |
| | | }, |
| | | toggleChecked : function (checkStatus, datas) { |
| | | // 전체 선택 체크 박스를 클릭했을 경우 |
| | | angular.forEach(datas, function (data) { |
| | | data.checked = checkStatus; |
| | | }); |
| | | }, |
| | | radioChecked : function (target, datas) { |
| | | // 해당 row 가 라디오 버튼일 경우 |
| | | angular.forEach(datas, function (data) { |
| | | if (target.id == data.id) { |
| | | data.checked = true; |
| | | } |
| | | else { |
| | | data.checked = false; |
| | | } |
| | | }); |
| | | }, |
| | | rowChecked : function (tableConfig, target, datas) { |
| | | // 각 row 의 체크박스/라디오 버튼을 클릭했을 경우 |
| | | if (tableConfig[0].dType == "checkbox") { |
| | | target.checked = !target.checked; |
| | | |
| | | for (var data in datas) { |
| | | if (!data.checked) { |
| | | this.hChecked = false; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else if (tableConfig[0].dType == "radio") { |
| | | this.radioChecked(target, datas); |
| | | } |
| | | }, |
| | | orderByColumn : "", // table order By column name |
| | | reverse : true, |
| | | setOrderByColumn : function (column) { |
| | | if (column == "") { |
| | | return; |
| | | } |
| | | |
| | | if (this.orderByColumn == column) { |
| | | this.reverse = !this.reverse; |
| | | } |
| | | else { |
| | | this.reverse = true; |
| | | } |
| | | |
| | | this.orderByColumn = column; |
| | | return this; |
| | | }, |
| | | getDateFormat : function (formatType, date) { |
| | | if (formatType == "" || formatType == null) { |
| | | formatType = "01"; |
| | | } |
| | | Date.prototype.format = function (f) { |
| | | if (!this.valueOf()) { |
| | | return " "; |
| | | } |
| | | var weekName = ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"]; |
| | | var d = this; |
| | | |
| | | return f.replace(/(yyyy|yy|MM|dd|E|hh|mm|ss|a\/p)/gi, function ($1) { |
| | | switch ($1) { |
| | | case "yyyy": |
| | | return d.getFullYear(); |
| | | case "yy": |
| | | return (d.getFullYear() % 1000).zf(2); |
| | | case "MM": |
| | | return (d.getMonth() + 1).zf(2); |
| | | case "dd": |
| | | return d.getDate().zf(2); |
| | | case "E": |
| | | return weekName[d.getDay()]; |
| | | case "HH": |
| | | return d.getHours().zf(2); |
| | | case "hh": |
| | | var h = d.getHours(); |
| | | return ((h = d.getHours() % 12) ? h : 12).zf(2); |
| | | case "mm": |
| | | return d.getMinutes().zf(2); |
| | | case "ss": |
| | | return d.getSeconds().zf(2); |
| | | case "a/p": |
| | | return d.getHours() < 12 ? "오전" : "오후"; |
| | | default: |
| | | return $1; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | String.prototype.string = function (len) { |
| | | var s = '', i = 0; |
| | | while (i++ < len) { |
| | | s += this; |
| | | } |
| | | return s; |
| | | }; |
| | | String.prototype.zf = function (len) { |
| | | return "0".string(len - this.length) + this; |
| | | }; |
| | | Number.prototype.zf = function (len) { |
| | | return this.toString().zf(len); |
| | | }; |
| | | |
| | | var dateFormat = ""; |
| | | var dynamicTime = false; |
| | | var today = new Date().format("yyyy-MM-dd"); |
| | | var compareDate = new Date(date).format("yyyy-MM-dd"); |
| | | |
| | | if (today == compareDate) { |
| | | dynamicTime = true; |
| | | } |
| | | |
| | | switch (formatType) { |
| | | case "01": // 날짜 |
| | | dateFormat = "yyyy-MM-dd"; |
| | | break; |
| | | case "02": // 날짜 + 시간 |
| | | dateFormat = "yyyy-MM-dd HH:mm"; |
| | | break; |
| | | case "03": // 유동적 표시 |
| | | if (dynamicTime) { |
| | | dateFormat = "HH:mm"; |
| | | } |
| | | else { |
| | | dateFormat = "yyyy-MM-dd HH:mm"; |
| | | } |
| | | |
| | | break; |
| | | } |
| | | |
| | | return dateFormat; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }); |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | define(['app', 'angular'], |
| | | function (app, angular) { |
| | | |
| | | app.directive('downColumnGenerator', ['$compile', '$log', '$rootScope', '$downProvider', '$filter', |
| | | function ($compile, $log, $rootScope, $downProvider, $filter) { |
| | | return { |
| | | restrict : "A", |
| | | compile : function (tElement, tAttrs) { |
| | | return function (scope, element, attrs) { |
| | | scope.data = scope[attrs["downColumnGenerator"]]; |
| | | |
| | | var myData = scope.data; |
| | | var makeTag = ""; |
| | | |
| | | scope.tableConfigs.forEach(function (tableConfig, index) { |
| | | |
| | | if (tableConfig.colSpan > 0) { |
| | | return; |
| | | } |
| | | |
| | | // 하위 단계 표시 추가 |
| | | var myToken = ""; |
| | | if ( scope.data.depth > 0) { |
| | | for(var i=0; i<scope.data.depth; i++) { |
| | | if (i == scope.data.depth - 1) { |
| | | myToken += treeStartToken; |
| | | } else { |
| | | myToken += " "; |
| | | } |
| | | } |
| | | myToken += " "; |
| | | } |
| | | |
| | | makeTag = '<td class="' + tableConfig.dAlign + ' ' + tableConfig.dVisible + '">'; |
| | | |
| | | if (tableConfig.dType === "checkbox") { |
| | | // 체크 박스일때 |
| | | /*if (scope.data.defaultYn) { |
| | | makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" disabled ng-click="$root.$downProvider.rowChecked(tableConfigs, data, fn.getResponseData())">'; |
| | | } |
| | | else {*/ |
| | | makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" ng-click="$root.$downProvider.rowChecked(tableConfigs, data, fn.getResponseData())">'; |
| | | //} |
| | | |
| | | tableConfig.hChecked = false; |
| | | } |
| | | else if (tableConfig.dType === "radio") { |
| | | // 라디오 버튼일때 |
| | | makeTag += '<input type="radio" ng-checked="data.checked == true ? true : false" ng-click="$root.$downProvider.rowChecked(tableConfigs, data, fn.getResponseData())">'; |
| | | } |
| | | else if (tableConfig.dType === "renderer") { |
| | | // 랜더러 일때 |
| | | switch (tableConfig.dRenderer) { |
| | | |
| | | // 하위 이슈 이동(제목) |
| | | case "ISSUE_DOWN_MOVE" : |
| | | makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data)\">" + scope.data.title + "</span></a>"; |
| | | break; |
| | | |
| | | // 하위 이슈 타입 |
| | | case "ISSUE_DOWN_STATUS_TYPE" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.issueStatusVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.issueStatusVo.color + "\", \"color\": \"#FFFFFF\" }'>" + scope.data.issueStatusVo.name + "</span>"; |
| | | break; |
| | | |
| | | // 하위 이슈 삭제 |
| | | case "ISSUE_DOWN_DELETE": |
| | | if (scope.data.modifyPermissionCheck) { |
| | | makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeDownIssue(data.id)">'; |
| | | } |
| | | break; |
| | | |
| | | // 하위 이슈 우선 순위 |
| | | case "DOWN_COMMON_PRIORITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>"; |
| | | break; |
| | | |
| | | // 하위 이슈 중요도 |
| | | case "DOWN_COMMON_SEVERITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>"; |
| | | break; |
| | | |
| | | // 하위 이슈 담당부서 |
| | | case "DOWN_ISSUE_DEPARTMENT" : |
| | | makeTag += "<ul class='ul-not-comma'>"; |
| | | makeTag += "<div style='color: #000000'>"; |
| | | angular.forEach(scope.data.departmentVos, function (departments) { |
| | | makeTag += "<li>" + departments.departmentName + "</li>"; |
| | | }); |
| | | makeTag += "</div>"; |
| | | makeTag += "</ul>"; |
| | | break; |
| | | |
| | | // 하위 이슈 등록자 |
| | | case "DOWN_REGISTER": |
| | | scope.data.registerVos = [scope.data.registerVo]; |
| | | makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>'; |
| | | break; |
| | | |
| | | // 하위 이슈 기간 |
| | | case "DOWN_ISSUE_DUE_DATE" : |
| | | if (!$rootScope.isDefined(scope.data.startDate) && !$rootScope.isDefined(scope.data.completeDate)) { |
| | | makeTag += "<span translate='common.noDate'>기간 없음</span>"; |
| | | } |
| | | else { |
| | | makeTag += "<span>" + scope.data.startDate + " ~ " + scope.data.completeDate + "</span>"; |
| | | } |
| | | break; |
| | | |
| | | // 하위 이슈 사용자 정의 필드 |
| | | case "DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW" : |
| | | var values = []; |
| | | |
| | | for (var count in scope.data.issueCustomFieldValueVos) { |
| | | var issueCustomFieldValueVo = scope.data.issueCustomFieldValueVos[count]; |
| | | // 테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다. |
| | | if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) { |
| | | values.push(issueCustomFieldValueVo.useValue); |
| | | } |
| | | } |
| | | angular.forEach(values, function (value) { |
| | | makeTag += '<span class="table-word-break-all">' + value + '<span><br>'; |
| | | }); |
| | | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | makeTag += '</td>'; |
| | | |
| | | var linkFn = $compile(makeTag); |
| | | var content = linkFn(scope); |
| | | |
| | | element.append(content); |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | }]); |
| | | }); |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | define(['app'], |
| | | function (app) { |
| | | app.directive('jsDown', ['$log', |
| | | function ($log) { |
| | | return { |
| | | restrict : 'E', |
| | | scope : { |
| | | event : '=', |
| | | data : '=', |
| | | tableConfigs : '=', |
| | | hideHeader : '=', // 헤더 부분 숨김 여부 |
| | | useSort : '=', // 정령 기능 사용 여부 |
| | | detailView : "=" // 이슈 목록 상세형 변경을 위해 사용. 다른 화면은 사용하지 않음. |
| | | }, |
| | | replace : true, |
| | | templateUrl : '/custom_components/js-down/js-down.html', |
| | | controller : function ($scope, $element, $attrs) { |
| | | $scope.fn = { |
| | | getResponseData : getResponseData |
| | | }; |
| | | |
| | | // 테이블 정보 가져오기 |
| | | function getResponseData() { |
| | | return $scope.data; |
| | | } |
| | | }, |
| | | link : function (scope, element, attrs) { |
| | | |
| | | } |
| | | }; |
| | | }]) |
| | | }); |
| | | |
| | | |
New file |
| | |
| | | <table class="table table-striped table-layout-fixed" ng-class="{ 'width768' : !detailView }" bindonce> |
| | | <!-- 테이블 머리 --> |
| | | <thead> |
| | | <tr ng-if="hideHeader != true"> |
| | | <th bindonce ng-repeat="tableConfig in tableConfigs" |
| | | bo-class="[tableConfig.hAlign, tableConfig.hWidth, tableConfig.dVisible]" |
| | | ng-click="$root.$downProvider.setOrderByColumn(tableConfig.dName)" |
| | | bo-style="{ 'cursor' : tableConfig.dName != '' ? 'pointer' : '' }" |
| | | rowspan="{{tableConfig.rowSpan}}" |
| | | colspan="{{tableConfig.colSpan}}" |
| | | ng-if="!tableConfig.subHead"> |
| | | <!-- 체크 박스일 경우 --> |
| | | <div bo-switch="tableConfig.dType"> |
| | | <div bo-switch-when="checkbox"> |
| | | <input type="checkbox" tabindex="-1" ng-model="tableConfig.hChecked" ng-click="$root.$downProvider.toggleChecked(tableConfig.hChecked, fn.getResponseData())"> |
| | | </div> |
| | | <div bo-switch-default> |
| | | <span ng-if="tableConfig.columnTooltip != ''" function-tool-tip data-placement="top" data-toggle="tooltip" data-original-title="{{tableConfig.columnTooltip}}" |
| | | translate="{{tableConfig.hName}}"></span> |
| | | <span ng-if="tableConfig.columnTooltip == ''" translate="{{tableConfig.hName}}"></span> |
| | | <span ng-if="($root.$downProvider.orderByColumn == tableConfig.dName) && (tableConfig.dName != '')"><i class="fa fa-arrow-circle-down" ng-show="!$root.$downProvider.reverse"></i> |
| | | <i class="fa fa-arrow-circle-up" ng-show="$root.$downProvider.reverse"></i> |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </th> |
| | | </tr> |
| | | </thead> |
| | | |
| | | <tbody> |
| | | <tr ng-if="useSort != false" ng-repeat="row in fn.getResponseData() | orderBy:$root.$downProvider.orderByColumn:$root.$downProvider.reverse" |
| | | bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]" |
| | | down-column-generator="row"> |
| | | </tr> |
| | | |
| | | <tr ng-if="useSort == false" ng-repeat="row in fn.getResponseData()" |
| | | bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]" |
| | | down-column-generator="row"> |
| | | </tr> |
| | | |
| | | <tr ng-if="fn.getResponseData().length == 0"> |
| | | <td colspan="{{tableConfigs.length}}"> |
| | | <span translate="common.noData">데이터가 없습니다.</span> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | define(['app'], |
| | | function (app) { |
| | | app.directive('jsRel', ['$log', |
| | | function ($log) { |
| | | return { |
| | | restrict : 'E', |
| | | scope : { |
| | | event : '=', |
| | | data : '=', |
| | | tableConfigs : '=', |
| | | hideHeader : '=', // 헤더 부분 숨김 여부 |
| | | useSort : '=', // 정령 기능 사용 여부 |
| | | detailView : "=" // 이슈 목록 상세형 변경을 위해 사용. 다른 화면은 사용하지 않음. |
| | | }, |
| | | replace : true, |
| | | templateUrl : '/custom_components/js-rel/js-rel.html', |
| | | controller : function ($scope, $element, $attrs) { |
| | | $scope.fn = { |
| | | getResponseData : getResponseData |
| | | }; |
| | | |
| | | // 테이블 정보 가져오기 |
| | | function getResponseData() { |
| | | return $scope.data; |
| | | } |
| | | }, |
| | | link : function (scope, element, attrs) { |
| | | |
| | | } |
| | | }; |
| | | }]) |
| | | }); |
| | | |
| | | |
New file |
| | |
| | | <table class="table table-striped table-layout-fixed" ng-class="{ 'width768' : !detailView }" bindonce> |
| | | <!-- 테이블 머리 --> |
| | | <thead> |
| | | <tr ng-if="hideHeader != true"> |
| | | <th bindonce ng-repeat="tableConfig in tableConfigs" |
| | | bo-class="[tableConfig.hAlign, tableConfig.hWidth, tableConfig.dVisible]" |
| | | ng-click="$root.$relProvider.setOrderByColumn(tableConfig.dName)" |
| | | bo-style="{ 'cursor' : tableConfig.dName != '' ? 'pointer' : '' }" |
| | | rowspan="{{tableConfig.rowSpan}}" |
| | | colspan="{{tableConfig.colSpan}}" |
| | | ng-if="!tableConfig.subHead"> |
| | | <!-- 체크 박스일 경우 --> |
| | | <div bo-switch="tableConfig.dType"> |
| | | <div bo-switch-when="checkbox"> |
| | | <input type="checkbox" tabindex="-1" ng-model="tableConfig.hChecked" ng-click="$root.$relProvider.toggleChecked(tableConfig.hChecked, fn.getResponseData())"> |
| | | </div> |
| | | <div bo-switch-default> |
| | | <span ng-if="tableConfig.columnTooltip != ''" function-tool-tip data-placement="top" data-toggle="tooltip" data-original-title="{{tableConfig.columnTooltip}}" |
| | | translate="{{tableConfig.hName}}"></span> |
| | | <span ng-if="tableConfig.columnTooltip == ''" translate="{{tableConfig.hName}}"></span> |
| | | <span ng-if="($root.$relProvider.orderByColumn == tableConfig.dName) && (tableConfig.dName != '')"><i class="fa fa-arrow-circle-down" ng-show="!$root.$relProvider.reverse"></i> |
| | | <i class="fa fa-arrow-circle-up" ng-show="$root.$relProvider.reverse"></i> |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </th> |
| | | </tr> |
| | | </thead> |
| | | |
| | | <tbody> |
| | | <tr ng-if="useSort != false" ng-repeat="row in fn.getResponseData() | orderBy:$root.$relProvider.orderByColumn:$root.$relProvider.reverse" |
| | | bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]" |
| | | rel-column-generator="row"> |
| | | </tr> |
| | | |
| | | <tr ng-if="useSort == false" ng-repeat="row in fn.getResponseData()" |
| | | bo-class="[row.checked == true ? 'table-active' : '', tableConfig.hWidth]" |
| | | rel-column-generator="row"> |
| | | </tr> |
| | | |
| | | <tr ng-if="fn.getResponseData().length == 0"> |
| | | <td colspan="{{tableConfigs.length}}"> |
| | | <span translate="common.noData">데이터가 없습니다.</span> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | define(['app', 'angular'], |
| | | function (app, angular) { |
| | | app.provider("$relProvider", function () { |
| | | return { |
| | | $get : function ($log) { |
| | | return { |
| | | config : function () { |
| | | var tableConfig = { |
| | | hName : "", // 헤더 이름 |
| | | hWidth : "", // 칼럼 길이 |
| | | hChecked : false, // 체크 박스 선택 여부 |
| | | hAlign : "text-center", // 헤더 정렬 기준 |
| | | hSort : true, // 정렬 가능 여부 |
| | | dName : "", // 데이터 이름 |
| | | dAlign : "text-left", // 데이터 정렬 기준 |
| | | dRenderer : "", // 렌더러 여부 |
| | | dVisible : "", // bootstrap 반응형 컬럼 표시 여부 |
| | | dType : "none", // 태그 타입 |
| | | dDateFormat : "", // 날짜 형식 |
| | | rowSpan : 0, // rowspan 을 지원한다. |
| | | colSpan : 0, // colspan 을 지원한다. |
| | | subHead : false, // 만약 rowspan, colspan 을 사용하게 되면 true 로 셋팅. |
| | | columnHint : "", // 컬럼 정보를 추출하기 위한 힌트 정보를 준다 - relColumnGenerator 의 사용자 정의 필드 부분에서 사용 |
| | | columnTooltip : "", // hover 시 툴팁 보여주기 |
| | | setHName : function (hName) { |
| | | this.hName = hName; |
| | | return this; |
| | | }, |
| | | setHWidth : function (hWidth) { |
| | | this.hWidth = hWidth; |
| | | return this; |
| | | }, |
| | | setHChecked : function (hChecked) { |
| | | this.hChecked = hChecked; |
| | | return this; |
| | | }, |
| | | setHAlign : function (hAlign) { |
| | | this.hAlign = hAlign; |
| | | return this; |
| | | }, |
| | | setHSort : function (hSort) { |
| | | this.hSort = hSort; |
| | | return this; |
| | | }, |
| | | setDName : function (dName) { |
| | | this.dName = dName; |
| | | return this; |
| | | }, |
| | | setDAlign : function (dAlign) { |
| | | this.dAlign = dAlign; |
| | | return this; |
| | | }, |
| | | setDRenderer : function (dRenderer) { |
| | | this.dRenderer = dRenderer; |
| | | return this; |
| | | }, |
| | | setDVisible : function (dVisible) { |
| | | this.dVisible = dVisible; |
| | | return this; |
| | | }, |
| | | setDType : function (dType) { |
| | | this.dType = dType; |
| | | return this; |
| | | }, |
| | | setDDateFormat : function (dDateFormat) { |
| | | this.dDateFormat = dDateFormat; |
| | | return this; |
| | | }, |
| | | setRowSpan : function (dRowSpan) { |
| | | this.rowSpan = dRowSpan; |
| | | return this; |
| | | }, |
| | | setColSpan : function (dColSpan) { |
| | | this.colSpan = dColSpan; |
| | | return this; |
| | | }, |
| | | setSubHead : function (dSubHead) { |
| | | this.subHead = dSubHead; |
| | | return this; |
| | | }, |
| | | setColumnHint : function (dColumnHint) { |
| | | this.columnHint = dColumnHint; |
| | | return this; |
| | | }, |
| | | setColumnTooltip : function (hTooltip) { |
| | | this.columnTooltip = hTooltip; |
| | | return this; |
| | | } |
| | | }; |
| | | |
| | | return tableConfig; |
| | | }, |
| | | toggleChecked : function (checkStatus, datas) { |
| | | // 전체 선택 체크 박스를 클릭했을 경우 |
| | | angular.forEach(datas, function (data) { |
| | | /*if (angular.isDefined(data.defaultYn)) { |
| | | if (!data.defaultYn) { |
| | | data.checked = checkStatus; |
| | | } |
| | | } |
| | | else {*/ |
| | | data.checked = checkStatus; |
| | | //} |
| | | }); |
| | | }, |
| | | radioChecked : function (target, datas) { |
| | | // 해당 row 가 라디오 버튼일 경우 |
| | | angular.forEach(datas, function (data) { |
| | | if (target.id == data.id) { |
| | | data.checked = true; |
| | | } |
| | | else { |
| | | data.checked = false; |
| | | } |
| | | }); |
| | | }, |
| | | rowChecked : function (tableConfig, target, datas) { |
| | | // 각 row 의 체크박스/라디오 버튼을 클릭했을 경우 |
| | | if (tableConfig[0].dType == "checkbox") { |
| | | target.checked = !target.checked; |
| | | |
| | | for (var data in datas) { |
| | | if (!data.checked) { |
| | | this.hChecked = false; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else if (tableConfig[0].dType == "radio") { |
| | | this.radioChecked(target, datas); |
| | | } |
| | | }, |
| | | orderByColumn : "", // table order By column name |
| | | reverse : true, |
| | | setOrderByColumn : function (column) { |
| | | if (column == "") { |
| | | return; |
| | | } |
| | | |
| | | if (this.orderByColumn == column) { |
| | | this.reverse = !this.reverse; |
| | | } |
| | | else { |
| | | this.reverse = true; |
| | | } |
| | | |
| | | this.orderByColumn = column; |
| | | return this; |
| | | }, |
| | | getDateFormat : function (formatType, date) { |
| | | if (formatType == "" || formatType == null) { |
| | | formatType = "01"; |
| | | } |
| | | Date.prototype.format = function (f) { |
| | | if (!this.valueOf()) { |
| | | return " "; |
| | | } |
| | | var weekName = ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"]; |
| | | var d = this; |
| | | |
| | | return f.replace(/(yyyy|yy|MM|dd|E|hh|mm|ss|a\/p)/gi, function ($1) { |
| | | switch ($1) { |
| | | case "yyyy": |
| | | return d.getFullYear(); |
| | | case "yy": |
| | | return (d.getFullYear() % 1000).zf(2); |
| | | case "MM": |
| | | return (d.getMonth() + 1).zf(2); |
| | | case "dd": |
| | | return d.getDate().zf(2); |
| | | case "E": |
| | | return weekName[d.getDay()]; |
| | | case "HH": |
| | | return d.getHours().zf(2); |
| | | case "hh": |
| | | var h = d.getHours(); |
| | | return ((h = d.getHours() % 12) ? h : 12).zf(2); |
| | | case "mm": |
| | | return d.getMinutes().zf(2); |
| | | case "ss": |
| | | return d.getSeconds().zf(2); |
| | | case "a/p": |
| | | return d.getHours() < 12 ? "오전" : "오후"; |
| | | default: |
| | | return $1; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | String.prototype.string = function (len) { |
| | | var s = '', i = 0; |
| | | while (i++ < len) { |
| | | s += this; |
| | | } |
| | | return s; |
| | | }; |
| | | String.prototype.zf = function (len) { |
| | | return "0".string(len - this.length) + this; |
| | | }; |
| | | Number.prototype.zf = function (len) { |
| | | return this.toString().zf(len); |
| | | }; |
| | | |
| | | var dateFormat = ""; |
| | | var dynamicTime = false; |
| | | var today = new Date().format("yyyy-MM-dd"); |
| | | var compareDate = new Date(date).format("yyyy-MM-dd"); |
| | | |
| | | if (today == compareDate) { |
| | | dynamicTime = true; |
| | | } |
| | | |
| | | switch (formatType) { |
| | | case "01": // 날짜 |
| | | dateFormat = "yyyy-MM-dd"; |
| | | break; |
| | | case "02": // 날짜 + 시간 |
| | | dateFormat = "yyyy-MM-dd HH:mm"; |
| | | break; |
| | | case "03": // 유동적 표시 |
| | | if (dynamicTime) { |
| | | dateFormat = "HH:mm"; |
| | | } |
| | | else { |
| | | dateFormat = "yyyy-MM-dd HH:mm"; |
| | | } |
| | | |
| | | break; |
| | | } |
| | | |
| | | return dateFormat; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }); |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | define(['app', 'angular'], |
| | | function (app, angular) { |
| | | |
| | | app.directive('relColumnGenerator', ['$compile', '$log', '$rootScope', '$relProvider', '$filter', |
| | | function ($compile, $log, $rootScope, $relProvider, $filter) { |
| | | return { |
| | | restrict : "A", |
| | | compile : function (tElement, tAttrs) { |
| | | return function (scope, element, attrs) { |
| | | scope.data = scope[attrs["relColumnGenerator"]]; |
| | | |
| | | var myData = scope.data; |
| | | var makeTag = ""; |
| | | |
| | | scope.tableConfigs.forEach(function (tableConfig, index) { |
| | | |
| | | if (tableConfig.colSpan > 0) { |
| | | return; |
| | | } |
| | | |
| | | // 하위 단계 표시 추가 |
| | | var myToken = ""; |
| | | if ( scope.data.depth > 0) { |
| | | for(var i=0; i<scope.data.depth; i++) { |
| | | if (i == scope.data.depth - 1) { |
| | | myToken += treeStartToken; |
| | | } else { |
| | | myToken += " "; |
| | | } |
| | | } |
| | | myToken += " "; |
| | | } |
| | | |
| | | makeTag = '<td class="' + tableConfig.dAlign + ' ' + tableConfig.dVisible + '">'; |
| | | |
| | | if (tableConfig.dType === "checkbox") { |
| | | // 체크 박스일때 |
| | | /*if (scope.data.defaultYn) { |
| | | makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" disabled ng-click="$root.$relProvider.rowChecked(tableConfigs, data, fn.getResponseData())">'; |
| | | } |
| | | else {*/ |
| | | makeTag += '<input type="checkbox" ng-checked="data.checked == true ? true : false" ng-click="$root.$relProvider.rowChecked(tableConfigs, data, fn.getResponseData())">'; |
| | | //} |
| | | |
| | | tableConfig.hChecked = false; |
| | | } |
| | | else if (tableConfig.dType === "radio") { |
| | | // 라디오 버튼일때 |
| | | makeTag += '<input type="radio" ng-checked="data.checked == true ? true : false" ng-click="$root.$relProvider.rowChecked(tableConfigs, data, fn.getResponseData())">'; |
| | | } |
| | | else if (tableConfig.dType === "renderer") { |
| | | // 랜더러 일때 |
| | | switch (tableConfig.dRenderer) { |
| | | |
| | | // 연관 이슈 이동(제목) |
| | | case "ISSUE_RELATION_MOVE" : |
| | | makeTag += "<span class=\"titlename cursor text-center\" ng-click=\"event.changeDetailView(data.issueRelation)\">" + scope.data.title + "</span></a>"; |
| | | break; |
| | | |
| | | // 연관이슈 구분 |
| | | case "ISSUE_RELATION_TYPE": |
| | | makeTag += "<span>" + scope.data.relationIssueTypeName + "</span>"; |
| | | break; |
| | | |
| | | // 연관이슈 삭제 |
| | | case "ISSUE_RELATION_DELETE": |
| | | if (scope.data.modifyPermissionCheck) { |
| | | makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeRelationIssue(data.id)">'; |
| | | } |
| | | break; |
| | | |
| | | // 연관 이슈 우선순위 |
| | | case "REL_COMMON_PRIORITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>"; |
| | | break; |
| | | |
| | | // 연관 이슈 중요도 |
| | | case "REL_COMMON_SEVERITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>"; |
| | | break; |
| | | |
| | | // 연관 이슈 등록자 |
| | | case "REL_REGISTER": |
| | | scope.data.registerVos = [scope.data.issueRelation.registerVo]; |
| | | makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>'; |
| | | break; |
| | | |
| | | break; |
| | | |
| | | // 연관 이슈 담당부서 |
| | | case "REL_ISSUE_DEPARTMENT" : |
| | | makeTag += "<ul class='ul-not-comma'>"; |
| | | makeTag += "<div style='color: #000000'>"; |
| | | angular.forEach(scope.data.issueRelation.departmentVos, function (departments) { |
| | | makeTag += "<li>" + departments.departmentName + "</li>"; |
| | | }); |
| | | makeTag += "</div>"; |
| | | makeTag += "</ul>"; |
| | | break; |
| | | |
| | | // 연관 이슈 목록에서 기간 표시 |
| | | case "REL_ISSUE_DUE_DATE" : |
| | | if (!$rootScope.isDefined(scope.data.issueRelation.startDate) && !$rootScope.isDefined(scope.data.issueRelation.completeDate)) { |
| | | makeTag += "<span translate='common.noDate'>기간 없음</span>"; |
| | | } else { |
| | | makeTag += "<span>" + scope.data.issueRelation.startDate + " ~ " + scope.data.issueRelation.completeDate + "</span>"; |
| | | } |
| | | break; |
| | | |
| | | // 연관 이슈 사용자 정의 필드 |
| | | case "REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW" : |
| | | var values = []; |
| | | |
| | | for (var count in scope.data.issueRelation.issueCustomFieldValueVos) { |
| | | var issueCustomFieldValueVo = scope.data.issueRelation.issueCustomFieldValueVos[count]; |
| | | // 테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다. |
| | | if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) { |
| | | values.push(issueCustomFieldValueVo.useValue); |
| | | } |
| | | } |
| | | angular.forEach(values, function (value) { |
| | | makeTag += '<span class="table-word-break-all cursor">' + value + '<span><br>'; |
| | | }); |
| | | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | makeTag += '</td>'; |
| | | |
| | | var linkFn = $compile(makeTag); |
| | | var content = linkFn(scope); |
| | | |
| | | element.append(content); |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | }]); |
| | | }); |
| | |
| | | break;*/ |
| | | |
| | | // 연관 이슈 이동(제목) |
| | | case "ISSUE_RELATION_MOVE" : |
| | | makeTag += "<span class=\"titlename cursor text-center\" ng-click=\"event.changeDetailView(data.issueRelation)\">" + scope.data.title + "</span></a>"; |
| | | break; |
| | | // case "ISSUE_RELATION_MOVE" : |
| | | // makeTag += "<span class=\"titlename cursor text-center\" ng-click=\"event.changeDetailView(data.issueRelation)\">" + scope.data.title + "</span></a>"; |
| | | // break; |
| | | |
| | | // 연관이슈 구분 |
| | | case "ISSUE_RELATION_TYPE": |
| | | makeTag += "<span>" + scope.data.relationIssueTypeName + "</span>"; |
| | | break; |
| | | // case "ISSUE_RELATION_TYPE": |
| | | // makeTag += "<span>" + scope.data.relationIssueTypeName + "</span>"; |
| | | // break; |
| | | |
| | | // 연관이슈 삭제 |
| | | case "ISSUE_RELATION_DELETE": |
| | | if (scope.data.modifyPermissionCheck) { |
| | | makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeRelationIssue(data.id)">'; |
| | | } |
| | | break; |
| | | // case "ISSUE_RELATION_DELETE": |
| | | // if (scope.data.modifyPermissionCheck) { |
| | | // makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeRelationIssue(data.id)">'; |
| | | // } |
| | | // break; |
| | | |
| | | // 연관 이슈 우선순위 |
| | | case "REL_COMMON_PRIORITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>"; |
| | | break; |
| | | // case "REL_COMMON_PRIORITY" : |
| | | // makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>"; |
| | | // break; |
| | | |
| | | // 연관 이슈 중요도 |
| | | case "REL_COMMON_SEVERITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>"; |
| | | break; |
| | | // case "REL_COMMON_SEVERITY" : |
| | | // makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>"; |
| | | // break; |
| | | |
| | | // 연관 이슈 등록자 |
| | | case "REL_REGISTER": |
| | | scope.data.registerVos = [scope.data.issueRelation.registerVo]; |
| | | makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>'; |
| | | break; |
| | | |
| | | break; |
| | | // case "REL_REGISTER": |
| | | // scope.data.registerVos = [scope.data.issueRelation.registerVo]; |
| | | // makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>'; |
| | | // break; |
| | | // |
| | | // break; |
| | | |
| | | // 연관 이슈 담당부서 |
| | | case "REL_ISSUE_DEPARTMENT" : |
| | | makeTag += "<ul class='ul-not-comma'>"; |
| | | makeTag += "<div style='color: #000000'>"; |
| | | angular.forEach(scope.data.issueRelation.departmentVos, function (departments) { |
| | | makeTag += "<li>" + departments.departmentName + "</li>"; |
| | | }); |
| | | makeTag += "</div>"; |
| | | makeTag += "</ul>"; |
| | | break; |
| | | // case "REL_ISSUE_DEPARTMENT" : |
| | | // makeTag += "<ul class='ul-not-comma'>"; |
| | | // makeTag += "<div style='color: #000000'>"; |
| | | // angular.forEach(scope.data.issueRelation.departmentVos, function (departments) { |
| | | // makeTag += "<li>" + departments.departmentName + "</li>"; |
| | | // }); |
| | | // makeTag += "</div>"; |
| | | // makeTag += "</ul>"; |
| | | // break; |
| | | |
| | | // 연관 이슈 목록에서 기간 표시 |
| | | case "REL_ISSUE_DUE_DATE" : |
| | | if (!$rootScope.isDefined(scope.data.issueRelation.startDate) && !$rootScope.isDefined(scope.data.issueRelation.completeDate)) { |
| | | makeTag += "<span translate='common.noDate'>기간 없음</span>"; |
| | | } |
| | | else { |
| | | makeTag += "<span>" + scope.data.issueRelation.startDate + " ~ " + scope.data.issueRelation.completeDate + "</span>"; |
| | | } |
| | | break; |
| | | // case "REL_ISSUE_DUE_DATE" : |
| | | // if (!$rootScope.isDefined(scope.data.issueRelation.startDate) && !$rootScope.isDefined(scope.data.issueRelation.completeDate)) { |
| | | // makeTag += "<span translate='common.noDate'>기간 없음</span>"; |
| | | // } |
| | | // else { |
| | | // makeTag += "<span>" + scope.data.issueRelation.startDate + " ~ " + scope.data.issueRelation.completeDate + "</span>"; |
| | | // } |
| | | // break; |
| | | |
| | | // 연관 이슈 사용자 정의 필드 |
| | | case "REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW" : |
| | | var values = []; |
| | | |
| | | for (var count in scope.data.issueRelation.issueCustomFieldValueVos) { |
| | | var issueCustomFieldValueVo = scope.data.issueRelation.issueCustomFieldValueVos[count]; |
| | | // 테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다. |
| | | if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) { |
| | | values.push(issueCustomFieldValueVo.useValue); |
| | | } |
| | | } |
| | | angular.forEach(values, function (value) { |
| | | makeTag += '<span class="table-word-break-all cursor">' + value + '<span><br>'; |
| | | }); |
| | | |
| | | break; |
| | | // case "REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW" : |
| | | // var values = []; |
| | | // |
| | | // for (var count in scope.data.issueRelation.issueCustomFieldValueVos) { |
| | | // var issueCustomFieldValueVo = scope.data.issueRelation.issueCustomFieldValueVos[count]; |
| | | // // 테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다. |
| | | // if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) { |
| | | // values.push(issueCustomFieldValueVo.useValue); |
| | | // } |
| | | // } |
| | | // angular.forEach(values, function (value) { |
| | | // makeTag += '<span class="table-word-break-all cursor">' + value + '<span><br>'; |
| | | // }); |
| | | // |
| | | // break; |
| | | |
| | | // 하위 이슈 이동(제목) |
| | | case "ISSUE_DOWN_MOVE" : |
| | | makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data)\">" + scope.data.title + "</span></a>"; |
| | | break; |
| | | |
| | | // 하위 이슈 타입 |
| | | case "ISSUE_DOWN_STATUS_TYPE" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.issueStatusVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.issueStatusVo.color + "\", \"color\": \"#FFFFFF\" }'>" + scope.data.issueStatusVo.name + "</span>"; |
| | | break; |
| | | |
| | | // case "ISSUE_DOWN_MOVE" : |
| | | // makeTag += "<span class=\"titlename cursor\" ng-click=\"event.changeDetailView(data)\">" + scope.data.title + "</span></a>"; |
| | | // break; |
| | | // |
| | | // // 하위 이슈 타입 |
| | | // case "ISSUE_DOWN_STATUS_TYPE" : |
| | | // makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.issueStatusVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.issueStatusVo.color + "\", \"color\": \"#FFFFFF\" }'>" + scope.data.issueStatusVo.name + "</span>"; |
| | | // break; |
| | | // |
| | | // 하위 이슈 삭제 |
| | | case "ISSUE_DOWN_DELETE": |
| | | if (scope.data.modifyPermissionCheck) { |
| | | makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeDownIssue(data.id)">'; |
| | | } |
| | | break; |
| | | |
| | | // case "ISSUE_DOWN_DELETE": |
| | | // if (scope.data.modifyPermissionCheck) { |
| | | // makeTag += '<img class="cursor" src="/assets/images/delete-icon.png" ng-click="event.removeDownIssue(data.id)">'; |
| | | // } |
| | | // break; |
| | | // |
| | | // 하위 이슈 우선 순위 |
| | | case "DOWN_COMMON_PRIORITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>"; |
| | | break; |
| | | |
| | | // case "DOWN_COMMON_PRIORITY" : |
| | | // makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.priorityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.priorityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.priorityVo.name + "'></span>"; |
| | | // break; |
| | | // |
| | | // 하위 이슈 중요도 |
| | | case "DOWN_COMMON_SEVERITY" : |
| | | makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>"; |
| | | break; |
| | | |
| | | // case "DOWN_COMMON_SEVERITY" : |
| | | // makeTag += "<span class='badge' ng-style='{ \"background-color\" : \"" + scope.data.severityVo.color + "\"," + "\"border-color\"" + " : \"" + scope.data.severityVo.color + "\", \"color\": \"#FFFFFF\" }' translate='" + scope.data.severityVo.name + "'></span>"; |
| | | // break; |
| | | // |
| | | // 하위 이슈 담당부서 |
| | | case "DOWN_ISSUE_DEPARTMENT" : |
| | | makeTag += "<ul class='ul-not-comma'>"; |
| | | makeTag += "<div style='color: #000000'>"; |
| | | angular.forEach(scope.data.departmentVos, function (departments) { |
| | | makeTag += "<li>" + departments.departmentName + "</li>"; |
| | | }); |
| | | makeTag += "</div>"; |
| | | makeTag += "</ul>"; |
| | | break; |
| | | |
| | | // case "DOWN_ISSUE_DEPARTMENT" : |
| | | // makeTag += "<ul class='ul-not-comma'>"; |
| | | // makeTag += "<div style='color: #000000'>"; |
| | | // angular.forEach(scope.data.departmentVos, function (departments) { |
| | | // makeTag += "<li>" + departments.departmentName + "</li>"; |
| | | // }); |
| | | // makeTag += "</div>"; |
| | | // makeTag += "</ul>"; |
| | | // break; |
| | | // |
| | | // 하위 이슈 등록자 |
| | | case "DOWN_REGISTER": |
| | | scope.data.registerVos = [scope.data.registerVo]; |
| | | makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>'; |
| | | break; |
| | | |
| | | // case "DOWN_REGISTER": |
| | | // scope.data.registerVos = [scope.data.registerVo]; |
| | | // makeTag += '<div owl-profile-over class="" table-user-image="data" target="registerVos"></div>'; |
| | | // break; |
| | | // |
| | | // 하위 이슈 기간 |
| | | case "DOWN_ISSUE_DUE_DATE" : |
| | | if (!$rootScope.isDefined(scope.data.startDate) && !$rootScope.isDefined(scope.data.completeDate)) { |
| | | makeTag += "<span translate='common.noDate'>기간 없음</span>"; |
| | | } |
| | | else { |
| | | makeTag += "<span>" + scope.data.startDate + " ~ " + scope.data.completeDate + "</span>"; |
| | | } |
| | | break; |
| | | |
| | | // case "DOWN_ISSUE_DUE_DATE" : |
| | | // if (!$rootScope.isDefined(scope.data.startDate) && !$rootScope.isDefined(scope.data.completeDate)) { |
| | | // makeTag += "<span translate='common.noDate'>기간 없음</span>"; |
| | | // } |
| | | // else { |
| | | // makeTag += "<span>" + scope.data.startDate + " ~ " + scope.data.completeDate + "</span>"; |
| | | // } |
| | | // break; |
| | | // |
| | | // 하위 이슈 사용자 정의 필드 |
| | | case "DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW" : |
| | | var values = []; |
| | | |
| | | for (var count in scope.data.issueCustomFieldValueVos) { |
| | | var issueCustomFieldValueVo = scope.data.issueCustomFieldValueVos[count]; |
| | | // 테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다. |
| | | if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) { |
| | | values.push(issueCustomFieldValueVo.useValue); |
| | | } |
| | | } |
| | | angular.forEach(values, function (value) { |
| | | makeTag += '<span class="table-word-break-all">' + value + '<span><br>'; |
| | | }); |
| | | |
| | | break; |
| | | // case "DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW" : |
| | | // var values = []; |
| | | // |
| | | // for (var count in scope.data.issueCustomFieldValueVos) { |
| | | // var issueCustomFieldValueVo = scope.data.issueCustomFieldValueVos[count]; |
| | | // // 테이블 설정에서 dName 부분에 사용자 정의 필드 id 를 넣고 해당 값을 추출한다. |
| | | // if (tableConfig.columnHint.id == issueCustomFieldValueVo.customFieldVo.id) { |
| | | // values.push(issueCustomFieldValueVo.useValue); |
| | | // } |
| | | // } |
| | | // angular.forEach(values, function (value) { |
| | | // makeTag += '<span class="table-word-break-all">' + value + '<span><br>'; |
| | | // }); |
| | | // |
| | | // break; |
| | | |
| | | // 이름을 클릭하면 수정 팝업 표시 |
| | | case "COMMON_MODIFY" : |
| | |
| | | "setIssueRelationTableDisplay": "연관 이슈 테이블 표시 설정", |
| | | "setIssueDownTableDisplay": "하위 이슈 테이블 표시 설정", |
| | | "columnName": "컬럼명", |
| | | "selectPartners": "업체 선택", |
| | | "partners" : "업체 이메일", |
| | | "area": "넓이", |
| | | "displayed": "표시 여부", |
| | | "sequence": "순서", |
| | | "cannotChangedIssueTitle": "이슈 제목은 변경할 수 없습니다.", |
| | | "cannotChangedIssueType": "이슈 구분은 변경할 수 없습니다.", |
| | | "selectSendIssueMail": "이슈 메일 발송 대상자 선택", |
| | | "selectSendIssueMail": "업체 메일 발송", |
| | | "CommonSendIssueMail": "일반 메일 발송", |
| | | "SendIssueMail": "메일 발송 입력", |
| | | "sendIssueSelectedUsers": "프로젝트에 참여하고 있는 다른 사용자에게 이슈 정보를 보냅니다.", |
| | | "sendMail": "이메일 발송", |
| | | "changedHistory": "이슈 변경 이력 상세정보", |
| | |
| | | "succeededIssueMail": "이슈 메일 발송 완료", |
| | | "sentToTheSelectedUser": "선택한 사용자에게 이메일이 발송되었습니다.", |
| | | "failedIssueMail": "이슈 메일 발송 실패", |
| | | "selectedPartnersMail": "업체 이메일을 선택하세요.", |
| | | "selectedPartnersTemplate": "업체 이메일 템플릿을 선택해주세요.", |
| | | "writeIssueMail": "이메일을 입력해주세요.", |
| | | "writeMail": "이메일을 입력하셔야 추가할수 있습니다.", |
| | | "issueVersionLookupFailed": "이슈 버전 조회 실패", |
| | | "relationIssueType1" : "다음 이슈와 관련됨", |
| | | "relationIssueType2" : "다음 이슈에 중복됨", |
| | |
| | | "checkAll": "전체 선택", |
| | | "unCheckAll": "전체 해제", |
| | | "send": "보내기", |
| | | "emailExplain": "받는 사람의 이메일 형식을 입력하셔야 합니다.", |
| | | "sendToPerson" : "다른 사용자에게 메일을 보냅니다.", |
| | | "selected": "선택됨", |
| | | "selectable": "선택 가능", |
| | | "password": "비밀번호", |
| | |
| | | "priority": "우선 순위", |
| | | "importance": "중요도", |
| | | "assignee": "담당자", |
| | | "toPerson": "받는 사람", |
| | | "assigneeTeam" : "담당부서", |
| | | "register": "등록자", |
| | | "startDate": "시작일", |
| | |
| | | var deferred = $q.defer(); |
| | | require([ |
| | | 'issueListTimelineController', 'issueManagerController', 'issueListController', 'issueAddController', 'issueModifyController', 'issueDetailController', 'issueAddRelationController', 'issueAddDownController', 'issueImportExcelController', |
| | | 'chartLoader', 'jsTable', 'jsTree', 'tableColumnGenerator', 'treeColumnGenerator', 'modalFormAutoScroll', 'summerNote', 'summerNote-ko-KR', 'fullScroll', 'workflowService', 'priorityService', 'issueSearchService', 'issueTableConfigService', 'inputRegex', |
| | | 'chartLoader', 'jsTable', 'jsTree', 'jsRel', 'jsDown', 'tableColumnGenerator', 'treeColumnGenerator', 'relColumnGenerator', 'downColumnGenerator', 'modalFormAutoScroll', 'summerNote', 'summerNote-ko-KR', 'fullScroll', 'workflowService', 'priorityService', 'issueSearchService', 'issueTableConfigService', 'inputRegex', |
| | | 'severityService', 'issueTypeService', 'issueTypeCustomFieldService', 'issueService', 'issueStatusService', 'emailTemplateService','issueUserService','issueDepartmentService','issueModifyUserController', 'issueModifyDepartmentController', 'customFieldService', 'issueSearchFieldKeyViewElement', |
| | | 'issueSearchCustomFieldViewElement', 'tableUserImage', 'fullScroll', 'issueCommentService', 'detectIssueEditor', 'formSubmit', 'issueModifyStatusController', 'downIssueModifyStatusController', 'jsShortCut', |
| | | 'issueAddTableConfigController','issueAddRelationTableConfigController','issueAddDownTableConfigController','domAppend', 'issueDetailImagePreview', 'issueSendMailPartnersController', 'htmlDiff', 'issueVersionViewController', 'issueVersionService', |
| | | 'issueAddTableConfigController','issueAddRelationTableConfigController','issueAddDownTableConfigController','domAppend', 'issueDetailImagePreview', 'issueSendMailPartnersController', 'issueCommonSendMailController', 'htmlDiff', 'issueVersionViewController', 'issueVersionService', |
| | | 'jsHtmlDiff', 'issueReservationController', 'issueReservationService', 'issueVersionService', 'issueStatusAutoFocus', 'issueRelationService' |
| | | ], function () { |
| | | deferred.resolve(); |
New file |
| | |
| | | 'use strict'; |
| | | |
| | | define([ |
| | | 'app' |
| | | ], |
| | | function (app) { |
| | | app.controller('issueCommonSendMailController', ['$scope', '$rootScope', '$state', '$log', '$resourceProvider', '$uibModalInstance', '$controller', '$injector', '$q','SweetAlert', '$filter', 'Issue', 'parameter', |
| | | function ($scope, $rootScope, $state, $log, $resourceProvider, $uibModalInstance, $controller, $injector, $q, SweetAlert, $filter, Issue, parameter) { |
| | | |
| | | $scope.fn = { |
| | | cancel : cancel, // 팝업 창 닫기 |
| | | formSubmit : formSubmit, // 폼 전송 |
| | | formCheck : formCheck, // 폼 체크 |
| | | addInput : addInput, |
| | | removeInput : removeInput |
| | | }; |
| | | |
| | | $scope.vm = { |
| | | form : { |
| | | issueId : parameter.issueId, |
| | | title : "", |
| | | description: "", |
| | | inputs : [0], |
| | | emails : {}, // 입력된 사용자 이메일 |
| | | }, |
| | | userName : "", |
| | | autoCompletePage : { |
| | | user : { |
| | | page : 0, |
| | | totalPage : 0 |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 폼 체크 |
| | | function formCheck(formInvalid) { |
| | | if (formInvalid) { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // 메일 주소 input 창 추가 버튼 |
| | | function addInput() { |
| | | var arrayFull = true; // 배열이 가득 차 있는지 여부 |
| | | var index = 0; |
| | | $scope.vm.form.inputs.forEach(function (email) { |
| | | if (!$rootScope.isDefined($scope.vm.form.emails[index])) { |
| | | arrayFull = false; |
| | | } |
| | | index++; |
| | | }); |
| | | |
| | | if (arrayFull) { |
| | | $scope.vm.form.inputs.push(index); |
| | | $scope.vm.form.emails[index] = "" |
| | | } else { |
| | | SweetAlert.warning($filter("translate")("issue.writeIssueMail"), $filter("translate")("issue.writeMail")); // 추가버튼 경고 |
| | | } |
| | | } |
| | | |
| | | // 폼 전송 |
| | | function formSubmit() { |
| | | $rootScope.spinner = true; |
| | | |
| | | var content = { |
| | | issueId : $scope.vm.form.issueId, |
| | | title : $scope.vm.form.title, |
| | | description : $scope.vm.form.description, |
| | | sendEmails : (function () { |
| | | var sendEmails = []; |
| | | var index = 0 |
| | | $scope.vm.form.inputs.forEach(function (email) { |
| | | if ($rootScope.isDefined($scope.vm.form.emails[index])) { |
| | | sendEmails.push($rootScope.encryption($scope.vm.form.emails[index])); // 이메일주소 암호화 |
| | | } |
| | | index++; |
| | | }); |
| | | |
| | | return sendEmails; |
| | | })() |
| | | }; |
| | | |
| | | Issue.sendCommonEmail($resourceProvider.getContent( |
| | | content, |
| | | $resourceProvider.getPageContent(0, 10))).then(function (result) { |
| | | |
| | | if (result.data.message.status === "success") { |
| | | SweetAlert.success($filter("translate")("issue.succeededIssueMail"), $filter("translate")("issue.sentToTheSelectedUser")); // "이슈 메일 발송 완료" |
| | | $scope.fn.cancel(); |
| | | } |
| | | else { |
| | | SweetAlert.error($filter("translate")("issue.failedIssueMail"), result.data.message.message); // "이슈 메일 발송 실패" |
| | | } |
| | | |
| | | $rootScope.spinner = false; |
| | | }); |
| | | } |
| | | |
| | | // 이메일 주소 input 삭제 |
| | | function removeInput(index) { |
| | | $scope.vm.form.inputs.splice(index, 1); |
| | | } |
| | | |
| | | function cancel() { |
| | | $rootScope.$broadcast("closeLayer"); // 팝업이 열리고 나서 js-multi, js-single 등에서 body 이벤트가 날아가는 현상 수정 |
| | | $uibModalInstance.dismiss('cancel'); |
| | | $(document).unbind("keydown"); // 단축키 이벤트 제거 |
| | | } |
| | | }]); |
| | | }); |
| | |
| | | 'angular' |
| | | ], |
| | | function (app, angular) { |
| | | app.controller('issueDetailController', ['$scope', '$rootScope', '$log', '$resourceProvider', '$tableProvider', '$state', '$uibModal', '$q', |
| | | app.controller('issueDetailController', ['$scope', '$rootScope', '$log', '$resourceProvider', '$tableProvider', '$relProvider', '$downProvider', '$state', '$uibModal', '$q', |
| | | '$controller', '$injector', 'SweetAlert', '$timeout', 'Issue', 'IssueComment', 'IssueRelation', 'AttachedFile', 'Priority', 'Severity','IssueStatus', 'IssueTableConfig', '$filter', |
| | | function ($scope, $rootScope, $log, $resourceProvider, $tableProvider, $state, $uibModal, $q, $controller, $injector, SweetAlert, $timeout, Issue, IssueComment, IssueRelation, AttachedFile, Priority, Severity, IssueStatus, IssueTableConfig, $filter) { |
| | | function ($scope, $rootScope, $log, $resourceProvider, $tableProvider, $relProvider, $downProvider, $state, $uibModal, $q, $controller, $injector, SweetAlert, $timeout, Issue, IssueComment, IssueRelation, AttachedFile, Priority, Severity, IssueStatus, IssueTableConfig, $filter) { |
| | | |
| | | // IssueListController vm, fn 변수 상속. |
| | | |
| | |
| | | $scope.fn.removeRelationIssue = removeRelationIssue; |
| | | $scope.fn.removeDownIssue = removeDownIssue; |
| | | $scope.fn.changeDetailPageRowCount = changeDetailPageRowCount; // 페이지 변경 |
| | | $scope.fn.sendCommonMail = sendCommonMail; |
| | | |
| | | // 이슈 목록 컨트롤러 vm, fn 상속 중 |
| | | $scope.vm.viewer = {}; // 현재 이슈 |
| | |
| | | } |
| | | |
| | | // 테이블의 연관 이슈 컬럼을 만들어준다. |
| | | function setRelTableColumn(Rel_issueTableConfig) { |
| | | function setRelTableColumn(issueTableConfig) { |
| | | |
| | | // 연관 이슈 컬럼 |
| | | switch(Rel_issueTableConfig.key) { |
| | | switch(issueTableConfig.key) { |
| | | case "RELATION_ISSUE_TYPE" : // 연관 이슈 구분 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueType") |
| | | .setDName("relationIssueType") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDRenderer("ISSUE_RELATION_TYPE")) |
| | | /*.setHWidth("width-30 bold")*/ |
| | | /*.setHSort(false)*/ |
| | | break; |
| | | case "RELATION_ISSUE_TITLE" : // 연관 이슈 제목 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueTitle") |
| | | .setDName("title") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDRenderer("ISSUE_RELATION_MOVE")) |
| | | /*.setHWidth("width-60 bold")*/ |
| | | /*.setHSort(true)*/ |
| | | break; |
| | | case "RELATION_PRIORITY" : // 연관 이슈 우선순위 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("common.priority") |
| | | .setDName("priorityVo.id") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("REL_COMMON_PRIORITY")); |
| | | break; |
| | | case "RELATION_SEVERITY" : // 연관 이슈 중요도 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("common.importance") |
| | | .setDName("severityVo.id") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("REL_COMMON_SEVERITY")); |
| | | break; |
| | | case "RELATION_ASSIGNEE_TEAM" : // 연관 이슈 담당부서 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("common.assigneeTeam") |
| | | .setDName("departmentVos.departmentName") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("REL_ISSUE_DEPARTMENT")); |
| | | break; |
| | | |
| | | case "RELATION_REGISTER" : // 연관 이슈 등록자 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("common.register") |
| | | .setDName("registerVo.id") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("REL_REGISTER")); |
| | | break; |
| | | case "RELATION_PERIOD" : // 연관 이슈 기간 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("common.period") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("REL_ISSUE_DUE_DATE")); |
| | | break; |
| | | case "RELATION_MODIFY_DATE" : // 연관 이슈 최근 변경일 |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("common.lastChangeDate") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setDAlign("text-center")); |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDName("modifyDate")); |
| | | break; |
| | | } |
| | | |
| | | // 사용자 정의 필드 컬럼 |
| | | if (Rel_issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) { |
| | | if (issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) { |
| | | // 만약 이슈 테이블 컬럼명이 표시되지 않으면 이쪽이 문제 |
| | | for (var count in $scope.vm.customFields) { |
| | | var customField = $scope.vm.customFields[count]; |
| | | |
| | | if (customField.id === Number(Rel_issueTableConfig.key.substring(13))) { |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | if (customField.id === Number(issueTableConfig.key.substring(13))) { |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName(customField.name) |
| | | .setDName("relCustomFieldName" + [count]) |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Rel_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setColumnHint(customField) |
| | | .setDRenderer("REL_ISSUE_CUSTOM_FIELD_VALUE_VIEW")); |
| | |
| | | |
| | | |
| | | // 테이블의 하위 이슈 컬럼을 만들어준다. |
| | | function setDownTableColumn(Down_issueTableConfig) { |
| | | function setDownTableColumn(issueTableConfig) { |
| | | // if (issueTableConfig == null) return; |
| | | |
| | | // 하위 이슈 컬럼 |
| | | switch(Down_issueTableConfig.key) { |
| | | switch(issueTableConfig.key) { |
| | | case "DOWN_ISSUE_TITLE" : // 하위 이슈 제목 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("issue.downIssueTitle") |
| | | .setDName("title") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("ISSUE_DOWN_MOVE")); |
| | | break; |
| | | |
| | | case "ISSUE_DOWN_STATUS_TYPE" : // 이슈 상태 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | case "ISSUE_DOWN_STATUS_TYPE" : // 하위 이슈 상태 |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("issue.issueStatus") |
| | | .setDName("issueStatusVo.id") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("ISSUE_DOWN_STATUS_TYPE")); |
| | | break; |
| | | |
| | | case "DOWN_PRIORITY" : // 하위 이슈 우선순위 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("common.priority") |
| | | .setDName("priorityVo.id") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("DOWN_COMMON_PRIORITY")); |
| | | break; |
| | | case "DOWN_SEVERITY" : // 중요도 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | case "DOWN_SEVERITY" : // 하위 이슈 중요도 |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("common.importance") |
| | | .setDName("severityVo.id") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("DOWN_COMMON_SEVERITY")); |
| | | break; |
| | | case "DOWN_ASSIGNEE_TEAM" : // 담당부서 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | case "DOWN_ASSIGNEE_TEAM" : // 하위 이슈 담당부서 |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("common.assigneeTeam") |
| | | .setDName("departmentVos.departmentName") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("DOWN_ISSUE_DEPARTMENT")); |
| | | break; |
| | | case "DOWN_REGISTER" : // 등록자 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | case "DOWN_REGISTER" : // 하위 이슈 등록자 |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("common.register") |
| | | .setDName("registerVo.id") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("DOWN_REGISTER")); |
| | | break; |
| | | case "DOWN_PERIOD" : // 기간 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | case "DOWN_PERIOD" : // 하위 이슈 기간 |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("common.period") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDRenderer("DOWN_ISSUE_DUE_DATE")); |
| | | break; |
| | | case "DOWN_MODIFY_DATE" : // 최근 변경일 |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | case "DOWN_MODIFY_DATE" : // 하위 이슈 최근 변경일 |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("common.lastChangeDate") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setDAlign("text-center")); |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setDName("modifyDate")); |
| | | break; |
| | | } |
| | | |
| | | // 사용자 정의 필드 컬럼 |
| | | if (Down_issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) { |
| | | if (issueTableConfig.key.indexOf("CUSTOM_FIELD_") !== -1) { |
| | | // 만약 이슈 테이블 컬럼명이 표시되지 않으면 이쪽이 문제 |
| | | for (var count in $scope.vm.customFields) { |
| | | var customField = $scope.vm.customFields[count]; |
| | | |
| | | if (customField.id === Number(Down_issueTableConfig.key.substring(13))) { |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | if (customField.id === Number(issueTableConfig.key.substring(13))) { |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName(customField.name) |
| | | .setDName("downCustomFieldName" + [count]) |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + Down_issueTableConfig.width) |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | | .setColumnHint(customField) |
| | | .setDRenderer("DOWN_ISSUE_CUSTOM_FIELD_VALUE_VIEW")); |
| | |
| | | // 연관 이슈 테이블 설정 |
| | | function makeRelTableConfigs() { |
| | | $scope.vm.relTableConfigs = []; |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setDType("checkbox") |
| | | .setHWidth("width-20-p") |
| | | .setDAlign("text-center")) |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueType") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | | .setHWidth("width-60-p bold") |
| | | .setHSort(false) |
| | | .setDRenderer("ISSUE_RELATION_TYPE")) |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueTitle") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | |
| | | .setHSort(false) |
| | | .setDRenderer("ISSUE_RELATION_MOVE")) |
| | | /*if($scope.vm.viewer.modifyPermissionCheck) { |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueDelete") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | |
| | | .setHSort(false) |
| | | .setDAlign("text-center")) |
| | | }*/ |
| | | angular.forEach($scope.vm.relTableConfigs, function (Rel_issueTableConfig) { |
| | | angular.forEach($scope.vm.relTableConfigs, function (issueTableConfig) { |
| | | // 표시 대상인 컬럼만 화면에 그려준다. |
| | | if (Rel_issueTableConfig.display) { |
| | | if (issueTableConfig.display) { |
| | | // 테이블의 컬럼을 만들어준다. |
| | | $scope.fn.setRelTableColumn(Rel_issueTableConfig); |
| | | $scope.fn.setRelTableColumn(issueTableConfig); |
| | | } |
| | | }); |
| | | } |
| | |
| | | // 하위 이슈 테이블 설정 |
| | | function makeDownTableConfigs() { |
| | | $scope.vm.downTableConfigs = []; |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setDType("checkbox") |
| | | .setHWidth("width-20-p") |
| | | .setDAlign("text-center")) |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("issue.downIssueTitle") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | |
| | | .setHSort(false) |
| | | .setDRenderer("ISSUE_DOWN_MOVE")) |
| | | /*if($scope.vm.viewer.modifyPermissionCheck){ |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("issue.relationIssueDelete") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | |
| | | .setDAlign("text-center")) |
| | | }*/ |
| | | |
| | | angular.forEach($scope.vm.downTableConfigs, function (Down_issueTableConfig) { |
| | | angular.forEach($scope.vm.downTableConfigs, function (issueTableConfig) { |
| | | // 표시 대상인 컬럼만 화면에 그려준다. |
| | | if (Down_issueTableConfig.display) { |
| | | if (issueTableConfig.display) { |
| | | // 테이블의 컬럼을 만들어준다. |
| | | $scope.fn.setDownTableColumn(Down_issueTableConfig); |
| | | $scope.fn.setDownTableColumn(issueTableConfig); |
| | | } |
| | | }); |
| | | } |
| | |
| | | } |
| | | var issueTableConfigs = issueTableConfigVo.issueTableConfigs; |
| | | |
| | | // 연관 슈 목록 테이블 설정 값을 가져와서 적용한다. |
| | | // 연관 이슈 목록 테이블 설정 값을 가져와서 적용한다. |
| | | if ($rootScope.isDefined(issueTableConfigs)) { |
| | | // 이슈 테이블 설정 정보를 저장 한다. |
| | | |
| | |
| | | }); |
| | | |
| | | $scope.vm.relTableConfigs = []; |
| | | /* $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | /* $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueType") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | | .setHWidth("width-30-p bold") |
| | | .setHSort(false) |
| | | .setDRenderer("ISSUE_RELATION_TYPE")) |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueTitle") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | | .setHWidth("width-60-p bold") |
| | | .setHSort(false) |
| | | .setDRenderer("ISSUE_RELATION_MOVE"))*/ |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setDType("checkbox") |
| | | .setHWidth("width-20-p") |
| | | .setDAlign("text-center")) |
| | | angular.forEach($scope.vm.issueRelTableConfigs, function (Rel_issueTableConfig) { |
| | | angular.forEach($scope.vm.issueRelTableConfigs, function (issueTableConfig) { |
| | | // 표시 대상인 컬럼만 화면에 그려준다. |
| | | if (Rel_issueTableConfig.display) { |
| | | if (issueTableConfig.display) { |
| | | // 테이블의 컬럼을 만들어준다. |
| | | $scope.fn.setRelTableColumn(Rel_issueTableConfig); |
| | | $scope.fn.setRelTableColumn(issueTableConfig); |
| | | |
| | | } |
| | | }); |
| | | /*if($scope.vm.viewer.modifyPermissionCheck) { |
| | | $scope.vm.relTableConfigs.push($tableProvider.config() |
| | | $scope.vm.relTableConfigs.push($relProvider.config() |
| | | .setHName("issue.relationIssueDelete") |
| | | .setDType("renderer") |
| | | .setHWidth("width-40-p bold") |
| | |
| | | if (issueTableConfigVo == null) return; |
| | | var issueTableConfigs = issueTableConfigVo.issueTableConfigs; |
| | | |
| | | // 연관 슈 목록 테이블 설정 값을 가져와서 적용한다. |
| | | // 연관 이슈 목록 테이블 설정 값을 가져와서 적용한다. |
| | | if ($rootScope.isDefined(issueTableConfigs)) { |
| | | // 이슈 테이블 설정 정보를 저장 한다. |
| | | $scope.vm.issueDownTableConfigs = []; |
| | |
| | | return a.position < b.position ? -1 : a.position > b.position ? 1 : 0; |
| | | }); |
| | | $scope.vm.downTableConfigs = []; |
| | | /* $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | /* $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("issue.downIssueTitle") |
| | | .setDType("renderer") |
| | | .setDAlign("text-center") |
| | | .setHWidth("width-60-p bold") |
| | | .setHSort(false) |
| | | .setDRenderer("ISSUE_DOWN_MOVE"))*/ |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setDType("checkbox") |
| | | .setHWidth("width-20-p") |
| | | .setDAlign("text-center")) |
| | | angular.forEach($scope.vm.issueDownTableConfigs, function (Down_issueTableConfig) { |
| | | angular.forEach($scope.vm.issueDownTableConfigs, function (issueTableConfig) { |
| | | // 표시 대상인 컬럼만 화면에 그려준다. |
| | | if (Down_issueTableConfig.display) { |
| | | if (issueTableConfig.display) { |
| | | // 테이블의 컬럼을 만들어준다. |
| | | $scope.fn.setDownTableColumn(Down_issueTableConfig); |
| | | $scope.fn.setDownTableColumn(issueTableConfig); |
| | | } |
| | | }); |
| | | /*if($scope.vm.viewer.modifyPermissionCheck) { |
| | | $scope.vm.downTableConfigs.push($tableProvider.config() |
| | | $scope.vm.downTableConfigs.push($downProvider.config() |
| | | .setHName("issue.relationIssueDelete") |
| | | .setDType("renderer") |
| | | .setHWidth("width-40-p bold") |
| | |
| | | $scope.vm.viewer.startDate = result.data.data.startDate == null ? "common.unspecified" : result.data.data.startDate; // 미지정 |
| | | $scope.vm.viewer.completeDate = result.data.data.completeDate == null ? "common.unspecified" : result.data.data.completeDate; // 미지정 |
| | | |
| | | $scope.vm.rangeDate = result.data.data.startDate + "~" + result.data.data.completeDate |
| | | |
| | | // 이슈 유형에 연결된 사용자 정의 필드 정보를 입력 폼에서 사용할 수 있게 가공한다. |
| | | $scope.fn.setFormByIssueTypeCustomFields(result.data.data.issueTypeCustomFieldVos); |
| | | // 이슈에서 사용자가 선택한 사용자 정의 필드 값을 입력 폼에 셋팅한다. |
| | |
| | | }); |
| | | } |
| | | |
| | | // 일반 메일 발송 (사용자 직접 작성) |
| | | function sendCommonMail() { |
| | | $uibModal.open({ |
| | | templateUrl : 'views/issue/issueCommonSendMail.html', |
| | | size : "md", |
| | | controller : 'issueCommonSendMailController', |
| | | backdrop : 'static', |
| | | resolve : { |
| | | parameter : { |
| | | issueId : $scope.vm.viewer.id, |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | function getParametersAll() { |
| | | var params = $scope.fn.getParameters(null, $scope.vm.viewer.issueCompanyVos); |
| | | params = $scope.fn.getParameters(params, $scope.vm.viewer.issueIspVos); |
| | |
| | | case "ISSUE_TITLE" : // 이슈 제목 |
| | | $scope.vm.tableConfigs.push($tableProvider.config() |
| | | .setHName("issue.issueTitle") |
| | | .setDName("issueNumber") /* todo 이건 타이틀로 변경해야하는데*/ |
| | | .setDName("issueTitle") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | |
| | | case "ASSIGNEE_TEAM" : // 담당부서 |
| | | $scope.vm.tableConfigs.push($tableProvider.config() |
| | | .setHName("common.assigneeTeam") |
| | | .setDName("departmentName") /* todo 체크*/ |
| | | .setDName("departmentName") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | |
| | | case "PERIOD" : // 기간 |
| | | $scope.vm.tableConfigs.push($tableProvider.config() |
| | | .setHName("common.period") |
| | | .setDName("startDate") |
| | | .setDType("renderer") |
| | | .setHWidth("bold " + issueTableConfig.width) |
| | | .setDAlign("text-center") |
| | |
| | | formCheck : formCheck, // 폼 체크 |
| | | onChangeEmailTemplate : onChangeEmailTemplate, // 이메일 템플릿 선택시 실행 |
| | | getEmailTemplateList : getEmailTemplateList // 이메일 템플릿 목록 가져오기 |
| | | // showEmailTemplate : showEmailTemplate, |
| | | }; |
| | | |
| | | $scope.vm = { |
| | |
| | | hostingVos : parameter.hostingVos, |
| | | partners : parameter.partnersAll.slice(), |
| | | html : "", |
| | | tab : "SEND_TEMPLATE", |
| | | form : { |
| | | id : parameter.issueId, // 이슈 번호 |
| | | projects : [{ id : parameter.projectId}], // 프로젝트 |
| | |
| | | $scope.vm.html = result.data.data.template; |
| | | } |
| | | else { |
| | | SweetAlert.error($filter("translate")("issue.failedIssueMail"), result.data.message.message); // "이슈 메일 발송 실패" |
| | | $scope.vm.html = ""; |
| | | //SweetAlert.warning($filter("translate")("issue.selectedPartnersMail"),$filter("translate")("issue.selectedPartnersTemplate")); // option 선택 경고 |
| | | } |
| | | |
| | | $rootScope.spinner = false; |
| | |
| | | |
| | | $scope.vm.emailTemplateId = 1; |
| | | $scope.vm.emailTitle = ""; |
| | | if ($rootScope.isDefined($scope.vm.emailTemplateType)) { |
| | | $scope.vm.emailTemplates.forEach(function (emailTemplate) { |
| | | /*if (emailTemplate.id === $scope.vm.emailTemplateId) { |
| | | $scope.vm.emailTitle = emailTemplate.title; |
| | | }*/ |
| | | if (emailTemplate.templateType === $scope.vm.emailTemplateType) { |
| | | $scope.vm.emailTitle = emailTemplate.title; |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | $scope.fn.getEmailTemplateList(); |
| | | |
| | | }]); |
| | | |
| | | }); |
| | |
| | | if (angular.isDefined(result.data.data)) { |
| | | $scope.vm.form.name = result.data.data.name; |
| | | $scope.vm.form.status = result.data.data.status; |
| | | if (result.data.data.startDate == "" && result.data.data.endDate == "") { |
| | | if (result.data.data.startDate == "" && result.data.data.endDate == "" || result.data.data.startDate == "null" && result.data.data.endDate == "null") { |
| | | $scope.vm.form.startEndDateRange = "" |
| | | } else { |
| | | $scope.vm.form.startEndDateRange = result.data.data.startDate + " ~ " + result.data.data.endDate; |
| | |
| | | $tableProvider.setOrderByColumn(); |
| | | $tableProvider.reverse = false; |
| | | |
| | | // 연관 테이블 컬럼 정렬 초기화 |
| | | var $relProvider = $injector.get('$relProvider'); |
| | | $relProvider.setOrderByColumn(); |
| | | $relProvider.reverse = false; |
| | | |
| | | // 하위 테이블 컬럼 정렬 초기화 |
| | | var $downProvider = $injector.get('$downProvider'); |
| | | $downProvider.setOrderByColumn(); |
| | | $downProvider.reverse = false; |
| | | |
| | | if (angular.isDefined(config.data)) { |
| | | $log.debug(config.url + " : ", config.data); |
| | | } |
| | |
| | | $log.debug("이슈 이메일 발송 결과 : ", response); |
| | | return response; |
| | | }); |
| | | }, |
| | | sendCommonEmail : function (conditions) { |
| | | return $http.post("issue/sendCommonEmail", conditions).then(function (response) { |
| | | $log.debug("이슈 이메일 발송 결과 : ", response); |
| | | return response; |
| | | }); |
| | | } |
| | | } |
| | | } |
| | |
| | | // 로그 제어 |
| | | $logProvider.debugEnabled(true); |
| | | }) |
| | | .run(function ($rootScope, $state, $sce, $log, $injector, $translate, $tableProvider, Principal, Auth, Language, SweetAlert, $filter, Workspace, $resourceProvider, User, constants, Project) { |
| | | .run(function ($rootScope, $state, $sce, $log, $injector, $translate, $tableProvider, $relProvider, $downProvider, Principal, Auth, Language, SweetAlert, $filter, Workspace, $resourceProvider, User, constants, Project) { |
| | | |
| | | $rootScope.$state = $state; |
| | | // html 태그 웹 보안 적용하여 바인딩. |
| | |
| | | |
| | | // 테이블 설정 및 기능을 관리하는 서비스 |
| | | $rootScope.$tableProvider = $tableProvider; |
| | | |
| | | // 연관테이블 설정 및 기능 관리하는 서비스 |
| | | $rootScope.$relProvider = $relProvider; |
| | | |
| | | // 하위테이블 설정 및 기능 관리하는 서비스 |
| | | $rootScope.$downProvider = $downProvider; |
| | | |
| | | // html tag convert - 신뢰할 수 있는 입력 값일 때만 사용, 사용자가 등록하는 값에는 사용 금지 |
| | | $rootScope.trustAsHtml = function (string) { |
| | |
| | | // table orderBy column init setting |
| | | $tableProvider.setOrderByColumn(); |
| | | $tableProvider.reverse = false; |
| | | |
| | | $relProvider.setOrderByColumn(); |
| | | $relProvider.reverse = false; |
| | | // 이슈 목록->상세화면에서 마지막으로 접근한 이슈 아이디 - 라우트 탈때마다 초기화 |
| | | $rootScope.currentDetailIssueId = null; |
| | | // 사용자 정보를 가져온다. |
| | |
| | | 'commonController' : 'app/common/common.controller', // 공통 컨트롤러 |
| | | 'tableProvider' : '../custom_components/js-table/table.provider', // 테이블 속성 값을 관리한다. |
| | | 'treeProvider' : '../custom_components/js-tree/tree.provider', // 트리 속성 값을 관리한다. |
| | | 'relProvider' : '../custom_components/js-rel/rel.provider', // 연관 테이블 속성 값을 관리한다. |
| | | 'downProvider' : '../custom_components/js-down/down.provider', // 하위 테이블 속성 값을 관리한다. |
| | | 'resourceProvider' : 'components/utils/resource.provider', // 공통적으로 서버 json 전송에 사용 |
| | | 'lodash' : '../bower_components/lodash/lodash.min', // 멀티 셀렉트, auto complete 컴포넌트들에서 사용 |
| | | 'angularDropMultiSelect' : '../custom_components/angular-multi-select/angularjs-dropdown-multiselect', // 멀티 셀렉트 컴포넌트 |
| | | 'jsTable' : '../custom_components/js-table/js-table.directive', // 목록 화면에서 사용되는 테이블을 호출한다. |
| | | 'jsTree' : '../custom_components/js-tree/js-tree.directive', // 목록 화면에서 사용되는 테이블(트리구조)을 호출한다. |
| | | 'jsRel' : '../custom_components/js-rel/js-rel.directive', // 이슈상세 화면에서 사용되는 연관 테이블을 호출한다. |
| | | 'jsDown' : '../custom_components/js-down/js-down.directive', // 이슈상세 화면에서 사용되는 하위 테이블을 호출한다. |
| | | 'tableColumnGenerator' : '../custom_components/js-table/tableColumnGenerator.directive', // 테이블 랜더러를 담당한다. |
| | | 'treeColumnGenerator' : '../custom_components/js-tree/treeColumnGenerator.directive', // 테이블 랜더러를 담당한다. |
| | | 'treeColumnGenerator' : '../custom_components/js-tree/treeColumnGenerator.directive', // 이슈리스트 트리 랜더러를 담당한다. |
| | | 'relColumnGenerator' : '../custom_components/js-rel/relColumnGenerator.directive', // 이슈상세 연관 랜더러를 담당한다. |
| | | 'downColumnGenerator' : '../custom_components/js-down/downColumnGenerator.directive', // 이슈상세 하위 랜더러를 담당한다. |
| | | 'jsAutoCompleteMulti' : '../custom_components/js-autocomplete-multi/js-autocomplete-multi', // 다중 선택이 가능한 autoComplete 컴포넌트 |
| | | 'jsInputAutoComplete' : '../custom_components/js-input-autocomplete/js-input-autocomplete', // input 박스에 autoComplete 기능이 붙은 컴포넌트 |
| | | 'jsAutoCompleteSingle' : '../custom_components/js-autocomplete-single/js-autocomplete-single', // input 박스에 한개의 대상만 선택 가능할수 있는 autoComplete 기능이 붙은 컴포넌트 |
| | |
| | | 'issueAddTableConfigController' : 'app/issue/issueAddTableConfig.controller', // 이슈 테이블 설정 컨트롤러 |
| | | 'issueAddRelationTableConfigController' : 'app/issue/issueAddRelationTableConfig.controller', // 이슈 테이블 설정 컨트롤러 |
| | | 'issueAddDownTableConfigController' : 'app/issue/issueAddDownTableConfig.controller', // 이슈 테이블 설정 컨트롤러 |
| | | 'issueSendMailPartnersController' : 'app/issue/issueSendMailPartners.controller', // 이슈 이메일 발송 컨트롤러 |
| | | 'issueSendMailPartnersController' : 'app/issue/issueSendMailPartners.controller', // 업체 이메일 발송 컨트롤러 |
| | | 'issueCommonSendMailController' : 'app/issue/issueCommonSendMail.controller', // 일반 이메일 발송 컨트롤러 |
| | | 'issueVersionViewController' : 'app/issue/issueVersionView.controller', // 이슈 버전 확인 컨트롤러 |
| | | 'issueReservationController' : 'app/issue/issueReservation.controller', // 이슈 발생 예약 컨트롤러 |
| | | 'issueModifyUserController' : 'app/issue/issueModifyUser.controller', // 이슈 담당자 컨트롤러 |
| | |
| | | 'jsTree' : { |
| | | deps : ['app'] |
| | | }, |
| | | 'jsRel' : { |
| | | deps : ['app'] |
| | | }, |
| | | 'jsDown' : { |
| | | deps : ['app'] |
| | | }, |
| | | 'tableColumnGenerator' : { |
| | | deps : ['app'] |
| | | }, |
| | | 'treeColumnGenerator' : { |
| | | deps : ['app'] |
| | | }, |
| | | 'relColumnGenerator' : { |
| | | deps : ['app'] |
| | | }, |
| | | 'downColumnGenerator' : { |
| | | deps : ['app'] |
| | | }, |
| | | 'ngStomp' : { |
| | |
| | | 'config', // angularJs 설정 - route 이동 관련, 이동시 초기화 로직이 들어있다. - 직접 로드 |
| | | 'constants', |
| | | 'commonController', |
| | | 'issueCommonSendMailController', |
| | | 'autoCompleteController', |
| | | 'userInviteController', |
| | | 'issueAddController', // 이슈 만들기에서 사용 |
| | |
| | | 'resourceProvider', |
| | | 'tableProvider', |
| | | 'treeProvider', |
| | | 'relProvider', |
| | | 'downProvider', |
| | | 'permissionService', |
| | | 'authService', |
| | | 'userInviteService', |
New file |
| | |
| | | <div class="formModal"> |
| | | <div class="modal-header faded smaller"> |
| | | <div class="modal-title"> |
| | | <strong translate="issue.CommonSendIssueMail">일반 메일 발송</strong> |
| | | </div> |
| | | <button aria-label="Close" class="close" type="button" ng-click="fn.cancel()"> |
| | | <span aria-hidden="true"> ×</span> |
| | | </button> |
| | | </div> |
| | | |
| | | <div class="modal-body"> |
| | | <form role="form" name="issueSendForm"> |
| | | <button type="button" class="btn btn-secondary mr-3 float-right mb-1" ng-click="fn.addInput()"> |
| | | <span translate="common.add">추가</span> |
| | | </button> |
| | | <div class="form-group"> |
| | | <label class="issue-label mt-2"><span translate="common.toPerson">받는 사람</span> <code class="highlighter-rouge">*</code></label> |
| | | <div class="input-group" ng-repeat="i in vm.form.inputs"> |
| | | <input type="text" |
| | | name="email" |
| | | class="form-control mt-1" |
| | | kr-input |
| | | ng-model="vm.form.emails[$index]" |
| | | ng-pattern="/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/" |
| | | required |
| | | autocomplete="off"> |
| | | <span class="select3-selection__email__remove" ng-click="fn.removeInput($index)">×</span> |
| | | </div> |
| | | <small translate="common.emailExplain">받는 사람의 이메일 형식을 입력하셔야 합니다.</small> |
| | | <div ng-if="issueSendForm.email.$error.pattern" class="help-block form-text text-danger" |
| | | translate="common.invalidEmailFormat">이메일 형식이 맞지 않습니다. |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | <label class="issue-label"><span translate="common.title">제목</span></label> |
| | | <input id="title" |
| | | type="text" |
| | | name="title" |
| | | class="form-control mt-1" |
| | | kr-input |
| | | ng-model="vm.form.title" |
| | | autocomplete="off"> |
| | | |
| | | <div class="form-group mb10 mt-10"> |
| | | <label class="issue-label"><span translate="common.content">내용</span></label> |
| | | <summernote |
| | | class="summernote mt-1" |
| | | lang="ko-KR" |
| | | summer-note-auto-focus |
| | | ng-model="vm.form.description" |
| | | data-editor="vm.summerNote.editor" |
| | | data-editable="vm.summerNote.editable" |
| | | on-image-upload="fn.imageUpload(files)" |
| | | target=".note-editable"></summernote> |
| | | </div> |
| | | <small class="mt-1" translate="common.sendToPerson">다른 사용자에게 메일을 보냅니다.</small> |
| | | </form> |
| | | </div> |
| | | |
| | | <div class="modal-footer buttons-on-right"> |
| | | <button type="button" class="btn btn-md btn-grey" ng-click="fn.cancel()"><span |
| | | translate="common.cancel">취소</span></button> |
| | | <button type="button" class="btn btn-md btn-primary bold" |
| | | ng-disabled="fn.formCheck(issueSendForm.$invalid)" |
| | | ng-click="fn.formSubmit()"><span translate="issue.sendMail">이메일 발송</span> |
| | | </button> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | </span> |
| | | <a class="show-ticket-info cursor"> |
| | | <i class="os-icon os-icon-email-forward mr-20" ng-if="vm.viewer.modifyPermissionCheck" ng-click="fn.sendMailAll()" data-toggle="tooltip" data-placement="right" title="다른 사용자에게 이슈 보내기"></i> |
| | | <i class="os-icon os-icon-email-2-at2 mr-20" ng-if="vm.viewer.modifyPermissionCheck" ng-click="fn.sendCommonMail()" data-toggle="tooltip" data-placement="right" title="직접 작성한 메일 보내기"></i> |
| | | <i class="os-icon os-icon-email-forward mr-20" ng-if="vm.viewer.modifyPermissionCheck" ng-click="fn.sendMailAll()" data-toggle="tooltip" data-placement="right" title="업체 메일 보내기"></i> |
| | | <i class="os-icon os-icon-airplay mr-20" ng-click="fn.versionView(vm.viewer.id)" data-toggle="tooltip" data-placement="right" title="이슈 변경 이력 상세 보기"></i> |
| | | <i class="os-icon os-icon-calendar-time mr-20" ng-if="vm.viewer.modifyPermissionCheck" |
| | | ng-click="fn.reservation(vm.viewer.id)" data-toggle="tooltip" data-placement="right" title="이슈 발생 예약 하기"></i> |
| | |
| | | |
| | | <!-- 연관 이슈 테이블 --> |
| | | <div class="mt-10 issue-detail-word-break width-100"> |
| | | <js-table data="vm.viewer.issueRelationVos" table-configs="vm.relTableConfigs" |
| | | event="relTableEvent" detail-view="true" hide-header="false" use-sort="true"></js-table> |
| | | <js-rel data="vm.viewer.issueRelationVos" table-configs="vm.relTableConfigs" |
| | | event="relTableEvent" detail-view="true" hide-header="false" use-sort="true"></js-rel> |
| | | |
| | | <div class="row" ng-if="vm.viewer.modifyPermissionCheck"> |
| | | <div class="col-sm-4"> |
| | |
| | | |
| | | <!-- 하위 이슈 테이블 --> |
| | | <div class="mt-10 issue-detail-word-break width-100"> |
| | | <js-table data="vm.viewer.issueDownVos" table-configs="vm.downTableConfigs" |
| | | event="downTableEvent" detail-view="true" hide-header="false" use-sort="true"></js-table> |
| | | <js-down data="vm.viewer.issueDownVos" table-configs="vm.downTableConfigs" |
| | | event="downTableEvent" detail-view="true" hide-header="false" use-sort="true"></js-down> |
| | | |
| | | <div class="row" ng-if="vm.viewer.modifyPermissionCheck"> |
| | | <div class="col-sm-6"> |
| | |
| | | <div class="formModal"> |
| | | <div class="modal-header faded smaller"> |
| | | <div class="modal-title"> |
| | | <strong translate="issue.selectSendIssueMail">이슈 메일 발송 대상자 선택</strong> |
| | | <strong translate="issue.selectSendIssueMail">이슈 메일 발송</strong> |
| | | </div> |
| | | <button aria-label="Close" class="close" type="button" ng-click="fn.cancel()"> |
| | | <span aria-hidden="true"> ×</span> |
| | |
| | | </span> |
| | | </div> |
| | | |
| | | <label class="issue-label mt-10"> |
| | | <span translate="issue.selectPartners">업체 선택</span> <code class="highlighter-rouge">*</code> |
| | | </label> |
| | | <js-input-autocomplete data-input-name="mailUsers" |
| | | owl-auto-focus |
| | | target=".auto-complete-i0nput" |
| | |
| | | page="vm.autoCompletePage.user.page" |
| | | total-page="vm.autoCompletePage.user.totalPage" |
| | | source="fn.getMailTargetAll(vm.form.mailUsers)" |
| | | translation-texts="{ empty : 'common.emptyUser'}" |
| | | translation-texts="{ empty : 'common.emptyCompanyPartners'}" |
| | | input-disabled="vm.form.mailUsers == null" |
| | | extra-settings="{ displayProp : 'name' , idProp : 'id', imageable : false, imagePathProp : 'profile', |
| | | type : 'partner', maxlength : 100, autoResize : true, stopRemoveBodyEvent : true }"></js-input-autocomplete> |
| | | <div class="Template-area mt-20"> |
| | | <div class="form-group mb10"> |
| | | |
| | | <div class="form-group mb10 mt-20"> |
| | | <label for="emailTemplateForm" class="issue-label"> |
| | | <span translate="common.emailTemplate">이메일 템플릿</span> |
| | | <span translate="issue.partners">업체 이메일</span> <code class="highlighter-rouge">*</code> |
| | | </label> |
| | | <select id="emailTemplateForm" |
| | | name="emailTemplate" |
| | |
| | | ng-model="vm.emailTemplateType" |
| | | ng-change="fn.onChangeEmailTemplate()" |
| | | required> |
| | | <option value="" ng-selected="true">선택하세요</option> |
| | | <option ng-repeat="emailTemplate in vm.emailTemplates" |
| | | value="{{emailTemplate.templateType}}" |
| | | translate="{{emailTemplate.title}}"> |
| | | </option> |
| | | </select> |
| | | </div> |
| | | </div> |
| | | |
| | | <label class="issue-label"><span translate="common.title">제목</span></label> |
| | | <input id="title" |
| | | type="text" |
| | | name="title" |
| | | class="form-control" |
| | | kr-input |
| | | ng-model="vm.emailTitle" |
| | | autocomplete="off"> |
| | | |
| | | <div class="form-group mb10 mt-10"> |
| | | <label class="issue-label"><span translate="common.content">내용</span></label> |
| | | <summernote |
| | | class="summernote" |
| | | lang="ko-KR" |
| | |
| | | ng-model="vm.html" |
| | | target=".note-editable"></summernote> |
| | | </div> |
| | | </div> |
| | | </form> |
| | | </div> |
| | | |
| | | |
| | | <div class="modal-footer buttons-on-right"> |
| | | <button type="button" class="btn btn-md btn-grey" ng-click="fn.cancel()"><span |