2026-02-13 contents bbs 수정
This commit is contained in:
@@ -0,0 +1,729 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<th:block layout:fragment="layout_css">
|
||||
<!-- Choices.js CSS -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.css" />
|
||||
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
margin: 0;
|
||||
background: #f7f7f9;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
#service-header {
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #ececec;
|
||||
padding: 14px 0 14px 24px;
|
||||
font-size: 0.98em;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.main-wrap {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
border-radius: 18px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.07);
|
||||
margin-top: 32px;
|
||||
padding: 0 0 32px 0;
|
||||
}
|
||||
|
||||
.top-section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 32px;
|
||||
padding: 32px 32px 0 32px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.img-box {
|
||||
border-radius: 18px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.img-box img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
flex: 1 1 300px;
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
.info-title {
|
||||
font-size: 1.7em;
|
||||
font-weight: 700;
|
||||
margin-bottom: 6px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.info-desc {
|
||||
color: #444;
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.info-price {
|
||||
font-size: 1.2em;
|
||||
font-weight: 700;
|
||||
color: #b23c3c;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.select-row {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.select-row label {
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.total-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.total-row .total-label {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.total-row .total-price {
|
||||
font-weight: bold;
|
||||
color: #b23c3c;
|
||||
}
|
||||
|
||||
.reserve-btn {
|
||||
width: 100%;
|
||||
padding: 14px 0;
|
||||
background: #b23c3c;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.reserve-btn:disabled {
|
||||
background: #ddd;
|
||||
color: #888;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.desc-section {
|
||||
margin-top: 36px;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.desc-title {
|
||||
font-size: 1.25em;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.desc-content {
|
||||
color: #444;
|
||||
font-size: 1.05em;
|
||||
line-height: 1.7;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.hashtag-section {
|
||||
margin-top: 30px;
|
||||
padding: 20px 0;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.hashtag-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.hashtag-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.hashtag {
|
||||
display: inline-block;
|
||||
background-color: #f8f9fa;
|
||||
color: #495057;
|
||||
padding: 8px 15px;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
border: 1px solid #dee2e6;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.hashtag:hover {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#thumbnail-bottom-txt {
|
||||
padding: 8px;
|
||||
margin-top: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* Choices.js 커스터마이징 - 개선된 버전 */
|
||||
.choices {
|
||||
border: 1px solid #ddd !important;
|
||||
border-radius: 6px !important;
|
||||
font-size: 1em !important;
|
||||
background: #fff !important;
|
||||
min-width: 300px !important;
|
||||
}
|
||||
|
||||
.choices__inner {
|
||||
background: #fff !important;
|
||||
padding: 8px 12px !important;
|
||||
min-height: 40px !important;
|
||||
color: #222 !important;
|
||||
min-width: 280px !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* 플레이스홀더 텍스트 잘림 방지 - 핵심 수정 */
|
||||
.choices__placeholder {
|
||||
color: #888 !important;
|
||||
opacity: 1 !important;
|
||||
width: 100% !important;
|
||||
min-width: 200px !important;
|
||||
white-space: nowrap !important;
|
||||
overflow: visible !important;
|
||||
text-overflow: clip !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.choices__input {
|
||||
color: #222 !important;
|
||||
background: transparent !important;
|
||||
min-width: 200px !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.choices__input::placeholder {
|
||||
color: #888 !important;
|
||||
opacity: 1 !important;
|
||||
width: 100% !important;
|
||||
min-width: 200px !important;
|
||||
white-space: nowrap !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
/* 다중 선택시 입력 필드 너비 확보 */
|
||||
.choices[data-type*="select-multiple"] .choices__input {
|
||||
min-width: 200px !important;
|
||||
width: auto !important;
|
||||
flex: 1 !important;
|
||||
}
|
||||
|
||||
/* 선택된 항목들과 입력 필드 공간 분배 */
|
||||
.choices__list--multiple {
|
||||
/* display: flex !important; */
|
||||
flex-wrap: wrap !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
.choices__list--multiple:empty+.choices__input {
|
||||
min-width: 200px !important;
|
||||
width: 100% !important;
|
||||
flex: 1 !important;
|
||||
}
|
||||
|
||||
/* 선택된 항목의 가격 표시 스타일 - 새로 추가 */
|
||||
.selected-item-content {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: flex-start !important;
|
||||
flex: 1 !important;
|
||||
}
|
||||
|
||||
.selected-item-name {
|
||||
font-weight: 500 !important;
|
||||
margin-bottom: 2px !important;
|
||||
}
|
||||
|
||||
.selected-item-price {
|
||||
font-size: 0.85em !important;
|
||||
}
|
||||
|
||||
.selected-price {
|
||||
color: #b23c3c !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.selected-price-discount {
|
||||
color: #b23c3c !important;
|
||||
font-weight: bold !important;
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
.selected-price-original {
|
||||
color: #aaa !important;
|
||||
font-size: 0.85em !important;
|
||||
text-decoration: line-through !important;
|
||||
margin-left: 4px !important;
|
||||
}
|
||||
|
||||
/* 선택된 항목들 스타일 수정 */
|
||||
.choices__list--multiple .choices__item {
|
||||
background-color: #f8f9fa !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
border-radius: 16px !important;
|
||||
padding: 8px 12px !important;
|
||||
margin: 2px !important;
|
||||
font-size: 0.9em !important;
|
||||
color: #495057 !important;
|
||||
flex-shrink: 0 !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
/* max-width: 300px !important; */
|
||||
}
|
||||
|
||||
/* 빨간색으로 변경 */
|
||||
.choices__button {
|
||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjYjIzYzNjIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==') !important;
|
||||
background-size: 14px 14px !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
border-left: 0 !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
width: 14px !important;
|
||||
}
|
||||
|
||||
/* 드롭다운 컨테이너 */
|
||||
.choices__list--dropdown {
|
||||
background: #fff !important;
|
||||
border: 1px solid #ddd !important;
|
||||
border-radius: 6px !important;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
/* 드롭다운 옵션들 스타일 */
|
||||
.choices__list--dropdown .choices__item {
|
||||
padding: 8px 12px !important;
|
||||
display: flex !important;
|
||||
justify-content: space-between !important;
|
||||
align-items: center !important;
|
||||
color: #222 !important;
|
||||
}
|
||||
|
||||
.choices__list--dropdown .choices__item--selectable:hover {
|
||||
background-color: #f5f5f5 !important;
|
||||
color: #222 !important;
|
||||
}
|
||||
|
||||
.choices__list--dropdown .choices__item--highlighted {
|
||||
background-color: #b23c3c !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* 포커스 상태 */
|
||||
.choices.is-focused .choices__inner {
|
||||
border-color: #b23c3c !important;
|
||||
}
|
||||
|
||||
/* 가격 표시 스타일 */
|
||||
.procedure-price {
|
||||
color: #b23c3c !important;
|
||||
font-weight: bold !important;
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
.procedure-price-discount {
|
||||
color: #b23c3c !important;
|
||||
font-weight: bold !important;
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
.procedure-price-original {
|
||||
color: #aaa !important;
|
||||
font-size: 0.85em !important;
|
||||
text-decoration: line-through !important;
|
||||
margin-left: 4px !important;
|
||||
}
|
||||
|
||||
/* 드롭다운이 열렸을 때 하이라이트된 항목의 가격 색상 */
|
||||
.choices__list--dropdown .choices__item--highlighted .procedure-price,
|
||||
.choices__list--dropdown .choices__item--highlighted .procedure-price-discount {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.choices__list--dropdown .choices__item--highlighted .procedure-price-original {
|
||||
color: #ddd !important;
|
||||
}
|
||||
|
||||
/* 검색 입력창 스타일 */
|
||||
.choices[data-type*="select-multiple"] .choices__input {
|
||||
background-color: transparent !important;
|
||||
color: #222 !important;
|
||||
}
|
||||
|
||||
/* 비활성화 상태 */
|
||||
.choices.is-disabled .choices__inner {
|
||||
background-color: #f8f9fa !important;
|
||||
color: #6c757d !important;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
/* 반응형 대응 */
|
||||
@media (max-width: 600px) {
|
||||
.choices {
|
||||
min-width: 250px !important;
|
||||
}
|
||||
|
||||
.choices__inner {
|
||||
min-width: 230px !important;
|
||||
}
|
||||
|
||||
.choices__placeholder,
|
||||
.choices__input,
|
||||
.choices__input::placeholder {
|
||||
min-width: 150px !important;
|
||||
}
|
||||
|
||||
.choices__list--multiple .choices__item {
|
||||
max-width: 250px !important;
|
||||
padding: 6px 10px !important;
|
||||
}
|
||||
|
||||
.selected-item-name {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
.selected-item-price {
|
||||
font-size: 0.8em !important;
|
||||
}
|
||||
|
||||
.choices__list--multiple .choices__item[data-deletable] .choices__button {
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
font-size: 16px !important;
|
||||
text-indent: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.main-wrap {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.top-section {
|
||||
flex-direction: column;
|
||||
gap: 18px;
|
||||
padding: 20px 10px 0 10px;
|
||||
}
|
||||
|
||||
.img-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.desc-section {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.main-wrap {
|
||||
margin-top: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.top-section {
|
||||
padding: 12px 2vw 0 2vw;
|
||||
}
|
||||
|
||||
.desc-section {
|
||||
padding: 0 2vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script th:inline="javascript">
|
||||
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layout_content">
|
||||
<div id="service-header">
|
||||
시술안내/가격 > <span id="header-category-nm"></span> > <span id="header-title"></span>
|
||||
</div>
|
||||
<div class="main-wrap">
|
||||
<div class="top-section">
|
||||
<div class="img-box">
|
||||
<img id="serviceThumb" th:src="${@environment.getProperty('madeu.logo.size800x450')}" alt="썸네일 이미지">
|
||||
<pre id="thumbnail-bottom-txt"></pre>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<div class="info-title" id="title"></div>
|
||||
<div class="info-desc" id="contents"></div>
|
||||
|
||||
<div class="hashtag-section">
|
||||
<div class="hashtag-container">
|
||||
<div class="hashtag-list">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-price"><span id="price">0</span>원 부터</div>
|
||||
|
||||
<div class="select-row">
|
||||
<label for="procedure-select">시술 선택</label>
|
||||
<select id="procedure-select" multiple></select>
|
||||
</div>
|
||||
|
||||
<div class="total-row">
|
||||
<span class="total-label">총 금액</span>
|
||||
<span class="total-price" id="total">0원</span>
|
||||
</div>
|
||||
<button class="reserve-btn" id="reserve-btn" disabled>시술 예약하기</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc-section">
|
||||
<div class="desc-content">
|
||||
<img id="contents_path" th:src="${@environment.getProperty('madeu.logo.size800x450')}" alt="컨텐츠 이미지"
|
||||
width="100%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layout_script">
|
||||
<!-- Choices.js JavaScript -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.js"></script>
|
||||
|
||||
<script>
|
||||
// 전역 변수
|
||||
let procedureChoices;
|
||||
let priceList = [];
|
||||
const totalEl = document.getElementById('total');
|
||||
const reserveBtn = document.getElementById('reserve-btn');
|
||||
|
||||
// 초기화 - Opener 데이터 로드 (DOM 로드 후 실행)
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
fn_initPreview();
|
||||
});
|
||||
|
||||
function fn_initPreview() {
|
||||
if (!window.opener) {
|
||||
alert('비정상적인 접근입니다.');
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
const opener = window.opener;
|
||||
const $ = opener.jQuery; // Use jQuery from opener if possible, or use current document
|
||||
|
||||
// 1. 기본 정보 설정
|
||||
document.getElementById('header-category-nm').innerText = opener.$("select[name=category] option:selected").text();
|
||||
document.getElementById('header-title').innerText = opener.$("#title").val();
|
||||
document.getElementById('title').innerText = opener.$("#title").val();
|
||||
document.getElementById('contents').innerText = opener.$("#content").val();
|
||||
document.getElementById('thumbnail-bottom-txt').innerText = opener.$("#thumbnailBottomTxt").val();
|
||||
|
||||
// 2. 이미지 설정
|
||||
let thumbSrc = opener.$(".img_box img").attr("src");
|
||||
if (!thumbSrc) thumbSrc = opener.$("#thumbnailImg").attr("src");
|
||||
if (thumbSrc) document.getElementById('serviceThumb').src = thumbSrc;
|
||||
|
||||
let contentSrc = opener.$(".file_box img").attr("src");
|
||||
if (!contentSrc) contentSrc = opener.$("#contentsImg").attr("src");
|
||||
if (contentSrc) document.getElementById('contents_path').src = contentSrc;
|
||||
else document.getElementById('contents_path').style.display = 'none';
|
||||
|
||||
// 3. 해시태그 설정
|
||||
let hashtagStr = opener.$("#hashtag").val();
|
||||
let hashtagHtml = '';
|
||||
if (hashtagStr) {
|
||||
let tags = hashtagStr.split('#');
|
||||
tags.forEach(function (tag) {
|
||||
let trimmed = tag.trim();
|
||||
if (trimmed) {
|
||||
hashtagHtml += '<span class="hashtag">#' + trimmed + '</span>';
|
||||
}
|
||||
});
|
||||
}
|
||||
document.querySelector('.hashtag-list').innerHTML = hashtagHtml;
|
||||
|
||||
// 4. 시술 목록 및 가격 설정
|
||||
let treatmentList = opener.getTreatmentListForPreview ? opener.getTreatmentListForPreview() : opener.treatmentList; // Access global variable from opener or fall back
|
||||
if (treatmentList && treatmentList.length > 0) {
|
||||
updateProcedureOptions(treatmentList);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Choices.js 초기화 및 옵션 업데이트
|
||||
****************************************************************************/
|
||||
function updateProcedureOptions(data) {
|
||||
priceList = data;
|
||||
|
||||
let minPrice = -1;
|
||||
|
||||
// 선택 옵션 데이터 생성
|
||||
const choices = data.map(item => {
|
||||
const price = parseInt(item.price) || 0;
|
||||
const discountPrice = parseInt(item.discountPrice) || 0;
|
||||
const finalPrice = (discountPrice > 0 && discountPrice < price) ? discountPrice : price;
|
||||
|
||||
if (minPrice === -1 || finalPrice < minPrice) {
|
||||
minPrice = finalPrice;
|
||||
}
|
||||
|
||||
return {
|
||||
value: item.muTreatmentProcedureId || item.muTreatmentId, // Adjust based on your object structure
|
||||
label: item.treatmentProcedureName,
|
||||
customProperties: {
|
||||
name: item.treatmentProcedureName,
|
||||
price: price,
|
||||
discountPrice: discountPrice
|
||||
}
|
||||
};
|
||||
}).filter(Boolean);
|
||||
|
||||
if (minPrice === -1) minPrice = 0;
|
||||
document.getElementById('price').textContent = minPrice.toLocaleString();
|
||||
|
||||
// Choices.js 초기화
|
||||
procedureChoices = new Choices('#procedure-select', {
|
||||
removeItemButton: true,
|
||||
searchEnabled: true,
|
||||
searchPlaceholderValue: '시술명으로 검색...',
|
||||
placeholder: true,
|
||||
placeholderValue: '시술을 선택하세요',
|
||||
maxItemCount: -1,
|
||||
choices: choices,
|
||||
shouldSort: false,
|
||||
searchResultLimit: 10,
|
||||
searchFields: ['label', 'value'],
|
||||
itemSelectText: '',
|
||||
noChoicesText: '선택 가능한 시술이 없습니다',
|
||||
noResultsText: '검색 결과가 없습니다',
|
||||
loadingText: '시술 정보를 불러오는 중...',
|
||||
|
||||
callbackOnCreateTemplates: function (template) {
|
||||
return {
|
||||
item: ({ classNames }, data) => {
|
||||
const customProps = data.customProperties || {};
|
||||
const name = customProps.name || data.label;
|
||||
const price = customProps.price || 0;
|
||||
const discountPrice = customProps.discountPrice;
|
||||
|
||||
let priceHtml = '';
|
||||
if (discountPrice && discountPrice < price) {
|
||||
priceHtml = `
|
||||
<span class="selected-price-discount">${discountPrice.toLocaleString()}원</span>
|
||||
<span class="selected-price-original">${price.toLocaleString()}원</span>
|
||||
`;
|
||||
} else {
|
||||
priceHtml = `<span class="selected-price">${price.toLocaleString()}원</span>`;
|
||||
}
|
||||
|
||||
return template(`
|
||||
<div class="${classNames.item} ${data.highlighted ? classNames.highlightedState : classNames.itemSelectable}" data-item data-id="${data.id}" data-value="${data.value}">
|
||||
<span class="selected-item-content">
|
||||
<span class="selected-item-name">${name}</span>
|
||||
<span class="selected-item-price">${priceHtml}</span>
|
||||
</span>
|
||||
<button type="button" class="${classNames.button}" aria-label="Remove item: '${data.value}'" data-button>X</button>
|
||||
</div>
|
||||
`);
|
||||
},
|
||||
choice: ({ classNames }, data) => {
|
||||
const customProps = data.customProperties || {};
|
||||
const name = customProps.name || data.label;
|
||||
const price = customProps.price || 0;
|
||||
const discountPrice = customProps.discountPrice;
|
||||
|
||||
let priceHtml = '';
|
||||
if (discountPrice && discountPrice < price) {
|
||||
priceHtml = `
|
||||
<span class="procedure-price-discount">${discountPrice.toLocaleString()}원</span>
|
||||
<span class="procedure-price-original">${price.toLocaleString()}원</span>
|
||||
`;
|
||||
} else {
|
||||
priceHtml = `<span class="procedure-price">${price.toLocaleString()}원</span>`;
|
||||
}
|
||||
|
||||
return template(`
|
||||
<div class="${classNames.item} ${classNames.itemChoice} ${data.disabled ? classNames.itemDisabled : classNames.itemSelectable}" data-select-text="" data-choice ${data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'} data-id="${data.id}" data-value="${data.value}">
|
||||
<div style="display: flex; justify-content: space-between; width: 100%; align-items: center;">
|
||||
<span>${name}</span>
|
||||
${priceHtml}
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const selectElement = document.getElementById('procedure-select');
|
||||
selectElement.addEventListener('change', updateTotalPrice);
|
||||
selectElement.addEventListener('addItem', updateTotalPrice);
|
||||
selectElement.addEventListener('removeItem', updateTotalPrice);
|
||||
}
|
||||
|
||||
function updateTotalPrice() {
|
||||
if (!procedureChoices) return;
|
||||
const selectedValues = procedureChoices.getValue(true);
|
||||
let total = 0;
|
||||
|
||||
selectedValues.forEach(value => {
|
||||
// Find item in local priceList (which is data passed to updateProcedureOptions)
|
||||
// Note: priceList elements structure depends on how we mapped it.
|
||||
// Oh wait, priceList = data; which comes from opener.treatmentList.
|
||||
// Items in treatmentList have { muTreatmentProcedureId, treatmentProcedureName, price, discountPrice ... }
|
||||
const item = priceList.find(p => (p.muTreatmentProcedureId || p.muTreatmentId) == value);
|
||||
|
||||
if (item) {
|
||||
const basePrice = parseInt(item.price) || 0;
|
||||
const discountPrice = parseInt(item.discountPrice) || 0;
|
||||
const finalPrice = (discountPrice > 0 && discountPrice < basePrice) ? discountPrice : basePrice;
|
||||
total += finalPrice;
|
||||
}
|
||||
});
|
||||
|
||||
totalEl.textContent = total.toLocaleString() + '원';
|
||||
reserveBtn.disabled = selectedValues.length === 0;
|
||||
}
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -1,116 +1,178 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{/web/layout/homeLayout}">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/homeLayout}">
|
||||
<th:block layout:fragment="layout_css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/web/ContentsBbsReg.css">
|
||||
<link rel="stylesheet" href="/css/web/grid.css?v1.1">
|
||||
<link rel="stylesheet" href="/css/web/ContentsBbsUpd.css">
|
||||
<link rel="stylesheet" href="/css/web/grid.css?v1.1">
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script src="/js/web/jquery.twbsPagination.js" type="text/javascript"></script>
|
||||
<script>
|
||||
let menuClass = "[[${param.menuClass}]]"==""?"":"[[${param.menuClass}]]";
|
||||
let categoryDivCd = "[[${param.categoryDivCd}]]"==""?"":"[[${param.categoryDivCd}]]";
|
||||
<!-- Pagination usage removed -->
|
||||
<script>
|
||||
let menuClass = "[[${param.menuClass}]]" == "" ? "" : "[[${param.menuClass}]]";
|
||||
let categoryDivCd = "[[${param.categoryDivCd}]]" == "" ? "" : "[[${param.categoryDivCd}]]";
|
||||
|
||||
let selectUseYn = "[[${selectUseYn}]]"==""?"N":"[[${selectUseYn}]]";
|
||||
let insertUseYn = "[[${insertUseYn}]]"==""?"N":"[[${insertUseYn}]]";
|
||||
let updateUseYn = "[[${updateUseYn}]]"==""?"N":"[[${updateUseYn}]]";
|
||||
let deleteUseYn = "[[${deleteUseYn}]]"==""?"N":"[[${deleteUseYn}]]";
|
||||
let downloadUseYn = "[[${downloadUseYn}]]"==""?"N":"[[${downloadUseYn}]]";
|
||||
|
||||
let categorytitle = "[[${title}]]";
|
||||
</script>
|
||||
let selectUseYn = "[[${selectUseYn}]]" == "" ? "N" : "[[${selectUseYn}]]";
|
||||
let insertUseYn = "[[${insertUseYn}]]" == "" ? "N" : "[[${insertUseYn}]]";
|
||||
let updateUseYn = "[[${updateUseYn}]]" == "" ? "N" : "[[${updateUseYn}]]";
|
||||
let deleteUseYn = "[[${deleteUseYn}]]" == "" ? "N" : "[[${deleteUseYn}]]";
|
||||
let downloadUseYn = "[[${downloadUseYn}]]" == "" ? "N" : "[[${downloadUseYn}]]";
|
||||
|
||||
let categorytitle = "[[${title}]]";
|
||||
|
||||
const CDN_URL = "[[${@environment.getProperty('url.cdn')}]]";
|
||||
</script>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_content">
|
||||
<!-- 센터쪽 -->
|
||||
<div class="center_box">
|
||||
<p class="page_title">[[${title}]]</p>
|
||||
<!-- 센터쪽 -->
|
||||
<div class="center_box">
|
||||
<p class="page_title">[[${title}]]</p>
|
||||
|
||||
<!-- 테이블 -->
|
||||
<div class="content_box">
|
||||
<div class="content clear">
|
||||
<div class="wp60">
|
||||
<div class="top">
|
||||
<label>썸네일 첨부파일</label>
|
||||
<label for="file" class="file_btn"><img src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<div class="img_box"><!-- img 미리보기 --></div>
|
||||
<input type="file" id="file" accept="image/jpeg, image/jpg, image/png" style="display: none;" multiple>
|
||||
<button id="delete_btn">삭제</button>
|
||||
</div>
|
||||
<p class="thumbnail-bottom-txt">
|
||||
썸네일 하단글
|
||||
</p>
|
||||
<textarea id="thumbnail-bottom-txt" placeholder="썸네일 하단글을 입력해주세요." ></textarea>
|
||||
<p class="content-file">
|
||||
컨텐츠 첨부파일
|
||||
<label for="content_file" class="file_btn"><img src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
</p>
|
||||
<input type="file" id="content_file" style="display: none;" placeholder="첨부파일을 입력해주세요."/>
|
||||
<div class="file_box"><!-- img 미리보기 --></div>
|
||||
<button id="content_delete_btn">삭제</button>
|
||||
</div>
|
||||
<div class="wp40">
|
||||
<div class="consultation-info">
|
||||
<p id="main_category">
|
||||
카테고리
|
||||
</p>
|
||||
<select th:name="categorylist">
|
||||
<option value="">선택하세요</option>
|
||||
<option th:each="category : ${categorylist}" th:value="${category.categoryNo}" th:text="${category.categoryNm}"></option>
|
||||
</select>
|
||||
<p id="main_title">
|
||||
제목
|
||||
</p>
|
||||
<input type="text" id="title" placeholder="제목을 입력해주세요."/>
|
||||
<p id="main_content">
|
||||
내용
|
||||
</p>
|
||||
<textarea id="content" placeholder="내용을 입력해주세요."></textarea>
|
||||
<p id="main_hashtag">
|
||||
해쉬태그
|
||||
</p>
|
||||
<input type="text" id="hashtag" placeholder="해쉬태그를 입력해주세요."/>
|
||||
<div>
|
||||
<label for="oldCrmItemId">OLD CRM 연동ID</label>
|
||||
<input type="text" id="oldCrmItemId" placeholder="OLD_CRM_ITEM_ID"/>
|
||||
<!-- 테이블 -->
|
||||
<div class="content_box">
|
||||
<div class="update-container">
|
||||
<!-- Left Panel: Data Forms -->
|
||||
<div class="left-panel">
|
||||
<!-- Row 1: Category & Title -->
|
||||
<div class="form-grid-row">
|
||||
<div class="form-group" style="flex: 0 0 150px;">
|
||||
<label>카테고리</label>
|
||||
<select name="category">
|
||||
<option value="">선택하세요</option>
|
||||
<option th:each="category : ${categorylist}" th:value="${category.categoryNo}"
|
||||
th:text="${category.categoryNm}"></option>
|
||||
</select>
|
||||
<input type="hidden" id="categoryNo" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="ordNo">홈페이지 출력순서</label>
|
||||
<div class="form-group">
|
||||
<label>제목</label>
|
||||
<input type="text" id="title" placeholder="제목을 입력해주세요." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 2: Content & Order -->
|
||||
<div class="form-grid-row">
|
||||
<div class="form-group" style="flex: 1;">
|
||||
<label>내용</label>
|
||||
<input type="text" id="content" placeholder="내용을 입력해주세요." />
|
||||
</div>
|
||||
<div class="form-group" style="flex: 0 0 150px;">
|
||||
<label>홈페이지 출력순서</label>
|
||||
<input type="text" id="ordNo" />
|
||||
</div>
|
||||
<p id="main_procedure">
|
||||
시술선택
|
||||
<button class="add_btn ml50" onclick="javascript:listOpen();">
|
||||
<img src="/image/web/add.svg" alt="추가">
|
||||
</button>
|
||||
<button class="add_btn" onclick="javascript:fn_removeRow();">
|
||||
<img src="/image/web/subtract.svg" alt="삭제">
|
||||
</button>
|
||||
</p>
|
||||
<div id="treatmentlist">
|
||||
</div>
|
||||
</div>
|
||||
<div class="button_box">
|
||||
<button class="registration_btn btnSave">등록</button>
|
||||
<button class="cancel_btn btnCancle">취소</button>
|
||||
</div>
|
||||
|
||||
<!-- Row 3: Hashtag & Old ID -->
|
||||
<div class="form-grid-row">
|
||||
<div class="form-group">
|
||||
<label>해쉬태그</label>
|
||||
<input type="text" id="hashtag" placeholder="해쉬태그를 입력해주세요." />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>OLD CRM 연동ID</label>
|
||||
<input type="text" id="oldCrmItemId" placeholder="OLD_CRM_ITEM_ID" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 4: Procedure Selection (Grid) -->
|
||||
<div class="grid-section">
|
||||
<div class="grid-header">
|
||||
<label>시술선택</label>
|
||||
<div class="grid-controls">
|
||||
<button class="add_btn" onclick="javascript:listOpen();">
|
||||
<img src="/image/web/add.svg" alt="추가">
|
||||
</button>
|
||||
<button class="add_btn" onclick="javascript:fn_removeRow();">
|
||||
<img src="/image/web/subtract.svg" alt="삭제">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-grid-container">
|
||||
<table class="treatment-table">
|
||||
<colgroup>
|
||||
<col style="width: 50px;">
|
||||
<col style="width: auto;">
|
||||
<col style="width: 120px;">
|
||||
<col style="width: 120px;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input type="checkbox" id="checkAll" onclick="fn_checkAll(this)">
|
||||
</th>
|
||||
<th>시술명</th>
|
||||
<th>가격</th>
|
||||
<th>할인가</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="treatmentListBody">
|
||||
<!-- Rows will be added here dynamically -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Buttons -->
|
||||
<div class="bottom-actions">
|
||||
<button class="btn-basic btnPreview" onclick="fn_openPreview();"
|
||||
style="width: 120px; height: 36px; border-radius: 4px; background: #fff; color: #333; border: 1px solid #ccc; margin-right: auto;">미리보기</button>
|
||||
<button class="registration_btn btnSave"
|
||||
style="width: 80px; height: 36px; border-radius: 4px; background: #3985EA; color: white;">등록</button>
|
||||
<button class="cancel_btn btnCancle"
|
||||
style="width: 80px; height: 36px; border-radius: 4px;">취소</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Panel: Images -->
|
||||
<div class="right-panel">
|
||||
<!-- Thumbnail Section -->
|
||||
<div class="panel-section">
|
||||
<div class="top-label">
|
||||
<span>썸네일 첨부파일</span>
|
||||
<div>
|
||||
<label for="file" class="file_btn" style="cursor: pointer;"><img
|
||||
src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
<button id="delete_btn"
|
||||
style="border:none; background:none; cursor:pointer; margin-left:5px; font-size:12px; color:#999;">삭제</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="img-preview-wrapper img_box">
|
||||
<img id="thumbnailImg" src="" />
|
||||
</div>
|
||||
<input type="file" id="file" accept="image/jpeg, image/jpg, image/png" style="display: none;"
|
||||
multiple>
|
||||
|
||||
<label style="margin-top: 10px; font-size: 13px; font-weight: 700;">썸네일 하단글</label>
|
||||
<textarea id="thumbnailBottomTxt" placeholder="썸네일 하단글을 입력해주세요."></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Content File Section -->
|
||||
<div class="panel-section">
|
||||
<div class="top-label">
|
||||
<span>컨텐츠 첨부파일</span>
|
||||
<div>
|
||||
<label for="content_file" class="file_btn" style="cursor: pointer;"><img
|
||||
src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
<button id="content_delete_btn"
|
||||
style="border:none; background:none; cursor:pointer; margin-left:5px; font-size:12px; color:#999;">삭제</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="img-preview-wrapper file_box">
|
||||
<!-- Using same class for consistent styling -->
|
||||
<img id="contentsImg" src="" />
|
||||
</div>
|
||||
<input type="file" id="content_file" style="display: none;" placeholder="첨부파일을 입력해주세요." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="excelForm" method="POST" target="_blank"></form>
|
||||
</div>
|
||||
</div>
|
||||
<form id="excelForm" method="POST" target="_blank"></form>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_popup">
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_script">
|
||||
<script src="/js/web/ag-grid-community-29.3.5.min.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsReg.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsPop.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsReg.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsPop.js"></script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -1,128 +1,183 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{/web/layout/homeLayout}">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/homeLayout}">
|
||||
<th:block layout:fragment="layout_css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/web/ContentsBbsReg.css">
|
||||
<link rel="stylesheet" href="/css/web/grid.css?v1.1">
|
||||
<link rel="stylesheet" href="/css/web/ContentsBbsUpd.css">
|
||||
<link rel="stylesheet" href="/css/web/grid.css?v1.1">
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script src="/js/web/jquery.twbsPagination.js" type="text/javascript"></script>
|
||||
<script>
|
||||
let menuClass = "[[${param.menuClass}]]"==""?"":"[[${param.menuClass}]]";
|
||||
<!-- Pagination usage removed -->
|
||||
<script>
|
||||
let menuClass = "[[${param.menuClass}]]" == "" ? "" : "[[${param.menuClass}]]";
|
||||
|
||||
let selectUseYn = "[[${selectUseYn}]]"==""?"N":"[[${selectUseYn}]]";
|
||||
let insertUseYn = "[[${insertUseYn}]]"==""?"N":"[[${insertUseYn}]]";
|
||||
let updateUseYn = "[[${updateUseYn}]]"==""?"N":"[[${updateUseYn}]]";
|
||||
let deleteUseYn = "[[${deleteUseYn}]]"==""?"N":"[[${deleteUseYn}]]";
|
||||
let downloadUseYn = "[[${downloadUseYn}]]"==""?"N":"[[${downloadUseYn}]]";
|
||||
|
||||
let categoryDivCd = "[[${param.categoryDivCd}]]";
|
||||
let categoryNo = "[[${param.categoryNo}]]";
|
||||
let postNo = "[[${param.postNo}]]";
|
||||
let categorytitle = "[[${title}]]";
|
||||
|
||||
const CDN_URL = "[[${@environment.getProperty('url.cdn')}]]";
|
||||
|
||||
</script>
|
||||
let selectUseYn = "[[${selectUseYn}]]" == "" ? "N" : "[[${selectUseYn}]]";
|
||||
let insertUseYn = "[[${insertUseYn}]]" == "" ? "N" : "[[${insertUseYn}]]";
|
||||
let updateUseYn = "[[${updateUseYn}]]" == "" ? "N" : "[[${updateUseYn}]]";
|
||||
let deleteUseYn = "[[${deleteUseYn}]]" == "" ? "N" : "[[${deleteUseYn}]]";
|
||||
let downloadUseYn = "[[${downloadUseYn}]]" == "" ? "N" : "[[${downloadUseYn}]]";
|
||||
|
||||
let categoryDivCd = "[[${param.categoryDivCd}]]";
|
||||
let categoryNo = "[[${param.categoryNo}]]";
|
||||
let postNo = "[[${param.postNo}]]";
|
||||
let categorytitle = "[[${title}]]";
|
||||
|
||||
const CDN_URL = "[[${@environment.getProperty('url.cdn')}]]";
|
||||
|
||||
</script>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_content">
|
||||
<!-- 센터쪽 -->
|
||||
<div class="center_box">
|
||||
<p class="page_title">[[${title}]]</p>
|
||||
<!-- 센터쪽 -->
|
||||
<div class="center_box">
|
||||
<p class="page_title">[[${title}]]</p>
|
||||
|
||||
<!-- 테이블 -->
|
||||
<div class="content_box">
|
||||
<div class="content clear">
|
||||
<div class="wp60">
|
||||
<div class="top">
|
||||
<label>썸네일 첨부파일</label>
|
||||
<label for="file" class="file_btn"><img src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
</div>
|
||||
<div class="btm">
|
||||
<div class="img_box">
|
||||
<img id="thumbnailImg" src="" width="800px" height="450px" />
|
||||
</div>
|
||||
<input type="file" id="file" accept="image/jpeg, image/jpg, image/png" style="display: none;" multiple>
|
||||
<button id="delete_btn">삭제</button>
|
||||
</div>
|
||||
<p class="thumbnail-bottom-txt">
|
||||
썸네일 하단글
|
||||
</p>
|
||||
<textarea id="thumbnailBottomTxt" placeholder="썸네일 하단글을 입력해주세요." ></textarea>
|
||||
<p class="content-file">
|
||||
컨텐츠 첨부파일
|
||||
<label for="content_file" class="file_btn"><img src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
</p>
|
||||
<input type="file" id="content_file" style="display: none;" placeholder="첨부파일을 입력해주세요."/>
|
||||
<div class="file_box">
|
||||
<img id="contentsImg" src="" width="100%" height="100%" />
|
||||
</div>
|
||||
<button id="content_delete_btn">삭제</button>
|
||||
</div>
|
||||
<div class="wp40">
|
||||
<div class="consultation-info">
|
||||
<p id="main_category">
|
||||
카테고리
|
||||
</p>
|
||||
<select th:name="category" th:disabled="true">
|
||||
<option value="">선택하세요</option>
|
||||
<option th:each="item : ${category}" th:value="${item['categoryNo']}" th:text="${item['categoryNm']}" ></option>
|
||||
</select>
|
||||
<!-- disabled된 select의 값을 전송하기 위한 hidden input -->
|
||||
<input type="hidden" id="categoryNo" />
|
||||
<p id="main_title">
|
||||
제목
|
||||
</p>
|
||||
<input type="text" id="title" placeholder="제목을 입력해주세요."/>
|
||||
<p id="main_content">
|
||||
내용
|
||||
</p>
|
||||
<textarea id="content" placeholder="내용을 입력해주세요."></textarea>
|
||||
<p id="main_hashtag">
|
||||
해쉬태그
|
||||
</p>
|
||||
<input type="text" id="hashtag" placeholder="해쉬태그를 입력해주세요."/>
|
||||
<div>
|
||||
<label for="oldCrmItemId">OLD CRM 연동ID</label>
|
||||
<input type="text" id="oldCrmItemId" placeholder="OLD_CRM_ITEM_ID"/>
|
||||
<!-- 테이블 -->
|
||||
<div class="content_box">
|
||||
<div class="update-container">
|
||||
<!-- Left Panel: Data Forms -->
|
||||
<div class="left-panel">
|
||||
<!-- Row 1: Category & Title -->
|
||||
<div class="form-grid-row">
|
||||
<div class="form-group" style="flex: 0 0 150px;">
|
||||
<label>카테고리</label>
|
||||
<select th:name="category" th:disabled="true">
|
||||
<option value="">선택하세요</option>
|
||||
<option th:each="item : ${category}" th:value="${item['categoryNo']}"
|
||||
th:text="${item['categoryNm']}"></option>
|
||||
</select>
|
||||
<input type="hidden" id="categoryNo" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="ordNo">홈페이지 출력순서</label>
|
||||
<div class="form-group">
|
||||
<label>제목</label>
|
||||
<input type="text" id="title" placeholder="제목을 입력해주세요." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 2: Content & Order -->
|
||||
<div class="form-grid-row">
|
||||
<div class="form-group" style="flex: 1;">
|
||||
<label>내용</label>
|
||||
<input type="text" id="content" placeholder="내용을 입력해주세요." />
|
||||
</div>
|
||||
<div class="form-group" style="flex: 0 0 70px;">
|
||||
<label>출력순서</label>
|
||||
<input type="text" id="ordNo" />
|
||||
</div>
|
||||
<p id="main_procedure">
|
||||
시술선택
|
||||
<button class="add_btn ml50" onclick="javascript:listOpen();">
|
||||
<img src="/image/web/add.svg" alt="추가">
|
||||
</button>
|
||||
<button class="add_btn" onclick="javascript:fn_removeRow();">
|
||||
<img src="/image/web/subtract.svg" alt="삭제">
|
||||
</button>
|
||||
</p>
|
||||
<div id="treatmentlist">
|
||||
</div>
|
||||
</div>
|
||||
<div class="button_box">
|
||||
<button class="registration_btn btnSave">수정</button>
|
||||
<button class="cancel_btn btnCancle">취소</button>
|
||||
</div>
|
||||
|
||||
<!-- Row 3: Hashtag & Old ID -->
|
||||
<div class="form-grid-row">
|
||||
<div class="form-group">
|
||||
<label>해쉬태그</label>
|
||||
<input type="text" id="hashtag" placeholder="해쉬태그를 입력해주세요." />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>OLD CRM 연동ID</label>
|
||||
<input type="text" id="oldCrmItemId" placeholder="OLD_CRM_ITEM_ID" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 4: Treatment Grid -->
|
||||
<div class="grid-section">
|
||||
<div class="grid-header">
|
||||
<p>시술선택</p>
|
||||
<div>
|
||||
<button class="add_btn" onclick="javascript:listOpen();"
|
||||
style="border:none; background:none; cursor:pointer;">
|
||||
<img src="/image/web/add.svg" alt="추가">
|
||||
</button>
|
||||
<button class="add_btn" onclick="javascript:fn_removeRow();"
|
||||
style="border:none; background:none; cursor:pointer; margin-left: 5px;">
|
||||
<img src="/image/web/subtract.svg" alt="삭제">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="custom-grid-container">
|
||||
<table class="treatment-table">
|
||||
<colgroup>
|
||||
<col style="width: 50px;">
|
||||
<col style="width: 250px;">
|
||||
<col style="width: 120px;">
|
||||
<col style="width: 120px;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<input type="checkbox" id="checkAll" onclick="fn_checkAll(this)">
|
||||
</th>
|
||||
<th>시술명</th>
|
||||
<th>가격</th>
|
||||
<th>할인가</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="treatmentListBody">
|
||||
<!-- Rows will be added here dynamically -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Buttons -->
|
||||
<div class="bottom-actions">
|
||||
<button class="btn-basic btnPreview" onclick="fn_openPreview();"
|
||||
style="width: 120px; height: 36px; border-radius: 4px; background: #fff; color: #333; border: 1px solid #ccc; margin-right: auto;">미리보기</button>
|
||||
<button class="registration_btn btnSave"
|
||||
style="width: 80px; height: 36px; border-radius: 4px; background: #3985EA; color: white;">수정</button>
|
||||
<button class="cancel_btn btnCancle"
|
||||
style="width: 80px; height: 36px; border-radius: 4px;">취소</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Panel: Images -->
|
||||
<div class="right-panel">
|
||||
<!-- Thumbnail Section -->
|
||||
<div class="panel-section">
|
||||
<div class="top-label">
|
||||
<span>썸네일 첨부파일</span>
|
||||
<div>
|
||||
<label for="file" class="file_btn" style="cursor: pointer;"><img
|
||||
src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
<button id="delete_btn"
|
||||
style="border:none; background:none; cursor:pointer; margin-left:5px; font-size:12px; color:#999;">삭제</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="img-preview-wrapper img_box">
|
||||
<img id="thumbnailImg" src="" />
|
||||
</div>
|
||||
<input type="file" id="file" accept="image/jpeg, image/jpg, image/png" style="display: none;"
|
||||
multiple>
|
||||
|
||||
<label style="margin-top: 10px; font-size: 13px; font-weight: 700;">썸네일 하단글</label>
|
||||
<textarea id="thumbnailBottomTxt" placeholder="썸네일 하단글을 입력해주세요."></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Content File Section -->
|
||||
<div class="panel-section">
|
||||
<div class="top-label">
|
||||
<span>컨텐츠 첨부파일</span>
|
||||
<div>
|
||||
<label for="content_file" class="file_btn" style="cursor: pointer;"><img
|
||||
src="/image/web/add.svg" alt="파일찾기"></label>
|
||||
<button id="content_delete_btn"
|
||||
style="border:none; background:none; cursor:pointer; margin-left:5px; font-size:12px; color:#999;">삭제</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="img-preview-wrapper file_box">
|
||||
<!-- Using same class for consistent styling -->
|
||||
<img id="contentsImg" src="" />
|
||||
</div>
|
||||
<input type="file" id="content_file" style="display: none;" placeholder="첨부파일을 입력해주세요." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<form id="excelForm" method="POST" target="_blank"></form>
|
||||
</div>
|
||||
</div>
|
||||
<form id="excelForm" method="POST" target="_blank"></form>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_popup">
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_script">
|
||||
<script src="/js/web/ag-grid-community-29.3.5.min.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsUpd.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsPop.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsUpd.js"></script>
|
||||
<script src="/js/web/contentsBbs/ContentsBbsPop.js"></script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user