v3.2.1: 카카오 자동매핑 + 채널링크 전송 + 날씨앱 개선
- OAuth 로그인 시 카카오 userId 자동 조회 → 현재 계정 자동 매핑 - 채널 링크 나에게 보내기 버튼 (OAuth 완료 후 표시) - 카카오 채널 설정: 링크·등록방법 안내, 기본 탭으로 변경 - 날씨앱: 지역 선택 드롭다운, 🚨 기상특보 버튼, 오버레이 한 줄 배치, 폰트 굵기 개선 - 모바일 브레이크포인트 1024px 통일 (갤럭시 폴드 대응) - 교통앱 마지막 지역 localStorage 저장/복원 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3906,6 +3906,8 @@ async function loadKakaoStatus() {
|
||||
else setChannelStatus('kk', 'off', '미설정');
|
||||
if (n.hasAppKey) document.getElementById('settings-kk-appkey').placeholder = '•••••••• (저장됨)';
|
||||
document.getElementById('settings-kk-channel-enabled').checked = !!c.enabled;
|
||||
const linkBtn = document.getElementById('kk-send-link-btn');
|
||||
if (linkBtn) linkBtn.style.display = (n.hasRefreshToken) ? 'inline-block' : 'none';
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -3928,6 +3930,23 @@ async function kakaoOAuthStart() {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async function kakaoSendChannelLink() {
|
||||
const btn = document.getElementById('kk-send-link-btn');
|
||||
const orig = btn?.textContent;
|
||||
if (btn) btn.textContent = '전송 중...';
|
||||
try {
|
||||
const data = await api('/api/kakao/send-channel-link', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ channelUrl: 'http://pf.kakao.com/_KxjxexfX/chat' }),
|
||||
});
|
||||
if (btn) btn.textContent = data.success ? '✅ 전송됨!' : '❌ 실패';
|
||||
} catch {
|
||||
if (btn) btn.textContent = '❌ 실패';
|
||||
}
|
||||
setTimeout(() => { if (btn) btn.textContent = orig; }, 3000);
|
||||
}
|
||||
|
||||
async function saveChannelSettings(channel) {
|
||||
const payload = readChannelPayload(channel);
|
||||
try {
|
||||
|
||||
+12
-1
@@ -1346,8 +1346,8 @@
|
||||
<div class="right-section-title" style="margin-bottom:8px">채널 연결</div>
|
||||
<label style="display:block;font-size:12px;color:var(--muted);margin-bottom:6px">채널</label>
|
||||
<select id="settings-channel-select" class="settings-input" onchange="onChannelTypeChange()" style="margin-bottom:10px">
|
||||
<option value="telegram">Telegram</option>
|
||||
<option value="kakao">카카오톡</option>
|
||||
<option value="telegram">Telegram</option>
|
||||
<option value="discord">Discord</option>
|
||||
<option value="whatsapp">WhatsApp</option>
|
||||
<option value="email">Email</option>
|
||||
@@ -1392,6 +1392,7 @@
|
||||
<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:6px">OAuth 로그인 (나에게 보내기 알림용)</div>
|
||||
<div style="font-size:11px;color:var(--muted);margin-bottom:8px">API 키 저장 후 아래 버튼으로 카카오 로그인하면 토큰이 자동 저장됩니다.</div>
|
||||
<button onclick="kakaoOAuthStart()" style="background:#FEE500;border:none;border-radius:7px;padding:6px 14px;font-size:12px;font-weight:700;color:#3C1E1E;cursor:pointer">🟡 카카오 로그인</button>
|
||||
<button id="kk-send-link-btn" onclick="kakaoSendChannelLink()" style="display:none;background:none;border:1px solid rgba(56,189,248,.4);border-radius:7px;padding:6px 12px;font-size:12px;font-weight:700;color:#38bdf8;cursor:pointer;margin-left:6px">📲 채널 링크 보내기</button>
|
||||
<span id="kk-oauth-status" style="font-size:11px;color:var(--muted);margin-left:8px"></span>
|
||||
</div>
|
||||
<label style="display:block;font-size:12px;color:var(--muted);margin:10px 0 6px">사용자 매핑 (선택, JSON)</label>
|
||||
@@ -1400,6 +1401,16 @@
|
||||
<input type="checkbox" id="settings-kk-channel-enabled" />
|
||||
챗봇 채널 활성화 (오픈빌더 연동)
|
||||
</label>
|
||||
<div style="margin-top:14px;padding:10px 12px;border:1px solid rgba(254,229,0,.25);border-radius:8px;background:rgba(254,229,0,.04);font-size:11px;line-height:2;">
|
||||
<div style="font-weight:700;color:#b8960a;margin-bottom:4px">📲 채널 접속 링크</div>
|
||||
<a href="http://pf.kakao.com/_KxjxexfX/chat" target="_blank" style="color:#38bdf8;word-break:break-all;">pf.kakao.com/_KxjxexfX/chat</a>
|
||||
<div style="margin-top:8px;font-weight:700;color:var(--muted)">등록 방법</div>
|
||||
<div style="color:var(--muted)">
|
||||
1. 카카오 로그인 → 본인 계정 자동 매핑됨<br>
|
||||
2. 다른 유저: 위 링크로 채널 추가 후 메시지 전송<br>
|
||||
3. 서버 로그에서 userId 확인 → 사용자 매핑에 추가
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="channel-form-discord" style="display:none">
|
||||
|
||||
+31
-6
@@ -10,7 +10,7 @@
|
||||
<style>
|
||||
:root{--brand:#38bdf8;}
|
||||
html,body{height:100%;margin:0;padding:0;}
|
||||
body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;display:flex;flex-direction:column;overflow:hidden;height:100dvh;}
|
||||
body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;font-weight:500;display:flex;flex-direction:column;overflow:hidden;height:100dvh;}
|
||||
|
||||
/* ── Header ── */
|
||||
.wt-hdr{display:flex;align-items:center;gap:8px;padding:6px 12px;background:var(--panel);border-bottom:1px solid var(--line);flex-shrink:0;}
|
||||
@@ -40,7 +40,7 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
|
||||
.wt-loc.active{background:rgba(56,189,248,.08);border-color:rgba(56,189,248,.25);}
|
||||
.wt-loc-info{flex:1;min-width:0;}
|
||||
.wt-loc-name{font-size:11px;font-weight:700;color:var(--text);display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
|
||||
.wt-loc-sub{font-size:10px;color:var(--muted);display:block;}
|
||||
.wt-loc-sub{font-size:10px;font-weight:500;color:var(--muted);display:block;}
|
||||
.wt-loc.active .wt-loc-sub{color:#7dd3fc;}
|
||||
.wt-loc-acts{display:flex;gap:1px;opacity:0;transition:.12s;flex-shrink:0;}
|
||||
.wt-loc-act{background:none;border:none;cursor:pointer;font-size:11px;color:var(--muted);padding:2px 3px;border-radius:3px;transition:.12s;line-height:1;}
|
||||
@@ -60,7 +60,7 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
|
||||
|
||||
/* Quick prompts */
|
||||
.wt-quick{padding:0 6px 6px;}
|
||||
.wt-qbtn{background:none;border:1px solid var(--line);border-radius:6px;padding:5px 9px;font-size:11px;color:var(--muted);cursor:pointer;font-family:inherit;text-align:left;transition:.15s;width:100%;margin-bottom:3px;line-height:1.4;}
|
||||
.wt-qbtn{background:none;border:1px solid var(--line);border-radius:6px;padding:5px 9px;font-size:11px;font-weight:600;color:var(--muted);cursor:pointer;font-family:inherit;text-align:left;transition:.15s;width:100%;margin-bottom:3px;line-height:1.4;}
|
||||
.wt-qbtn:hover{border-color:#38bdf8;color:#38bdf8;background:rgba(56,189,248,.04);}
|
||||
|
||||
/* Alert badges */
|
||||
@@ -80,7 +80,9 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
|
||||
.wt-go-btn:hover{background:#0e5a80;}
|
||||
|
||||
/* Overlay tabs */
|
||||
.wt-overlays{display:flex;gap:4px;flex-wrap:wrap;}
|
||||
.wt-overlays{display:flex;gap:4px;flex-wrap:nowrap;overflow-x:auto;padding-bottom:2px;}
|
||||
.wt-overlays::-webkit-scrollbar{height:3px;}
|
||||
.wt-overlays::-webkit-scrollbar-thumb{background:var(--line);border-radius:3px;}
|
||||
.wt-ov{padding:3px 9px;border:1.5px solid var(--line);border-radius:16px;font-size:11px;font-weight:600;cursor:pointer;background:none;color:var(--muted);font-family:inherit;transition:.12s;white-space:nowrap;}
|
||||
.wt-ov:hover{border-color:#38bdf8;color:#38bdf8;}
|
||||
.wt-ov.active{border-color:#0ea5e9;background:#082f49;color:#7dd3fc;}
|
||||
@@ -202,6 +204,8 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
|
||||
<div class="wt-divider"></div>
|
||||
<div class="wt-sb-sec"><span>빠른 질문</span></div>
|
||||
<div class="wt-quick">
|
||||
<select id="quick-loc-sel" class="wt-lf-input" style="width:100%;margin-bottom:6px;font-size:11px;" onchange="localStorage.setItem('wt_quick_loc',this.value)"></select>
|
||||
<button class="wt-qbtn" onclick="askWeather('alert')" style="color:#f87171;border-color:rgba(239,68,68,.3);">🚨 기상 특보</button>
|
||||
<button class="wt-qbtn" onclick="askWeather('today')">☀️ 오늘 날씨</button>
|
||||
<button class="wt-qbtn" onclick="askWeather('week')">📅 주간 예보</button>
|
||||
<button class="wt-qbtn" onclick="askWeather('air')">🌫️ 미세먼지·대기질</button>
|
||||
@@ -250,7 +254,7 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
|
||||
</div>
|
||||
<div class="wt-map-area">
|
||||
<div class="wt-map-loading" id="map-loading">🌍 Windy 지도 로딩 중...</div>
|
||||
<iframe class="wt-map-frame" id="windy-frame" src="about:blank" onload="document.getElementById('map-loading').classList.add('hidden')"></iframe>
|
||||
<iframe class="wt-map-frame" id="windy-frame" src="about:blank" allow="geolocation" onload="document.getElementById('map-loading').classList.add('hidden')"></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -369,6 +373,7 @@ function escHtml(s){return String(s||'').replace(/&/g,'&').replace(/</g,'<
|
||||
function escAttr(s){return String(s||'').replace(/'/g,''').replace(/"/g,'"');}
|
||||
|
||||
function renderLocList(){
|
||||
updateQuickLocSel();
|
||||
const locs=getLocs();
|
||||
const container=document.getElementById('loc-list');
|
||||
container.innerHTML=`<div class="wt-locs">${locs.map((l,i)=>`
|
||||
@@ -492,7 +497,21 @@ function processWindyUrl(text){
|
||||
}
|
||||
|
||||
// Quick ask helpers
|
||||
const currentLoc=()=>{const locs=getLocs();return locs[0]?.name||'서울';};
|
||||
function updateQuickLocSel(){
|
||||
const sel=document.getElementById('quick-loc-sel');
|
||||
if(!sel)return;
|
||||
const locs=getLocs();
|
||||
const saved=localStorage.getItem('wt_quick_loc');
|
||||
const presets=['서울','부산','대구','인천','광주','대전','울산','수원','구미','강릉','제주'];
|
||||
const locNames=locs.map(l=>l.name);
|
||||
const all=[...new Set([...locNames,...presets])];
|
||||
sel.innerHTML=all.map(n=>`<option value="${n}"${n===(saved||locNames[0]||'서울')?'selected':''}>${n}</option>`).join('');
|
||||
}
|
||||
const currentLoc=()=>{
|
||||
const sel=document.getElementById('quick-loc-sel');
|
||||
if(sel&&sel.value)return sel.value;
|
||||
const locs=getLocs();return locs[0]?.name||'서울';
|
||||
};
|
||||
function askWeather(type){
|
||||
const loc=currentLoc();
|
||||
const msgs={
|
||||
@@ -504,10 +523,16 @@ function askWeather(type){
|
||||
uv:`${loc} 오늘 자외선 지수와 시간대별 변화를 알려주세요.`,
|
||||
climate:`${loc}의 월별 기후 평균(기온·강수량)을 30년 기준으로 알려주세요.`,
|
||||
past:`${loc} 오늘 날짜 기준 역대 같은 날 날씨 기록을 알려주세요.`,
|
||||
alert:`현재 ${loc} 및 전국 기상 특보(태풍·호우·폭염·한파·강풍·풍랑·황사)가 발효 중인지 알려주세요. 특보 종류, 대상 지역, 해제 예상 시간을 포함해주세요.`,
|
||||
};
|
||||
sendToChat(msgs[type]||'날씨를 알려주세요.');
|
||||
}
|
||||
|
||||
function fetchAlerts(){
|
||||
document.getElementById('alert-content').textContent='💬 채팅창에서 확인하세요';
|
||||
sendToChat('현재 한국 전국 기상 특보(태풍·호우·폭염·한파·강풍·황사 등)가 발효 중인지 알려주세요. 없으면 "현재 특보 없음"이라고만 답하세요.');
|
||||
}
|
||||
|
||||
// ── Chat ──────────────────────────────────────────────────────────────────────
|
||||
function addMsg(role,html){
|
||||
const msgs=document.getElementById('chat-msgs');
|
||||
|
||||
Reference in New Issue
Block a user