사용약품 저장기능
This commit is contained in:
11
sql/alter_medical_divi_list.sql
Normal file
11
sql/alter_medical_divi_list.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- =====================================================
|
||||
-- medical_divi_list 테이블 엔진 & 캐릭터셋 변경
|
||||
-- MyISAM → InnoDB (FK 지원을 위해)
|
||||
-- utf8mb3 → utf8mb4 (medical_divi_product와 일치시키기 위해)
|
||||
-- =====================================================
|
||||
|
||||
-- 1) 엔진 변경: MyISAM → InnoDB
|
||||
ALTER TABLE `medical_divi_list` ENGINE = InnoDB;
|
||||
|
||||
-- 2) 캐릭터셋 변경: utf8mb3 → utf8mb4
|
||||
ALTER TABLE `medical_divi_list` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
24
sql/create_medical_divi_product.sql
Normal file
24
sql/create_medical_divi_product.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- =====================================================
|
||||
-- medical_divi_product : 용량/출력(Depth4) 카테고리별 약품 매핑 테이블
|
||||
-- 참조: MU_TREATMENT_PROCEDURE_PRODUCT
|
||||
-- =====================================================
|
||||
|
||||
CREATE TABLE `medical_divi_product` (
|
||||
`pid` INT(11) NOT NULL AUTO_INCREMENT COMMENT '고유 식별자',
|
||||
`store_pid` INT(11) NOT NULL DEFAULT 1 COMMENT '병원(지점) 식별자',
|
||||
`divi_pid` INT(11) NOT NULL COMMENT '진료유형 카테고리 pid (medical_divi_list.pid, Depth4 기준)',
|
||||
`product_name` VARCHAR(200) NOT NULL COMMENT '약품/제품 명칭',
|
||||
`product_code` VARCHAR(100) DEFAULT NULL COMMENT '약품 코드 (재고관리용)',
|
||||
`volume` DECIMAL(10,2) DEFAULT 0 COMMENT '제품 1개당 용량',
|
||||
`use_volume` DECIMAL(10,2) DEFAULT 0 COMMENT '1회 사용량',
|
||||
`unit_cd` VARCHAR(50) DEFAULT NULL COMMENT '단위 코드 (UNIT_CD 공통코드)',
|
||||
`unit_nm` VARCHAR(100) DEFAULT NULL COMMENT '단위 명칭',
|
||||
`price` INT(11) DEFAULT 0 COMMENT '입고 단가',
|
||||
`order_number` INT(11) DEFAULT 0 COMMENT '정렬 순서',
|
||||
`list_use` CHAR(1) DEFAULT 'y' COMMENT '사용여부 (y/n)',
|
||||
`reg_date` DATETIME DEFAULT CURRENT_TIMESTAMP() COMMENT '등록일시',
|
||||
`up_date` DATETIME DEFAULT CURRENT_TIMESTAMP() ON UPDATE CURRENT_TIMESTAMP() COMMENT '수정일시',
|
||||
PRIMARY KEY (`pid`),
|
||||
KEY `idx_divi_pid` (`divi_pid`),
|
||||
CONSTRAINT `fk_mdp_divi_pid` FOREIGN KEY (`divi_pid`) REFERENCES `medical_divi_list` (`pid`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='진료유형 카테고리별 약품/제품 매핑 (재고관리)';
|
||||
@@ -15,6 +15,7 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
import com.madeu.constants.Constants;
|
||||
import com.madeu.crm.settings.medicalcategory.dto.MedicalCategoryDTO;
|
||||
import com.madeu.crm.settings.medicalcategory.service.MedicalCategoryService;
|
||||
import com.madeu.crm.settings.medicalcategory.service.MedicalDiviProductService;
|
||||
import com.madeu.init.ManagerDraftAction;
|
||||
import com.madeu.util.HttpUtil;
|
||||
|
||||
@@ -30,6 +31,9 @@ public class MedicalCategoryController extends ManagerDraftAction {
|
||||
@Autowired
|
||||
private MedicalCategoryService medicalCategoryService;
|
||||
|
||||
@Autowired
|
||||
private MedicalDiviProductService diviProductService;
|
||||
|
||||
// ==================== 뷰 반환 메서드 ====================
|
||||
|
||||
/**
|
||||
@@ -288,4 +292,127 @@ public class MedicalCategoryController extends ManagerDraftAction {
|
||||
log.debug("MedicalCategoryController updateBatchMedicalCategory END");
|
||||
return map;
|
||||
}
|
||||
|
||||
// ==================== 약품 관련 API ====================
|
||||
|
||||
/**
|
||||
* 약품 리스트 조회
|
||||
*/
|
||||
@PostMapping("/getDiviProductList.do")
|
||||
public HashMap<String, Object> getDiviProductList(HttpServletRequest request, HttpServletResponse response) {
|
||||
log.debug("MedicalCategoryController getDiviProductList START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = diviProductService.getDiviProductList(paramMap);
|
||||
} catch (Exception e) {
|
||||
log.error("getDiviProductList : ", e);
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||
}
|
||||
log.debug("MedicalCategoryController getDiviProductList END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 등록
|
||||
*/
|
||||
@PostMapping("/putDiviProduct.do")
|
||||
public HashMap<String, Object> putDiviProduct(@RequestBody HashMap<String, Object> paramMap,
|
||||
HttpServletRequest request) {
|
||||
log.debug("MedicalCategoryController putDiviProduct START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = diviProductService.insertDiviProduct(paramMap);
|
||||
} catch (Exception e) {
|
||||
log.error("putDiviProduct : ", e);
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||
}
|
||||
log.debug("MedicalCategoryController putDiviProduct END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 삭제
|
||||
*/
|
||||
@PostMapping("/delDiviProduct.do")
|
||||
public HashMap<String, Object> delDiviProduct(HttpServletRequest request, HttpServletResponse response) {
|
||||
log.debug("MedicalCategoryController delDiviProduct START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = diviProductService.deleteDiviProduct(paramMap);
|
||||
} catch (Exception e) {
|
||||
log.error("delDiviProduct : ", e);
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||
}
|
||||
log.debug("MedicalCategoryController delDiviProduct END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 수정
|
||||
*/
|
||||
@PostMapping("/modDiviProduct.do")
|
||||
public HashMap<String, Object> modDiviProduct(@RequestBody HashMap<String, Object> paramMap,
|
||||
HttpServletRequest request) {
|
||||
log.debug("MedicalCategoryController modDiviProduct START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = diviProductService.updateDiviProduct(paramMap);
|
||||
} catch (Exception e) {
|
||||
log.error("modDiviProduct : ", e);
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||
}
|
||||
log.debug("MedicalCategoryController modDiviProduct END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 일괄 저장 (등록/수정/삭제)
|
||||
*/
|
||||
|
||||
@PostMapping("/saveDiviProductBatch.do")
|
||||
public HashMap<String, Object> saveDiviProductBatch(@RequestBody List<HashMap<String, Object>> list,
|
||||
HttpServletRequest request) {
|
||||
log.debug("MedicalCategoryController saveDiviProductBatch START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = diviProductService.saveDiviProductBatch(list);
|
||||
} catch (Exception e) {
|
||||
log.error("saveDiviProductBatch : ", e);
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||
}
|
||||
log.debug("MedicalCategoryController saveDiviProductBatch END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 제품(약품) 검색 (MU_PRODUCT 기반)
|
||||
*/
|
||||
@PostMapping("/searchProductList.do")
|
||||
public HashMap<String, Object> searchProductList(HttpServletRequest request, HttpServletResponse response) {
|
||||
log.debug("MedicalCategoryController searchProductList START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = diviProductService.searchProductList(paramMap);
|
||||
} catch (Exception e) {
|
||||
log.error("searchProductList : ", e);
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||
}
|
||||
log.debug("MedicalCategoryController searchProductList END");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.madeu.crm.settings.medicalcategory.mapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface MedicalDiviProductMapper {
|
||||
|
||||
/**
|
||||
* 특정 카테고리(divi_pid)에 연결된 약품 리스트 조회
|
||||
*
|
||||
* @param paramMap (diviPid, storePid)
|
||||
* @return 약품 리스트
|
||||
*/
|
||||
List<Map<String, Object>> getDiviProductList(HashMap<String, Object> paramMap);
|
||||
|
||||
/**
|
||||
* 약품 등록
|
||||
*
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
int insertDiviProduct(HashMap<String, Object> paramMap);
|
||||
|
||||
/**
|
||||
* 약품 수정
|
||||
*
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
int updateDiviProduct(HashMap<String, Object> paramMap);
|
||||
|
||||
/**
|
||||
* 약품 삭제 (논리 삭제)
|
||||
*
|
||||
* @param paramMap (pid)
|
||||
* @return
|
||||
*/
|
||||
int deleteDiviProduct(HashMap<String, Object> paramMap);
|
||||
|
||||
/**
|
||||
* 제품(약품) 목록 검색 (MU_PRODUCT 기준)
|
||||
*
|
||||
* @param paramMap (keyword)
|
||||
* @return 제품 리스트
|
||||
*/
|
||||
List<Map<String, Object>> searchProductList(HashMap<String, Object> paramMap);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.madeu.crm.settings.medicalcategory.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.madeu.constants.Constants;
|
||||
import com.madeu.crm.settings.medicalcategory.mapper.MedicalDiviProductMapper;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MedicalDiviProductService {
|
||||
|
||||
@Autowired
|
||||
private MedicalDiviProductMapper diviProductMapper;
|
||||
|
||||
/**
|
||||
* 약품 리스트 조회
|
||||
*/
|
||||
public HashMap<String, Object> getDiviProductList(HashMap<String, Object> paramMap) {
|
||||
HashMap<String, Object> returnMap = new HashMap<>();
|
||||
List<Map<String, Object>> rows = diviProductMapper.getDiviProductList(paramMap);
|
||||
returnMap.put("msgCode", Constants.OK);
|
||||
returnMap.put("rows", rows);
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 등록
|
||||
*/
|
||||
public HashMap<String, Object> insertDiviProduct(HashMap<String, Object> paramMap) throws Exception {
|
||||
HashMap<String, Object> returnMap = new HashMap<>();
|
||||
|
||||
int result = diviProductMapper.insertDiviProduct(paramMap);
|
||||
if (result > 0) {
|
||||
returnMap.put("msgCode", Constants.OK);
|
||||
returnMap.put("msgDesc", "약품이 등록되었습니다.");
|
||||
} else {
|
||||
returnMap.put("msgCode", Constants.FAIL);
|
||||
returnMap.put("msgDesc", "등록에 실패했습니다.");
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 수정
|
||||
*/
|
||||
public HashMap<String, Object> updateDiviProduct(HashMap<String, Object> paramMap) throws Exception {
|
||||
HashMap<String, Object> returnMap = new HashMap<>();
|
||||
|
||||
int result = diviProductMapper.updateDiviProduct(paramMap);
|
||||
if (result > 0) {
|
||||
returnMap.put("msgCode", Constants.OK);
|
||||
returnMap.put("msgDesc", "약품 정보가 수정되었습니다.");
|
||||
} else {
|
||||
returnMap.put("msgCode", Constants.FAIL);
|
||||
returnMap.put("msgDesc", "수정에 실패했습니다.");
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 삭제 (논리 삭제)
|
||||
*/
|
||||
public HashMap<String, Object> deleteDiviProduct(HashMap<String, Object> paramMap) throws Exception {
|
||||
HashMap<String, Object> returnMap = new HashMap<>();
|
||||
|
||||
int result = diviProductMapper.deleteDiviProduct(paramMap);
|
||||
if (result > 0) {
|
||||
returnMap.put("msgCode", Constants.OK);
|
||||
returnMap.put("msgDesc", "약품이 삭제되었습니다.");
|
||||
} else {
|
||||
returnMap.put("msgCode", Constants.FAIL);
|
||||
returnMap.put("msgDesc", "삭제에 실패했습니다.");
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 약품 일괄 저장 (등록/수정/삭제)
|
||||
*/
|
||||
public HashMap<String, Object> saveDiviProductBatch(List<HashMap<String, Object>> list) throws Exception {
|
||||
HashMap<String, Object> returnMap = new HashMap<>();
|
||||
int successCnt = 0;
|
||||
|
||||
for (HashMap<String, Object> item : list) {
|
||||
String action = (String) item.getOrDefault("_action", "");
|
||||
if ("insert".equals(action)) {
|
||||
diviProductMapper.insertDiviProduct(item);
|
||||
successCnt++;
|
||||
} else if ("update".equals(action)) {
|
||||
diviProductMapper.updateDiviProduct(item);
|
||||
successCnt++;
|
||||
} else if ("delete".equals(action)) {
|
||||
diviProductMapper.deleteDiviProduct(item);
|
||||
successCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
returnMap.put("msgCode", Constants.OK);
|
||||
returnMap.put("msgDesc", successCnt + "건이 처리되었습니다.");
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 제품(약품) 목록 검색
|
||||
*/
|
||||
public HashMap<String, Object> searchProductList(HashMap<String, Object> paramMap) {
|
||||
HashMap<String, Object> returnMap = new HashMap<>();
|
||||
List<Map<String, Object>> rows = diviProductMapper.searchProductList(paramMap);
|
||||
returnMap.put("msgCode", Constants.OK);
|
||||
returnMap.put("rows", rows);
|
||||
return returnMap;
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,10 @@
|
||||
DATE_FORMAT(a.reg_date, '%Y-%m-%d %H:%i:%s') AS reg_date,
|
||||
DATE_FORMAT(a.up_date, '%Y-%m-%d %H:%i:%s') AS up_date,
|
||||
a.store_pid,
|
||||
a.npay_use
|
||||
a.npay_use,
|
||||
ucl.code_nm AS kind_unit_nm
|
||||
FROM medical_divi_list a
|
||||
LEFT JOIN crm_code_list ucl ON ucl.grp_cd = 'UNIT_CD' AND ucl.code_cd = a.kind_unit AND ucl.store_pid = a.store_pid AND ucl.list_use = 'y'
|
||||
WHERE a.list_use = 'y'
|
||||
<if test='storePid != null and storePid != ""'>
|
||||
AND a.store_pid = #{storePid}
|
||||
@@ -79,9 +81,11 @@
|
||||
DATE_FORMAT(a.up_date, '%Y-%m-%d %H:%i:%s') AS up_date,
|
||||
a.store_pid,
|
||||
a.npay_use,
|
||||
p.divi_name AS parent_name
|
||||
p.divi_name AS parent_name,
|
||||
ucl.code_nm AS kind_unit_nm
|
||||
FROM medical_divi_list a
|
||||
LEFT JOIN medical_divi_list p ON a.divi_parent = p.pid
|
||||
LEFT JOIN crm_code_list ucl ON ucl.grp_cd = 'UNIT_CD' AND ucl.code_cd = a.kind_unit AND ucl.store_pid = a.store_pid AND ucl.list_use = 'y'
|
||||
WHERE a.pid = #{pid}
|
||||
</select>
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.madeu.crm.settings.medicalcategory.mapper.MedicalDiviProductMapper">
|
||||
|
||||
<!-- 1. 특정 카테고리(divi_pid)에 연결된 약품 리스트 조회 -->
|
||||
<select id="getDiviProductList" parameterType="java.util.HashMap" resultType="java.util.HashMap">
|
||||
SELECT a.pid,
|
||||
a.store_pid,
|
||||
a.divi_pid,
|
||||
a.product_name,
|
||||
a.product_code,
|
||||
a.volume,
|
||||
a.use_volume,
|
||||
a.unit_cd,
|
||||
IFNULL(ucl.code_nm, a.unit_nm) AS unit_nm,
|
||||
a.price,
|
||||
a.order_number,
|
||||
a.list_use,
|
||||
IFNULL(mc.COMPANY_NAME, '') AS company_name,
|
||||
IFNULL(mp.VOLUME, 0) AS stock_volume,
|
||||
IFNULL(mp.UNIT_NAME, '') AS stock_unit_nm,
|
||||
IFNULL((SELECT FORMAT(SUM(IFNULL(mss.QUANTITY,0)),1)
|
||||
FROM MU_STOCK_SUM mss
|
||||
WHERE mss.MU_PRODUCT_ID = a.product_code
|
||||
AND mss.USE_YN = 'Y'), '0') AS stock_quantity,
|
||||
DATE_FORMAT(a.reg_date, '%Y-%m-%d %H:%i:%s') AS reg_date,
|
||||
DATE_FORMAT(a.up_date, '%Y-%m-%d %H:%i:%s') AS up_date
|
||||
FROM medical_divi_product a
|
||||
LEFT JOIN crm_code_list ucl ON ucl.grp_cd = 'UNIT_CD' AND ucl.code_cd = a.unit_cd AND ucl.store_pid = a.store_pid AND ucl.list_use = 'y'
|
||||
LEFT JOIN MU_PRODUCT mp ON mp.MU_PRODUCT_ID = a.product_code AND mp.USE_YN = 'Y'
|
||||
LEFT JOIN MU_COMPANY_PRODUCT mcp ON mcp.MU_PRODUCT_ID = a.product_code
|
||||
LEFT JOIN MU_COMPANY mc ON mc.MU_COMPANY_ID = mcp.MU_COMPANY_ID
|
||||
WHERE a.list_use = 'y'
|
||||
AND a.divi_pid = #{diviPid}
|
||||
<if test='storePid != null and storePid != ""'>
|
||||
AND a.store_pid = #{storePid}
|
||||
</if>
|
||||
GROUP BY a.pid
|
||||
ORDER BY a.order_number ASC, a.pid ASC
|
||||
</select>
|
||||
|
||||
<!-- 2. 약품 등록 -->
|
||||
<insert id="insertDiviProduct" parameterType="java.util.HashMap" useGeneratedKeys="true" keyProperty="pid">
|
||||
INSERT INTO medical_divi_product (
|
||||
store_pid,
|
||||
divi_pid,
|
||||
product_name,
|
||||
product_code,
|
||||
volume,
|
||||
use_volume,
|
||||
unit_cd,
|
||||
unit_nm,
|
||||
price,
|
||||
order_number,
|
||||
list_use,
|
||||
reg_date,
|
||||
up_date
|
||||
) VALUES (
|
||||
#{storePid},
|
||||
#{diviPid},
|
||||
#{productName},
|
||||
#{productCode, jdbcType=VARCHAR},
|
||||
IFNULL(#{volume}, 0),
|
||||
IFNULL(#{useVolume}, 0),
|
||||
#{unitCd, jdbcType=VARCHAR},
|
||||
#{unitNm, jdbcType=VARCHAR},
|
||||
IFNULL(#{price}, 0),
|
||||
IFNULL(#{orderNumber}, 0),
|
||||
'y',
|
||||
NOW(),
|
||||
NOW()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 3. 약품 수정 -->
|
||||
<update id="updateDiviProduct" parameterType="java.util.HashMap">
|
||||
UPDATE medical_divi_product
|
||||
<set>
|
||||
<if test='productName != null and productName != ""'>
|
||||
product_name = #{productName},
|
||||
</if>
|
||||
<if test='productCode != null'>
|
||||
product_code = #{productCode},
|
||||
</if>
|
||||
<if test='volume != null'>
|
||||
volume = #{volume},
|
||||
</if>
|
||||
<if test='useVolume != null'>
|
||||
use_volume = #{useVolume},
|
||||
</if>
|
||||
<if test='unitCd != null'>
|
||||
unit_cd = #{unitCd},
|
||||
</if>
|
||||
<if test='unitNm != null'>
|
||||
unit_nm = #{unitNm},
|
||||
</if>
|
||||
<if test='price != null'>
|
||||
price = #{price},
|
||||
</if>
|
||||
<if test='orderNumber != null'>
|
||||
order_number = #{orderNumber},
|
||||
</if>
|
||||
up_date = NOW()
|
||||
</set>
|
||||
WHERE pid = #{pid}
|
||||
</update>
|
||||
|
||||
<!-- 4. 약품 삭제 (논리 삭제) -->
|
||||
<update id="deleteDiviProduct" parameterType="java.util.HashMap">
|
||||
UPDATE medical_divi_product
|
||||
SET list_use = 'n', up_date = NOW()
|
||||
WHERE pid = #{pid}
|
||||
</update>
|
||||
|
||||
<!-- 5. 제품(약품) 목록 검색 (MU_PRODUCT 기준) -->
|
||||
<select id="searchProductList" parameterType="java.util.HashMap" resultType="java.util.HashMap">
|
||||
SELECT MP.MU_PRODUCT_ID AS "muProductId"
|
||||
,MP.PRODUCT_NAME AS "productName"
|
||||
,MP.PRODUCT_CODE AS "productCode"
|
||||
,IFNULL(MC.COMPANY_NAME,'') AS "companyName"
|
||||
,IFNULL(MCI.CATEGORY_ITEM_NAME,'') AS "treatmentName"
|
||||
,MP.VOLUME AS "volume"
|
||||
,MP.UNIT_CODE AS "unitCode"
|
||||
,MP.UNIT_NAME AS "unitName"
|
||||
,FORMAT(IFNULL(MSS.PRICE,0),0) AS "price"
|
||||
,CASE
|
||||
WHEN FLOOR(SUM(IFNULL(MSS.QUANTITY,0))) = SUM(IFNULL(MSS.QUANTITY,0))
|
||||
THEN FORMAT(SUM(IFNULL(MSS.QUANTITY,0)),0)
|
||||
ELSE TRIM(TRAILING '0' FROM CAST(FORMAT(SUM(IFNULL(MSS.QUANTITY,0)), 2) AS CHAR))
|
||||
END AS "quantity"
|
||||
FROM MU_PRODUCT AS MP
|
||||
LEFT JOIN MU_COMPANY_PRODUCT AS MCP
|
||||
ON MP.MU_PRODUCT_ID = MCP.MU_PRODUCT_ID
|
||||
LEFT JOIN MU_STOCK_SUM MSS
|
||||
ON MP.MU_PRODUCT_ID = MSS.MU_PRODUCT_ID AND MSS.USE_YN='Y'
|
||||
LEFT JOIN MU_CATEGORY_ITEM AS MCI
|
||||
ON MCI.MU_CATEGORY_ITEM_ID = MP.MU_TREATMENT_ID AND MCI.USE_YN = 'Y'
|
||||
LEFT JOIN MU_COMPANY AS MC
|
||||
ON MC.MU_COMPANY_ID = MCP.MU_COMPANY_ID
|
||||
WHERE MP.USE_YN = 'Y'
|
||||
<if test='keyword != null and keyword != ""'>
|
||||
AND MP.PRODUCT_NAME LIKE CONCAT('%', TRIM(#{keyword}), '%')
|
||||
</if>
|
||||
GROUP BY MP.MU_PRODUCT_ID
|
||||
ORDER BY MCI.CATEGORY_ITEM_NAME ASC, MP.PRODUCT_NAME ASC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
1
src/main/resources/static/image/web/settings_36px.svg
Normal file
1
src/main/resources/static/image/web/settings_36px.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="40px" viewBox="0 -960 960 960" width="40px" fill="#1f1f1f"><path d="m382-80-18.67-126.67q-17-6.33-34.83-16.66-17.83-10.34-32.17-21.67L178-192.33 79.33-365l106.34-78.67q-1.67-8.33-2-18.16-.34-9.84-.34-18.17 0-8.33.34-18.17.33-9.83 2-18.16L79.33-595 178-767.67 296.33-715q14.34-11.33 32.34-21.67 18-10.33 34.66-16L382-880h196l18.67 126.67q17 6.33 35.16 16.33 18.17 10 31.84 22L782-767.67 880.67-595l-106.34 77.33q1.67 9 2 18.84.34 9.83.34 18.83 0 9-.34 18.5Q776-452 774-443l106.33 78-98.66 172.67-118-52.67q-14.34 11.33-32 22-17.67 10.67-35 16.33L578-80H382Zm55.33-66.67h85l14-110q32.34-8 60.84-24.5T649-321l103.67 44.33 39.66-70.66L701-415q4.33-16 6.67-32.17Q710-463.33 710-480q0-16.67-2-32.83-2-16.17-7-32.17l91.33-67.67-39.66-70.66L649-638.67q-22.67-25-50.83-41.83-28.17-16.83-61.84-22.83l-13.66-110h-85l-14 110q-33 7.33-61.5 23.83T311-639l-103.67-44.33-39.66 70.66L259-545.33Q254.67-529 252.33-513 250-497 250-480q0 16.67 2.33 32.67 2.34 16 6.67 32.33l-91.33 67.67 39.66 70.66L311-321.33q23.33 23.66 51.83 40.16 28.5 16.5 60.84 24.5l13.66 110Zm43.34-200q55.33 0 94.33-39T614-480q0-55.33-39-94.33t-94.33-39q-55.67 0-94.5 39-38.84 39-38.84 94.33t38.84 94.33q38.83 39 94.5 39ZM480-480Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -598,7 +598,8 @@ $(document).ready(function () {
|
||||
let height = 300; // Depth 2, 3, 5는 기본 300px
|
||||
|
||||
if (diviDept == 4) {
|
||||
height = 500; // Depth 4 (용량/출력)는 입력 필드가 많아 500px
|
||||
width = 780; // 약품 관리 그리드 포함으로 넓힘
|
||||
height = 700; // Depth 4 (용량/출력 + 약품 관리)
|
||||
}
|
||||
|
||||
let left = (screen.width - width) / 2;
|
||||
@@ -651,7 +652,13 @@ $(document).ready(function () {
|
||||
{ title: "깊이", field: "divi_dept", width: "4%", hozAlign: "center", editor: "number", editorParams: { min: 1, max: 5, step: 1 } },
|
||||
{ title: "단가", field: "kind_cost", width: "10%", formatter: costFormatter, hozAlign: "right", editor: "number" },
|
||||
{ title: "할인가", field: "dc_cost", width: "10%", formatter: costFormatter, hozAlign: "right", editor: "number" },
|
||||
{ title: "단위", field: "kind_unit", width: "8%", hozAlign: "center", editor: "input" },
|
||||
{
|
||||
title: "단위", field: "kind_unit_nm", width: "8%", hozAlign: "center",
|
||||
formatter: function (cell) {
|
||||
var data = cell.getRow().getData();
|
||||
return data.kind_unit_nm || data.kind_unit || '';
|
||||
}
|
||||
},
|
||||
{ title: "사용여부", field: "list_use", width: "6%", formatter: ynFormatter, hozAlign: "center", editor: "list", editorParams: { values: { "y": "Y", "n": "N" } } },
|
||||
{ title: "면세여부", field: "tax_free", width: "6%", formatter: ynFormatter, hozAlign: "center", editor: "list", editorParams: { values: { "y": "Y", "n": "N" } } }
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 카테고리 Depth 4 팝업 스크립트
|
||||
* 카테고리 Depth 4 팝업 스크립트 (약품 관리 그리드 포함)
|
||||
*/
|
||||
$(document).ready(function () {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
@@ -9,10 +9,16 @@ $(document).ready(function () {
|
||||
const diviParent = params.get('diviParent');
|
||||
const parentName = params.get('parentName');
|
||||
|
||||
var productTable = null; // Tabulator 인스턴스
|
||||
var searchResultTable = null; // 검색결과 Tabulator 인스턴스
|
||||
var unitCodeCache = []; // 단위 코드 캐시
|
||||
|
||||
loadUnitCodes(null, function () {
|
||||
initForm();
|
||||
});
|
||||
bindEvents();
|
||||
|
||||
// 금액 포맷팅 함수
|
||||
// ====== 금액 포맷팅 ======
|
||||
function formatNumber(num) {
|
||||
if (!num) return '0';
|
||||
return num.toString().replace(/[^0-9]/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
@@ -23,12 +29,61 @@ $(document).ready(function () {
|
||||
return parseFloat(str.toString().replace(/,/g, '')) || 0;
|
||||
}
|
||||
|
||||
// ====== 공통코드 단위 로드 ======
|
||||
function loadUnitCodes(selectedVal, callback) {
|
||||
$.ajax({
|
||||
url: '/settings/code/getCodeList.do',
|
||||
type: 'POST',
|
||||
data: { grpCd: 'UNIT_CD', storePid: '1' },
|
||||
success: function (res) {
|
||||
if (res.msgCode === '0' && res.rows) {
|
||||
unitCodeCache = res.rows;
|
||||
|
||||
// 메인 단위 셀렉트 세팅
|
||||
var $sel = $('#kindUnit');
|
||||
$sel.find('option:not(:first)').remove();
|
||||
|
||||
$.each(res.rows, function (i, item) {
|
||||
$sel.append('<option value="' + item.code_cd + '">' + item.code_nm + '</option>');
|
||||
});
|
||||
|
||||
if (selectedVal) {
|
||||
$sel.val(selectedVal);
|
||||
}
|
||||
}
|
||||
if (typeof callback === 'function') callback();
|
||||
},
|
||||
error: function () {
|
||||
console.error('단위 코드 목록 로드 실패');
|
||||
if (typeof callback === 'function') callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 단위코드 → 단위명 변환 헬퍼
|
||||
function getUnitName(unitCd) {
|
||||
if (!unitCd) return '';
|
||||
for (var i = 0; i < unitCodeCache.length; i++) {
|
||||
if (unitCodeCache[i].code_cd === unitCd) return unitCodeCache[i].code_nm;
|
||||
}
|
||||
return unitCd;
|
||||
}
|
||||
|
||||
// ====== 폼 초기화 ======
|
||||
function initForm() {
|
||||
if (mode === 'add') {
|
||||
$("#popTitle").text('용량/출력 신규 등록');
|
||||
$("#pid").val('');
|
||||
$("#diviParent").val(diviParent);
|
||||
$("#btn_delete").hide();
|
||||
$("#productSection").show();
|
||||
$("#btn_add_product").prop('disabled', true).css('opacity', '0.5');
|
||||
initProductGrid();
|
||||
// 저장 전 안내 placeholder
|
||||
if (productTable) {
|
||||
productTable.options.placeholder = "카테고리 저장 후 약품을 추가할 수 있습니다.";
|
||||
productTable.setData([]);
|
||||
}
|
||||
|
||||
if (diviParent !== '0' && parentName) {
|
||||
$("#parentNameRow").show();
|
||||
@@ -38,10 +93,13 @@ $(document).ready(function () {
|
||||
$("#popTitle").text('용량/출력 정보 수정');
|
||||
$("#pid").val(pid);
|
||||
$("#btn_delete").show();
|
||||
$("#productSection").show();
|
||||
loadDetail(pid);
|
||||
initProductGrid();
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 상세 정보 로드 ======
|
||||
function loadDetail(id) {
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/getMedicalCategory.do',
|
||||
@@ -55,13 +113,12 @@ $(document).ready(function () {
|
||||
$("#diviSort").val(data.divi_sort);
|
||||
$("#diviColor").val(data.divi_color || '#000000');
|
||||
|
||||
// 단가/제품 정보 (복구)
|
||||
$("#kindCost").val(formatNumber(data.kind_cost));
|
||||
$("#dcCost").val(formatNumber(data.dc_cost));
|
||||
$("#kindUnit").val(data.kind_unit || '');
|
||||
$("#kindUnitVol").val(data.kind_unit_vol || 0);
|
||||
|
||||
// 상위 카테고리 명칭 표시 (Edit 모드)
|
||||
loadUnitCodes(data.kind_unit || '');
|
||||
|
||||
if (data.parent_name) {
|
||||
$("#parentNameRow").show();
|
||||
$("#parentNameTxt").text(data.parent_name);
|
||||
@@ -81,6 +138,274 @@ $(document).ready(function () {
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 약품 그리드 초기화 ======
|
||||
function initProductGrid() {
|
||||
// 단위코드 셀렉트용 values 생성 (배열: 정렬 보장)
|
||||
var unitValuesMap = {};
|
||||
unitValuesMap[''] = '선택';
|
||||
|
||||
// code_cd 오름차순 정렬
|
||||
var sortedUnits = unitCodeCache.slice().sort(function (a, b) {
|
||||
return (a.code_cd || '').localeCompare(b.code_cd || '');
|
||||
});
|
||||
|
||||
var unitSelectValues = [{ label: '선택', value: '' }];
|
||||
for (var i = 0; i < sortedUnits.length; i++) {
|
||||
unitSelectValues.push({ label: sortedUnits[i].code_nm, value: sortedUnits[i].code_cd });
|
||||
unitValuesMap[sortedUnits[i].code_cd] = sortedUnits[i].code_nm;
|
||||
}
|
||||
|
||||
productTable = new Tabulator("#productGrid", {
|
||||
layout: "fitColumns",
|
||||
placeholder: "등록된 약품이 없습니다.",
|
||||
height: "200px",
|
||||
columnDefaults: {
|
||||
headerHozAlign: "center",
|
||||
headerSort: false,
|
||||
tooltip: true
|
||||
},
|
||||
columns: [
|
||||
{ title: "거래처", field: "company_name", width: 90, hozAlign: "center" },
|
||||
{ title: "약품명", field: "product_name", minWidth: 120 },
|
||||
{
|
||||
title: "재고", field: "stock_quantity", width: 65, hozAlign: "right"
|
||||
},
|
||||
{ title: "재고단위", field: "stock_unit_nm", width: 70, hozAlign: "center" },
|
||||
{
|
||||
title: "사용량", field: "use_volume", width: 70, hozAlign: "right",
|
||||
editor: "number",
|
||||
editorParams: { step: 0.1, min: 0 },
|
||||
formatter: function (cell) {
|
||||
var v = cell.getValue();
|
||||
return (v && Number(v) > 0) ? Number(v).toFixed(1) : '0';
|
||||
},
|
||||
cssClass: "editable-cell"
|
||||
},
|
||||
{
|
||||
title: "사용단위", field: "unit_cd", width: 80, hozAlign: "center",
|
||||
editor: "list",
|
||||
editorParams: { values: unitSelectValues, defaultValue: '' },
|
||||
formatter: function (cell) {
|
||||
var val = cell.getValue();
|
||||
if (!val || val === '') return '선택';
|
||||
if (unitValuesMap[val]) return unitValuesMap[val];
|
||||
// CRM 코드에 없으면 unit_nm(단위명) 표시
|
||||
var rowData = cell.getRow().getData();
|
||||
return rowData.unit_nm || '선택';
|
||||
},
|
||||
cssClass: "editable-cell"
|
||||
},
|
||||
{
|
||||
title: "삭제", width: 45, hozAlign: "center",
|
||||
formatter: function () {
|
||||
return '<span style="color:#ff4444; cursor:pointer; font-weight:600;">✕</span>';
|
||||
},
|
||||
cellClick: function (e, cell) {
|
||||
e.stopPropagation();
|
||||
var data = cell.getRow().getData();
|
||||
if (!confirm("'" + data.product_name + "' 약품을 삭제하시겠습니까?")) return;
|
||||
deleteProduct(data.pid, cell.getRow());
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 셀 수정 시 자동 저장
|
||||
productTable.on("cellEdited", function (cell) {
|
||||
var data = cell.getRow().getData();
|
||||
var field = cell.getField();
|
||||
|
||||
var updateObj = { pid: data.pid };
|
||||
|
||||
if (field === 'use_volume') {
|
||||
updateObj.useVolume = parseFloat(data.use_volume || 0);
|
||||
} else if (field === 'unit_cd') {
|
||||
updateObj.unitCd = data.unit_cd || '';
|
||||
updateObj.unitNm = getUnitName(data.unit_cd);
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/modDiviProduct.do',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(updateObj),
|
||||
success: function (res) {
|
||||
if (res.msgCode !== '0') {
|
||||
alert(res.msgDesc || "수정에 실패했습니다.");
|
||||
loadProductList();
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("수정 중 오류가 발생했습니다.");
|
||||
loadProductList();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 그리드 데이터 로드
|
||||
loadProductList();
|
||||
}
|
||||
|
||||
// ====== 약품 리스트 로드 ======
|
||||
function loadProductList() {
|
||||
if (!pid) return;
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/getDiviProductList.do',
|
||||
type: 'POST',
|
||||
data: { diviPid: pid, storePid: '1' },
|
||||
success: function (res) {
|
||||
if (res.msgCode === '0' && productTable) {
|
||||
productTable.setData(res.rows || []);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
console.error('약품 리스트 로드 실패');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 약품 등록 (검색 팝업에서 선택 시 호출) ======
|
||||
function selectAndAddProduct(productData) {
|
||||
if (!productData) return;
|
||||
|
||||
var submitObj = {
|
||||
storePid: $("#storePid").val(),
|
||||
diviPid: pid,
|
||||
productName: productData.productName || '',
|
||||
productCode: productData.muProductId || '',
|
||||
volume: parseFloat(productData.volume || '0'),
|
||||
useVolume: 0,
|
||||
unitCd: null,
|
||||
unitNm: null,
|
||||
price: parseInt((productData.price || '0').toString().replace(/,/g, ''), 10),
|
||||
orderNumber: 0
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/putDiviProduct.do',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(submitObj),
|
||||
success: function (res) {
|
||||
if (res.msgCode === '0') {
|
||||
loadProductList();
|
||||
closeProductSearchPopup();
|
||||
} else {
|
||||
alert(res.msgDesc || "등록에 실패했습니다.");
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("약품 등록 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 약품 삭제 ======
|
||||
function deleteProduct(productPid, row) {
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/delDiviProduct.do',
|
||||
type: 'POST',
|
||||
data: { pid: productPid },
|
||||
success: function (res) {
|
||||
if (res.msgCode === '0') {
|
||||
loadProductList();
|
||||
} else {
|
||||
alert(res.msgDesc || "삭제에 실패했습니다.");
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("약품 삭제 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 제품 검색 팝업 열기 ======
|
||||
function openProductSearchPopup() {
|
||||
$("#searchProductKeyword").val('');
|
||||
$("#productSearchOverlay").addClass('active');
|
||||
initSearchResultGrid();
|
||||
// 팝업 열릴 때 전체 목록 바로 조회
|
||||
searchProducts();
|
||||
setTimeout(function () {
|
||||
$("#searchProductKeyword").focus();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// ====== 제품 검색 팝업 닫기 ======
|
||||
function closeProductSearchPopup() {
|
||||
$("#productSearchOverlay").removeClass('active');
|
||||
}
|
||||
|
||||
// ====== 검색 결과 그리드 초기화 ======
|
||||
function initSearchResultGrid() {
|
||||
if (searchResultTable) return; // 이미 초기화됨
|
||||
|
||||
searchResultTable = new Tabulator("#searchResultGrid", {
|
||||
layout: "fitColumns",
|
||||
placeholder: "검색 결과가 없습니다.",
|
||||
height: "300px",
|
||||
columnDefaults: {
|
||||
headerHozAlign: "center",
|
||||
headerSort: true,
|
||||
tooltip: true
|
||||
},
|
||||
columns: [
|
||||
{ title: "No", formatter: "rownum", width: 35, hozAlign: "center", headerSort: false },
|
||||
{ title: "재고구분", field: "treatmentName", width: 90, hozAlign: "center" },
|
||||
{ title: "거래처", field: "companyName", width: 100 },
|
||||
{
|
||||
title: "제품명", field: "productName", minWidth: 140,
|
||||
formatter: function (cell) {
|
||||
return '<span style="color:#3985EA; cursor:pointer; font-weight:600;">' + (cell.getValue() || '') + '</span>';
|
||||
},
|
||||
cellClick: function (e, cell) {
|
||||
e.stopPropagation();
|
||||
var data = cell.getRow().getData();
|
||||
if (confirm("'" + data.productName + "' 제품을 약품으로 추가하시겠습니까?")) {
|
||||
selectAndAddProduct(data);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "용량", field: "volume", width: 60, hozAlign: "right",
|
||||
formatter: function (cell) {
|
||||
var v = cell.getValue();
|
||||
return (v && Number(v) > 0) ? Number(v).toFixed(1) : '';
|
||||
}
|
||||
},
|
||||
{ title: "단위", field: "unitName", width: 55, hozAlign: "center" },
|
||||
{
|
||||
title: "단가(원)", field: "price", width: 80, hozAlign: "right"
|
||||
},
|
||||
{
|
||||
title: "재고", field: "quantity", width: 60, hozAlign: "right"
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 제품 검색 실행 ======
|
||||
function searchProducts() {
|
||||
var keyword = $.trim($("#searchProductKeyword").val());
|
||||
|
||||
$.ajax({
|
||||
url: '/settings/medicalCategory/searchProductList.do',
|
||||
type: 'POST',
|
||||
data: { keyword: keyword },
|
||||
success: function (res) {
|
||||
if (res.msgCode === '0' && searchResultTable) {
|
||||
searchResultTable.setData(res.rows || []);
|
||||
} else {
|
||||
if (searchResultTable) searchResultTable.setData([]);
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("제품 검색 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 이벤트 바인딩 ======
|
||||
function bindEvents() {
|
||||
$("#btn_close").on("click", function () {
|
||||
window.close();
|
||||
@@ -94,12 +419,41 @@ $(document).ready(function () {
|
||||
deleteCategory();
|
||||
});
|
||||
|
||||
// 금액 콤마 자동 입력 이벤트
|
||||
// 금액 콤마 자동 입력
|
||||
$("#kindCost, #dcCost").on("keyup", function () {
|
||||
$(this).val(formatNumber($(this).val()));
|
||||
});
|
||||
|
||||
// 약품 추가 (검색 팝업 열기)
|
||||
$("#btn_add_product").on("click", function () {
|
||||
openProductSearchPopup();
|
||||
});
|
||||
|
||||
// 검색 팝업 닫기
|
||||
$("#btn_close_search").on("click", function () {
|
||||
closeProductSearchPopup();
|
||||
});
|
||||
|
||||
// 오버레이 클릭 시 닫기
|
||||
$("#productSearchOverlay").on("click", function (e) {
|
||||
if (e.target === this) closeProductSearchPopup();
|
||||
});
|
||||
|
||||
// 검색 버튼
|
||||
$("#btn_search_product").on("click", function () {
|
||||
searchProducts();
|
||||
});
|
||||
|
||||
// 검색 Enter 키
|
||||
$("#searchProductKeyword").on("keydown", function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
searchProducts();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 카테고리 저장 ======
|
||||
function saveCategory() {
|
||||
const dName = $("#diviName").val().trim();
|
||||
if (!dName) {
|
||||
@@ -112,12 +466,10 @@ $(document).ready(function () {
|
||||
pid: $("#pid").val() || null,
|
||||
storePid: $("#storePid").val(),
|
||||
diviName: dName,
|
||||
diviDept: $("#diviDept").val(), // hidden = 4
|
||||
diviDept: $("#diviDept").val(),
|
||||
diviParent: $("#diviParent").val(),
|
||||
diviSort: parseInt($("#diviSort").val() || "0", 10),
|
||||
diviColor: $("#diviColor").val(),
|
||||
|
||||
// 단가/제품 정보 (복구 및 포맷팅 처리)
|
||||
kindCost: unformatNumber($("#kindCost").val()),
|
||||
dcCost: unformatNumber($("#dcCost").val()),
|
||||
kindUnit: $("#kindUnit").val(),
|
||||
@@ -137,8 +489,17 @@ $(document).ready(function () {
|
||||
if (window.opener && typeof window.opener.loadData === 'function') {
|
||||
window.opener.loadData(true);
|
||||
}
|
||||
// 신규 등록 후 수정 모드로 전환하여 약품 관리 가능하게
|
||||
if (mode === 'add' && res.pid) {
|
||||
window.location.href = window.location.pathname +
|
||||
'?mode=edit&pid=' + res.pid +
|
||||
'&diviDept=' + diviDept +
|
||||
'&diviParent=' + diviParent +
|
||||
'&parentName=' + encodeURIComponent(parentName || '');
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
alert("저장 중 시스템 오류가 발생했습니다.");
|
||||
@@ -146,6 +507,7 @@ $(document).ready(function () {
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 카테고리 삭제 ======
|
||||
function deleteCategory() {
|
||||
const pidVal = $("#pid").val();
|
||||
if (!pidVal) return;
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<head>
|
||||
<title>진료유형 정보</title>
|
||||
<link rel="stylesheet" th:href="@{/css/common.css}">
|
||||
<link rel="stylesheet" href="https://unpkg.com/tabulator-tables@5.6.1/dist/css/tabulator.min.css">
|
||||
<script th:src="@{/js/web/jquery.min.js}"></script>
|
||||
<script src="https://unpkg.com/tabulator-tables@5.6.1/dist/js/tabulator.min.js"></script>
|
||||
<style>
|
||||
.pop_wrap {
|
||||
max-width: 600px;
|
||||
max-width: 750px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@@ -137,6 +139,148 @@
|
||||
padding: 8px 0 4px 0;
|
||||
border-bottom: 1px solid #e9ecf0;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.section-title .btn_sm {
|
||||
padding: 3px 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
background: #3985EA;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.section-title .btn_sm:hover {
|
||||
background: #2c6fd1;
|
||||
}
|
||||
|
||||
/* 약품 그리드 영역 */
|
||||
#productGridWrap {
|
||||
margin-top: 8px;
|
||||
border: 1px solid #e9ecf0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#productGrid {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 편집 가능한 셀 스타일 */
|
||||
.editable-cell {
|
||||
background-color: #f0f7ff !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.editable-cell:hover {
|
||||
background-color: #e0efff !important;
|
||||
}
|
||||
|
||||
.no-product-msg {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* ===== 제품 검색 레이어팝업 ===== */
|
||||
.search-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
z-index: 9999;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-overlay.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.search-popup {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
|
||||
width: 680px;
|
||||
max-height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.search-popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 14px 18px;
|
||||
background: #3985EA;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.search-popup-header h4 {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.search-popup-header .popup-close {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.search-popup-body {
|
||||
padding: 14px 18px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.search-input-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.search-input-row input {
|
||||
flex: 1;
|
||||
height: 34px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 0 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.search-input-row button {
|
||||
padding: 0 18px;
|
||||
height: 34px;
|
||||
background: #3985EA;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.search-input-row button:hover {
|
||||
background: #2c6fd1;
|
||||
}
|
||||
|
||||
#searchResultGrid {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -176,7 +320,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 용량/출력 정보 (Depth 4 전용) 복구 -->
|
||||
<!-- 용량/출력 정보 (Depth 4 전용) -->
|
||||
<div class="section-title">용량/출력 정보</div>
|
||||
<table class="board_write">
|
||||
<colgroup>
|
||||
@@ -202,19 +346,43 @@
|
||||
<input type="number" id="kindUnitVol" class="w120" value="0" step="0.1" placeholder="용량">
|
||||
<select id="kindUnit" style="width: 100px; margin-left: 5px;">
|
||||
<option value="">선택</option>
|
||||
<!-- 추후 공통코드 연동을 통해 데이터 바인딩 -->
|
||||
<option value="CC">CC</option>
|
||||
<option value="ML">ML</option>
|
||||
<option value="샷">샷</option>
|
||||
<option value="회">회</option>
|
||||
<option value="V">V</option>
|
||||
<option value="줄">줄</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 약품 관리 (재고관리용) - 수정 모드에서만 표시 -->
|
||||
<div id="productSection" style="display:none;">
|
||||
<div class="section-title">
|
||||
<span>사용 약품 관리 (재고관리)</span>
|
||||
<button type="button" class="btn_sm" id="btn_add_product">+ 약품 추가 (검색)</button>
|
||||
</div>
|
||||
|
||||
<!-- 약품 그리드 -->
|
||||
<div id="productGridWrap">
|
||||
<div id="productGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== 제품 검색 레이어 팝업 ===== -->
|
||||
<div id="productSearchOverlay" class="search-overlay">
|
||||
<div class="search-popup">
|
||||
<div class="search-popup-header">
|
||||
<h4>약품(제품) 검색</h4>
|
||||
<button type="button" class="popup-close" id="btn_close_search">×</button>
|
||||
</div>
|
||||
<div class="search-popup-body">
|
||||
<div class="search-input-row">
|
||||
<input type="text" id="searchProductKeyword" placeholder="제품명을 입력하세요">
|
||||
<button type="button" id="btn_search_product">검색</button>
|
||||
</div>
|
||||
<div id="searchResultGrid"></div>
|
||||
<p style="margin-top:8px; font-size:11px; color:#999;">* 제품명을 클릭하면 약품이 자동 추가됩니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pop_btn_area">
|
||||
<button type="button" class="btn_blue" id="btn_save">저장</button>
|
||||
<button type="button" class="btn_red" id="btn_delete" style="display:none;">삭제</button>
|
||||
|
||||
Reference in New Issue
Block a user