관련사이트 이미지 드래그앤드롭 업로드, 직접선택 업로드, 미리보기
parent
ce748c7ec1
commit
5f0bed4df0
|
|
@ -332,4 +332,79 @@ select::-ms-expand {display:none;}
|
||||||
|
|
||||||
.recharts-legend-item-text {
|
.recharts-legend-item-text {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.uploadIcon {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file::file-selector-button {
|
||||||
|
font-size: 14px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #111;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 4px 32px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview {
|
||||||
|
width: 400px;
|
||||||
|
height: 350px;
|
||||||
|
margin: auto;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 3px dashed #eee;
|
||||||
|
padding: 70px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview_image {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview:hover {
|
||||||
|
border-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview_msg {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 18px;
|
||||||
|
margin: 20px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview_desc {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview_info {
|
||||||
|
width: 100%;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
gap: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview_info .info_key {
|
||||||
|
display: block;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview_info .info_value {
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ function AboutSiteModal({props, reloadFunction}) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const checkRef = useRef([]);
|
const checkRef = useRef([]);
|
||||||
|
const fileInputRef = useRef(null);
|
||||||
|
|
||||||
console.log("AboutSiteModal [location] : ", location);
|
console.log("AboutSiteModal [location] : ", location);
|
||||||
|
|
||||||
|
|
@ -32,7 +33,18 @@ function AboutSiteModal({props, reloadFunction}) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initMode();
|
initMode();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
const fileDOM = document.querySelector('#file');
|
||||||
|
const preview = document.querySelector('.preview');
|
||||||
|
|
||||||
|
if(fileDOM) {
|
||||||
|
fileDOM.addEventListener('change', () => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = ({target}) => {
|
||||||
|
preview.src = target.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(fileDOM.files[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const initMode = () => {
|
const initMode = () => {
|
||||||
|
|
@ -45,24 +57,22 @@ function AboutSiteModal({props, reloadFunction}) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const form = e.target;
|
const form = e.target;
|
||||||
const info = {
|
const formData = new FormData(form); // 새 FormData 객체 생성
|
||||||
siteTitle: form.siteTitle.value,
|
|
||||||
siteUrl: form.siteUrl.value,
|
// FormData 객체에 파일 데이터 추가
|
||||||
fileGrpId: form.fileGrpId.value,
|
console.log("@@@ current : " + fileInputRef.current);
|
||||||
siteOrder: form.siteOrder.value,
|
console.log("@@@ file : " + fileInputRef.current.files[0]);
|
||||||
useYn: form.useYn.value
|
formData.append('file', currentFile);
|
||||||
}
|
formData.append('fileGrpId', props.fileGrpId);
|
||||||
|
|
||||||
if (modeInfo.mode === CODE.MODE_MODIFY) {
|
if (modeInfo.mode === CODE.MODE_MODIFY) {
|
||||||
info.siteSeq = props.siteSeq;
|
formData.append('siteSeq', props.siteSeq); // 수정 모드일 때 필요한 추가 정보 추가
|
||||||
}
|
}
|
||||||
EgovNet.requestFetch(
|
EgovNet.requestFetch(
|
||||||
'/admin/config/partner-site-mgt',
|
'/admin/config/partner-site-mgt',
|
||||||
{
|
{
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
body: formData
|
||||||
'Content-type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(info)
|
|
||||||
},
|
},
|
||||||
(resp) => {
|
(resp) => {
|
||||||
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
|
if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) {
|
||||||
|
|
@ -102,6 +112,100 @@ function AboutSiteModal({props, reloadFunction}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Logo = () => (
|
||||||
|
<svg className="uploadIcon" x="0px" y="0px" viewBox="0 0 24 24">
|
||||||
|
<path fill="transparent" d="M0,0h24v24H0V0z"/>
|
||||||
|
<path fill="#000" d="M20.5,5.2l-1.4-1.7C18.9,3.2,18.5,3,18,3H6C5.5,3,5.1,3.2,4.8,3.5L3.5,5.2C3.2,5.6,3,6,3,6.5V19 c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V6.5C21,6,20.8,5.6,20.5,5.2z M12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5z M5.1,5l0.8-1h12l0.9,1 H5.1z"/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const [currentFile, setCurrentFile] = useState(null);
|
||||||
|
const [uploadedInfo, setUploadedInfo] = useState(null);
|
||||||
|
const [previewImage, setPreviewImage] = useState(null);
|
||||||
|
|
||||||
|
const UploadBox = () => {
|
||||||
|
const [isActive, setActive] = useState(false);
|
||||||
|
|
||||||
|
const onDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
const onDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
const onDragOver = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
const setFileInfo = (file) => {
|
||||||
|
const { name, size: byteSize, type } = file;
|
||||||
|
const isImage = type.includes('image');
|
||||||
|
const size = (byteSize / (1024 * 1024)).toFixed(2) + 'mb';
|
||||||
|
setUploadedInfo({ name, size, type }); // name, size, type 정보를 uploadedInfo에 저장
|
||||||
|
|
||||||
|
if (!isImage) {
|
||||||
|
setUploadedInfo({ name, size, type });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = () => {
|
||||||
|
setPreviewImage(reader.result);
|
||||||
|
setUploadedInfo({ name, size, type, imageUrl: String(reader.result) });
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDrop = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setActive(false);
|
||||||
|
|
||||||
|
const droppedFile = e.dataTransfer.files[0];
|
||||||
|
console.log("@@@ handleDrop file : " + droppedFile);
|
||||||
|
if (droppedFile.type.startsWith('image/')) {
|
||||||
|
setCurrentFile(droppedFile);
|
||||||
|
setFileInfo(droppedFile);
|
||||||
|
} else {
|
||||||
|
// 이미지 파일이 아닌 경우에 대한 처리
|
||||||
|
alert('이미지 파일만 업로드할 수 있습니다.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpload = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
console.log("@@@ handleUpload file : " + file);
|
||||||
|
if (file.type.startsWith('image/')) {
|
||||||
|
setCurrentFile(file);
|
||||||
|
setFileInfo(file);
|
||||||
|
} else {
|
||||||
|
// 이미지 파일이 아닌 경우에 대한 처리
|
||||||
|
alert('이미지 파일만 업로드할 수 있습니다.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
className={`preview${isActive ? ' active' : ''}`}
|
||||||
|
onDragEnter={onDragEnter}
|
||||||
|
onDragOver={onDragOver}
|
||||||
|
onDragLeave={onDragLeave}
|
||||||
|
onDrop={onDrop}
|
||||||
|
>
|
||||||
|
<input type="file" className="file" onChange={handleUpload} ref={fileInputRef} />
|
||||||
|
{previewImage && <img src={previewImage} alt="Preview Image" className="preview_image" />}
|
||||||
|
{!uploadedInfo && (
|
||||||
|
<>
|
||||||
|
<Logo />
|
||||||
|
<p className="preview_msg">클릭 혹은 파일을 이곳에 드롭하세요.</p>
|
||||||
|
<p className="preview_desc">파일당 최대 3MB</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
console.log("------------------------------AboutSiteModal [End]");
|
console.log("------------------------------AboutSiteModal [End]");
|
||||||
console.groupEnd("AboutSiteModal");
|
console.groupEnd("AboutSiteModal");
|
||||||
|
|
||||||
|
|
@ -118,6 +222,7 @@ function AboutSiteModal({props, reloadFunction}) {
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
|
|
||||||
<Modal.Body>
|
<Modal.Body>
|
||||||
|
<UploadBox/>
|
||||||
<div className="board_view2">
|
<div className="board_view2">
|
||||||
<Form onSubmit={(e) => {editPartnerSite(e)}} noValidate>
|
<Form onSubmit={(e) => {editPartnerSite(e)}} noValidate>
|
||||||
<dl>
|
<dl>
|
||||||
|
|
@ -134,13 +239,6 @@ function AboutSiteModal({props, reloadFunction}) {
|
||||||
defaultValue={props?.siteUrl}/>
|
defaultValue={props?.siteUrl}/>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
|
||||||
<dt><label htmlFor="fileGrpId">배너이미지</label><span className="req">필수</span></dt>
|
|
||||||
<dd>
|
|
||||||
<Form.Control className="f_txtar w_full" type="text" name="fileGrpId" placeholder="배너이미지" required
|
|
||||||
defaultValue={props?.fileGrpId}/>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt><label htmlFor="siteOrder">정렬순서</label><span className="req">필수</span></dt>
|
<dt><label htmlFor="siteOrder">정렬순서</label><span className="req">필수</span></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.validation.Errors;
|
import org.springframework.validation.Errors;
|
||||||
import org.springframework.validation.FieldError;
|
import org.springframework.validation.FieldError;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
@ -516,7 +517,12 @@ public class AdminConfigController extends BaseController {
|
||||||
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
|
@ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
|
||||||
})
|
})
|
||||||
@RequestMapping(method = RequestMethod.PUT, value = "/partner-site-mgt")
|
@RequestMapping(method = RequestMethod.PUT, value = "/partner-site-mgt")
|
||||||
public ResultVO savePartnerSite(@RequestBody @Valid TnPartnerSite tnPartnerSite, Errors errors, @AuthenticationPrincipal LoginVO user) {
|
public ResultVO savePartnerSite(
|
||||||
|
@Valid TnPartnerSite tnPartnerSite,
|
||||||
|
HttpServletRequest request,
|
||||||
|
Errors errors,
|
||||||
|
@RequestParam(required = false) MultipartFile[] file,
|
||||||
|
@AuthenticationPrincipal LoginVO user) throws Exception {
|
||||||
ResultVO resultVO = new ResultVO();
|
ResultVO resultVO = new ResultVO();
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
resultVO.setResultCode(ResponseCode.TOKEN_EXPIRED.getCode());
|
resultVO.setResultCode(ResponseCode.TOKEN_EXPIRED.getCode());
|
||||||
|
|
@ -531,7 +537,8 @@ public class AdminConfigController extends BaseController {
|
||||||
resultVO.setResultMessage(msg.toString());
|
resultVO.setResultMessage(msg.toString());
|
||||||
} else {
|
} else {
|
||||||
System.out.println("@@@ bbs.getBbsSeq() : " + tnPartnerSite.getSiteSeq());
|
System.out.println("@@@ bbs.getBbsSeq() : " + tnPartnerSite.getSiteSeq());
|
||||||
adminConfigService.savePartnerSite(tnPartnerSite, user.getId());
|
System.out.println("@@@ file : " + file);
|
||||||
|
adminConfigService.savePartnerSite(tnPartnerSite, request, user, file);
|
||||||
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
|
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,17 +8,24 @@ import com.dbnt.kcscbackend.admin.config.mapper.TcMenuMapper;
|
||||||
import com.dbnt.kcscbackend.admin.config.repository.TbMenuRoleRepository;
|
import com.dbnt.kcscbackend.admin.config.repository.TbMenuRoleRepository;
|
||||||
import com.dbnt.kcscbackend.admin.config.repository.TcMenuRepository;
|
import com.dbnt.kcscbackend.admin.config.repository.TcMenuRepository;
|
||||||
import com.dbnt.kcscbackend.admin.config.repository.TnPartnerSiteRepository;
|
import com.dbnt.kcscbackend.admin.config.repository.TnPartnerSiteRepository;
|
||||||
|
import com.dbnt.kcscbackend.auth.entity.LoginVO;
|
||||||
import com.dbnt.kcscbackend.commonCode.entity.TcCodeGrp;
|
import com.dbnt.kcscbackend.commonCode.entity.TcCodeGrp;
|
||||||
import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem;
|
import com.dbnt.kcscbackend.commonCode.entity.TcCodeItem;
|
||||||
import com.dbnt.kcscbackend.commonCode.repository.TcCodeGrpRepository;
|
import com.dbnt.kcscbackend.commonCode.repository.TcCodeGrpRepository;
|
||||||
import com.dbnt.kcscbackend.commonCode.repository.TcCodeItemRepository;
|
import com.dbnt.kcscbackend.commonCode.repository.TcCodeItemRepository;
|
||||||
|
import com.dbnt.kcscbackend.file.entity.TnAttachFile;
|
||||||
|
import com.dbnt.kcscbackend.file.service.FileService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
|
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
@ -32,6 +39,7 @@ public class AdminConfigService extends EgovAbstractServiceImpl {
|
||||||
private final TbMenuRoleRepository menuRoleRepository;
|
private final TbMenuRoleRepository menuRoleRepository;
|
||||||
private final TcMenuMapper menuMapper;
|
private final TcMenuMapper menuMapper;
|
||||||
private final TnPartnerSiteRepository tnPartnerSiteRepository;
|
private final TnPartnerSiteRepository tnPartnerSiteRepository;
|
||||||
|
private final FileService fileService;
|
||||||
|
|
||||||
public List<TcCodeGrp> selectCodeGrpList(){
|
public List<TcCodeGrp> selectCodeGrpList(){
|
||||||
return codeGrpRepository.findByUseYn("Y");
|
return codeGrpRepository.findByUseYn("Y");
|
||||||
|
|
@ -175,17 +183,47 @@ public class AdminConfigService extends EgovAbstractServiceImpl {
|
||||||
return tnPartnerSiteRepository.findAllByOrderBySiteOrder();
|
return tnPartnerSiteRepository.findAllByOrderBySiteOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
/**
|
||||||
public void savePartnerSite(TnPartnerSite tnPartnerSite, String userId) {
|
* 파일이 저장될 중간 경로를 생성한다.
|
||||||
|
* D:/kcscUploadFiles/XXXX/abc.jpg XXXX에 해당하는 경로다.
|
||||||
|
*
|
||||||
|
* @return 중간 경로
|
||||||
|
*/
|
||||||
|
private String getMiddlePath() {
|
||||||
|
//파일이 저장될 경로를 생성한다.
|
||||||
|
String domainPath = "partnerSite";
|
||||||
|
Date nowDate = new Date();
|
||||||
|
String strNowYyyy = new SimpleDateFormat("yyyy").format(nowDate);
|
||||||
|
String strNowYyyyMmdd = new SimpleDateFormat("yyyyMMdd").format(nowDate);
|
||||||
|
String middlePath = domainPath + "/" + strNowYyyy + "/" + strNowYyyyMmdd + "/";
|
||||||
|
|
||||||
|
return middlePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void savePartnerSite(TnPartnerSite tnPartnerSite, HttpServletRequest request, LoginVO user, MultipartFile[] file) throws Exception {
|
||||||
if (tnPartnerSite.getSiteSeq() == null) {
|
if (tnPartnerSite.getSiteSeq() == null) {
|
||||||
|
String fileGrpId = fileService.addTnAttachFile(request, user, file, this.getMiddlePath());
|
||||||
|
tnPartnerSite.setFileGrpId(fileGrpId);
|
||||||
tnPartnerSiteRepository.save(tnPartnerSite);
|
tnPartnerSiteRepository.save(tnPartnerSite);
|
||||||
} else {
|
} else {
|
||||||
|
String fileGrpId = tnPartnerSite.getFileGrpId();
|
||||||
|
System.out.println("@@@ fileGrpId : " + fileGrpId);
|
||||||
|
if (file != null && file.length > 0) {
|
||||||
|
List<TnAttachFile> tnAttachFileList = fileService.findByFileGrpId(fileGrpId);
|
||||||
|
if (tnAttachFileList != null) {
|
||||||
|
for (TnAttachFile item : tnAttachFileList) {
|
||||||
|
fileService.deleteTnAttachFile(request, user, item.getFileSeq().longValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileGrpId = fileService.addTnAttachFile(request, user, file, this.getMiddlePath());
|
||||||
|
}
|
||||||
TnPartnerSite savedPartnerSite = tnPartnerSiteRepository.findById(tnPartnerSite.getSiteSeq()).orElse(null);
|
TnPartnerSite savedPartnerSite = tnPartnerSiteRepository.findById(tnPartnerSite.getSiteSeq()).orElse(null);
|
||||||
savedPartnerSite.setSiteTitle(tnPartnerSite.getSiteTitle());
|
savedPartnerSite.setSiteTitle(tnPartnerSite.getSiteTitle());
|
||||||
savedPartnerSite.setSiteUrl(tnPartnerSite.getSiteUrl());
|
savedPartnerSite.setSiteUrl(tnPartnerSite.getSiteUrl());
|
||||||
savedPartnerSite.setFileGrpId(tnPartnerSite.getFileGrpId());
|
savedPartnerSite.setFileGrpId(tnPartnerSite.getFileGrpId());
|
||||||
savedPartnerSite.setSiteOrder(tnPartnerSite.getSiteOrder());
|
savedPartnerSite.setSiteOrder(tnPartnerSite.getSiteOrder());
|
||||||
savedPartnerSite.setUseYn(tnPartnerSite.getUseYn());
|
savedPartnerSite.setUseYn(tnPartnerSite.getUseYn());
|
||||||
|
savedPartnerSite.setFileGrpId(fileGrpId);
|
||||||
tnPartnerSiteRepository.save(savedPartnerSite);
|
tnPartnerSiteRepository.save(savedPartnerSite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue