"""Read-only mobile illustration of the user-confirmed meal-detail / handlePhone entry."""
from pathlib import Path
import re,json,hashlib,subprocess,urllib.request,base64
from urllib.parse import urlsplit
R=Path(__file__).parent.resolve();repo=R.parents[1];app=repo.parent/'zhctproject/ai_app';out=R/'public-build';cache=out/'meal-assets';cache.mkdir(parents=True,exist_ok=True)
p=app/'pagescourses/meals/meal-detail.vue';source=p.read_text();assert '拍照添加' in source and 'handlePhone()' in source and "pagescourses/meals/identify" in source
style=re.search(r'<style lang="scss" scoped>([\s\S]*?)</style>',source).group(1);scss=out/'meal-source.scss';scss.write_text(style)
cmd='const s=require(process.argv[1]);process.stdout.write(s.renderSync({file:process.argv[2],outputStyle:"compressed"}).css.toString())'
css=subprocess.check_output(['node','-e',cmd,str(repo.parent/'zhctproject/store/public/static/node_modules/sass'),str(scss)],text=True)
css=re.sub(r'(-?\d+(?:\.\d+)?)rpx',lambda m:'calc('+m.group(1)+' * var(--rpx))',css)
assets=[]
def asset(path):
 url='https://img.kxunpt.cn/ai/'+path;f=cache/(hashlib.sha256(url.encode()).hexdigest()[:18]+Path(path).suffix)
 if not f.exists():
  with urllib.request.urlopen(url,timeout=20) as r:f.write_bytes(r.read())
 b=f.read_bytes();mime='image/png' if b.startswith(b'\x89PNG') else 'image/jpeg' if b.startswith(b'\xff\xd8') else 'image/svg+xml' if b'<svg' in b[:600] else None
 if not mime:raise ValueError(url)
 assets.append({'url':url,'sha256':hashlib.sha256(b).hexdigest()})
 return 'data:'+mime+';base64,'+base64.b64encode(b).decode()
