save code
This commit is contained in:
+56
-17
@@ -21,7 +21,12 @@
|
||||
.form-group { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
|
||||
.form-group label { font-size: 13px; font-weight: 600; color: #374151; }
|
||||
.form-group select { padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; }
|
||||
.form-group input[type=text] { padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 14px; width: 150px; }
|
||||
.hair-checkboxes { display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center; }
|
||||
.hair-checkboxes label { font-size: 13px; font-weight: 500; color: #374151; cursor: pointer; display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }
|
||||
.hair-checkboxes label input[type=checkbox] { cursor: pointer; }
|
||||
.checkbox-actions { display: flex; gap: 6px; margin-left: 4px; }
|
||||
.checkbox-actions button { font-size: 11px; padding: 2px 8px; border-radius: 4px; border: 1px solid #d1d5db; background: #f9fafb; cursor: pointer; }
|
||||
.checkbox-actions button:hover { background: #e5e7eb; }
|
||||
.btn { padding: 10px 28px; border: none; border-radius: 8px; font-size: 15px; cursor: pointer; font-weight: 600; transition: .2s; }
|
||||
.btn-primary { background: #2563eb; color: #fff; }
|
||||
.btn-primary:hover { background: #1d4ed8; }
|
||||
@@ -50,14 +55,6 @@
|
||||
.result-card .info { padding: 10px 12px; font-size: 12px; display: flex; justify-content: space-between; align-items: center; }
|
||||
.result-card .info .badge { background: #2563eb; color: #fff; padding: 1px 8px; border-radius: 10px; font-size: 11px; }
|
||||
|
||||
/* 预览叠加 */
|
||||
.preview-stack { position: relative; display: inline-block; line-height: 0; background: #222; border-radius: 8px; overflow: hidden; }
|
||||
.preview-stack img { display: block; max-width: 100%; max-height: 450px; }
|
||||
.preview-stack .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
|
||||
|
||||
.preview-controls { display: flex; gap: 14px; align-items: center; font-size: 12px; color: #9ca3af; }
|
||||
.preview-controls label { display: flex; align-items: center; gap: 4px; cursor: pointer; }
|
||||
|
||||
/* 三档 + 生发图 横向排列 */
|
||||
.level-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
|
||||
.level-cell { background: #222; border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; }
|
||||
@@ -89,16 +86,22 @@
|
||||
<div class="file-input"><input type="file" id="imageFile" accept="image/jpeg,image/png,.jpg,.jpeg,.png"></div>
|
||||
<div class="form-group">
|
||||
<label>性别</label>
|
||||
<select id="gender"><option value="female" selected>👩 Female(5种)</option><option value="male">👨 Male(4种)</option></select>
|
||||
<select id="gender" onchange="onGenderChange()"><option value="female" selected>👩 Female(5种)</option><option value="male">👨 Male(4种)</option></select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label title="必填,逗号分隔多选如 1,2,3">发型序号 *</label>
|
||||
<input type="text" id="hairStyle" placeholder="必填 如 1,2,3">
|
||||
<div class="form-group" style="align-items:flex-start">
|
||||
<label style="padding-top:3px">发型 *</label>
|
||||
<div>
|
||||
<div class="hair-checkboxes" id="hairStyleGroup"></div>
|
||||
<div class="checkbox-actions" style="margin-top:4px">
|
||||
<button type="button" onclick="selectAllHair(true)">全选</button>
|
||||
<button type="button" onclick="selectAllHair(false)">全不选</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" id="submitBtn" onclick="submitTest()">🚀 提交</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="clearResults()">清除</button>
|
||||
</div>
|
||||
<div class="hint">JPG/PNG 正面照 | 发型序号 Female: 1椭圆/2花瓣/3心形/4直线/5波浪 | Male: 1椭圆/2倒弧/3M形/4直线 | 每个发型返回 middle/high/low 三档 + 生发图</div>
|
||||
<div class="hint">JPG/PNG 正面照 | Female: 椭圆/花瓣/心形/直线/波浪 | Male: 椭圆/倒弧/M形/直线 | 每个发型返回 middle/high/low 三档 + 生发图</div>
|
||||
<div id="statusBar" class="status hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,17 +141,52 @@ let _images = [], _origUrl = '', _center = null;
|
||||
function $(id) { return document.getElementById(id); }
|
||||
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
||||
|
||||
// 发型列表(同接口2)
|
||||
const HAIR_STYLES = {
|
||||
female: [
|
||||
{ value:'1', label:'1. ellipse 椭圆' },
|
||||
{ value:'2', label:'2. flower 花瓣' },
|
||||
{ value:'3', label:'3. heart 心形' },
|
||||
{ value:'4', label:'4. straight 直线' },
|
||||
{ value:'5', label:'5. wave 波浪' },
|
||||
],
|
||||
male: [
|
||||
{ value:'1', label:'1. ellipse 椭圆' },
|
||||
{ value:'2', label:'2. inverse_arc 倒弧' },
|
||||
{ value:'3', label:'3. m M形' },
|
||||
{ value:'4', label:'4. straight 直线' },
|
||||
]
|
||||
};
|
||||
|
||||
function onGenderChange() {
|
||||
const g = $('gender').value;
|
||||
const div = $('hairStyleGroup');
|
||||
div.innerHTML = '';
|
||||
HAIR_STYLES[g].forEach(s => {
|
||||
const cb = document.createElement('input');
|
||||
cb.type = 'checkbox'; cb.value = s.value; cb.id = 'hs_' + s.value;
|
||||
const lb = document.createElement('label');
|
||||
lb.htmlFor = cb.id; lb.appendChild(cb);
|
||||
lb.appendChild(document.createTextNode(' ' + s.label));
|
||||
div.appendChild(lb);
|
||||
});
|
||||
}
|
||||
|
||||
function selectAllHair(select) {
|
||||
document.querySelectorAll('#hairStyleGroup input[type=checkbox]').forEach(cb => { cb.checked = select; });
|
||||
}
|
||||
|
||||
async function submitTest() {
|
||||
const f = $('imageFile').files[0];
|
||||
if (!f) { setStatus('请选择图片', 'error'); return; }
|
||||
const _hs = $('hairStyle').value.trim();
|
||||
if (!_hs) { setStatus('请填写发型序号(必填,如 1,2,3)', 'error'); return; }
|
||||
const checked = [...document.querySelectorAll('#hairStyleGroup input:checked')].map(cb => cb.value);
|
||||
if (!checked.length) { setStatus('请至少选择一个发型', 'error'); return; }
|
||||
|
||||
_origUrl = URL.createObjectURL(f);
|
||||
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ ...';
|
||||
setStatus('请求中...', 'info'); $('resultsArea').classList.add('hidden');
|
||||
|
||||
const fd = new FormData(); fd.append('image_file', f); fd.append('gender', $('gender').value); fd.append('hair_style', _hs);
|
||||
const fd = new FormData(); fd.append('image_file', f); fd.append('gender', $('gender').value); fd.append('hair_style', checked.join(','));
|
||||
const _reqStart = performance.now();
|
||||
try {
|
||||
const r = await fetch(API_BASE + '/api/v1/hairline/generate', { method:'POST', body:fd });
|
||||
@@ -214,6 +252,7 @@ function copyJson() {
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
onGenderChange(); // 初始填充发型列表
|
||||
const dz = $('imageFile');
|
||||
dz.addEventListener('dragover', e => { e.preventDefault(); dz.style.borderColor='#2563eb'; });
|
||||
dz.addEventListener('dragleave', () => dz.style.borderColor='#ddd');
|
||||
|
||||
Reference in New Issue
Block a user