diff --git a/alembic/versions/761ef181ce7c_merge_jd_cps_order_fields_and_coupon_.py b/alembic/versions/761ef181ce7c_merge_jd_cps_order_fields_and_coupon_.py new file mode 100644 index 0000000..80d5d01 --- /dev/null +++ b/alembic/versions/761ef181ce7c_merge_jd_cps_order_fields_and_coupon_.py @@ -0,0 +1,26 @@ +"""merge jd_cps_order_fields and coupon_session_origin_package heads + +Revision ID: 761ef181ce7c +Revises: coupon_session_origin_package, jd_cps_order_fields +Create Date: 2026-07-01 13:52:16.068808 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '761ef181ce7c' +down_revision: Union[str, Sequence[str], None] = ('coupon_session_origin_package', 'jd_cps_order_fields') +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + pass + + +def downgrade() -> None: + pass diff --git a/app/admin/repositories/ad_audit.py b/app/admin/repositories/ad_audit.py index d81f725..888467c 100644 --- a/app/admin/repositories/ad_audit.py +++ b/app/admin/repositories/ad_audit.py @@ -136,12 +136,16 @@ def _feed_scene_matches(rec: AdFeedRewardRecord, scene: str | None) -> bool: """该信息流记录是否落入请求的展示筛选 scene。 - scene=="feed":ad_type in ("feed", NULL)(旧数据 NULL 视为 feed,向后兼容) - scene=="draw":ad_type=="draw" + - scene=="feed_all":所有信息流(feed/draw/NULL 都要)——业务已全切 Draw 信息流,收益报表把「Draw 信息流」 + 当作整个信息流口径(含历史误标 feed/NULL),用它避免筛选漏历史。 - scene 为 None:不筛(两类都要)。 """ if scene == "feed": return rec.ad_type in (None, "feed") if scene == "draw": return rec.ad_type == "draw" + if scene == "feed_all": + return True return True @@ -184,6 +188,7 @@ def _feed_rows( "record_id": rec.id, "user_id": rec.user_id, "ad_session_id": rec.ad_session_id, + "trace_id": rec.trace_id, "app_env": rec.app_env, "our_code_id": rec.our_code_id, "created_at": rec.created_at, @@ -209,6 +214,7 @@ def _feed_rows( "record_id": rec.id, "user_id": rec.user_id, "ad_session_id": rec.ad_session_id, + "trace_id": rec.trace_id, "app_env": rec.app_env, "our_code_id": rec.our_code_id, "created_at": rec.created_at, @@ -241,7 +247,7 @@ def audit_rows( rows: list[dict] = [] if scene in (None, "reward_video"): rows.extend(_reward_video_rows(db, date=date, user_id=user_id)) - if scene in (None, "feed", "draw"): + if scene in (None, "feed", "draw", "feed_all"): rows.extend(_feed_rows(db, date=date, user_id=user_id, scene=scene)) return rows diff --git a/app/admin/repositories/ad_revenue.py b/app/admin/repositories/ad_revenue.py index ec6bd4a..8dfcf2d 100644 --- a/app/admin/repositories/ad_revenue.py +++ b/app/admin/repositories/ad_revenue.py @@ -3,9 +3,11 @@ 只读。每行 = 一次广告事件(不再按用户聚合): - **激励视频**:一次观看 = 1 条展示(ad_ecpm)+ 1 条发奖(ad_reward),按 ad_session_id 合并成一行, 直接给出 eCPM / 收益 + 状态 / 应发 / 实发 / 一致;点开看该条金币复算因子。 -- **信息流**:轮播每条展示各一行(impressionId 各自独立);整场发奖(ad_feed_reward,client_event_id) - 与逐条展示无法对应,单独成「纯发奖」行。 -- 兜底:有展示无发奖(中途关 / 未达发奖)、有发奖无展示(未上报 eCPM)都各自成行。 +- **信息流(比价/领券)**:一次比价 / 一次领券 = 一条整场发奖(ad_feed_reward)一行,给出 eCPM / + 发奖金币 + 应发 / 实发 / 一致;点开看金币复算因子。⚠️ draw 的逐条展示(ad_ecpm,impressionId 各自 + 独立、与整场发奖无公共键、无法归到「哪一次」)**不再单独占行**(2026-07 按「一次比价/领券放一块」调整)—— + 其展示数 / eCPM / 预估收益仍进全量统计(合计 / 趋势 / 分类大盘 / 穿山甲对照),只是主表不逐条铺开。 +- 兜底:激励视频有展示无发奖(中途关 / 未达发奖)、有发奖无展示(未上报 eCPM)仍各自成行。 展示与收益来自 ad_ecpm_record(收益 = eCPM元 ÷ 1000);应发 / 实发金币复用金币审计逐条复算 (ad_audit.audit_rows,与正式发奖同一公式口径,不另写公式)。合计与对账在全量上统计, @@ -58,14 +60,6 @@ def _date_range(date_from: str, date_to: str) -> list[str]: _AUDIT_SCENES = {"reward_video", "feed", "draw"} -def _event_ad_type(row: dict) -> str: - """纯发奖事件行的 ad_type:信息流行用 audit 带回的真实 ad_type(feed/draw),回退 feed; - 激励视频行恒 reward_video。不再用 scene 硬映射,避免把 draw 丢成 feed。""" - if row["scene"] == "reward_video": - return "reward_video" - return row.get("ad_type") or "feed" - - # 发奖复算明细字段(展开下钻看「金币怎么算出来的」)——从 audit 行原样取这些 key。 _REWARD_DETAIL_KEYS = ( "record_id", "created_at", "status", "ecpm", "ecpm_factor", "units", @@ -108,9 +102,14 @@ def ad_revenue_report( # 同时保留全量列表,未被展示合并的成「纯发奖」事件。 reward_by_session: dict[tuple[int, str], list[dict]] = {} all_reward_rows: list[dict] = [] - # 报表 ad_type 直接当 audit scene 用(取值一致);未知/无效 ad_type 不取发奖行。draw 在此被 - # 正确传成 scene="draw",audit 会按 ad_type 筛出 Draw 发奖,不再丢成 feed。 - audit_scene = ad_type if ad_type in _AUDIT_SCENES else None + # 报表 ad_type → audit scene:reward_video/feed 直传;**draw(前端「Draw 信息流」)映射成 feed_all** + # ——业务已全切 Draw,把「Draw 信息流」当作整个信息流口径(含历史误标 feed/NULL),否则筛选会漏历史。 + if ad_type == "draw": + audit_scene = "feed_all" + elif ad_type in _AUDIT_SCENES: + audit_scene = ad_type + else: + audit_scene = None if ad_type is None or audit_scene is not None: for d in _date_range(date_from, date_to): for row in ad_audit.audit_rows(db, date=d, user_id=user_id, scene=audit_scene): @@ -140,7 +139,10 @@ def ad_revenue_report( ) if user_id is not None: stmt = stmt.where(AdEcpmRecord.user_id == user_id) - if ad_type is not None: + if ad_type == "draw": + # draw = 所有信息流展示(业务已全 Draw,含历史误标 feed);展示行只进统计,不占主表行 + stmt = stmt.where(AdEcpmRecord.ad_type.in_(["draw", "feed"])) + elif ad_type is not None: stmt = stmt.where(AdEcpmRecord.ad_type == ad_type) for rec in db.execute(stmt).scalars(): rwd = _pop_reward(rec.user_id, rec.ad_session_id) @@ -165,6 +167,8 @@ def ad_revenue_report( ), "adn": rec.adn, "slot_id": rec.slot_id, + "sub_rewards": [], + "sub_count": 1, } if rwd is not None: ev.update({ @@ -184,33 +188,88 @@ def ad_revenue_report( }) events.append(ev) - # 3) 未被展示合并的发奖行 → 「纯发奖」事件(信息流整场发奖 / 有发奖无展示)。 - # 收益恒 0(收益只算展示侧,避免与展示行重复计)。 + # 3) 未被展示合并的发奖行 → 事件: + # - 激励视频(reward_video):逐条成「纯发奖」事件(每次一个 ad_session_id;有发奖无展示等)。 + # - 信息流(feed/draw):同一次比价/领券的多条广告共享**整场 ad_session_id**(客户端整场复用), + # 按 (user_id, ad_session_id) 聚成**一次比价 / 一次领券**父事件;sub_rewards 为组内逐条明细, + # 应发/实发取组内合计;业务已全 Draw → 类型统一 "draw"。session 缺失(极少旧数据)各自单独成组。 + feed_groups: dict[tuple[int, str], list[dict]] = {} for row in all_reward_rows: if row["record_id"] in used_reward_ids: continue + if row["scene"] == "reward_video": + events.append({ + "event_key": f"rwd-{row['record_id']}", + "report_date": row["_report_date"], + "user_id": row["user_id"], + "ad_type": "reward_video", + "feed_scene": row.get("feed_scene"), + "app_env": row.get("app_env"), + "our_code_id": row.get("our_code_id"), + "created_at": row["created_at"], + "hour": _cn_hour(row["created_at"]) if by_hour else None, + "has_impression": False, + "impressions": 0, + "ecpm": row["ecpm"], + "revenue_yuan": 0.0, + "adn": None, + "slot_id": None, + "has_reward": True, + "status": row["status"], + "expected_coin": int(row["expected_coin"]), + "actual_coin": int(row["actual_coin"]), + "matched": bool(row["matched"]), + "reward_detail": _reward_detail(row), + "sub_rewards": [], + "sub_count": 1, + }) + else: + # 聚合单位 = 一次完整比价/领券流程:优先用 trace_id(比价带 comparisonTraceId、领券带 sessionTraceId, + # 整个流程不变;即使中途点广告致浮层关闭重弹、ad_session_id 变了,trace_id 仍不变 → 全流程聚成一行)。 + # 无 trace_id(历史领券未上报 / 旧数据)回退整场 ad_session_id;再无则 record_id 各自成组、不误并。 + grp_key = row.get("trace_id") or row.get("ad_session_id") or f"_rid-{row['record_id']}" + feed_groups.setdefault((row["user_id"], grp_key), []).append(row) + + # 信息流分组 → 「一次比价 / 一次领券」父事件(收益恒 0:收益只算展示侧,避免与展示行重复计)。 + for (uid, grp_key), group in feed_groups.items(): + group.sort(key=lambda r: (r["created_at"], r["record_id"])) + rep = group[-1] # 代表条(最新一条):时间/场景/应用/代码位取它 + expected_sum = sum(int(g["expected_coin"]) for g in group) + actual_sum = sum(int(g["actual_coin"]) for g in group) + # 父行 eCPM:组内各条 eCPM(分)均值(展示用,各条不同);无有效值则取代表条 + ecpm_fens = [rewards.parse_ecpm_fen(g["ecpm"]) for g in group if g.get("ecpm")] + avg_ecpm = str(round(sum(ecpm_fens) / len(ecpm_fens))) if ecpm_fens else rep.get("ecpm") + # 主表逐行显示用:这次发奖广告的预估收益之和(发奖侧 eCPM 折算,钳顶同展示侧)。只放进 + # row_revenue_yuan 给主表逐行展示,不进 revenue_yuan/合计/趋势——避免与展示侧 total 重复计。 + row_revenue = round(sum( + min(rewards.parse_ecpm_yuan(g["ecpm"]), rewards.AD_ECPM_MAX_FEN / 100.0) / 1000.0 + for g in group if g.get("ecpm") + ), 6) events.append({ - "event_key": f"rwd-{row['record_id']}", - "report_date": row["_report_date"], - "user_id": row["user_id"], - "ad_type": _event_ad_type(row), - "feed_scene": row.get("feed_scene"), - "app_env": row.get("app_env"), - "our_code_id": row.get("our_code_id"), - "created_at": row["created_at"], - "hour": _cn_hour(row["created_at"]) if by_hour else None, + "event_key": f"feedgrp-{uid}-{grp_key}", + "report_date": rep["_report_date"], + "user_id": uid, + "ad_type": "draw", # 业务已全切 Draw 信息流,聚合行统一 draw + "feed_scene": rep.get("feed_scene"), + "app_env": rep.get("app_env"), + "our_code_id": rep.get("our_code_id"), + "created_at": rep["created_at"], + "hour": _cn_hour(rep["created_at"]) if by_hour else None, "has_impression": False, "impressions": 0, - "ecpm": row["ecpm"], + "ecpm": avg_ecpm, "revenue_yuan": 0.0, + "row_revenue_yuan": row_revenue, "adn": None, "slot_id": None, "has_reward": True, - "status": row["status"], - "expected_coin": int(row["expected_coin"]), - "actual_coin": int(row["actual_coin"]), - "matched": bool(row["matched"]), - "reward_detail": _reward_detail(row), + "status": rep["status"], # 代表状态(逐条见展开) + "expected_coin": expected_sum, + "actual_coin": actual_sum, + "matched": all(bool(g["matched"]) for g in group), + "reward_detail": None, + "sub_rewards": [_reward_detail(g) for g in group], + "sub_count": len(group), }) # 「场景」作为全局筛选(与 user_id/ad_type 一致):同时作用于明细、合计与 daily/hourly 趋势。 @@ -331,9 +390,20 @@ def ad_revenue_report( is_today = date_from == date_to == rewards.cn_today().isoformat() dau = admin_stats.today_dau(db) if is_today else None + # 主表「逐行」= 单次广告行为(2026-07 按「一次比价/领券放一块」聚合):激励视频 = 一次观看一行(展示+发奖 + # 按 ad_session_id 合并);一次比价 / 一次领券 = 该次整场多条广告按 ad_session_id 聚成一行(展开看逐条)。 + # 信息流(draw/feed)的逐条展示(ad_ecpm,impressionId 各自独立、与整场发奖无公共键)不再单独占行 + # ——其展示数 / eCPM / 预估收益已计入上面的全量统计(total_*、daily / hourly、type_stats、穿山甲对照), + # 只是主表不逐条铺开;逐条明细在父行展开里看(sub_rewards)。合计 / 趋势 / 分类大盘均基于全量 events, + # 不受此过滤影响;total / 分页只作用于主表行。 + main_rows = [ + e for e in events + if not (e["ad_type"] in ("draw", "feed") and e["has_impression"] and not e["has_reward"]) + ] + return { - "total": len(events), - "truncated": len(events) > offset + limit, + "total": len(main_rows), + "truncated": len(main_rows) > offset + limit, "total_impressions": total_impressions, "total_revenue_yuan": total_revenue_yuan, # 穿山甲后台收益合计(元):预估 revenue + 收益Api;非全量视图(带 user/类型/场景过滤)或无数据为 None。 @@ -347,5 +417,5 @@ def ad_revenue_report( "hourly": hourly, "type_stats": type_stats, "dau": dau, - "items": events[offset:offset + limit], + "items": main_rows[offset:offset + limit], } diff --git a/app/admin/repositories/queries.py b/app/admin/repositories/queries.py index 488bcf7..51ef145 100644 --- a/app/admin/repositories/queries.py +++ b/app/admin/repositories/queries.py @@ -806,6 +806,12 @@ def get_user_overview(db: Session, user_id: int) -> dict | None: } +def _as_utc_naive(value: datetime) -> datetime: + """窗口入参 → UTC naive(= _as_utc 去时区),与库里按 naive UTC 存取的 created_at 同口径比较。 + 历史遗留:_window_conds 一直引用本函数却未定义(自定义区间会 NameError),此处补上。""" + return _as_utc(value).replace(tzinfo=None) + + def _window_conds(col, date_from: datetime | None, date_to: datetime | None) -> list: """把 [date_from, date_to] 转成对 col(created_at)的过滤条件;都为 None = 全量(注册至今)。""" conds = [] @@ -895,6 +901,13 @@ def user_reward_stats( } +def _cn_wall_to_utc(dt: datetime) -> datetime: + """coin_transaction 存的是北京 wall-clock(naive,见 wallet.grant_coins「存北京 wall-clock」),转成 UTC naive, + 与广告表(func.now() UTC)统一 —— 让本函数按同一绝对时刻排序、且前端 apiTime(把无时区时间当 UTC 再 +8 展示) + 口径一致;否则签到会比实际多显示 8 小时(北京时间又被 +8)。""" + return dt.replace(tzinfo=rewards.CN_TZ).astimezone(timezone.utc).replace(tzinfo=None) + + def user_coin_records( db: Session, user_id: int, @@ -915,6 +928,9 @@ def user_coin_records( offset = max(cursor or 0, 0) fetch = offset + limit + 1 rows: list[dict] = [] + # coin_transaction 存北京 wall-clock(其余表存 UTC);签到窗口边界 +8h 对齐北京,过滤/计数才不偏移 8 小时 + signin_from = date_from + timedelta(hours=8) if date_from is not None else None + signin_to = date_to + timedelta(hours=8) if date_to is not None else None for rec in db.execute( select(AdRewardRecord) @@ -958,7 +974,7 @@ def user_coin_records( .where( CoinTransaction.user_id == user_id, CoinTransaction.biz_type == "signin", - *_window_conds(CoinTransaction.created_at, date_from, date_to), + *_window_conds(CoinTransaction.created_at, signin_from, signin_to), ) .order_by(CoinTransaction.created_at.desc()) .limit(fetch) @@ -966,7 +982,8 @@ def user_coin_records( rows.append({ "source": "signin", "source_label": "签到", - "created_at": rec.created_at, + # 北京 wall-clock → UTC,与广告记录统一(前端 apiTime 会 +8 回北京展示,不然签到会多 8 小时) + "created_at": _cn_wall_to_utc(rec.created_at), "ecpm": None, "coin": rec.amount, }) @@ -992,7 +1009,7 @@ def user_coin_records( + _count( CoinTransaction, CoinTransaction.user_id == user_id, CoinTransaction.biz_type == "signin", - *_window_conds(CoinTransaction.created_at, date_from, date_to), + *_window_conds(CoinTransaction.created_at, signin_from, signin_to), ) ) return rows[offset:offset + limit], (offset + limit if has_more else None), total diff --git a/app/admin/schemas/ad_revenue.py b/app/admin/schemas/ad_revenue.py index a45ec5e..cec29b2 100644 --- a/app/admin/schemas/ad_revenue.py +++ b/app/admin/schemas/ad_revenue.py @@ -94,6 +94,11 @@ class AdRevenueRow(BaseModel): impressions: int = Field(..., description="本行展示条数:有展示=1 / 纯发奖=0(供日汇总、趋势图复用)") ecpm: str | None = Field(None, description="eCPM 原始值(分/千次);展示行取展示值,纯发奖行取发奖采用值") revenue_yuan: float = Field(..., description="本次展示预估收益(元)= eCPM元 ÷ 1000;纯发奖行=0") + row_revenue_yuan: float | None = Field( + None, + description="主表逐行展示用的预估收益(元):一次比价/领券聚合行=该次发奖广告 eCPM 折算之和;" + "其它行为空(前端回退取 revenue_yuan)。不进合计/趋势,避免与展示侧重复计", + ) adn: str | None = Field(None, description="实际填充 ADN 子渠道(pangle/gdt…);纯发奖行为空") slot_id: str | None = Field(None, description="底层 mediation rit(非我们配置的广告位 ID);纯发奖行为空") # ── 发奖侧 ── @@ -106,6 +111,15 @@ class AdRevenueRow(BaseModel): None, description="发奖复算明细(eCPM/因子1/份数/LT/因子2/应发/实发/一致);点行展开下钻用,纯展示为空", ) + sub_rewards: list[AdRevenueRecord] = Field( + default_factory=list, + description="一次比价/领券聚合行的组内逐条发奖明细(同一整场 ad_session_id 的多条广告);" + "点行展开渲染多行。激励视频/纯展示行为空(单条看 reward_detail)", + ) + sub_count: int = Field( + 1, + description="本行聚合的发奖条数:一次比价/领券=该次广告条数(≥1);激励视频/纯展示=1", + ) class AdRevenueReportOut(BaseModel): diff --git a/app/admin/schemas/user.py b/app/admin/schemas/user.py index 8e7020e..2e554a8 100644 --- a/app/admin/schemas/user.py +++ b/app/admin/schemas/user.py @@ -17,6 +17,7 @@ class AdminUserListItem(BaseModel): status: str debug_trace_enabled: bool = False wechat_openid: str | None = None + wechat_nickname: str | None = None created_at: datetime last_login_at: datetime diff --git a/app/main.py b/app/main.py index 6aded37..9ac9e27 100644 --- a/app/main.py +++ b/app/main.py @@ -167,3 +167,22 @@ app.mount( StaticFiles(directory=str(_media_root)), name="media", ) + +# 业务 H5 同源托管(/h5)。与 /api/v1 同 host → H5 用相对路径调后端,免 CORS。 +# .html 加 no-cache:后端改完用户重开页即拉新(远程热更核心);js/图片走默认缓存。 +class _NoCacheHTMLStaticFiles(StaticFiles): + async def get_response(self, path: str, scope): + resp = await super().get_response(path, scope) + # 按响应 content-type 判定,而非请求 path:html=True 时目录式 URL(/h5/x/) + # 经 Starlette 内部回落到 index.html,此刻 path 仍是 "x/"(不带 .html)。 + if resp.headers.get("content-type", "").startswith("text/html"): + resp.headers["Cache-Control"] = "no-cache" + return resp + + +_h5_root = Path(__file__).resolve().parent.parent / "h5" +app.mount( + "/h5", + _NoCacheHTMLStaticFiles(directory=str(_h5_root), html=True), + name="h5", +) diff --git a/docs/H5-WebView改造方案.md b/docs/H5-WebView改造方案.md new file mode 100644 index 0000000..0dc6e41 --- /dev/null +++ b/docs/H5-WebView改造方案.md @@ -0,0 +1,154 @@ +# H5 / WebView 改造方案(app-server 端) + +> 仓库:`shaguabijia-app-server` 分支:`feat/h5-sgbridge` 日期:2026-06-29 +> 配套文档:`shaguabijia-app-android` 仓库 `docs/H5-WebView改造方案.md`(原生壳 + SGBridge.kt) +> 本方案 = **方案1:以本仓已有 `SGBridge` 为统一基准**,安卓退役其 `NativeBridge`。 + +--- + +## 1. 背景与现状 + +项目里同时存在**两套互不兼容**的 H5 方案,尚未收敛: + +| | 本仓那套(已在 `main`,PR #89) | 安卓那套(`feat/records-h5`,未进 main) | +|---|---|---| +| 桥 | `SGBridge`(JS)↔ `SGBridgeNative`(原生),协议丰富 + 事件总线 | `NativeBridge`,仅 4 法 | +| 托管 | **设计为**后端同源托管(相对 `/api/v1`、免 CORS) | 本地 assets `file://`(跨域 + 放行 CORS) | +| 页面 | `h5/mine/index.html`(7771)+ `h5/shared/bridge.js`+`api.js` | `records`(1778)、`reports`(603) | +| 落地 | **半成品**:安卓从无 `SGBridge.kt`;且 `h5/` 实际没挂(StaticFiles 只挂了 `data/media` 头像上传) | 已接进安卓导航但只在分支上 | + +**结论(已对齐):** 目标是「远程后端托管 + 四 tab 全 H5」,该方向天然契合本仓 SGBridge(同源相对路径、`mine` 已成型、`shared/` 已就绪)。故统一到 SGBridge,把安卓的 records/reports 页**迁入本仓** `h5/`。 + +--- + +## 2. 目标与范围 + +**目标:** 由 app-server 同源托管全部业务 H5,配齐 `shared/` 桥与接口封装,支持安卓「原生壳 + 远程 H5」一套桥贯通,可不发版热更。 + +**本仓(app-server)范围:** +- H5 托管:新增 **FastAPI StaticFiles 挂载 `/h5`** → 指向仓库 `h5/` 目录(同源、免 CORS) +- 迁入 records / reports 两页(从安卓 `feat/records-h5` 移植),改用 `SGBridge` / `SGApi` +- `shared/bridge.js` 补 **`closePage`(返回)**;`shared/api.js` 已同源就绪(必要时补 multipart 说明) +- 远程开关配置接口(返回 per-page `native`/`h5` 标志) +- 缓存 / 热更策略(cache-control + 版本) + +**不在本仓(见 android 文档):** `SGBridge.kt`、WebView 宿主、原生/H5 切换接线。 + +**后端业务接口:零改动** —— H5 复用现有 `/api/v1/...`(`/compare/records`、`/report`、`/wallet/account`、`/coupon/stats` 等),只是请求方从 Kotlin 改成网页 fetch。 + +--- + +## 3. 关键决策(已锁定) + +| # | 决策 | 选定 | 理由 | +|---|---|---|---| +| D1 | 桥基准 | **SGBridge**(安卓退役 NativeBridge) | 协议齐、mine 成型、三端对齐 | +| D2 | 托管 | **FastAPI StaticFiles 挂 `/h5`** | 同源免 CORS、复用现有 `/media` 方式、nginx 已反代 `/`→uvicorn,dev+prod 都能跑 | +| D3 | 离线兜底 | 纯远程 + 安卓侧重试页 | YAGNI;后端不需为离线做特殊处理 | +| D4 | 地址 | 安卓用 `BackendUrl.current` 推导 H5 地址(同源) | H5 与 `/api/v1` 同 host,自动跟随环境 | +| D5 | 迁移顺序 | records → reports → 首页/福利;mine 最后校准 | 用小页验证桥,风险分散 | + +--- + +## 4. H5 托管(D2) + +`app/main.py` 现有挂载(仅头像): + +```python +app.mount(settings.MEDIA_URL_PREFIX, StaticFiles(directory=str(_media_root)), name="media") +``` + +**新增** H5 静态挂载(指向仓库根 `h5/`,`html=True` 让目录路径回落到 `index.html`): + +```python +_h5_root = Path(__file__).resolve().parent.parent / "h5" # 仓库根 h5/ +app.mount("/h5", StaticFiles(directory=str(_h5_root), html=True), name="h5") +``` + +- 访问:`https://app-api.shaguabijia.com/h5/records/index.html`(prod)/ `http://:8770/h5/...`(debug)。 +- 与 `/api/v1` **同 host → 同源**:H5 内 `SGApi` 用相对 `/api/v1`,免 CORS、免 `getApiBase`。 +- prod 可选改由 nginx 直发 `h5/`(绕过 uvicorn)以提性能——本期先用 StaticFiles,nginx 优化留后。 + +--- + +## 5. H5 工程结构 + +``` +h5/ +├── shared/ +│ ├── bridge.js # SGBridge:H5↔原生桥(本期补 closePage) +│ └── api.js # SGApi:同源相对 /api/v1 封装(已就绪) +├── mine/index.html # 我的页(已成型,M4 按真实 SGBridge.kt 校准) +├── records/index.html # ← 从安卓迁入(M1) +└── reports/index.html # ← 从安卓迁入(M2) +``` + +各页头部引入:`` + ``。 + +--- + +## 6. records / reports 页迁入(从安卓移植) + +**搬运 + 改桥(迁移、非重写,UI/CSS/逻辑占绝大部分原样保留):** + +| 安卓原写法(NativeBridge) | 迁入后(SGBridge / SGApi) | +|---|---| +| `NativeBridge.getApiBase()` 拼绝对 URL(8 处) | **删除**,改相对 `/api/v1/...`(同源) | +| `NativeBridge.getToken()`(7 处) | `SGBridge.getToken()`(同名) | +| `NativeBridge.onUnauthorized()`(6 处) | 走 `SGApi` 内置 401 → `SGBridge.requestLogin()` | +| `NativeBridge.closePage()`(5 处) | `SGBridge.closePage()`(**bridge.js 本期新增**) | +| 普通 GET/POST | 改用 `SGApi.get/post('/...')`(自动带 token、处理 401) | + +**上报传图(records)特别说明:** 走 `` + 客户端压缩 + **`FormData` multipart** POST `/api/v1/report`。`SGApi` 只发 JSON,**不覆盖 multipart**,故这段**保留自定义 `fetch`**:URL 改相对 `/api/v1/report`、`Authorization` 头取 `SGBridge.getToken()`。文件选择依赖**安卓宿主 `onShowFileChooser`**(见 android 文档),后端无需改动。 + +--- + +## 7. `shared/bridge.js` 改动 + +- **新增 `closePage()`**:`SGBridge.closePage()` → 调 `SGBridgeNative.closePage()`(无桥时 mock `console.log`)。records/reports 顶栏返回箭头、`?from=profile` 返回都用它。 +- 其余方法(`getToken`/`requestLogin`/`navigate`/`getAuthState`/事件总线…)已就绪,保持签名,供 mine 及后续 tab 使用。 +- 浏览器无 `SGBridgeNative` 时走 MOCK,便于本地 `python -m http.server` 或 StaticFiles 直接调样式。 + +--- + +## 8. SGBridge 接口契约(三端共享) + +> 与 android 文档同表;`shared/bridge.js` 为权威。新增方法三端同步。 + +**查询类(同步返回 String):** `getAuthState` / `getToken` ✓ / `getDeviceId` / `getAppVersion` / `getInstalledApps` / `getCouponClaimedToday` +**动作类(无返回):** `navigate` / `requestLogin` ✓ / `toast` / `openMeituan` / `startCompare` / `startCouponClaim` / `launchApp` / **`closePage`【新增】✓** +**事件类(原生→H5,`_emit`):** `onAuthChange` / `onBalanceChange` / `onSigninChange` / `onResume` +(✓ = records 阶段 M1 最小子集) + +--- + +## 9. 远程开关配置接口 + +- 提供一个轻量配置:返回各页渲染方式 `{ records: "h5"|"native", reports: ..., home: ..., welfare: ..., mine: ... }`。 +- 安卓 `AppNavHost` 据此决定加载 H5 还是原生页,**不发版即可灰度 / 一键回退**。 +- 复用现有远程配置/开关基建(参考安卓 `ad-config-remote-delivery`、`comparing-ad-remote-flag` 的下发方式),无则新增一个 `GET /api/v1/app/ui-flags` 之类端点。 + +--- + +## 10. 缓存与热更 + +- H5 是后端托管 → **改完即生效**(用户重开页即拉新),这是远程方案的核心收益。 +- `index.html` 用 `Cache-Control: no-cache`(或短 TTL)保证及时性;`shared/*.js`、图片等带版本/指纹便于长缓存。StaticFiles 可配响应头或交 nginx 处理。 + +--- + +## 11. 迁移顺序与风险 + +| 里程碑 | server 侧动作 | +|---|---| +| **M1 records** | 挂 `/h5`;`bridge.js` 加 `closePage`;records 迁入 + 改桥;配 `index.html` no-cache | +| **M2 reports** | reports 迁入 + 改桥 | +| **M3 首页/福利** | 首页/福利页 H5 化(需 SGBridge P2+ 协议,配合安卓) | +| **M4 mine + 收尾** | mine 按真实 SGBridge.kt 校准;远程开关接口上线 | + +| 风险 | 缓解 | +|---|---| +| SGBridge 原生侧未验证 | M1 用 records 小页验证(详见 android 文档) | +| multipart 上传被误套进 SGApi | 文档明确:上报保留自定义 multipart fetch,不走 SGApi | +| 同源被破坏(H5 与 API 不同 host) | 坚持 StaticFiles 同源托管;若改独立前端域名,需回评 SGApi 相对路径策略 | +| 缓存导致改了不生效 | `index.html` no-cache + 资源指纹 | diff --git a/h5/agreement/privacy/index.html b/h5/agreement/privacy/index.html new file mode 100644 index 0000000..953f315 --- /dev/null +++ b/h5/agreement/privacy/index.html @@ -0,0 +1,223 @@ + + + + + + + + + +
生效日期:【2026 年 06 月 25 日】
+ +
+
万德一博(北京)科技有限公司(以下简称“我们”)深知个人信息对您的重要性,并会尽全力保护您的个人信息安全可靠。我们致力于维持您对我们的信任,恪守适用法律和我们对您的承诺,遵循正当、合法、必要、诚信、最小必要的原则处理您的个人信息。
+
请您在使用“傻瓜比价”App(以下简称“本 App”或“本产品”)前,仔细阅读并充分理解本《傻瓜比价隐私政策》(以下简称“本政策”,我们已将重点内容以加粗形式提示,请您特别关注),并在确认充分理解并同意后再开始使用。如您对本政策有任何疑问,可通过本政策第八条“如何联系我们”提供的方式与我们联系。
+ +
【特别提示】本 App 是一款“比价工具”。我们本身不销售任何商品、不提供外卖/团购等交易服务,也不是您与电商/外卖/团购平台之间交易的相对方。您看到的商品、价格、优惠均来自淘宝、京东、拼多多、抖音、美团等第三方平台,最终下单、支付、履约均在相应第三方平台内完成,受该第三方平台自己的协议与隐私政策约束。
+ +
本政策将帮助您了解以下内容:
+ + +
+
一、我们如何收集和使用您的个人信息
+
本 App 的基本功能为“跨平台商品比价”。您同意本政策表示您已了解本 App 提供的基本功能,以及基本功能运行所必需的个人信息,并给予相应的收集使用授权。但这并不代表您同意我们收集、处理非必要个人信息;扩展功能所需的个人信息、以及涉及敏感个人信息、第三方共享、调用系统权限等情形,我们将在您实际使用具体功能时单独征求您的同意。如您拒绝开启扩展功能或提供非必要个人信息,不会影响您使用基本功能。
+
我们会遵循正当、合法、必要的原则,出于以下目的收集和使用您的个人信息:
+ +
(一)帮助您注册和登录账号
+
当您注册、登录本 App 时,您需要向我们提供手机号码,我们通过发送短信验证码验证您的身份。您的手机号码用于创建账号、登录、账号安全保护以及向您发送服务通知。
+
为方便您快捷登录,您可以选择“一键登录”功能,我们会使用基础电信运营商提供的快捷登录能力,经您授权后获取您当前设备的本机手机号为您完成注册/登录。如您不希望使用,可通过短信验证码方式登录。
+
在您完成首次比价体验前,您无需登录即可使用核心比价功能(详见下文第(三)条);只有在您需要领取金币奖励、提现、查看比价记录等需要账号的功能时,才需要登录。
+ +
(二)权限与设备信息的获取
+
为实现比价功能、保障账号与运行安全,我们会在您授权后获取以下信息。所有系统权限我们均不会默认开启,会在您使用到对应功能时向您申请,您可随时在系统设置中关闭:
+
    +
  1. 悬浮窗权限(在其他应用上层显示):用于在您浏览购物平台时显示“比价”悬浮按钮、比价进度与比价结果。这是本产品“无需打开 App 即可比价”体验的必要权限。
  2. +
  3. 无障碍服务权限(Accessibility Service):用于实现核心比价功能,详见第(三)条专门说明。
  4. +
  5. 设备与网络信息:为保障账号安全、识别风险、适配界面并排查故障,我们会收集您的设备型号、操作系统及版本、应用版本、屏幕分辨率、语言设置、设备标识符(如 OAID、Android ID,安卓系统不再提供 IMEI 时不强制收集)、网络状态、IP 地址、电信运营商等软硬件特征信息。
  6. +
  7. 自启动、忽略电池优化等系统设置:为保证比价与悬浮窗服务在后台稳定运行、避免被系统中断,我们会引导您开启应用自启动、将本 App 加入电池优化白名单(忽略电池优化)。这些设置仅用于维持服务可用性,不收集您的个人信息。您可随时在系统设置中关闭,关闭后可能影响比价服务的稳定性。
  8. +
+ +
(三)核心比价功能所需的系统能力
+
为实现“在购物页面一键比价”以及“省钱记录”,本 App 需要您开启系统的无障碍服务与悬浮窗权限。开启后,仅在您使用比价相关功能时,本 App 会:①当您点击“比价”时,识别您当前查看的商品信息(如名称、价格、规格),并代您在其他购物平台搜索同款、读取价格,生成比价结果;②当您通过比价结果跳转并在第三方平台完成购买后,识别下单/支付成功结果,用于为您生成省钱记录。我们就此说明:
+ + +
(四)为您提供比价记录与“省钱统计”
+
为向您展示历史比价记录与累计为您节省的金额,我们会记录:
+ +
此外,返佣/返现结算:我们通过所对接的 CPS 联盟接口(京东联盟、淘宝闪购联盟、美团联盟等)获取相关订单的结算状态,用于发放返现/奖励。
+ +
(五)金币、奖励与提现功能(含敏感个人信息)
+
本 App 提供金币体系:您可通过签到、记录比价战绩、观看激励视频、邀请好友等任务获取金币,金币可按 App 内公示规则提现(具体兑换比例、提现门槛以 App 内最新公示为准)。为此我们会处理:
+ + +
(六)为您展示内容与改进服务
+
为向您展示首页低价商品、“低价盲盒”、福利任务等内容,并改进我们的产品与服务,我们会收集您的浏览、点击、搜索、比价、收藏等行为信息进行统计分析。我们不基于上述信息对您进行个性化推荐。
+ +
(七)广告功能
+
在比价等待期的悬浮窗中、以及福利 Tab“看视频赚金币”任务中,我们会向您展示广告(含激励视频广告)。为实现广告展示与反作弊,接入的广告 SDK 可能收集设备信息等(详见第九条 SDK 清单)。
+ + +
(八)跳转第三方平台与私域社群
+ + +
(九)为您提供客服与安全保障
+ + +
(十)征得授权同意的例外
+
根据法律法规,在下列情形下我们处理您的个人信息无需征得您的授权同意:与履行法定义务相关、与国家安全/公共安全/公共卫生/重大公共利益直接相关、为订立或履行您作为一方当事人的合同所必需、在合理范围内处理您自行公开或已合法公开的信息、应急情况下为保护自然人生命健康和财产安全所必需,以及法律法规规定的其他情形。
+ +
+
二、我们如何使用 Cookie 和同类技术
+
为确保本产品正常运转、为您提供更便捷的体验,我们会在您的设备上存储名为 Cookie、设备标识或同类技术的小型数据文件,用于:记住您的身份与偏好设置、保障登录与数据安全、分析产品使用情况以优化体验。您可在系统/浏览器中清除或管理上述数据,但清除后可能影响您使用部分功能。
+ +
+
三、我们如何共享、转让、公开披露您的个人信息
+
(一)共享
+
我们不会与任何公司、组织和个人共享您的个人信息,但以下情形除外:
+
    +
  1. 事先取得您的明确同意或授权;涉及敏感个人信息或向第三方提供个人信息时,我们将取得您的单独同意;
  2. +
  3. 根据法律法规、行政或司法机关的强制性要求;
  4. +
  5. 在符合法律法规的前提下,为实现本政策所述目的,与下列合作伙伴在必要范围内共享: +
      +
    • 第三方 SDK 服务商(如广告、统计、推送、一键登录、崩溃监控等,详见第九条清单);
    • +
    • CPS/CPA 联盟平台:为完成返佣结算、订单追踪、拉新结算,我们会与所对接的电商/外卖联盟在必要范围内交互订单/设备标识等信息;
    • +
    • 云服务、短信、实名核验、收款/支付通道服务商:为实现注册登录、提现到账、实名核验等。
    • +
    +
  6. +
+
对受托处理个人信息的合作方,我们会与其签订严格的数据保护协议,要求其按照本政策及法律法规处理您的个人信息。
+
(二)转让
+
我们不会向任何公司、组织和个人转让您的个人信息,但以下情形除外:取得您的明确同意;在涉及合并、分立、收购、资产转让或类似交易时,我们会要求新的持有方继续受本政策约束,否则将要求其重新征得您的授权同意。
+
(三)公开披露
+
我们仅在取得您单独同意、或基于法律法规、强制性行政/司法要求的情形下公开披露您的个人信息,并采取符合业界标准的安全防护措施。
+ +
+
四、我们如何保存和保护您的个人信息
+
(一)保存地点
+
您的个人信息存储于中华人民共和国境内(我们使用阿里云作为云服务商,数据存储于其境内数据中心)。我们不会向境外传输您的个人信息。
+
(二)保存期限
+
我们仅在实现本政策所述目的所必需的最短期限内保存您的个人信息,并结合法律的强制留存要求确定保存期限(例如《电子商务法》要求商品和服务信息、交易信息自交易完成之日起保存不少于三年)。超出保存期限后,我们将对您的个人信息进行删除或匿名化处理。
+
(三)保护措施
+
我们采用符合业界标准的安全防护措施保护您的个人信息,包括传输与存储加密(如 HTTPS)、访问权限控制、数据脱敏、内部安全管理制度与员工保密义务等,防止信息遭到未经授权的访问、使用、修改或泄露、损毁、丢失。
+
(四)安全事件处置
+
若不幸发生个人信息安全事件,我们将按法律法规要求及时向您告知:事件基本情况与可能影响、我们已采取或将采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等,并以推送、短信、邮件、公告等方式告知您,同时按规定向监管部门上报。
+
(五)产品或服务停止运营时的处置
+
如本 App 停止运营,我们将:①以推送、公告等显著方式通知您;②停止继续收集您的个人信息;③对我们持有的您的个人信息进行删除或匿名化处理,法律法规另有强制留存要求的除外。
+ +
+
五、您如何管理您的个人信息
+
您对您的个人信息享有以下权利,可通过【我的 → 设置 → 隐私管理】或本政策第八条的联系方式行使:
+
    +
  1. 访问、复制、更正、补充您的个人信息;
  2. +
  3. 删除您的个人信息(在我们违法处理、未经同意处理、或您注销账号等情形下,您可请求删除);
  4. +
  5. 改变或撤回授权同意:您可关闭相应系统权限或在设置中撤回授权。请您理解,撤回同意不影响撤回前基于您同意已进行的处理;撤回后我们将无法继续提供对应功能;
  6. +
  7. 注销账号:您可通过【我的 → 设置 → 账户与安全 → 注销账号】注销。注销后我们将停止为您提供产品/服务,并依法删除或匿名化您的个人信息;
  8. +
  9. 获取个人信息副本;
  10. +
  11. 响应您的请求:我们将在收到并核验您身份后的 15 天内予以答复。对合理请求原则上不收取费用;对重复、超出合理限度的请求,我们可能酌情收取成本费用或予以拒绝。
  12. +
+
如您对我们的答复不满意,特别是认为我们的处理行为损害了您的合法权益,您可向网信、电信、公安、市场监管等监管部门投诉、举报。
+ +
+
六、未成年人的个人信息保护
+
本 App 主要面向成年人。若您是 18 周岁以下的未成年人,请在监护人陪同下阅读本政策,并在监护人同意后再使用本产品及提供个人信息。对于不满 14 周岁儿童的个人信息,我们将依据《儿童个人信息网络保护规定》等要求,在取得其监护人单独同意后方可处理,并采取严格保护措施。如您是未成年人的监护人,对未成年人个人信息有任何疑问,请通过第八条方式联系我们。
+ +
+
七、通知和修订
+
为提供更好的服务,本政策可能适时更新。未经您明确同意,我们不会削减您依据本政策应享有的权利。政策更新后,我们会通过 App 内公告、弹窗、推送或其他适当方式提示您。对于重大变更(如处理目的、处理信息类型、共享对象、您行使权利的方式发生重大变化,或所有权结构发生重大变化等),我们会提供更显著的通知并在生效前再次征得您的同意(如适用)。
+ +
+
八、如何联系我们
+
如您对本政策、您的个人信息处理、或需要投诉、举报、咨询,请通过以下方式与我们联系:
+ +
一般情况下,我们将在 15 天内回复您的请求。
+ +
+
九、附录
+
附录一:第三方 SDK 与合作方清单
+
本清单是应用商店审核与监管检查的重点项。穿山甲为聚合广告平台(GroMore),其下游可能调用快手、腾讯优量汇等第三方广告网络,这些下游网络也会收集设备标识等信息,已在表中一并披露。
+ + + + + + + + + + + + + + + +
SDK / 合作方名称提供方公司全称使用目的收集的个人信息隐私政策链接
穿山甲(GroMore 聚合广告平台,含激励视频广告)北京巨量引擎网络技术有限公司展示激励视频广告、广告归因与反作弊设备标识符(OAID 等)、设备信息、网络信息、广告交互数据https://www.csjplatform.com/privacy
└ 经穿山甲聚合调用的下游广告网络(快手广告)北京快手科技有限公司通过聚合平台填充与展示广告设备标识符、设备信息、网络信息https://www.kuaishou.com/about/policy
└ 经穿山甲聚合调用的下游广告网络(腾讯优量汇)深圳市腾讯计算机系统有限公司通过聚合平台填充与展示广告设备标识符、设备信息、网络信息https://e.qq.com/optout.html
极光(JIGUANG,一键登录 / 号码认证 / 短信验证)深圳市和讯华谷信息技术有限公司一键登录取号、短信验证码下发与号码认证本机号码(运营商掩码取号)、设备信息、网络信息https://www.jiguang.cn/license/privacy
美团联盟(API,无 SDK)北京三快科技有限公司外卖/团购比价的返佣订单追踪与结算订单信息、推广标识以美团联盟官方规则为准
京东联盟(API/链接,无 SDK)北京京东叁佰陆拾度电子商务有限公司及其关联公司电商比价的返佣订单追踪与结算订单信息、推广标识以京东联盟官方规则为准
淘宝闪购联盟(API/链接,无 SDK)阿里巴巴(中国)软件有限公司 / 阿里妈妈电商/闪购比价的返佣订单追踪与结算订单信息、推广标识以对应联盟官方规则为准
阿里云阿里云计算有限公司云服务器、数据存储等基础设施(受托处理)受托存储上述各项个人信息https://www.aliyun.com/
微信支付(提现)财付通支付科技有限公司向用户发放微信提现、实名核验与收款(由微信侧完成)微信授权标识/OpenID、提现金额与记录以微信支付官方规则为准
+
说明:本 App 未接入独立的统计分析、消息推送 SDK,也不会将屏幕图像上传至云端 AI 大模型。
+ +
附录二:本政策涉及的敏感个人信息清单
+
为便于您识别,下列为本 App 在特定功能下处理的、属于敏感或受单独同意约束的信息:
+ +
+ +
傻瓜比价 · 隐私政策
万德一博(北京)科技有限公司
+ + diff --git a/h5/agreement/user/index.html b/h5/agreement/user/index.html new file mode 100644 index 0000000..9e915e4 --- /dev/null +++ b/h5/agreement/user/index.html @@ -0,0 +1,133 @@ + + + + + + + + + +
生效日期:【2026 年 06 月 25 日】
+ +
+
欢迎您使用“傻瓜比价”App!本《傻瓜比价用户服务协议》(以下简称“本协议”)是您与万德一博(北京)科技有限公司(注册地址:北京市丰台区丰管路甲1号北楼三层302-765室,以下简称“我们”或“傻瓜比价”)之间就您注册、使用“傻瓜比价”App(以下简称“本 App”或“本服务”)所订立的协议。
+
请您务必审慎阅读、充分理解本协议各条款,特别是以加粗形式提示您的免除或限制我们责任、需您自行承担风险或责任的条款。如您未满 18 周岁,请在监护人陪同下阅读并在其同意后使用本服务。
+
当您勾选同意、或以注册、登录、使用本服务等任何方式表示接受本协议时,即视为您已阅读并同意本协议的全部内容,自愿接受其约束。如您不同意本协议任何内容,请勿注册或使用本服务。
+
本协议内容同时包括《傻瓜比价隐私政策》及我们在 App 内公示的与本服务相关的各项规则(如金币规则、活动规则等),上述内容为本协议不可分割的组成部分,与本协议正文具有同等效力。
+ +
+
一、服务说明(请重点阅读本 App 的性质)
+
    +
  1. 本 App 是一款“比价工具”/信息服务,不是商品或服务的销售方、交易方。本 App 帮助您在淘宝、京东、拼多多、抖音、美团等第三方平台浏览商品时,自动跨平台搜索同款商品并展示价格对比结果。
  2. +
  3. 我们不销售任何商品、不提供外卖/团购/物流等交易及履约服务。您看到的商品、价格、优惠、店铺均来自第三方平台;您的下单、支付、发货、售后、退换货等全部在相应第三方平台内完成,并受该第三方平台自身的用户协议、规则与隐私政策约束。因商品质量、发货、售后、虚假宣传等产生的争议,应由您与该第三方平台或商家解决,我们不承担销售者/服务提供者责任,但会在合理范围内为您提供必要协助。
  4. +
  5. 比价结果仅供参考。各平台价格、库存、优惠券、满减、返现等实时变动,且受地域、账号、活动、时间等多种因素影响。我们力求比价结果准确及时,但不对比价结果(包括但不限于“全网最低价”的表述、同款匹配的准确性、价格的实时性)作任何明示或默示的保证;最终价格、优惠及交易以第三方平台实际展示和结算为准。请您在下单前自行核对。
  6. +
  7. 本服务的核心功能依赖系统无障碍服务与悬浮窗权限。您在使用前需要在系统设置中授予相应权限。关于该等权限读取与处理信息的范围、本地处理原则及您的关闭方式,详见《傻瓜比价隐私政策》第一条第(三)项。
  8. +
+ +
二、比价功能的开启与使用
+
    +
  1. 本服务的比价功能需要您开启系统的无障碍服务与悬浮窗权限。开启后,仅在您使用比价相关功能时,本 App 会识别您当前查看的商品并代您在其他购物平台搜索同款、比对价格,并在您完成购买后识别下单结果用于为您生成省钱记录;不会代您下单、支付或修改账户信息,也不会进行与比价、省钱记录无关的操作。关于权限读取与处理信息的范围、本地处理原则及关闭方式,详见《傻瓜比价隐私政策》第一条第(三)项。
  2. +
  3. 您理解并同意,是否使用比价功能由您自主选择。您可随时在系统设置中关闭相关权限,关闭后比价功能将不可用,但不影响您使用 App 内其他功能。
  4. +
+ +
三、账号的注册与使用
+
    +
  1. 【注册资料】您应以诚实信用原则提供真实、准确、合法的注册信息(如手机号码),并在信息变动时及时更新。因您提供的信息不真实、不准确或未及时更新导致的后果,由您自行承担。
  2. +
  3. 【实名与提现】因法律法规、反洗钱及收款渠道要求,您在使用提现等功能时可能需要完成实名核验并提供收款账号信息,详见《傻瓜比价隐私政策》。未完成必要核验的,您可能无法使用相应功能。
  4. +
  5. 【账号安全】您应妥善保管账号及密码,对账号项下的全部行为负责。如发现账号被盗用或存在安全问题,应立即通知我们。因您自身保管不善导致的账号丢失、泄露及由此产生的损失,我们不承担责任(我们存在过错的除外)。
  6. +
  7. 【账号管理】原则上一名用户对应一个账号。如您存在不当注册或不当使用多个账号、利用账号从事违规行为的情形,我们有权对相关账号采取限制、冻结、合并、注销等措施。
  8. +
+ +
四、金币、奖励与提现规则
+
    +
  1. 【金币性质】金币是本 App 内用于激励用户的虚拟权益,不是法定货币、不可在用户间转让、不可用于本 App 约定用途之外的交易。金币的获取、消耗、兑换、提现规则以 App 内公示的最新规则为准。
  2. +
  3. 【提现】金币可按 App 内公示的兑换比例与提现门槛提现(具体数值以 App 内最新公示页面为准)。当前提现通过微信支付发放,实名核验与收款由微信支付侧完成。
  4. +
  5. 【反作弊】(请重点阅读)您不得通过作弊、外挂、机器批量操作、虚假注册、刷量、薅羊毛、利用系统漏洞等任何不正当方式获取金币或奖励。一经发现,我们有权扣除相应金币/奖励、驳回提现、冻结或注销账号,并保留追究法律责任的权利。金币规则及反作弊规则如需调整,我们将提前以合理方式公示;如您对反作弊判定有异议,可通过第五条约定的申诉渠道提出申诉。
  6. +
  7. 【活动规则】各项福利任务、裂变、邀请等活动的具体规则以活动页面公示为准;如活动规则与本协议不一致,就该活动事项以活动规则为准。
  8. +
+ +
五、用户行为规范
+
您承诺在使用本服务过程中遵守法律法规,不从事下列行为,否则我们有权视情形采取警告、限制功能、冻结或注销账号等措施,由此产生的责任由您承担:
+
    +
  1. 发布、传播违反宪法确定的基本原则,危害国家安全、社会稳定、违背公序良俗,或法律法规禁止的其他内容;
  2. +
  3. 侵犯他人知识产权、隐私权、名誉权等合法权益;
  4. +
  5. 实施网络攻击、传播病毒/木马,破解、干扰、破坏本服务或其相关系统;
  6. +
  7. 未经我们书面许可,自行或协助第三方对本服务进行非法抓取、反向工程、反编译,或使用外挂、插件、机器人等干扰本服务正常运行;
  8. +
  9. 利用本服务从事诈骗、洗钱、刷单炒信、薅羊毛等违法或不正当行为;
  10. +
  11. 其他违反法律法规或损害我们、其他用户、第三方合法权益的行为。
  12. +
+
【处罚与申诉】我们对账号采取限制、冻结、注销等处罚措施时,将根据违规行为的性质与严重程度合理处理,并以适当方式告知您处罚的事由。如您认为处罚有误,可通过 support@wonderable.ai 或 App 内客服渠道提出申诉,我们将在收到申诉后 15 个工作日内核实并答复。我们不会在不提供任何申诉渠道的情况下对账号作出无理由的永久封禁。
+ +
六、知识产权
+
    +
  1. 除另有声明外,本服务所包含的内容(包括但不限于软件、技术、程序、界面、文字、图片、图标、音视频、版面设计、商标、标识等)的知识产权归我们或相关权利人所有,受法律保护。
  2. +
  3. 未经我们事先书面许可,您不得以任何形式使用、复制、修改、发布、出售、出租、反向工程、反编译上述内容,或制作衍生作品。
  4. +
  5. 您在本服务中上传/发布的内容(如“反馈更低价”提交的链接、截图、文字等),应为您原创或已获合法授权,不侵犯他人合法权益;您授权我们在为提供和改进本服务所必需的范围内对该等内容进行使用。
  6. +
  7. 【侵权投诉处理】如您认为本服务中的内容侵犯了您的知识产权或其他合法权益,可通过 support@wonderable.ai 向我们发起投诉并提供权属证明及相关材料。我们核实后将依法采取删除、屏蔽等必要措施;被投诉方可提交不侵权声明进行申诉。
  8. +
+ +
七、第三方平台与第三方服务
+
    +
  1. 本服务包含跳转至第三方平台(电商/外卖/团购平台、CPS 联盟链接、私域社群、广告等)的功能。该等第三方平台与服务由第三方独立提供并独立承担责任,受其自身协议与规则约束。我们对第三方平台的内容、商品、服务、价格及其行为不作保证,亦不承担责任。
  2. +
  3. 您通过本服务跳转第三方平台进行的交易,是您与该第三方平台/商家之间的交易,相关权利义务由您与该第三方解决。
  4. +
+ +
八、广告
+
    +
  1. 您理解并同意,为维持本服务的免费运营,我们或我们授权的第三方可能在本服务中(如比价等待期悬浮窗、福利任务)向您展示广告(含激励视频广告)。
  2. +
  3. 您应对广告内容自行审慎判断,除法律法规明确规定外,您应对依广告信息进行的交易自行负责。您可按《傻瓜比价隐私政策》的说明管理个性化广告。
  4. +
+ +
九、免责声明与责任限制(请重点阅读)
+
    +
  1. 【服务“现状”提供】在法律允许的范围内,本服务按“现状”和“可得”基础提供。我们不保证本服务不会中断,也不保证其及时性、安全性、准确性、无错误。
  2. +
  3. 【比价准确性免责】如前所述,我们不对比价结果的准确性、完整性、实时性及“最低价”表述作保证,您应在第三方平台下单前自行核对价格与优惠。
  4. +
  5. 【第三方原因免责】对因第三方平台规则变化、接口变动、风控封禁、第三方 SDK/服务故障等非我们直接原因导致的服务异常或损失,在法律允许范围内我们不承担责任。
  6. +
  7. 【第三方平台规则风险】您理解并同意,是否使用本服务由您自主选择。各第三方平台对其平台的访问与使用有其自身规则,若您与第三方平台之间因平台规则产生账号限制等后果,在法律允许范围内由您与该第三方平台依其规则处理,我们不对该等第三方平台的处理结果承担责任;我们会在合理范围内持续优化服务以降低此类情况发生。
  8. +
  9. 【不可抗力】因不可抗力(如自然灾害、网络故障、电力中断、政府行为、法律法规变动等)导致服务中断或无法提供的,在法律允许范围内我们免责,但会尽力减少对您的影响。
  10. +
  11. 【责任限额】在法律允许的最大范围内,对于因使用或无法使用本服务造成的间接、偶然、惩罚性损失(如利润损失、数据损失),我们不承担责任;我们对您承担的累计赔偿责任总额,以法律强制规定为限【如需设置上限,由法务确定具体表述】。本条不排除或限制依法不可排除或限制的责任(如因我们故意或重大过失、或侵害您人身权益依法应承担的责任)。
  12. +
+ +
十、协议的变更、中止与终止
+
    +
  1. 【协议变更】我们可根据法律法规变化或运营需要修订本协议,并通过 App 内公告、弹窗、推送等合理方式提前通知。变更内容将在公示的生效日期起施行(通常不短于公示后 7-8 个自然日)。如您不同意变更内容,应停止使用相关服务;变更生效后您继续使用的,视为同意变更后的协议。
  2. +
  3. 【服务中止/终止】在您违反本协议、法律法规要求、或我们基于合理商业安排经合理通知终止服务等情形下,我们有权中止或终止向您提供部分或全部服务。
  4. +
  5. 【账号注销】您可按 App 内流程注销账号;注销后我们将停止为您提供服务,并依法处理您的个人信息。
  6. +
  7. 协议终止不影响在此之前已产生的权利义务,以及知识产权、责任限制等依其性质应继续有效的条款。
  8. +
+ +
十一、通知与送达
+
我们可通过以下任一方式向您送达通知:App 内公告/弹窗、站内信、推送、向您注册的手机号发送短信、向您提供的邮箱发送邮件等。上述通知于发送成功或刊登完成时视为送达。请您保证联系方式真实有效并及时更新,因联系方式不准确或未及时更新导致通知无法送达的后果由您承担。
+ +
十二、法律适用与争议解决
+
    +
  1. 本协议的订立、生效、履行、解释及争议解决,适用中华人民共和国法律(不含冲突法及港澳台地区法律)。
  2. +
  3. 因本协议或本服务产生的争议,您与我们应友好协商解决;协商不成的,任何一方均可向本协议签订地有管辖权的人民法院提起诉讼。本协议签订地为北京市丰台区。(注:约定公司所在地法院管辖属合理约定;不得约定与双方无实际联系的偏远地区法院,否则该管辖约定可能被认定无效。)
  4. +
+ +
十三、其他
+
    +
  1. 本协议各条款标题仅为方便阅读,不影响条款含义的解释。
  2. +
  3. 本协议任一条款被认定为无效或不可执行的,不影响其余条款的效力。
  4. +
  5. 如您对本协议有任何问题或建议,可通过《傻瓜比价隐私政策》“如何联系我们”中的方式与我们联系。
  6. +
+
+ +
傻瓜比价 · 用户服务协议
万德一博(北京)科技有限公司
+ + diff --git a/h5/coinhistory/assets/wechat-pay-check-icon.png b/h5/coinhistory/assets/wechat-pay-check-icon.png new file mode 100644 index 0000000..bda0e57 Binary files /dev/null and b/h5/coinhistory/assets/wechat-pay-check-icon.png differ diff --git a/h5/coinhistory/index.html b/h5/coinhistory/index.html new file mode 100644 index 0000000..4b53bdf --- /dev/null +++ b/h5/coinhistory/index.html @@ -0,0 +1,298 @@ + + + + + + +收益明细 · 傻瓜比价 + + + + +
+
+
+ +
收益明细
+
+ +
兑换比例:10000 金币=1元;金币到账可能会有延迟
+ +
+
+
+
我的金币
+
0
+
+
+
我的现金
+
+ 0.00 + +
+
+
+
0点自动兑现金(可能存在延迟)
+
+ +
+ + +
+
+ +
+
+
+
+
+
+
+
+ + + + + + diff --git a/h5/feedback/assets/welfare/index/checkin-coin-single.png b/h5/feedback/assets/welfare/index/checkin-coin-single.png new file mode 100644 index 0000000..4a33906 Binary files /dev/null and b/h5/feedback/assets/welfare/index/checkin-coin-single.png differ diff --git a/h5/feedback/index.html b/h5/feedback/index.html new file mode 100644 index 0000000..e20ffed --- /dev/null +++ b/h5/feedback/index.html @@ -0,0 +1,335 @@ + + + + + + + +意见反馈 · 傻瓜比价 + + + + +
+
+
+ + 意见反馈 + +
+ +
+
+

您的建议和问题我们都会认真查看,评价越真实详细,金币奖励越高,感谢您帮我们做得更好~

+
+ + 反馈采纳后,即得金币奖励 +
+
+ +
+ + +
+ +
+ +
+
+ +
+
+ +
+ + + +
+
+ +
+
+
+ +
+ + + + + + + diff --git a/h5/feedback_history/assets/welfare/index/checkin-coin-single.png b/h5/feedback_history/assets/welfare/index/checkin-coin-single.png new file mode 100644 index 0000000..4a33906 Binary files /dev/null and b/h5/feedback_history/assets/welfare/index/checkin-coin-single.png differ diff --git a/h5/feedback_history/index.html b/h5/feedback_history/index.html new file mode 100644 index 0000000..ec8ab12 --- /dev/null +++ b/h5/feedback_history/index.html @@ -0,0 +1,266 @@ + + + + + + + +反馈历史 · 傻瓜比价 + + + + +
+
+
+ +
反馈历史
+
+ +
+ + +
+
全部0
+
审核中0
+
已采纳0
+
未采纳0
+
+ +
+ +
+ +
+
+ +
+
还没有反馈记录
+
你的每条建议我们都会认真查看
被采纳还能领金币奖励
+ +
+
+
+ + + + + + + diff --git a/h5/home/assets/home/index/banner-top-cropped.png b/h5/home/assets/home/index/banner-top-cropped.png new file mode 100644 index 0000000..930b1c6 Binary files /dev/null and b/h5/home/assets/home/index/banner-top-cropped.png differ diff --git a/h5/home/assets/home/index/banner-top.png b/h5/home/assets/home/index/banner-top.png new file mode 100644 index 0000000..46a3d6e Binary files /dev/null and b/h5/home/assets/home/index/banner-top.png differ diff --git a/h5/home/assets/home/index/card-stats-bg.png b/h5/home/assets/home/index/card-stats-bg.png new file mode 100644 index 0000000..54d9994 Binary files /dev/null and b/h5/home/assets/home/index/card-stats-bg.png differ diff --git a/h5/home/assets/home/index/card-waimai-bg.png b/h5/home/assets/home/index/card-waimai-bg.png new file mode 100644 index 0000000..63dd02e Binary files /dev/null and b/h5/home/assets/home/index/card-waimai-bg.png differ diff --git a/h5/home/assets/home/index/categories/express.png b/h5/home/assets/home/index/categories/express.png new file mode 100644 index 0000000..5c4038e Binary files /dev/null and b/h5/home/assets/home/index/categories/express.png differ diff --git a/h5/home/assets/home/index/categories/hotel.png b/h5/home/assets/home/index/categories/hotel.png new file mode 100644 index 0000000..478665e Binary files /dev/null and b/h5/home/assets/home/index/categories/hotel.png differ diff --git a/h5/home/assets/home/index/categories/invite-earn.png b/h5/home/assets/home/index/categories/invite-earn.png new file mode 100644 index 0000000..621b9c7 Binary files /dev/null and b/h5/home/assets/home/index/categories/invite-earn.png differ diff --git a/h5/home/assets/home/index/categories/movie.png b/h5/home/assets/home/index/categories/movie.png new file mode 100644 index 0000000..1fe6802 Binary files /dev/null and b/h5/home/assets/home/index/categories/movie.png differ diff --git a/h5/home/assets/home/index/categories/taxi.png b/h5/home/assets/home/index/categories/taxi.png new file mode 100644 index 0000000..9ff52f4 Binary files /dev/null and b/h5/home/assets/home/index/categories/taxi.png differ diff --git a/h5/home/assets/home/index/chevron-double-fade.png b/h5/home/assets/home/index/chevron-double-fade.png new file mode 100644 index 0000000..3e71d69 Binary files /dev/null and b/h5/home/assets/home/index/chevron-double-fade.png differ diff --git a/h5/home/assets/home/index/chevron-double.png b/h5/home/assets/home/index/chevron-double.png new file mode 100644 index 0000000..4731397 Binary files /dev/null and b/h5/home/assets/home/index/chevron-double.png differ diff --git a/h5/home/assets/home/index/coupon-claim-bg.png b/h5/home/assets/home/index/coupon-claim-bg.png new file mode 100644 index 0000000..f6349c0 Binary files /dev/null and b/h5/home/assets/home/index/coupon-claim-bg.png differ diff --git a/h5/home/assets/home/index/coupon-ticket-cluster.png b/h5/home/assets/home/index/coupon-ticket-cluster.png new file mode 100644 index 0000000..342ea3b Binary files /dev/null and b/h5/home/assets/home/index/coupon-ticket-cluster.png differ diff --git a/h5/home/assets/home/index/feed/chabaidao.png b/h5/home/assets/home/index/feed/chabaidao.png new file mode 100644 index 0000000..839cb64 Binary files /dev/null and b/h5/home/assets/home/index/feed/chabaidao.png differ diff --git a/h5/home/assets/home/index/feed/jubaoyuan.png b/h5/home/assets/home/index/feed/jubaoyuan.png new file mode 100644 index 0000000..d00185f Binary files /dev/null and b/h5/home/assets/home/index/feed/jubaoyuan.png differ diff --git a/h5/home/assets/home/index/feed/luckin.png b/h5/home/assets/home/index/feed/luckin.png new file mode 100644 index 0000000..577e0e9 Binary files /dev/null and b/h5/home/assets/home/index/feed/luckin.png differ diff --git a/h5/home/assets/home/index/feed/mcdonalds.png b/h5/home/assets/home/index/feed/mcdonalds.png new file mode 100644 index 0000000..c7ecfac Binary files /dev/null and b/h5/home/assets/home/index/feed/mcdonalds.png differ diff --git a/h5/home/assets/home/index/feed/pizzahut.png b/h5/home/assets/home/index/feed/pizzahut.png new file mode 100644 index 0000000..c98d5a9 Binary files /dev/null and b/h5/home/assets/home/index/feed/pizzahut.png differ diff --git a/h5/home/assets/home/index/feed/subway.png b/h5/home/assets/home/index/feed/subway.png new file mode 100644 index 0000000..7dce2cc Binary files /dev/null and b/h5/home/assets/home/index/feed/subway.png differ diff --git a/h5/home/assets/home/index/feed/yoshinoya.png b/h5/home/assets/home/index/feed/yoshinoya.png new file mode 100644 index 0000000..0255fcd Binary files /dev/null and b/h5/home/assets/home/index/feed/yoshinoya.png differ diff --git a/h5/home/assets/home/index/home-tri-arrow-button.svg b/h5/home/assets/home/index/home-tri-arrow-button.svg new file mode 100644 index 0000000..159b613 --- /dev/null +++ b/h5/home/assets/home/index/home-tri-arrow-button.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/h5/home/assets/home/index/money-bag.png b/h5/home/assets/home/index/money-bag.png new file mode 100644 index 0000000..a5ad643 Binary files /dev/null and b/h5/home/assets/home/index/money-bag.png differ diff --git a/h5/home/assets/home/index/no-deal-search.png b/h5/home/assets/home/index/no-deal-search.png new file mode 100644 index 0000000..de623d9 Binary files /dev/null and b/h5/home/assets/home/index/no-deal-search.png differ diff --git a/h5/home/assets/home/index/oneclick-claim.png b/h5/home/assets/home/index/oneclick-claim.png new file mode 100644 index 0000000..3710296 Binary files /dev/null and b/h5/home/assets/home/index/oneclick-claim.png differ diff --git a/h5/home/assets/home/index/piggy-bank.png b/h5/home/assets/home/index/piggy-bank.png new file mode 100644 index 0000000..73be580 Binary files /dev/null and b/h5/home/assets/home/index/piggy-bank.png differ diff --git a/h5/home/assets/home/index/tap-hand-generated.png b/h5/home/assets/home/index/tap-hand-generated.png new file mode 100644 index 0000000..9a59318 Binary files /dev/null and b/h5/home/assets/home/index/tap-hand-generated.png differ diff --git a/h5/home/assets/shared/badges/lowest-price.png b/h5/home/assets/shared/badges/lowest-price.png new file mode 100644 index 0000000..d39ea1e Binary files /dev/null and b/h5/home/assets/shared/badges/lowest-price.png differ diff --git a/h5/home/assets/shared/cta/compare-result.png b/h5/home/assets/shared/cta/compare-result.png new file mode 100644 index 0000000..4af3995 Binary files /dev/null and b/h5/home/assets/shared/cta/compare-result.png differ diff --git a/h5/home/assets/shared/cta/one-click-compare-gray.png b/h5/home/assets/shared/cta/one-click-compare-gray.png new file mode 100644 index 0000000..380a34d Binary files /dev/null and b/h5/home/assets/shared/cta/one-click-compare-gray.png differ diff --git a/h5/home/assets/shared/cta/one-click-compare-square.png b/h5/home/assets/shared/cta/one-click-compare-square.png new file mode 100644 index 0000000..10ca133 Binary files /dev/null and b/h5/home/assets/shared/cta/one-click-compare-square.png differ diff --git a/h5/home/assets/shared/cta/one-click-compare.png b/h5/home/assets/shared/cta/one-click-compare.png new file mode 100644 index 0000000..4af3995 Binary files /dev/null and b/h5/home/assets/shared/cta/one-click-compare.png differ diff --git a/h5/home/assets/shared/cta/tap-hint.svg b/h5/home/assets/shared/cta/tap-hint.svg new file mode 100644 index 0000000..daeda05 --- /dev/null +++ b/h5/home/assets/shared/cta/tap-hint.svg @@ -0,0 +1,3 @@ + + + diff --git a/h5/home/assets/shared/cta/today-coupon-orange.png b/h5/home/assets/shared/cta/today-coupon-orange.png new file mode 100644 index 0000000..f886244 Binary files /dev/null and b/h5/home/assets/shared/cta/today-coupon-orange.png differ diff --git a/h5/home/assets/shared/gestures/tap-hint.svg b/h5/home/assets/shared/gestures/tap-hint.svg new file mode 100644 index 0000000..daeda05 --- /dev/null +++ b/h5/home/assets/shared/gestures/tap-hint.svg @@ -0,0 +1,3 @@ + + + diff --git a/h5/home/assets/shared/home-snapshots/sb-home.png b/h5/home/assets/shared/home-snapshots/sb-home.png new file mode 100644 index 0000000..873147f Binary files /dev/null and b/h5/home/assets/shared/home-snapshots/sb-home.png differ diff --git a/h5/home/assets/shared/icons/README.md b/h5/home/assets/shared/icons/README.md new file mode 100644 index 0000000..5555930 --- /dev/null +++ b/h5/home/assets/shared/icons/README.md @@ -0,0 +1,43 @@ +# Shared Icons + +通用图标的单一事实源(canonical source)。每个图标都是独立 SVG 文件,但**实际页面里必须内联 SVG markup**(不用 `` 或 `` 引用),符合 prototypes 仓库"每个 HTML 自包含"原则。 + +## 工作流 + +1. 改图标 → 改这里的 SVG 文件 +2. 在所有用到的 HTML 里同步替换内联 SVG markup +3. DESIGN.md 引用本目录路径作为基准 + +## 现有图标 + +| 文件 | 用途 | 推荐内联尺寸 | +|---|---|---| +| `back-chevron.svg` | 顶部导航返回按钮 | 24×24 | +| `tab-home-outline.svg` | 底 tab "首页" 未选中态 | 24×24 | +| `tab-home-filled.svg` | 底 tab "首页" 选中态(黄填充)| 24×24 | +| `tab-welfare-outline.svg` | 底 tab "福利" 未选中态 | 24×24 | +| `tab-welfare-filled.svg` | 底 tab "福利" 选中态(黄填充)| 24×24 | +| `tab-profile-outline.svg` | 底 tab "我的" 未选中态 | 24×24 | +| `tab-profile-filled.svg` | 底 tab "我的" 选中态(黄填充)| 24×24 | + +## 标准 button 包装 + +```html + +``` + +```css +.btn-back { + width: 44px; height: 44px; + display: flex; align-items: center; justify-content: center; + background: transparent; border: none; padding: 0; + cursor: pointer; -webkit-tap-highlight-color: transparent; + flex-shrink: 0; +} +.btn-back:active { opacity: 0.5; } +.btn-back svg { width: 24px; height: 24px; display: block; } +``` diff --git a/h5/home/assets/shared/icons/back-chevron.svg b/h5/home/assets/shared/icons/back-chevron.svg new file mode 100644 index 0000000..5eeb353 --- /dev/null +++ b/h5/home/assets/shared/icons/back-chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/h5/home/assets/shared/icons/tab-home-filled.svg b/h5/home/assets/shared/icons/tab-home-filled.svg new file mode 100644 index 0000000..2e6fe3d --- /dev/null +++ b/h5/home/assets/shared/icons/tab-home-filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/h5/home/assets/shared/icons/tab-home-outline.svg b/h5/home/assets/shared/icons/tab-home-outline.svg new file mode 100644 index 0000000..f453eca --- /dev/null +++ b/h5/home/assets/shared/icons/tab-home-outline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/h5/home/assets/shared/icons/tab-profile-filled.svg b/h5/home/assets/shared/icons/tab-profile-filled.svg new file mode 100644 index 0000000..defee4c --- /dev/null +++ b/h5/home/assets/shared/icons/tab-profile-filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/h5/home/assets/shared/icons/tab-profile-outline.svg b/h5/home/assets/shared/icons/tab-profile-outline.svg new file mode 100644 index 0000000..57c4dab --- /dev/null +++ b/h5/home/assets/shared/icons/tab-profile-outline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/h5/home/assets/shared/icons/tab-welfare-filled.svg b/h5/home/assets/shared/icons/tab-welfare-filled.svg new file mode 100644 index 0000000..6cb269c --- /dev/null +++ b/h5/home/assets/shared/icons/tab-welfare-filled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/h5/home/assets/shared/icons/tab-welfare-outline.svg b/h5/home/assets/shared/icons/tab-welfare-outline.svg new file mode 100644 index 0000000..b597121 --- /dev/null +++ b/h5/home/assets/shared/icons/tab-welfare-outline.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/h5/home/assets/shared/logos/jd-waimai.png b/h5/home/assets/shared/logos/jd-waimai.png new file mode 100644 index 0000000..6de9605 Binary files /dev/null and b/h5/home/assets/shared/logos/jd-waimai.png differ diff --git a/h5/home/assets/shared/logos/jd.png b/h5/home/assets/shared/logos/jd.png new file mode 100644 index 0000000..ed939da Binary files /dev/null and b/h5/home/assets/shared/logos/jd.png differ diff --git a/h5/home/assets/shared/logos/meituan-waimai.png b/h5/home/assets/shared/logos/meituan-waimai.png new file mode 100644 index 0000000..9ef0783 Binary files /dev/null and b/h5/home/assets/shared/logos/meituan-waimai.png differ diff --git a/h5/home/assets/shared/logos/meituan.png b/h5/home/assets/shared/logos/meituan.png new file mode 100644 index 0000000..71cede9 Binary files /dev/null and b/h5/home/assets/shared/logos/meituan.png differ diff --git a/h5/home/assets/shared/logos/sb-brand-vector.svg b/h5/home/assets/shared/logos/sb-brand-vector.svg new file mode 100644 index 0000000..1451bff --- /dev/null +++ b/h5/home/assets/shared/logos/sb-brand-vector.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/h5/home/assets/shared/logos/sb-brand.old.png b/h5/home/assets/shared/logos/sb-brand.old.png new file mode 100644 index 0000000..106b7c5 Binary files /dev/null and b/h5/home/assets/shared/logos/sb-brand.old.png differ diff --git a/h5/home/assets/shared/logos/sb-brand.png b/h5/home/assets/shared/logos/sb-brand.png new file mode 100644 index 0000000..c8f1c13 Binary files /dev/null and b/h5/home/assets/shared/logos/sb-brand.png differ diff --git a/h5/home/assets/shared/logos/taobao-shanguang.png b/h5/home/assets/shared/logos/taobao-shanguang.png new file mode 100644 index 0000000..3091d33 Binary files /dev/null and b/h5/home/assets/shared/logos/taobao-shanguang.png differ diff --git a/h5/home/assets/shared/logos/taobao.png b/h5/home/assets/shared/logos/taobao.png new file mode 100644 index 0000000..7e0f742 Binary files /dev/null and b/h5/home/assets/shared/logos/taobao.png differ diff --git a/h5/home/assets/shared/overlays/aurora-decoration.png b/h5/home/assets/shared/overlays/aurora-decoration.png new file mode 100644 index 0000000..6f0a98f Binary files /dev/null and b/h5/home/assets/shared/overlays/aurora-decoration.png differ diff --git a/h5/home/assets/shared/overlays/floating-window.jpg b/h5/home/assets/shared/overlays/floating-window.jpg new file mode 100644 index 0000000..6d3f2c2 Binary files /dev/null and b/h5/home/assets/shared/overlays/floating-window.jpg differ diff --git a/h5/home/assets/shared/products/aomiao-detergent.jpg b/h5/home/assets/shared/products/aomiao-detergent.jpg new file mode 100644 index 0000000..20595ec Binary files /dev/null and b/h5/home/assets/shared/products/aomiao-detergent.jpg differ diff --git a/h5/home/assets/shared/products/coca-cola.jpg b/h5/home/assets/shared/products/coca-cola.jpg new file mode 100644 index 0000000..3eb4a36 Binary files /dev/null and b/h5/home/assets/shared/products/coca-cola.jpg differ diff --git a/h5/home/assets/shared/products/hfs-shampoo.jpg b/h5/home/assets/shared/products/hfs-shampoo.jpg new file mode 100644 index 0000000..d9086c8 Binary files /dev/null and b/h5/home/assets/shared/products/hfs-shampoo.jpg differ diff --git a/h5/home/assets/shared/products/jly-rice.jpg b/h5/home/assets/shared/products/jly-rice.jpg new file mode 100644 index 0000000..f304d5f Binary files /dev/null and b/h5/home/assets/shared/products/jly-rice.jpg differ diff --git a/h5/home/assets/shared/products/vinda-tissue.jpg b/h5/home/assets/shared/products/vinda-tissue.jpg new file mode 100644 index 0000000..ed70010 Binary files /dev/null and b/h5/home/assets/shared/products/vinda-tissue.jpg differ diff --git a/h5/home/assets/shared/products/yili-milk.jpg b/h5/home/assets/shared/products/yili-milk.jpg new file mode 100644 index 0000000..da6d3c5 Binary files /dev/null and b/h5/home/assets/shared/products/yili-milk.jpg differ diff --git a/h5/home/assets/welfare/index/checkin-coins-600.png b/h5/home/assets/welfare/index/checkin-coins-600.png new file mode 100644 index 0000000..3fb3bf4 Binary files /dev/null and b/h5/home/assets/welfare/index/checkin-coins-600.png differ diff --git a/h5/home/assets/welfare/index/coin-icon.png b/h5/home/assets/welfare/index/coin-icon.png new file mode 100644 index 0000000..02861d3 Binary files /dev/null and b/h5/home/assets/welfare/index/coin-icon.png differ diff --git a/h5/home/index.html b/h5/home/index.html new file mode 100644 index 0000000..941ff5e --- /dev/null +++ b/h5/home/index.html @@ -0,0 +1,10397 @@ + + + + + + + + +比价APP 高保真原型 (外卖版) + + + + + + + + + +
+ +
+

方案切换

+
暂无多方案模块
在 variants 配置中添加模块即可
+
+
+ +
+ +
返回
+ + + + + + + + + + + + +
+ +
+
+ + 傻瓜比价 +
+ 跨平台比价,用傻瓜 +
+
+ +
+
+
+ 如何使用傻瓜比价 · 新手指南 +
+
+
+
邀好友 赚金币
+
立即邀请 ›
+
🎁
+
+
+
+
+ + +
+
+ + +
+
+
+
+ + 14:23:18省***手比价后节省88888.88 +
+
+ + 14:22:451***2比价后节省42.40 +
+
+ + 14:20:31小**比价后节省7.90 +
+
+ + 14:18:077***0比价后节省156.30 +
+
+ + 14:15:42团**比价后节省23.50 +
+
+ + 14:11:296***0比价后节省89.40 +
+ +
+ + 14:23:18省***手比价后节省88888.88 +
+
+
+
+ + +
+
+
帮助用户
+
12847
+
+
+
完成比价
+
86532
+
+
+
累计节省
+
37621.4
+
+
+ + + + +
+ +
+
今日大额优惠券
+
AI 一键自动领
+
+ +
+ + +
+ + +
+
点外卖,赚金币
+
快去解锁全网底价
+
+ +
+
+ + + +
+ +
+
+ + + + + +
+
+
智能推荐
+
距离最近
+
销量最高
+
+ + + + + + + + + +
+ +
+
+
+
首页
+
赚钱
+
记录
+
我的
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
🍱
+
请选择您常用的平台
+
进入平台选好商品后,AI 一键替你比多家
+
+
+
+ + + +
+
+ +
连续签到14天 最高可领2888金币
+

签到领取今日金币

+
已连续签到 2 天,今天可领 220 金币
+ +
+
+
已领取
+
180
+
+
+
已领取
+
380
+
+
+
+
220
+
+
+
+
260
+
+
+
+
888
+
+
+ +
+
+
第1天
+
第2天
+
今天
+
明天
+
第7天
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
🎉🎊✨🎊🎉
+
新手大礼包
+
专享新客福利,开启领取
+
+
+
+
+
+
+
+
+
+
+
+
🎁
+
+
+5,000金币
+
已存入「福利」,随时可提现
+ +
+
+ + +
+5,000 金币
+ +
+ + + + + + +
+ +

「开启省钱之旅」按钮样式

+
点击切换,预览不同方案
+
+
红橙渐变当前
+
黄底黑字品牌主色
+
黑底黄字高对比
+
金色光泽动态扫光
+
玻璃质感立体黄
+
描边偏移克制款
+
红包喜庆红+金
+
呼吸跳动动效款
+
蜜糖渐变黄→琥珀
+
金币描边深金细边
+
+ +
+

领券弹窗副标题样式

+
主标题下那行小字,强化"收益"信号
+
+
基线灰当前最弱
+
金币胶囊品牌黄徽章
+
关键词高亮黄色荧光笔
+
优惠券小票齿边+朱红
+
数字徽章预计立省¥
+
双行节奏预告+承诺
+
V2b 金币翻转动效活力
+
V2c 双色分段黑黄拼接
+
V2d 闪光描边轻盈款
+
V2e 数字嵌入¥18+ 内嵌
+
V2f 双图标金币+闪电
+
V2g 立体浮起金属高光
+
流程植入领券→比价→底价
+
+ +
+

「完成设置」弹窗版式

+
点击切换,下次进入弹窗即生效
+
+
轻收尾·重期待承上小,起下大
+
分割式三段节奏
+
叙事流递进式
+
行为优先主舞台让给行为
+
徽章+行动卡chip 强调最后一步
+
进度条推进脉动黄推进感
+
数字步骤① ✓ → ② 当前
+
极简专注大字承担引导
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/h5/mine/assets/home/index/coupon-claim-bg.png b/h5/mine/assets/home/index/coupon-claim-bg.png new file mode 100644 index 0000000..f6349c0 Binary files /dev/null and b/h5/mine/assets/home/index/coupon-claim-bg.png differ diff --git a/h5/mine/assets/login/index/redpacket-bg.png b/h5/mine/assets/login/index/redpacket-bg.png new file mode 100644 index 0000000..10459a7 Binary files /dev/null and b/h5/mine/assets/login/index/redpacket-bg.png differ diff --git a/h5/mine/assets/onboarding/index/first-banner.png b/h5/mine/assets/onboarding/index/first-banner.png new file mode 100644 index 0000000..3ca6670 Binary files /dev/null and b/h5/mine/assets/onboarding/index/first-banner.png differ diff --git a/h5/mine/assets/onboarding/index/full-bg.png b/h5/mine/assets/onboarding/index/full-bg.png new file mode 100644 index 0000000..6a3792f Binary files /dev/null and b/h5/mine/assets/onboarding/index/full-bg.png differ diff --git a/h5/mine/assets/onboarding/index/guide-1.jpg b/h5/mine/assets/onboarding/index/guide-1.jpg new file mode 100644 index 0000000..3bf5f05 Binary files /dev/null and b/h5/mine/assets/onboarding/index/guide-1.jpg differ diff --git a/h5/mine/assets/onboarding/index/guide-2.jpg b/h5/mine/assets/onboarding/index/guide-2.jpg new file mode 100644 index 0000000..bc37440 Binary files /dev/null and b/h5/mine/assets/onboarding/index/guide-2.jpg differ diff --git a/h5/mine/assets/onboarding/index/guide-3.jpg b/h5/mine/assets/onboarding/index/guide-3.jpg new file mode 100644 index 0000000..a1aecff Binary files /dev/null and b/h5/mine/assets/onboarding/index/guide-3.jpg differ diff --git a/h5/mine/assets/onboarding/index/guide-4.jpg b/h5/mine/assets/onboarding/index/guide-4.jpg new file mode 100644 index 0000000..e7c35e4 Binary files /dev/null and b/h5/mine/assets/onboarding/index/guide-4.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/meituan/1-home.jpg b/h5/mine/assets/onboarding/index/platform-flows/meituan/1-home.jpg new file mode 100644 index 0000000..fef11ff Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/meituan/1-home.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/meituan/2-shop-top.jpg b/h5/mine/assets/onboarding/index/platform-flows/meituan/2-shop-top.jpg new file mode 100644 index 0000000..9fd697f Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/meituan/2-shop-top.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/meituan/5-shop-cart.jpg b/h5/mine/assets/onboarding/index/platform-flows/meituan/5-shop-cart.jpg new file mode 100644 index 0000000..25f44bb Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/meituan/5-shop-cart.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/meituan/6-checkout.jpg b/h5/mine/assets/onboarding/index/platform-flows/meituan/6-checkout.jpg new file mode 100644 index 0000000..61258f8 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/meituan/6-checkout.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/meituan/7-coupon-select.jpg b/h5/mine/assets/onboarding/index/platform-flows/meituan/7-coupon-select.jpg new file mode 100644 index 0000000..2614835 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/meituan/7-coupon-select.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/meituan/8-checkout-coupon.jpg b/h5/mine/assets/onboarding/index/platform-flows/meituan/8-checkout-coupon.jpg new file mode 100644 index 0000000..12c3ee9 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/meituan/8-checkout-coupon.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/meituan/result.jpg b/h5/mine/assets/onboarding/index/platform-flows/meituan/result.jpg new file mode 100644 index 0000000..9705d59 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/meituan/result.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/1-home.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/1-home.jpg new file mode 100644 index 0000000..57014df Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/1-home.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/2-coupon-center.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/2-coupon-center.jpg new file mode 100644 index 0000000..7650add Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/2-coupon-center.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/3-coupon-claimed.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/3-coupon-claimed.jpg new file mode 100644 index 0000000..0f833a5 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/3-coupon-claimed.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/4-search.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/4-search.jpg new file mode 100644 index 0000000..3ef8238 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/4-search.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/5-shop-top.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/5-shop-top.jpg new file mode 100644 index 0000000..d0719ee Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/5-shop-top.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/6-shop-item.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/6-shop-item.jpg new file mode 100644 index 0000000..7ac92ed Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/6-shop-item.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/7-spec.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/7-spec.jpg new file mode 100644 index 0000000..b1471b6 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/7-spec.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/8-checkout.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/8-checkout.jpg new file mode 100644 index 0000000..4128e2c Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/8-checkout.jpg differ diff --git a/h5/mine/assets/onboarding/index/platform-flows/taobao/result.jpg b/h5/mine/assets/onboarding/index/platform-flows/taobao/result.jpg new file mode 100644 index 0000000..0508498 Binary files /dev/null and b/h5/mine/assets/onboarding/index/platform-flows/taobao/result.jpg differ diff --git a/h5/mine/assets/onboarding/index/waimai-guide/add-required-item.png b/h5/mine/assets/onboarding/index/waimai-guide/add-required-item.png new file mode 100644 index 0000000..bcb2662 Binary files /dev/null and b/h5/mine/assets/onboarding/index/waimai-guide/add-required-item.png differ diff --git a/h5/mine/assets/onboarding/index/waimai-guide/add-to-cart.png b/h5/mine/assets/onboarding/index/waimai-guide/add-to-cart.png new file mode 100644 index 0000000..c0e1abd Binary files /dev/null and b/h5/mine/assets/onboarding/index/waimai-guide/add-to-cart.png differ diff --git a/h5/mine/assets/onboarding/index/waimai-guide/missing-required.png b/h5/mine/assets/onboarding/index/waimai-guide/missing-required.png new file mode 100644 index 0000000..dd4336f Binary files /dev/null and b/h5/mine/assets/onboarding/index/waimai-guide/missing-required.png differ diff --git a/h5/mine/assets/profile/index/coin.png b/h5/mine/assets/profile/index/coin.png new file mode 100644 index 0000000..aea8a8b Binary files /dev/null and b/h5/mine/assets/profile/index/coin.png differ diff --git a/h5/mine/assets/profile/index/help.png b/h5/mine/assets/profile/index/help.png new file mode 100644 index 0000000..943faca Binary files /dev/null and b/h5/mine/assets/profile/index/help.png differ diff --git a/h5/mine/assets/profile/index/laurel.png b/h5/mine/assets/profile/index/laurel.png new file mode 100644 index 0000000..6d2ab36 Binary files /dev/null and b/h5/mine/assets/profile/index/laurel.png differ diff --git a/h5/mine/assets/profile/index/lower-price-report-medal.png b/h5/mine/assets/profile/index/lower-price-report-medal.png new file mode 100644 index 0000000..4b8bd1c Binary files /dev/null and b/h5/mine/assets/profile/index/lower-price-report-medal.png differ diff --git a/h5/mine/assets/profile/index/orders.svg b/h5/mine/assets/profile/index/orders.svg new file mode 100644 index 0000000..c2b0d8f --- /dev/null +++ b/h5/mine/assets/profile/index/orders.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/h5/mine/assets/profile/index/piggy-coins.png b/h5/mine/assets/profile/index/piggy-coins.png new file mode 100644 index 0000000..ebc45f9 Binary files /dev/null and b/h5/mine/assets/profile/index/piggy-coins.png differ diff --git a/h5/mine/assets/profile/index/savings-bg.png b/h5/mine/assets/profile/index/savings-bg.png new file mode 100644 index 0000000..41b4797 Binary files /dev/null and b/h5/mine/assets/profile/index/savings-bg.png differ diff --git a/h5/mine/assets/profile/index/settings.png b/h5/mine/assets/profile/index/settings.png new file mode 100644 index 0000000..809b098 Binary files /dev/null and b/h5/mine/assets/profile/index/settings.png differ diff --git a/h5/mine/assets/profile/index/top-clouds.png b/h5/mine/assets/profile/index/top-clouds.png new file mode 100644 index 0000000..8846ce6 Binary files /dev/null and b/h5/mine/assets/profile/index/top-clouds.png differ diff --git a/h5/mine/assets/shared/badges/lowest-price.png b/h5/mine/assets/shared/badges/lowest-price.png new file mode 100644 index 0000000..d39ea1e Binary files /dev/null and b/h5/mine/assets/shared/badges/lowest-price.png differ diff --git a/h5/mine/assets/shared/logos/jd.png b/h5/mine/assets/shared/logos/jd.png new file mode 100644 index 0000000..ed939da Binary files /dev/null and b/h5/mine/assets/shared/logos/jd.png differ diff --git a/h5/mine/assets/shared/logos/meituan.png b/h5/mine/assets/shared/logos/meituan.png new file mode 100644 index 0000000..71cede9 Binary files /dev/null and b/h5/mine/assets/shared/logos/meituan.png differ diff --git a/h5/mine/assets/shared/logos/taobao.png b/h5/mine/assets/shared/logos/taobao.png new file mode 100644 index 0000000..7e0f742 Binary files /dev/null and b/h5/mine/assets/shared/logos/taobao.png differ diff --git a/h5/mine/assets/welfare/index/checkin-chest-8888.png b/h5/mine/assets/welfare/index/checkin-chest-8888.png new file mode 100644 index 0000000..b936155 Binary files /dev/null and b/h5/mine/assets/welfare/index/checkin-chest-8888.png differ diff --git a/h5/mine/assets/welfare/index/checkin-coin-single.png b/h5/mine/assets/welfare/index/checkin-coin-single.png new file mode 100644 index 0000000..4a33906 Binary files /dev/null and b/h5/mine/assets/welfare/index/checkin-coin-single.png differ diff --git a/h5/mine/assets/welfare/index/checkin-coins-3888.png b/h5/mine/assets/welfare/index/checkin-coins-3888.png new file mode 100644 index 0000000..98b0daf Binary files /dev/null and b/h5/mine/assets/welfare/index/checkin-coins-3888.png differ diff --git a/h5/mine/assets/welfare/index/checkin-coins-600.png b/h5/mine/assets/welfare/index/checkin-coins-600.png new file mode 100644 index 0000000..b18cdec Binary files /dev/null and b/h5/mine/assets/welfare/index/checkin-coins-600.png differ diff --git a/h5/mine/index.html b/h5/mine/index.html index 936b725..2d3cc32 100644 --- a/h5/mine/index.html +++ b/h5/mine/index.html @@ -4,13 +4,26 @@ + - -比价APP 高保真原型 (外卖版) + + +我的 · 傻瓜比价 + + +
9:41
@@ -3457,7 +3478,7 @@ TODO: 补充 @owner / @from / @to / @notes(参照 FLOW.md)
- +
未登录
登录后查看你的省钱战绩
@@ -3465,18 +3486,18 @@ TODO: 补充 @owner / @from / @to / @notes(参照 FLOW.md)
-
上报更低价赚金币
-
比价记录
-
意见反馈
-
设置
+
上报更低价赚金币
+
比价记录
+
意见反馈
+
设置
', @@ -7174,7 +7222,7 @@ const couponPromptVariants = { '
AI 跨平台一键领取,无需手动切换 APP
' + '
' + '
' + - ['美团', '../../assets/shared/logos/meituan.png', '淘宝', '../../assets/shared/logos/taobao.png', '京东', '../../assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + + ['美团', 'assets/shared/logos/meituan.png', '淘宝', 'assets/shared/logos/taobao.png', '京东', 'assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + '
' + '
' + '
将在以上平台领取
' + @@ -7189,7 +7237,7 @@ const couponPromptVariants = { '
🎁 领取后立享更低好价
' + '
' + '
' + - ['美团', '../../assets/shared/logos/meituan.png', '淘宝', '../../assets/shared/logos/taobao.png', '京东', '../../assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + + ['美团', 'assets/shared/logos/meituan.png', '淘宝', 'assets/shared/logos/taobao.png', '京东', 'assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + '
' + '
' + '
将在以上平台领取
' + @@ -7208,7 +7256,7 @@ const couponPromptVariants = { '
' + '
' + '
' + - ['美团', '../../assets/shared/logos/meituan.png', '淘宝', '../../assets/shared/logos/taobao.png', '京东', '../../assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + + ['美团', 'assets/shared/logos/meituan.png', '淘宝', 'assets/shared/logos/taobao.png', '京东', 'assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + '
' + '
' + '
将在以上平台领取
' + @@ -7223,7 +7271,7 @@ const couponPromptVariants = { '
发现您有未领取的大额优惠券
' + '
' + '
' + - ['美团', '../../assets/shared/logos/meituan.png', '淘宝', '../../assets/shared/logos/taobao.png', '京东', '../../assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + + ['美团', 'assets/shared/logos/meituan.png', '淘宝', 'assets/shared/logos/taobao.png', '京东', 'assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + '
' + '
' + '
将在以上平台领取
' + @@ -7238,7 +7286,7 @@ const couponPromptVariants = { '
⏰ 仅今日有效,错过自动失效
' + '
' + '
' + - ['美团', '../../assets/shared/logos/meituan.png', '淘宝', '../../assets/shared/logos/taobao.png', '京东', '../../assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + + ['美团', 'assets/shared/logos/meituan.png', '淘宝', 'assets/shared/logos/taobao.png', '京东', 'assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + '
' + '
' + '
将在以上平台领取
' + @@ -7253,7 +7301,7 @@ const couponPromptVariants = { '
先领券再比价
' + '
' + '
' + - ['美团', '../../assets/shared/logos/meituan.png', '淘宝', '../../assets/shared/logos/taobao.png', '京东', '../../assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + + ['美团', 'assets/shared/logos/meituan.png', '淘宝', 'assets/shared/logos/taobao.png', '京东', 'assets/shared/logos/jd.png'].reduce(function(acc, _, i, arr){ if (i % 2) return acc; return acc + '
' + arr[i] + '
'; }, '') + '
' + '
' + '
将在以上平台领取
' + diff --git a/h5/records/index.html b/h5/records/index.html new file mode 100644 index 0000000..b2056c4 --- /dev/null +++ b/h5/records/index.html @@ -0,0 +1,1798 @@ + + + + + + + +比价记录 · 傻瓜比价 + + + + +
+ + +
+ 9:41 + +
+ + +
+
全部记录
+
已下单
+
+ + +
+
取消
+ + +
比价记录
+ + + +
+ + + + +
+ + +
+
+ 最近搜索 + 清除 +
+
+ +
+ + +
+ + +
没有找到匹配的比价记录
试试其他关键词
+ +
+ + +
+
首页
+
福利
+
记录
+
我的
+
+ + + + + +
+ +
+ + + + + +
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
.
+
0
+
+ +
+
+ + + + + + + +
+
+ +
+ + +
+ +
+ + + + + diff --git a/h5/records/logos/jd.png b/h5/records/logos/jd.png new file mode 100644 index 0000000..ed939da Binary files /dev/null and b/h5/records/logos/jd.png differ diff --git a/h5/records/logos/meituan.png b/h5/records/logos/meituan.png new file mode 100644 index 0000000..71cede9 Binary files /dev/null and b/h5/records/logos/meituan.png differ diff --git a/h5/records/logos/taobao.png b/h5/records/logos/taobao.png new file mode 100644 index 0000000..7e0f742 Binary files /dev/null and b/h5/records/logos/taobao.png differ diff --git a/h5/reports/index.html b/h5/reports/index.html new file mode 100644 index 0000000..d5d8263 --- /dev/null +++ b/h5/reports/index.html @@ -0,0 +1,610 @@ + + + + + + + +上报记录 · 傻瓜比价 + + + + + +
+
返回
+ +
+ +
+ 9:41 + + + + + +
+ +
+ + +
上报记录
+
+ +
+ +
+
全部0
+
审核中0
+
已通过0
+
未通过0
+
+ + +
+ + +
+ + +
+
+
+
+ + + + + diff --git a/h5/reports/logos/jd-waimai.png b/h5/reports/logos/jd-waimai.png new file mode 100644 index 0000000..6de9605 Binary files /dev/null and b/h5/reports/logos/jd-waimai.png differ diff --git a/h5/reports/logos/jd.png b/h5/reports/logos/jd.png new file mode 100644 index 0000000..ed939da Binary files /dev/null and b/h5/reports/logos/jd.png differ diff --git a/h5/reports/logos/meituan-waimai.png b/h5/reports/logos/meituan-waimai.png new file mode 100644 index 0000000..9ef0783 Binary files /dev/null and b/h5/reports/logos/meituan-waimai.png differ diff --git a/h5/reports/logos/meituan.png b/h5/reports/logos/meituan.png new file mode 100644 index 0000000..71cede9 Binary files /dev/null and b/h5/reports/logos/meituan.png differ diff --git a/h5/reports/logos/taobao-shanguang.png b/h5/reports/logos/taobao-shanguang.png new file mode 100644 index 0000000..3091d33 Binary files /dev/null and b/h5/reports/logos/taobao-shanguang.png differ diff --git a/h5/reports/logos/taobao.png b/h5/reports/logos/taobao.png new file mode 100644 index 0000000..7e0f742 Binary files /dev/null and b/h5/reports/logos/taobao.png differ diff --git a/h5/settings/assets/shared/logos/sb-brand.png b/h5/settings/assets/shared/logos/sb-brand.png new file mode 100644 index 0000000..c8f1c13 Binary files /dev/null and b/h5/settings/assets/shared/logos/sb-brand.png differ diff --git a/h5/settings/index.html b/h5/settings/index.html new file mode 100644 index 0000000..a2c16d8 --- /dev/null +++ b/h5/settings/index.html @@ -0,0 +1,541 @@ + + + + + + +设置 · 傻瓜比价 + + + + +
+
+
+ +
设置
+
+ + +
+
+
+
+ 头像 +
+ + +
+
+
+
+ 昵称 +
+
+
+
+ 手机号 +
+
+
+ +
+
+ 通知设置 +
+
+
+ +
+
+ 关于傻瓜比价 +
+
+
+
+ +
+
+
退出登录
+
+
+
+ + + + + + + + + + + + +
+
+ + +
+
+
+
+ + +
+ +
+ + + + +
+
+ + 移动和缩放 + +
+
+ + +
+
捏合手势可缩放,拖动可调整位置
+
+ + +
+
+
修改昵称
+ +
0/20
+
+ + +
+
+
+ + +
+
+
退出登录
+
退出后将无法继续累积金币收益
+
+ + +
+
+
+ + +
+
+
⚠️
+
确认注销账号?
+
注销后以下数据将永久删除且无法恢复
+
· 全部金币余额和现金收益
· 比价记录和购买战绩
· 邀请好友关系和返佣收益
+
+ + +
+
+
+ +
+
+ + + + + + + diff --git a/h5/shared/bridge.js b/h5/shared/bridge.js index ed70e0f..cbacdf7 100644 --- a/h5/shared/bridge.js +++ b/h5/shared/bridge.js @@ -118,6 +118,35 @@ else console.log('[SGBridge mock] launchApp →', json); } + /** 网页请求返回上一页(原生 popBackStack;无桥时浏览器仅 log)。 */ + function closePage() { + if (hasNative && native.closePage) native.closePage(); + else console.log('[SGBridge mock] closePage'); + } + + /** H5「去授权」→ 触发系统定位权限窗(原生侧永久拒绝跳设置)。结果异步,H5 回前台 visibilitychange 自行重查。 */ + function requestLocationPermission() { + if (hasNative && native.requestLocationPermission) native.requestLocationPermission(); + else console.log('[SGBridge mock] requestLocationPermission'); + } + + /** 定位权限是否已授予(FINE/COARSE)。H5 据此切「未授权空态 / feed」。浏览器无原生 → mock 返 true(便于预览 feed)。 */ + function isLocationGranted() { + if (hasNative && native.isLocationGranted) return !!native.isLocationGranted(); + return true; + } + + /** 取设备当前经纬度 → {longitude, latitude};原生拿不到(未授权/无缓存)返 null,浏览器无原生 mock 北京。 + * 原生侧同步返宿主缓存的 lastLocation(见 SGBridge.kt getLocation);H5 拿到 null 自行落默认坐标。 */ + function getLocation() { + if (hasNative && native.getLocation) { + var o = safeParse(native.getLocation(), null); + if (o && typeof o.longitude === 'number' && typeof o.latitude === 'number') return o; + return null; + } + return { longitude: 116.404, latitude: 39.928 }; + } + // ====== 原生 → H5 事件总线 ====== var listeners = {}; // event → [fn] @@ -147,6 +176,8 @@ getAppVersion: getAppVersion, getInstalledApps: getInstalledApps, getCouponClaimedToday: getCouponClaimedToday, + isLocationGranted: isLocationGranted, + getLocation: getLocation, // 动作 navigate: navigate, requestLogin: requestLogin, @@ -155,6 +186,8 @@ startCompare: startCompare, startCouponClaim: startCouponClaim, launchApp: launchApp, + closePage: closePage, + requestLocationPermission: requestLocationPermission, // 事件 on: on, _emit: _emit, diff --git a/h5/shared/fonts.css b/h5/shared/fonts.css new file mode 100644 index 0000000..fd5f148 --- /dev/null +++ b/h5/shared/fonts.css @@ -0,0 +1,13 @@ +/* + * 阿里巴巴普惠体 3.0(GB2312 子集 + 拉丁 + 标点,5 档)—— H5 全局中文字重对齐原型。 + * 与原生 res/font/puhuiti_* 同一套字体;安卓系统 CJK 只有 Regular/Bold 两档,原型的 + * 600/700/800/900 在系统字体下会被压成偏细 → 之前靠 text-shadow 伪粗(易过粗)。 + * 内嵌真字体后 font-weight 由字模原生渲染,与原型一致,伪粗体脚本已移除。 + * woff2 同源加载,浏览器按页面实际用到的字重懒下载并缓存(跨页只下一次)。 + * 档位对齐原型:400→Regular / 600→SemiBold / 700→Bold / 800→ExtraBold / 900→Heavy。 + */ +@font-face { font-family: 'PuHuiTi'; font-style: normal; font-weight: 400; font-display: swap; src: url('fonts/puhuiti_regular.woff2') format('woff2'); } +@font-face { font-family: 'PuHuiTi'; font-style: normal; font-weight: 600; font-display: swap; src: url('fonts/puhuiti_semibold.woff2') format('woff2'); } +@font-face { font-family: 'PuHuiTi'; font-style: normal; font-weight: 700; font-display: swap; src: url('fonts/puhuiti_bold.woff2') format('woff2'); } +@font-face { font-family: 'PuHuiTi'; font-style: normal; font-weight: 800; font-display: swap; src: url('fonts/puhuiti_extrabold.woff2') format('woff2'); } +@font-face { font-family: 'PuHuiTi'; font-style: normal; font-weight: 900; font-display: swap; src: url('fonts/puhuiti_heavy.woff2') format('woff2'); } diff --git a/h5/shared/fonts/puhuiti_bold.woff2 b/h5/shared/fonts/puhuiti_bold.woff2 new file mode 100644 index 0000000..bb0915f Binary files /dev/null and b/h5/shared/fonts/puhuiti_bold.woff2 differ diff --git a/h5/shared/fonts/puhuiti_extrabold.woff2 b/h5/shared/fonts/puhuiti_extrabold.woff2 new file mode 100644 index 0000000..983a13a Binary files /dev/null and b/h5/shared/fonts/puhuiti_extrabold.woff2 differ diff --git a/h5/shared/fonts/puhuiti_heavy.woff2 b/h5/shared/fonts/puhuiti_heavy.woff2 new file mode 100644 index 0000000..3df8e6a Binary files /dev/null and b/h5/shared/fonts/puhuiti_heavy.woff2 differ diff --git a/h5/shared/fonts/puhuiti_regular.woff2 b/h5/shared/fonts/puhuiti_regular.woff2 new file mode 100644 index 0000000..f432b68 Binary files /dev/null and b/h5/shared/fonts/puhuiti_regular.woff2 differ diff --git a/h5/shared/fonts/puhuiti_semibold.woff2 b/h5/shared/fonts/puhuiti_semibold.woff2 new file mode 100644 index 0000000..23228d3 Binary files /dev/null and b/h5/shared/fonts/puhuiti_semibold.woff2 differ diff --git a/h5/welfare/assets/asset-illustration.png b/h5/welfare/assets/asset-illustration.png new file mode 100644 index 0000000..e36fceb Binary files /dev/null and b/h5/welfare/assets/asset-illustration.png differ diff --git a/h5/welfare/assets/checkin-chest-8888.png b/h5/welfare/assets/checkin-chest-8888.png new file mode 100644 index 0000000..b936155 Binary files /dev/null and b/h5/welfare/assets/checkin-chest-8888.png differ diff --git a/h5/welfare/assets/checkin-coin-single.png b/h5/welfare/assets/checkin-coin-single.png new file mode 100644 index 0000000..4a33906 Binary files /dev/null and b/h5/welfare/assets/checkin-coin-single.png differ diff --git a/h5/welfare/assets/checkin-coins-3888.png b/h5/welfare/assets/checkin-coins-3888.png new file mode 100644 index 0000000..98b0daf Binary files /dev/null and b/h5/welfare/assets/checkin-coins-3888.png differ diff --git a/h5/welfare/assets/checkin-coins-600.png b/h5/welfare/assets/checkin-coins-600.png new file mode 100644 index 0000000..b18cdec Binary files /dev/null and b/h5/welfare/assets/checkin-coins-600.png differ diff --git a/h5/welfare/assets/coin-icon.png b/h5/welfare/assets/coin-icon.png new file mode 100644 index 0000000..3b58d25 Binary files /dev/null and b/h5/welfare/assets/coin-icon.png differ diff --git a/h5/welfare/assets/wechat-pay-check-icon.png b/h5/welfare/assets/wechat-pay-check-icon.png new file mode 100644 index 0000000..bda0e57 Binary files /dev/null and b/h5/welfare/assets/wechat-pay-check-icon.png differ diff --git a/h5/welfare/index.html b/h5/welfare/index.html new file mode 100644 index 0000000..3e9d97e --- /dev/null +++ b/h5/welfare/index.html @@ -0,0 +1,429 @@ + + + + + + +赚钱中心 · 傻瓜比价 + + + + +
+
+
+ +
+
+
赚金币
+
+
+
+ +
+ + 预览签到:关 + + +
+
+
+
+ +
+
+ +
连续签到7天,必得2500金币
+

签到领取今日金币

+
+
+
+ + +
+
+ +
+ + + + + + diff --git a/h5/welfare_rules/index.html b/h5/welfare_rules/index.html new file mode 100644 index 0000000..e321f72 --- /dev/null +++ b/h5/welfare_rules/index.html @@ -0,0 +1,74 @@ + + + + + + +活动规则 · 傻瓜比价 + + + + +
+
+
+ +
活动规则
+
+ +
+
+
活动规则
+
+
1
金币获取用户可通过签到、观看视频、打开消息提醒等任务获得金币,具体奖励以页面展示为准。
+
2
任务发放完成任务后,金币通常会即时到账;如遇网络延迟或系统审核,到账可能会稍有延迟。
+
3
兑换说明金币可按页面展示比例兑换现金,当前按 10000 金币 = 1 元展示,实际兑换以活动页说明为准。
+
4
邀请奖励邀请好友奖励按元/现金展示,需好友完成有效注册或指定任务后发放,同一设备、同一账号重复参与不重复计奖。
+
5
异常处理如发现刷奖励、虚假邀请、异常设备等违规行为,平台有权取消对应奖励和提现资格。
+
+
+
+
+
+ + + + + diff --git a/scripts/seed_mock_compare.py b/scripts/seed_mock_compare.py new file mode 100644 index 0000000..d00629e --- /dev/null +++ b/scripts/seed_mock_compare.py @@ -0,0 +1,139 @@ +"""开发用:给指定用户造几条比价记录(真机验收 records 页用)。 + +走真实 upsert_record 路径(best/saved/is_source_best 由后端派生),写入 .env 指向的库 +(默认 data/app.db)。幂等:同 trace_id 重复跑只覆盖、不重复。 + +用法(server 仓根): + python scripts/seed_mock_compare.py [user_id] # 默认 user_id=15 +""" +from __future__ import annotations + +import logging +import sys +from datetime import datetime, timedelta + +logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING) # 静音 SQL 回显 + +from app.core.rewards import CN_TZ +from app.db.session import SessionLocal +from app.repositories import comparison as crud +from app.schemas.compare_record import ( + ComparisonItemIn, + ComparisonRecordIn, + ComparisonResultIn, +) + +USER_ID = int(sys.argv[1]) if len(sys.argv) > 1 else 15 + +# 平台 id 用后端短名,records H5 按别名映射到 美团/淘宝/京东 三列格(meituan/taobao/jd)。 +RECORDS: list[tuple[ComparisonRecordIn, timedelta]] = [ + # ① 源美团,京东最低(发现可省 ¥5.9) + ( + ComparisonRecordIn( + trace_id="mock-rec-001", + business_type="food", + store_name="瑞幸咖啡(国贸店)", + source_platform_id="meituan", + source_platform_name="美团", + source_price=35.8, + total_dish_count=3, + items=[ + ComparisonItemIn(name="生椰拿铁", qty=2, specs=["大杯", "少冰"]), + ComparisonItemIn(name="厚乳拿铁", qty=1, specs=["标准糖"]), + ], + comparison_results=[ + ComparisonResultIn(platform_id="meituan", platform_name="美团", price=35.8, is_source=True, rank=2, status="success"), + ComparisonResultIn(platform_id="jd", platform_name="京东", price=29.9, is_source=False, rank=1, status="success", coupon_saved=5.0, coupon_name="百亿补贴"), + ComparisonResultIn(platform_id="taobao", platform_name="淘宝", price=33.0, is_source=False, rank=3, status="success"), + ], + ), + timedelta(minutes=8), + ), + # ② 源淘宝,美团最低(发现可省 ¥3.7) + ( + ComparisonRecordIn( + trace_id="mock-rec-002", + business_type="food", + store_name="麦当劳(三里屯店)", + source_platform_id="taobao", + source_platform_name="淘宝", + source_price=42.5, + total_dish_count=2, + items=[ + ComparisonItemIn(name="巨无霸套餐", qty=1, specs=["可乐", "中薯"]), + ComparisonItemIn(name="麦辣鸡翅", qty=1, specs=["2块"]), + ], + comparison_results=[ + ComparisonResultIn(platform_id="meituan", platform_name="美团", price=38.8, is_source=False, rank=1, status="success"), + ComparisonResultIn(platform_id="taobao", platform_name="淘宝", price=42.5, is_source=True, rank=3, status="success"), + ComparisonResultIn(platform_id="jd", platform_name="京东", price=41.0, is_source=False, rank=2, status="success"), + ], + ), + timedelta(minutes=95), + ), + # ③ 源美团且本身最优(is_source_best=True,可省 ¥0) + ( + ComparisonRecordIn( + trace_id="mock-rec-003", + business_type="food", + store_name="蜜雪冰城(中关村店)", + source_platform_id="meituan", + source_platform_name="美团", + source_price=12.0, + total_dish_count=2, + items=[ComparisonItemIn(name="冰鲜柠檬水", qty=2, specs=["大杯"])], + comparison_results=[ + ComparisonResultIn(platform_id="meituan", platform_name="美团", price=12.0, is_source=True, rank=1, status="success"), + ComparisonResultIn(platform_id="jd", platform_name="京东", price=13.0, is_source=False, rank=2, status="success"), + ComparisonResultIn(platform_id="taobao", platform_name="淘宝", price=13.5, is_source=False, rank=3, status="success"), + ], + ), + timedelta(days=1, hours=2), + ), + # ④ 源美团,京东最低,淘宝未满起送(多态:有平台无价) + ( + ComparisonRecordIn( + trace_id="mock-rec-004", + business_type="food", + store_name="星巴克(望京SOHO店)", + source_platform_id="meituan", + source_platform_name="美团", + source_price=45.0, + total_dish_count=2, + items=[ + ComparisonItemIn(name="燕麦拿铁", qty=1, specs=["大杯", "热"]), + ComparisonItemIn(name="美式", qty=1, specs=["中杯"]), + ], + comparison_results=[ + ComparisonResultIn(platform_id="meituan", platform_name="美团", price=45.0, is_source=True, rank=2, status="success"), + ComparisonResultIn(platform_id="jd", platform_name="京东", price=41.5, is_source=False, rank=1, status="success"), + ComparisonResultIn(platform_id="taobao", platform_name="淘宝", price=None, is_source=False, rank=None, status="below_minimum"), + ], + ), + timedelta(days=2, hours=5), + ), +] + + +def main() -> None: + db = SessionLocal() + try: + print(f"seeding {len(RECORDS)} 条比价记录 → user_id={USER_ID}") + for payload, age in RECORDS: + rec = crud.upsert_record(db, user_id=USER_ID, payload=payload) + # 错开 created_at,让记录页按日期分组更真实(今天/昨天/前天) + rec.created_at = (datetime.now(CN_TZ) - age).replace(tzinfo=None) + db.commit() + print( + f" #{rec.id} {rec.store_name} status={rec.status} " + f"source={rec.source_price_cents} best={rec.best_price_cents}" + f"({rec.best_platform_name}) saved={rec.saved_amount_cents} " + f"is_source_best={rec.is_source_best} created={rec.created_at}" + ) + print("done. 真机记录页下拉刷新 / 重进即可见。") + finally: + db.close() + + +if __name__ == "__main__": + main() diff --git a/tests/test_h5_hosting.py b/tests/test_h5_hosting.py new file mode 100644 index 0000000..9f1d4b0 --- /dev/null +++ b/tests/test_h5_hosting.py @@ -0,0 +1,101 @@ +"""H5 静态托管冒烟:/h5 同源服务页面 + .html no-cache(热更核心)。""" +from __future__ import annotations + + +def test_h5_shared_bridge_served(client) -> None: + resp = client.get("/h5/shared/bridge.js") + assert resp.status_code == 200 + + +def test_h5_html_no_cache(client) -> None: + # records 迁入前,先用已在仓库的 mine 页验证 .html 的 no-cache 响应头 + resp = client.get("/h5/mine/index.html") + assert resp.status_code == 200 + assert resp.headers.get("cache-control") == "no-cache" + + +def test_h5_html_no_cache_via_dir_url(client) -> None: + # 目录式 URL(WebView 规范入口)经 html=True 回落 index.html,也必须带 no-cache + resp = client.get("/h5/mine/") + assert resp.status_code == 200 + assert resp.headers.get("cache-control") == "no-cache" + + +def test_h5_records_served_and_migrated(client) -> None: + resp = client.get("/h5/records/index.html") + assert resp.status_code == 200 + assert resp.headers.get("cache-control") == "no-cache" + body = resp.text + assert "SGBridge" in body # 已切到新桥 + assert "NativeBridge" not in body # 旧桥名清零 + assert "getApiBase" not in body # 同源:绝对地址拼接已移除 + assert "../shared/bridge.js" in body + + +def test_h5_home_served(client) -> None: + resp = client.get("/h5/home/index.html") + assert resp.status_code == 200 + assert resp.headers.get("cache-control") == "no-cache" + body = resp.text + assert 'id="home"' in body + assert "data-cc-id" not in body # 原型编辑器留痕已剥 + assert "../../assets/" not in body # 素材路径已本地化 + assert "/api/v1/platform/stats" in body # 已接同源数据 + assert body.count('class="screen') == 1 # 只剩首页一屏 + + +def test_h5_home_asset_served(client) -> None: + resp = client.get("/h5/home/assets/shared/logos/sb-brand.png") + assert resp.status_code == 200 + + +def test_h5_bridge_has_get_location(client) -> None: + # H2b: 首页 feed 需经纬度, bridge 暴露同步 getLocation()(无桥 mock 北京) + resp = client.get("/h5/shared/bridge.js") + assert resp.status_code == 200 + body = resp.text + assert "getLocation" in body + assert "116.404" in body and "39.928" in body # 浏览器 mock 北京兜底 + + +def test_h5_home_feed_wired(client) -> None: + # H2b: 首页 feed 接真实美团端点 + 抢换链;mock 静态卡已移除 + resp = client.get("/h5/home/index.html") + assert resp.status_code == 200 + body = resp.text + assert "/api/v1/meituan/feed" in body # rec/distance + assert "/api/v1/meituan/top-sales" in body # 销量最高 + assert "/api/v1/meituan/referral-link" in body # 抢 + assert "HomeFeed" in body # feed 模块已挂 + assert "茶百道" not in body # 写死的 mock 卡(店名)已移除 + assert "chabaidao.png" not in body # 写死的 mock 头图已移除 + assert "比团购省 5.5 元" not in body # 随原生:mock 卡的「比团购省」标签已删(渲染只用 price_label/rank_label) + + +def test_h5_home_last_compare_wired(client) -> None: + # 「上次比价」横幅改接真实 /api/v1/compare/records + 4 分钟新鲜窗口;原写死 mock 默认值已移除 + resp = client.get("/h5/home/index.html") + assert resp.status_code == 200 + body = resp.text + assert "/api/v1/compare/records" in body # 接真实比价记录端点 + assert "pickFreshLastCompare" in body # 4 分钟新鲜窗口逻辑 + assert "DEFAULT_LAST_COMPARE_RECORD" not in body # 写死 mock 默认已移除 + assert 'id="lastCompareShop">窑鸡王' not in body # 横幅店名静态 mock 占位已清空 + + +def test_compare_records_requires_auth(client) -> None: + # 横幅靠 Bearer token 才拿得到数据;无鉴权必须 401(无桥/未登录时横幅隐藏) + resp = client.get("/api/v1/compare/records?limit=5") + assert resp.status_code == 401 + + +def test_h5_home_coupon_popup_coin_icon_served(client) -> None: + # 「去领取」弹窗右上角金币图标:welfare 资源子树曾漏本地化 → 404 不显示;补齐后须 200 + resp = client.get("/h5/home/assets/welfare/index/coin-icon.png") + assert resp.status_code == 200 + + +def test_h5_home_coupon_ad_reward_coins_served(client) -> None: + # 领券「看广告赚金币」到账 toast(showCouponAdRewardToast)的金币堆图标:同属漏拷的 welfare 子树,补齐后须 200 + resp = client.get("/h5/home/assets/welfare/index/checkin-coins-600.png") + assert resp.status_code == 200