breakfast=asset('static/home/breakfast.svg');food=asset('default_dish.png');arrow=asset('static/right.svg');select=asset('select-add.svg');camera=asset('phone-add.svg')
# Buttons, labels and layout follow source. Diet data are synthetic, not copied from the screenshot.
rows=''.join(f'<div class="goods-item"><img class="image" data-default-dish alt="菜品示例图"><div class="goods-item-right"><div class="goods-name"><span>{name}</span><div class="item-prices">{weight}克</div></div><div class="desc-right"><span class="price-x">{energy}千卡</span><img src="{arrow}" style="width:8px;height:15px"></div></div></div>' for name,weight,energy in [('示例食物 A',100,100),('示例食物 B',100,120),('示例食物 C',150,160)])
body=f'''<div class="status"><b>09:41</b><span>▮▮▮ ◉ ▰</span></div><header><span>‹</span><strong>餐品详情</strong><i>••• │ ◉</i></header><main class="detail"><div class="card"><div class="card-title"><div><img src="{breakfast}">早餐及早加餐</div><span class="sub-title">350克</span></div><div class="card-content">{rows}</div></div><section class="card energy"><h2>当餐供能营养素摄入 ✦</h2><div class="ring"><div><strong>380</strong><small>千卡</small></div></div><p>蛋白质 20%　脂肪 25%　碳水化合物 55%</p><small>合成数据示意，非用户实际餐品</small></section><div class="static-btn"><button class="custom-button" data-existing-action="handleAddFood"><img class="custom-icon" src="{select}">选择添加</button><button class="custom-button" id="photo-add" data-existing-action="handlePhone" style="background-color:#f57440"><img class="custom-icon" src="{camera}">拍照添加</button></div></main><div class="entry-note" hidden role="status"></div>'''
bridge="""function size(){var w=Math.min(innerWidth,430);document.documentElement.style.setProperty('--rpx',w/750+'px');document.documentElement.style.setProperty('--page-width',w+'px')}size();addEventListener('resize',size);function locate(){document.querySelector('#photo-add').classList.add('highlight');const n=document.querySelector('.entry-note');n.textContent='已有入口：餐品详情 → 拍照添加 → handlePhone() → 识别页。此页只定位，不调用相机或上传。';n.hidden=false;setTimeout(()=>{n.hidden=true;document.querySelector('#photo-add').classList.remove('highlight')},6000)}document.querySelector('#photo-add').onclick=locate;document.querySelector('[data-existing-action=handleAddFood]').onclick=()=>{const n=document.querySelector('.entry-note');n.textContent='选择添加是原有手工选菜入口；本次图片识别使用右侧“拍照添加”。';n.hidden=false};addEventListener('message',e=>{if(e.source===parent&&e.origin===location.origin&&e.data?.type==='dwm-locate-image')locate()})"""
adapter='''html,body{margin:0;background:#f5f6fa;color:#111;font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif}*{box-sizing:border-box}body{max-width:430px;margin:auto}.status{display:flex;justify-content:space-between;padding:16px 24px 8px;font-size:13px}header{display:flex;align-items:center;justify-content:center;height:56px;position:relative}header strong{font-size:19px}header>span{position:absolute;left:16px;font-size:32px}header i{position:absolute;right:12px;font-style:normal;border-radius:20px;background:#fff7;font-size:13px;padding:4px 10px}.card{background:white;border-radius:16px;padding:18px 16px;margin:10px 0}.card-title{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #eee;padding-bottom:15px;font-size:18px;font-weight:650}.card-title>div{display:flex;align-items:center}.card-title img{width:43px;height:43px;margin-right:8px}.sub-title{font-size:15px;color:#999;font-weight:400}.goods-name .item-prices{color:#999;font-weight:400}.energy h2{font-size:19px;margin:0}.energy{padding-bottom:35px;margin-bottom:90px}.ring{width:160px;height:160px;margin:32px auto 20px;background:conic-gradient(#a9c9ff 0 20%,#f5aeae 20% 45%,#ffdc67 45% 100%);border-radius:50%;display:grid;place-items:center}.ring>div{width:118px;height:118px;border-radius:50%;background:white;display:flex;align-items:center;justify-content:center;flex-direction:column}.ring strong{font-size:27px}.ring small{color:#999}.energy p,.energy>small{font-size:11px;color:#999;text-align:center;display:block}.static-btn{max-width:430px;width:var(--page-width);left:50%!important;right:auto!important;transform:translateX(-50%)}.custom-button{border:0;padding:13px 6px;font-family:inherit;cursor:pointer;margin:0 12px!important}.custom-icon{object-fit:contain}.highlight{outline:3px solid #ffb02e;outline-offset:4px}.entry-note{position:fixed;left:50%;bottom:95px;transform:translateX(-50%);max-width:380px;width:90%;padding:12px;border-radius:10px;background:#243c5e;color:white;font-size:12px;z-index:10000}.entry-note[hidden]{display:none}'''
bridge='const dishImage='+json.dumps(food)+';document.querySelectorAll("[data-default-dish]").forEach(i=>i.src=dishImage);'+bridge
page='<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="mini-program-source" content="ai_app/pagescourses/meals/meal-detail.vue"><title>餐品详情 · 拍照添加 · 源码示意</title><style>'+css+adapter+'</style></head><body>'+body+'<script>'+bridge+'</script></body></html>'
(out/'mini-program-review.html').write_text(page)
(R/'mini-program-code-evidence.json').write_text(json.dumps({'source':'ai_app/pagescourses/meals/meal-detail.vue','sha256':hashlib.sha256(p.read_bytes()).hexdigest(),'entry':'餐品详情 → 拍照添加 → handlePhone → uni.chooseMedia(camera,album) → pagescourses/meals/identify','parameters':['mealId','selectDate','src'],'user_confirmed':'Screenshot and explicit instruction in current turn','code_condition':'isType8 hides photo add; standard non-type8 sample shown','method':'Original meal-detail SCSS and existing brand assets; synthetic food rows and chart; native tag/viewport adapter. Not live capture.','assets':assets},ensure_ascii=False,indent=2)+'\n')
print('Meal detail photo-add source page built')
