feat(接口2/7): hair_style改为多选复选框,新增接口7测试页,网关注册v2路由
- 接口2/7测试页:发型从单选下拉框改为多选复选框+全选/全不选,提交时逗号分隔 - 新建static/test_interface7.html(基于接口2测试页,紫色主题,调用/api/v1/hair/grow-v2) - gateway/app.py:注册/api/v1/hair/grow-v2代理路由 + 首页索引 - integration.html:新增接口7完整文档卡片(入参/出参/测试页链接) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +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; }
|
||||
.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; }
|
||||
@@ -63,7 +69,7 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>💇 接口2 — C端生发 测试</h1>
|
||||
<p class="subtitle">POST /api/v1/hair/grow | 正面照 + 性别 → 每个方案展示:原图 / 发际线叠加 / 生发效果</p>
|
||||
<p class="subtitle">POST /api/v1/hair/grow | 正面照 + 性别 + 发型多选 → 所选发型的预览图与生发图</p>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@@ -71,7 +77,17 @@
|
||||
<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</option><option value="male">👨 Male</option></select>
|
||||
<select id="gender" onchange="onGenderChange()"><option value="female" selected>👩 Female</option><option value="male">👨 Male</option></select>
|
||||
</div>
|
||||
<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>
|
||||
<div class="form-group">
|
||||
<label>inpaint 遮罩</label>
|
||||
@@ -95,7 +111,7 @@
|
||||
<div class="results-layout hidden" id="resultsArea">
|
||||
<div class="col-main">
|
||||
<div class="card">
|
||||
<div class="card-header"><span>🗂️ 全部方案 — 一覧</span></div>
|
||||
<div class="card-header"><span>🗂️ 生发结果</span></div>
|
||||
<div class="card-body" id="schemesContainer"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,7 +144,10 @@ async function submitTest() {
|
||||
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ 请求中...';
|
||||
setStatus('⏳ 请求中(生发图生成较慢,请耐心)...', 'info'); $('resultsArea').classList.add('hidden');
|
||||
|
||||
const checked = [...document.querySelectorAll('#hairStyleGroup input:checked')].map(cb => cb.value);
|
||||
if (checked.length === 0) { setStatus('请至少勾选一个发型', 'error'); $('submitBtn').disabled = false; $('submitBtn').textContent = '🚀 提交'; return; }
|
||||
const fd = new FormData(); fd.append('image_file', f); fd.append('gender', $('gender').value);
|
||||
fd.append('hair_style', checked.join(','));
|
||||
fd.append('use_mask', $('useMask').value);
|
||||
fd.append('prompt', $('promptInput').value);
|
||||
try {
|
||||
@@ -196,7 +215,42 @@ function copyJson() {
|
||||
});
|
||||
}
|
||||
|
||||
const HAIR_STYLES = {
|
||||
female: [
|
||||
{ value:'1', label:'ellipse 椭圆形' },
|
||||
{ value:'2', label:'flower 花瓣形' },
|
||||
{ value:'3', label:'heart 心形' },
|
||||
{ value:'4', label:'straight 直线形' },
|
||||
{ value:'5', label:'wave 波浪形' },
|
||||
],
|
||||
male: [
|
||||
{ value:'1', label:'ellipse 椭圆形' },
|
||||
{ value:'2', label:'inverse_arc 倒弧形' },
|
||||
{ value:'3', label:'m M形' },
|
||||
{ value:'4', label:'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; });
|
||||
}
|
||||
|
||||
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