初始化兜爸心选 App 官网项目(构建与发布)
- src/:从线上 shop.douba.top/public/app 拉取的页面源码(v0.3.8) - 版本号、更新日期、安装包大小改为模板变量,统一由 site.config.json 管理, 安装包大小在构建时从 APK 实际字节数计算 - scripts/build.mjs:构建到 dist/,校验 APK、模板变量与资源引用 - scripts/deploy.mjs:与线上比对差异 → 上传 → 备份 → 原子切换 → 线上验证 - scripts/rollback.mjs、scripts/preview.mjs:回滚与本地预览 - AGENTS.md:项目说明、发版流程与服务器/nginx 约定 由 AI 助手协助完成。
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
dist/
|
||||||
|
releases/*.apk
|
||||||
|
node_modules/
|
||||||
|
.DS_Store
|
||||||
133
AGENTS.md
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
# AGENTS.md · 兜爸心选 App 官网(介绍与下载页)
|
||||||
|
|
||||||
|
「兜爸心选」移动应用的官方介绍与下载页。
|
||||||
|
|
||||||
|
- **对外访问地址:<https://shop.douba.top/app>**(不带斜杠,应用商店登记的就是这个地址,对外宣传一律用它)
|
||||||
|
- `https://shop.douba.top/app/` 同样可以访问;页面里的 `canonical`、`og:url` 和 JSON-LD 的 `url` 写的是带斜杠的版本
|
||||||
|
- 开发者主体:北京臻惠网络科技有限公司 · 京ICP备17065521号
|
||||||
|
- 应用包名:`com.yizhezhe.douba`(基于 DCloud uni-app 构建)
|
||||||
|
- 代码仓库:`git@gitea.nexjs.com:jone/douba-app-web.git`(分支 `main`;APK 和 dist 不进仓库)
|
||||||
|
|
||||||
|
站点是纯静态的:手写 HTML + CSS + 原生 JS,**运行时没有任何依赖**。本项目只负责一件事:在本地编辑 `src/`,构建出 `dist/`,再发布到服务器。构建和发布脚本只用 Node 内置模块,**不需要 `npm install`**。
|
||||||
|
|
||||||
|
## 常用命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build # src/ → dist/,渲染版本变量并校验资源引用
|
||||||
|
npm run preview # 构建并在 http://localhost:8080/app 本地预览
|
||||||
|
npm run deploy:check # 构建并列出与线上的差异,不改服务器(发布前先跑这个)
|
||||||
|
npm run deploy # 正式发布到 8.130.191.152
|
||||||
|
npm run rollback # 线上目录换回最近一次发布前的备份
|
||||||
|
npm run rollback:list # 列出服务器上的备份
|
||||||
|
```
|
||||||
|
|
||||||
|
发布需要本机能免密 SSH 到 `root@8.130.191.152`(公钥登录),需要 Node 18 及以上版本。
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
douba-app/
|
||||||
|
├── site.config.json 版本号、发布日期、部署目标 —— 发版时改这里
|
||||||
|
├── src/ 站点源码(HTML 中可以使用 {{变量}})
|
||||||
|
│ ├── index.html 官网首页(单页:首屏 / 三条承诺 / 品牌理念 / 应用功能 / 应用截图 / 下载 / FAQ / 页脚)
|
||||||
|
│ ├── styles.css 首页样式(含响应式断点)
|
||||||
|
│ ├── main.js 首页轻交互(无依赖 IIFE)
|
||||||
|
│ ├── terms.html 《用户服务协议》
|
||||||
|
│ ├── permissions.html 《权限说明》(Android 权限清单与第三方 SDK)
|
||||||
|
│ ├── legal.css 两个合规文本页共用的样式
|
||||||
|
│ └── assets/
|
||||||
|
│ ├── brand.webp 品牌 Logo
|
||||||
|
│ ├── favicon.png
|
||||||
|
│ ├── og.jpg 分享卡片图(og:image)
|
||||||
|
│ ├── qr.svg 指向 shop.douba.top/app 的二维码
|
||||||
|
│ ├── shot-mama-1~3.webp 孕育模块真实截图(600×1301)
|
||||||
|
│ ├── shot-mall-1~3.webp 商城模块真实截图(600×1360)
|
||||||
|
│ └── p1~p5.webp 商品图,只用于「应用截图」区的 HTML 仿真手机界面
|
||||||
|
├── releases/ APK 安装包,文件名必须是 douba-v<版本>.apk(不进 git)
|
||||||
|
├── scripts/
|
||||||
|
│ ├── build.mjs 构建 + 校验
|
||||||
|
│ ├── deploy.mjs 发布
|
||||||
|
│ ├── rollback.mjs 回滚
|
||||||
|
│ └── preview.mjs 本地预览服务器
|
||||||
|
└── dist/ 构建产物(不进 git,不要手改)
|
||||||
|
```
|
||||||
|
|
||||||
|
《隐私政策》不属于本项目:页面链接的是站点根目录的 `/protocol.html`,由 CRMEB 商城维护,改它之前先确认。
|
||||||
|
|
||||||
|
## 模板变量与 site.config.json
|
||||||
|
|
||||||
|
构建时只渲染 `.html` 里的 `{{变量}}`。CSS 和 JS 原样复制。使用未定义的变量会导致构建失败。
|
||||||
|
|
||||||
|
| 变量 | 来源 | 用在哪里 |
|
||||||
|
|---|---|---|
|
||||||
|
| `{{version}}` | `version` | JSON-LD `softwareVersion`、首屏、下载区、FAQ |
|
||||||
|
| `{{channel}}` | `channel`(如「内测」) | 「v0.3.8(内测)」「内测版」 |
|
||||||
|
| `{{releaseDate}}` | `releaseDate`(YYYY-MM-DD,北京时间) | 下载区「更新时间」 |
|
||||||
|
| `{{screenshotVersion}}` | `screenshotVersion` | 截图区「截图取自 Android 版 v…」 |
|
||||||
|
| `{{apkFile}}` | 由 `version` 推出:`douba-v<version>.apk` | 下载按钮链接 |
|
||||||
|
| `{{apkSize}}` | **自动读取** `releases/` 里 APK 的实际大小(十进制 MB) | 首屏、下载按钮、下载区 |
|
||||||
|
| `{{permissions.version}}` / `{{permissions.updatedCn}}` | `permissions.version` / `permissions.updated` | 权限说明页的适用版本、更新日期 |
|
||||||
|
|
||||||
|
截图版本和权限说明有单独的变量,因为它们只在截图或权限确实变了的时候才更新,不一定跟着每个版本走。
|
||||||
|
`terms.html` 里的协议更新日期、生效日期属于法律文本,是写死的,不做成变量。
|
||||||
|
|
||||||
|
构建会做三项校验,任何一项不通过都会中止,不会产出 dist:
|
||||||
|
- `releases/` 里存在与 `version` 对应的 APK;
|
||||||
|
- 没有未定义的模板变量;
|
||||||
|
- HTML 的 `src`/`href`/`content`(包括 `og:image` 这类写成 `https://shop.douba.top/app/...` 的完整地址)和 CSS 的 `url()`,凡是指向 `/app` 内的文件都必须存在。指向站点根目录的路径(如 `/protocol.html`)跳过不查。
|
||||||
|
|
||||||
|
## 发布新版 APK
|
||||||
|
|
||||||
|
1. 把新安装包放进 `releases/douba-v<新版本>.apk`。
|
||||||
|
2. 修改 `site.config.json`:`version`、`releaseDate`(按北京时间);渠道变了就改 `channel`;截图换了就改 `screenshotVersion`;权限或 SDK 有变化就改 `permissions` 并同步修改 `src/permissions.html` 的清单。
|
||||||
|
3. 截图有变化的话,替换 `src/assets/shot-*.webp`(保持 600px 宽)。
|
||||||
|
4. `npm run preview` 本地看一遍,然后 `npm run deploy:check` 确认差异,没问题再 `npm run deploy`。
|
||||||
|
|
||||||
|
iOS 上架后:在 `src/index.html` 里把 `.dl-actions` 中 `is-disabled` 的「iOS 版即将上架」换成 App Store 链接,同时更新首屏 `.hero-meta`、FAQ「iPhone 可以用吗?」和 JSON-LD 的 `operatingSystem`。
|
||||||
|
|
||||||
|
## 发布机制(deploy.mjs)
|
||||||
|
|
||||||
|
1. 构建,然后用 sha256 对比 dist 和线上文件,列出新增(+)、修改(~)、删除(-)的文件。没有差异就直接退出。
|
||||||
|
2. 把站点文件打包上传。APK 只有在线上没有同一文件(sha256 不同)时才上传。
|
||||||
|
3. 在服务器的 `/www/wwwroot/shop.douba.top/.deploy/`(位于 `public/` 之外,公网访问不到)组装新目录:
|
||||||
|
- 线上 `download/` 里已有的 APK 全部以**硬链接**保留,旧版下载链接不会失效,也不占额外空间;
|
||||||
|
- 校验 APK 的 sha256,统一设为 `root:root`,目录权限 755、文件权限 644。
|
||||||
|
4. `mv public/app → .deploy/backups/app-<北京时间>`,再 `mv 新目录 → public/app`。两步都在同一分区内重命名,切换是瞬间完成的。备份保留最近 `keepBackups` 份(默认 5 份)。
|
||||||
|
5. 线上验证:请求 `/app`,确认页面版本号正确;请求 APK 地址,确认大小和本地一致。验证失败会报错,这时用 `npm run rollback` 回滚。
|
||||||
|
|
||||||
|
不要直接在服务器上改 `public/app/` 下的文件:下次发布会被 `src/` 覆盖。确实需要临时在线上修改的话,事后要同步回 `src/`。
|
||||||
|
|
||||||
|
## 页面要点
|
||||||
|
|
||||||
|
- `index.html` 各区块用 `<!-- ============ 名称 ============ -->` 注释分隔,锚点:`#about` `#features` `#screens` `#download` `#faq`。
|
||||||
|
- **首屏手机**(`#heroSlides`):6 张真实截图自动轮播,由 `main.js` 控制(4.2 秒一张;悬停、切到后台时暂停;系统开启「减少动效」时不轮播)。第一张不加 `loading="lazy"`,其余都加。
|
||||||
|
- **应用截图区**(`.shots`):前 3 张是真实截图(`shot-mama-*`);后 3 张(商城首页 / 分类 / 商品详情)是**用 HTML + CSS 画出来的仿真界面**,商品名和价格是写死的示例数据。换成真实截图时,按前 3 个 `<figure>` 的写法改,同时更新 `figcaption`。
|
||||||
|
- **入场动画**:给元素加 `data-reveal`,`main.js` 用 IntersectionObserver 在元素进入视口时加 `.is-in`;`html.js` 类表示 JS 已运行(没有 JS 时内容照常显示)。
|
||||||
|
- **FAQ**:用原生 `<details class="qa">`,`main.js` 保证同时只展开一个。
|
||||||
|
|
||||||
|
## 编码约定
|
||||||
|
|
||||||
|
- **首页资源一律用绝对路径 `/app/...`。** 因为 nginx 让 `/app`(不带斜杠)直接返回 `index.html`,这时相对路径会解析到站点根目录,样式和图片会全部失效。
|
||||||
|
- 合规页(`terms.html`、`permissions.html`)用的是相对路径(`legal.css`、`assets/...`)。它们只会通过 `/app/xxx.html` 访问,所以没问题;返回首页统一链接 `/app/`。
|
||||||
|
- 视觉方向是「品牌手账」:纸感底色、印章红、宋体标题、楷体手写批注。颜色、字体只用 `:root` 里的 CSS 变量(`--paper` `--ink` `--red` `--serif` `--hand` 等),不要新写死色值。`legal.css` 里复制了一份同名变量,改主色时**两处都要改**。
|
||||||
|
- 不引入任何框架、CDN、字体文件或统计脚本;`main.js` 保持 ES5 写法、无依赖。
|
||||||
|
- 图片用 webp,`<img>` 写上 `width`/`height`,防止加载时布局跳动;首屏以外的图片加 `loading="lazy" decoding="async"`。
|
||||||
|
- 无障碍:保留 skip link、`aria-label`、装饰元素上的 `aria-hidden="true"`,以及 `prefers-reduced-motion` 下关闭动效的处理。
|
||||||
|
- 文案为简体中文,中文与英文、数字之间留空格(如「Android 5.0 及以上」「61.5 MB」)。
|
||||||
|
- 响应式断点:1080 / 900 / 760 / 560px(见 `styles.css` 末尾)。
|
||||||
|
- 公司名、ICP 备案号、包名、客服时间(工作日 9:00–18:00)在多个页面里写死,修改时全局搜索替换。
|
||||||
|
- 合规文本(用户协议、权限说明、隐私政策)的内容改动要经过运营或法务确认,不要只为了排版顺手改措辞。
|
||||||
|
|
||||||
|
## 服务器与 nginx
|
||||||
|
|
||||||
|
- 站点:`shop.douba.top` 是 CRMEB PRO(ThinkPHP)商城,Web 根目录是 `/www/wwwroot/shop.douba.top/public/`。本项目只管 `public/app/`,**不要动 `public/` 下的其他文件**。
|
||||||
|
- 站点配置(宝塔面板):`/www/server/panel/vhost/nginx/shop.douba.top.conf`
|
||||||
|
- 本页专用规则:`/www/server/panel/vhost/nginx/extension/shop.douba.top/app.conf`
|
||||||
|
```nginx
|
||||||
|
location = /app { root /www/wwwroot/shop.douba.top/public; try_files /app/index.html =404; }
|
||||||
|
```
|
||||||
|
应用商店登记的地址不带斜杠,所以 `/app` 不能 301 跳转,**不要删这条规则**。
|
||||||
|
同一个文件里还有一条 `location ~ ^/app/download/[^/]+\.apk$` 规则:让 APK 以标准类型 `application/vnd.android.package-archive` 返回,不存在的 APK 返回 404(不会被商城接走)。改这个文件前,先把原文件备份到 `/www/wwwroot/shop.douba.top/.deploy/nginx-backup/`。
|
||||||
|
- 不存在的路径会被商城的 rewrite 规则接走,返回 CRMEB 页面和 **200 状态码**,所以不能用状态码判断文件是否存在,要看返回的内容。
|
||||||
|
- 静态文件的缓存头是 `max-age=43200` + `no-cache`(每次请求都会向服务器验证),发布后一般刷新就能看到;微信内置浏览器缓存可能更久。
|
||||||
|
- 改 nginx 配置后先 `nginx -t` 检查,再 `nginx -s reload`。
|
||||||
17
package.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "douba-app",
|
||||||
|
"private": true,
|
||||||
|
"description": "兜爸心选 App 官网(介绍与下载页),发布到 https://shop.douba.top/app",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "node scripts/build.mjs",
|
||||||
|
"preview": "node scripts/build.mjs && node scripts/preview.mjs",
|
||||||
|
"deploy:check": "node scripts/deploy.mjs --dry-run",
|
||||||
|
"deploy": "node scripts/deploy.mjs",
|
||||||
|
"rollback": "node scripts/rollback.mjs",
|
||||||
|
"rollback:list": "node scripts/rollback.mjs --list"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
}
|
||||||
117
scripts/build.mjs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// 构建:src/ → dist/,渲染 {{变量}},拷入 APK,并校验页面引用的本地资源都存在
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||||
|
const SRC = path.join(ROOT, 'src');
|
||||||
|
const DIST = path.join(ROOT, 'dist');
|
||||||
|
const RELEASES = path.join(ROOT, 'releases');
|
||||||
|
|
||||||
|
export function loadConfig() {
|
||||||
|
return JSON.parse(fs.readFileSync(path.join(ROOT, 'site.config.json'), 'utf8'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function apkFileName(cfg) {
|
||||||
|
return `douba-v${cfg.version}.apk`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2026-10-29 → 2026 年 10 月 29 日
|
||||||
|
function cnDate(iso) {
|
||||||
|
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso || '');
|
||||||
|
if (!m) throw new Error(`日期格式应为 YYYY-MM-DD:${iso}`);
|
||||||
|
return `${m[1]} 年 ${Number(m[2])} 月 ${Number(m[3])} 日`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字节 → "61.5 MB"(十进制,和手机系统显示一致)
|
||||||
|
function mb(bytes) {
|
||||||
|
return `${(bytes / 1e6).toFixed(1)} MB`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function walk(dir) {
|
||||||
|
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((e) => {
|
||||||
|
const p = path.join(dir, e.name);
|
||||||
|
return e.isDirectory() ? walk(p) : [p];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function render(text, vars, file) {
|
||||||
|
return text.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, key) => {
|
||||||
|
if (!(key in vars)) throw new Error(`${file}: 未定义的模板变量 {{${key}}}`);
|
||||||
|
return vars[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找出 HTML 的 src/href 和 CSS 的 url(),确认指向 /app 内的文件都存在
|
||||||
|
function checkRefs(files) {
|
||||||
|
const missing = [];
|
||||||
|
for (const file of files) {
|
||||||
|
const ext = path.extname(file);
|
||||||
|
if (ext !== '.html' && ext !== '.css') continue;
|
||||||
|
const text = fs.readFileSync(file, 'utf8');
|
||||||
|
const re = ext === '.html' ? /\s(?:src|href|content)="([^"]+)"/g : /url\(["']?([^"')]+)["']?\)/g;
|
||||||
|
for (let [, raw] of text.matchAll(re)) {
|
||||||
|
raw = raw.replace(/^https:\/\/shop\.douba\.top(?=\/app)/, ''); // og:image 等写的是本站完整地址
|
||||||
|
if (/\s/.test(raw) || (!raw.includes('/') && !raw.includes('.'))) continue; // content 里的普通文本
|
||||||
|
const ref = raw.split(/[?#]/)[0];
|
||||||
|
if (!ref || /^(https?:|data:|mailto:|tel:|\/\/)/.test(raw) || /^(#|%23)/.test(raw)) continue; // %23 = 内联 SVG 里的 url(#id)
|
||||||
|
let target;
|
||||||
|
if (ref.startsWith('/app/')) target = path.join(DIST, ref.slice(5));
|
||||||
|
else if (ref === '/app' || ref === '/app/') target = path.join(DIST, 'index.html');
|
||||||
|
else if (ref.startsWith('/')) continue; // 站点根下的商城页面(如 /protocol.html),不归本项目管
|
||||||
|
else target = path.join(path.dirname(file), ref);
|
||||||
|
if (fs.existsSync(target) && fs.statSync(target).isDirectory()) target = path.join(target, 'index.html');
|
||||||
|
if (!fs.existsSync(target)) missing.push(`${path.relative(DIST, file)} → ${raw}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (missing.length) throw new Error(`以下引用的文件不存在:\n ${missing.join('\n ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function build() {
|
||||||
|
const cfg = loadConfig();
|
||||||
|
const apkFile = apkFileName(cfg);
|
||||||
|
const apkSrc = path.join(RELEASES, apkFile);
|
||||||
|
if (!fs.existsSync(apkSrc)) {
|
||||||
|
throw new Error(`找不到安装包 releases/${apkFile}(site.config.json 的 version 是 ${cfg.version})`);
|
||||||
|
}
|
||||||
|
const apkBytes = fs.statSync(apkSrc).size;
|
||||||
|
|
||||||
|
const vars = {
|
||||||
|
version: cfg.version,
|
||||||
|
channel: cfg.channel,
|
||||||
|
releaseDate: cfg.releaseDate,
|
||||||
|
screenshotVersion: cfg.screenshotVersion,
|
||||||
|
'permissions.version': cfg.permissions.version,
|
||||||
|
'permissions.updatedCn': cnDate(cfg.permissions.updated),
|
||||||
|
apkFile,
|
||||||
|
apkSize: mb(apkBytes),
|
||||||
|
};
|
||||||
|
cnDate(cfg.releaseDate); // 只做格式校验
|
||||||
|
|
||||||
|
fs.rmSync(DIST, { recursive: true, force: true });
|
||||||
|
for (const file of walk(SRC)) {
|
||||||
|
const out = path.join(DIST, path.relative(SRC, file));
|
||||||
|
fs.mkdirSync(path.dirname(out), { recursive: true });
|
||||||
|
if (path.extname(file) === '.html') {
|
||||||
|
fs.writeFileSync(out, render(fs.readFileSync(file, 'utf8'), vars, path.relative(ROOT, file)));
|
||||||
|
} else {
|
||||||
|
fs.copyFileSync(file, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs.mkdirSync(path.join(DIST, 'download'), { recursive: true });
|
||||||
|
fs.copyFileSync(apkSrc, path.join(DIST, 'download', apkFile));
|
||||||
|
|
||||||
|
checkRefs(walk(DIST));
|
||||||
|
return { cfg, apkFile, apkBytes, vars };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||||
|
try {
|
||||||
|
const { cfg, apkFile, vars } = build();
|
||||||
|
console.log(`构建完成 → dist/`);
|
||||||
|
console.log(` 版本 v${cfg.version}(${cfg.channel}) · ${apkFile} · ${vars.apkSize} · 更新时间 ${cfg.releaseDate}`);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`构建失败:${e.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
136
scripts/deploy.mjs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// 发布:构建 → 对比线上差异 → 上传 → 备份线上目录 → 切换 → 线上验证
|
||||||
|
// node scripts/deploy.mjs 正式发布
|
||||||
|
// node scripts/deploy.mjs --dry-run 只构建并列出差异,不改服务器
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import os from 'node:os';
|
||||||
|
import path from 'node:path';
|
||||||
|
import crypto from 'node:crypto';
|
||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { build } from './build.mjs';
|
||||||
|
|
||||||
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||||
|
const DIST = path.join(ROOT, 'dist');
|
||||||
|
const dryRun = process.argv.includes('--dry-run');
|
||||||
|
|
||||||
|
function run(cmd, args, opts = {}) {
|
||||||
|
const r = spawnSync(cmd, args, { encoding: 'utf8', maxBuffer: 64 << 20, ...opts });
|
||||||
|
if (r.status !== 0) {
|
||||||
|
throw new Error(`${cmd} ${args.slice(0, 2).join(' ')} 失败(退出码 ${r.status})\n${r.stderr || ''}`);
|
||||||
|
}
|
||||||
|
return r.stdout;
|
||||||
|
}
|
||||||
|
const ssh = (host, script) => run('ssh', ['-o', 'BatchMode=yes', host, 'bash -s'], { input: `set -euo pipefail\n${script}` });
|
||||||
|
|
||||||
|
const sha256 = (file) => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
||||||
|
|
||||||
|
function walk(dir) {
|
||||||
|
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((e) => {
|
||||||
|
const p = path.join(dir, e.name);
|
||||||
|
return e.isDirectory() ? walk(p) : [p];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 北京时间时间戳,用作备份目录名
|
||||||
|
function stamp() {
|
||||||
|
const d = new Date(Date.now() + 8 * 3600e3).toISOString();
|
||||||
|
return d.slice(0, 19).replace(/[-:]/g, '').replace('T', '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const { cfg, apkFile, apkBytes, vars } = build();
|
||||||
|
const { host, siteDir, publicUrl, keepBackups } = cfg.deploy;
|
||||||
|
const live = `${siteDir}/public/app`;
|
||||||
|
const deployDir = `${siteDir}/.deploy`; // 在 public/ 之外,不会被公网访问
|
||||||
|
const ts = stamp();
|
||||||
|
console.log(`构建完成:v${cfg.version}(${cfg.channel}) · ${apkFile} · ${vars.apkSize}`);
|
||||||
|
|
||||||
|
// ---- 对比线上(APK 单独比较,download/ 里的其他旧包不参与) ----
|
||||||
|
const local = new Map(
|
||||||
|
walk(DIST)
|
||||||
|
.filter((f) => !f.startsWith(path.join(DIST, 'download') + path.sep))
|
||||||
|
.map((f) => [path.relative(DIST, f), sha256(f)]),
|
||||||
|
);
|
||||||
|
const remoteOut = ssh(host, `
|
||||||
|
cd ${live}
|
||||||
|
find . -type f ! -path './download/*' -exec sha256sum {} + | sed 's| \\./| |'
|
||||||
|
echo "__APK__ $(sha256sum download/${apkFile} 2>/dev/null | cut -d' ' -f1)"
|
||||||
|
`);
|
||||||
|
const remote = new Map();
|
||||||
|
let remoteApkSha = '';
|
||||||
|
for (const line of remoteOut.trim().split('\n')) {
|
||||||
|
if (line.startsWith('__APK__')) remoteApkSha = line.slice(8).trim();
|
||||||
|
else if (line) {
|
||||||
|
const [sum, file] = line.split(/\s{2}/);
|
||||||
|
remote.set(file, sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const added = [...local.keys()].filter((f) => !remote.has(f));
|
||||||
|
const changed = [...local.keys()].filter((f) => remote.has(f) && remote.get(f) !== local.get(f));
|
||||||
|
const removed = [...remote.keys()].filter((f) => !local.has(f));
|
||||||
|
const localApkSha = sha256(path.join(DIST, 'download', apkFile));
|
||||||
|
const uploadApk = remoteApkSha !== localApkSha;
|
||||||
|
|
||||||
|
console.log('\n与线上的差异:');
|
||||||
|
for (const f of added) console.log(` + ${f}`);
|
||||||
|
for (const f of changed) console.log(` ~ ${f}`);
|
||||||
|
for (const f of removed) console.log(` - ${f}`);
|
||||||
|
console.log(` APK ${apkFile}:${uploadApk ? (remoteApkSha ? '线上不同,需上传' : '线上没有,需上传') : '线上已是同一文件,跳过上传'}`);
|
||||||
|
if (!added.length && !changed.length && !removed.length && !uploadApk) {
|
||||||
|
console.log('\n线上已经是最新,无需发布。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dryRun) {
|
||||||
|
console.log('\n--dry-run:未改动服务器。');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 上传 ----
|
||||||
|
const tgz = path.join(os.tmpdir(), `douba-app-${ts}.tgz`);
|
||||||
|
run('tar', ['czf', tgz, '-C', DIST, '--exclude=./download', '.']);
|
||||||
|
const remoteTgz = `/tmp/douba-app-${ts}.tgz`;
|
||||||
|
const remoteApk = `/tmp/douba-app-${ts}.apk`;
|
||||||
|
console.log('\n上传站点文件…');
|
||||||
|
run('scp', ['-q', '-o', 'BatchMode=yes', tgz, `${host}:${remoteTgz}`]);
|
||||||
|
fs.rmSync(tgz);
|
||||||
|
if (uploadApk) {
|
||||||
|
console.log(`上传 ${apkFile}(${vars.apkSize},需要一会儿)…`);
|
||||||
|
run('scp', ['-q', '-o', 'BatchMode=yes', path.join(DIST, 'download', apkFile), `${host}:${remoteApk}`], { stdio: ['ignore', 'inherit', 'pipe'] });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 服务器端:组装新目录 → 备份旧目录 → 切换 ----
|
||||||
|
// 新目录与线上同在一个分区,两次 mv 都是瞬间完成的重命名
|
||||||
|
console.log('切换线上目录…');
|
||||||
|
ssh(host, `
|
||||||
|
stage=${deployDir}/stage-${ts}
|
||||||
|
mkdir -p "$stage/download" ${deployDir}/backups
|
||||||
|
tar xzf ${remoteTgz} -C "$stage"
|
||||||
|
# 保留线上已有的 APK(硬链接,不占额外空间),旧版下载链接不会失效
|
||||||
|
for f in ${live}/download/*.apk; do [ -e "$f" ] && ln "$f" "$stage/download/"; done
|
||||||
|
${uploadApk ? `mv -f ${remoteApk} "$stage/download/${apkFile}"` : ':'}
|
||||||
|
[ "$(sha256sum "$stage/download/${apkFile}" | cut -d' ' -f1)" = "${localApkSha}" ] || { echo "APK 校验失败" >&2; exit 1; }
|
||||||
|
chown -R root:root "$stage"
|
||||||
|
find "$stage" -type d -exec chmod 755 {} +
|
||||||
|
find "$stage" -type f -exec chmod 644 {} +
|
||||||
|
mv ${live} ${deployDir}/backups/app-${ts}
|
||||||
|
mv "$stage" ${live}
|
||||||
|
rm -f ${remoteTgz}
|
||||||
|
ls -1d ${deployDir}/backups/app-* | sort -r | tail -n +${keepBackups + 1} | xargs -r rm -rf
|
||||||
|
`);
|
||||||
|
|
||||||
|
// ---- 线上验证 ----
|
||||||
|
console.log('验证线上…');
|
||||||
|
const page = run('curl', ['-fsS', '-H', 'Cache-Control: no-cache', publicUrl]);
|
||||||
|
if (!page.includes(`"softwareVersion": "${cfg.version}"`)) throw new Error(`${publicUrl} 返回的页面不是 v${cfg.version}`);
|
||||||
|
const head = run('curl', ['-fsSI', `${publicUrl}/download/${apkFile}`]);
|
||||||
|
const len = Number((/content-length:\s*(\d+)/i.exec(head) || [])[1]);
|
||||||
|
if (len !== apkBytes) throw new Error(`APK 下载地址返回的大小 ${len} 与本地 ${apkBytes} 不一致`);
|
||||||
|
|
||||||
|
console.log(`\n发布成功:${publicUrl} (v${cfg.version},备份 ${deployDir}/backups/app-${ts})`);
|
||||||
|
console.log('如需回滚:npm run rollback');
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((e) => {
|
||||||
|
console.error(`\n发布失败:${e.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
28
scripts/preview.mjs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// 本地预览 dist/:按线上路径挂在 /app 下(/app 和 /app/ 都返回首页)
|
||||||
|
import http from 'node:http';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const DIST = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'dist');
|
||||||
|
const PORT = Number(process.env.PORT) || 8080;
|
||||||
|
const TYPES = {
|
||||||
|
'.html': 'text/html; charset=utf-8', '.css': 'text/css; charset=utf-8', '.js': 'text/javascript; charset=utf-8',
|
||||||
|
'.svg': 'image/svg+xml', '.webp': 'image/webp', '.png': 'image/png', '.jpg': 'image/jpeg',
|
||||||
|
'.apk': 'application/vnd.android.package-archive',
|
||||||
|
};
|
||||||
|
|
||||||
|
http.createServer((req, res) => {
|
||||||
|
const url = decodeURIComponent(req.url.split('?')[0]);
|
||||||
|
if (url === '/') { res.writeHead(302, { Location: '/app' }); return res.end(); }
|
||||||
|
if (url !== '/app' && !url.startsWith('/app/')) {
|
||||||
|
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
||||||
|
return res.end(`本地预览只包含 /app,${url} 属于线上商城`);
|
||||||
|
}
|
||||||
|
let file = path.join(DIST, url.slice(4));
|
||||||
|
if (!file.startsWith(DIST)) { res.writeHead(403); return res.end(); }
|
||||||
|
if (fs.existsSync(file) && fs.statSync(file).isDirectory()) file = path.join(file, 'index.html');
|
||||||
|
if (!fs.existsSync(file)) { res.writeHead(404); return res.end('Not Found'); }
|
||||||
|
res.writeHead(200, { 'Content-Type': TYPES[path.extname(file)] || 'application/octet-stream' });
|
||||||
|
fs.createReadStream(file).pipe(res);
|
||||||
|
}).listen(PORT, () => console.log(`本地预览:http://localhost:${PORT}/app`));
|
||||||
27
scripts/rollback.mjs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// 回滚:把线上目录换回最近一次发布前的备份
|
||||||
|
// node scripts/rollback.mjs 回滚到最近的备份
|
||||||
|
// node scripts/rollback.mjs --list 列出可用备份
|
||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
import { loadConfig } from './build.mjs';
|
||||||
|
|
||||||
|
const { host, siteDir, publicUrl } = loadConfig().deploy;
|
||||||
|
const live = `${siteDir}/public/app`;
|
||||||
|
const backups = `${siteDir}/.deploy/backups`;
|
||||||
|
const list = process.argv.includes('--list');
|
||||||
|
|
||||||
|
const script = list
|
||||||
|
? `ls -1d ${backups}/app-* 2>/dev/null | sort -r || echo "(没有备份)"`
|
||||||
|
: `
|
||||||
|
latest=$(ls -1d ${backups}/app-* 2>/dev/null | sort -r | head -1)
|
||||||
|
[ -n "$latest" ] || { echo "没有可回滚的备份" >&2; exit 1; }
|
||||||
|
mv ${live} ${siteDir}/.deploy/rolled-back-$(date +%Y%m%d-%H%M%S)
|
||||||
|
mv "$latest" ${live}
|
||||||
|
echo "已回滚到 $latest"
|
||||||
|
`;
|
||||||
|
|
||||||
|
const r = spawnSync('ssh', ['-o', 'BatchMode=yes', host, 'bash -s'], {
|
||||||
|
input: `set -euo pipefail\n${script}`,
|
||||||
|
stdio: ['pipe', 'inherit', 'inherit'],
|
||||||
|
});
|
||||||
|
if (r.status !== 0) process.exit(r.status ?? 1);
|
||||||
|
if (!list) console.log(`请打开 ${publicUrl} 确认。`);
|
||||||
16
site.config.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"version": "0.3.8",
|
||||||
|
"channel": "内测",
|
||||||
|
"releaseDate": "2026-10-29",
|
||||||
|
"screenshotVersion": "0.3.8",
|
||||||
|
"permissions": {
|
||||||
|
"version": "0.3.8",
|
||||||
|
"updated": "2026-10-29"
|
||||||
|
},
|
||||||
|
"deploy": {
|
||||||
|
"host": "root@8.130.191.152",
|
||||||
|
"siteDir": "/www/wwwroot/shop.douba.top",
|
||||||
|
"publicUrl": "https://shop.douba.top/app",
|
||||||
|
"keepBackups": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/assets/brand.webp
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/favicon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/og.jpg
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
src/assets/p1.webp
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
src/assets/p2.webp
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
src/assets/p3.webp
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
src/assets/p4.webp
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
src/assets/p5.webp
Normal file
|
After Width: | Height: | Size: 22 KiB |
1
src/assets/qr.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" width="320" height="320" viewBox="0 0 29 29" shape-rendering="crispEdges"><path fill="#ffffff" d="M0 0h29v29H0z"/><path stroke="#000000" d="M2 2.5h7m1 0h1m2 0h6m1 0h7M2 3.5h1m5 0h1m5 0h3m3 0h1m5 0h1M2 4.5h1m1 0h3m1 0h1m2 0h3m2 0h1m1 0h1m1 0h1m1 0h3m1 0h1M2 5.5h1m1 0h3m1 0h1m1 0h3m1 0h2m1 0h2m1 0h1m1 0h3m1 0h1M2 6.5h1m1 0h3m1 0h1m1 0h3m3 0h3m1 0h1m1 0h3m1 0h1M2 7.5h1m5 0h1m1 0h1m3 0h1m3 0h1m1 0h1m5 0h1M2 8.5h7m1 0h1m1 0h1m1 0h1m1 0h1m1 0h1m1 0h7M10 9.5h2m2 0h1m2 0h1M2 10.5h1m3 0h1m1 0h4m1 0h1m4 0h6m2 0h1M5 11.5h2m2 0h1m2 0h1m1 0h2m1 0h2m3 0h2m1 0h1M3 12.5h2m1 0h5m1 0h1m3 0h2m1 0h6M2 13.5h2m1 0h1m3 0h1m2 0h2m5 0h1m4 0h2M2 14.5h2m1 0h1m1 0h2m1 0h1m1 0h1m1 0h1m2 0h1m1 0h2m2 0h4M2 15.5h2m1 0h1m5 0h2m1 0h1m1 0h3m3 0h1m2 0h1M4 16.5h1m1 0h1m1 0h1m1 0h1m2 0h1m1 0h4m1 0h5M4 17.5h2m1 0h1m1 0h1m2 0h2m2 0h2m2 0h3m1 0h2M2 18.5h8m8 0h7M10 19.5h2m1 0h1m1 0h1m2 0h1m3 0h1M2 20.5h7m1 0h4m4 0h1m1 0h1m1 0h1M2 21.5h1m5 0h1m2 0h3m4 0h1m3 0h5M2 22.5h1m1 0h3m1 0h1m1 0h1m5 0h1m1 0h7M2 23.5h1m1 0h3m1 0h1m2 0h1m1 0h1m2 0h1m1 0h4m2 0h3M2 24.5h1m1 0h3m1 0h1m3 0h5m3 0h1m2 0h1m1 0h1M2 25.5h1m5 0h1m3 0h2m2 0h2m1 0h1m1 0h5M2 26.5h7m1 0h1m3 0h1m5 0h1m3 0h3"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src/assets/shot-mall-1.webp
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
src/assets/shot-mall-2.webp
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
src/assets/shot-mall-3.webp
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
src/assets/shot-mama-1.webp
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
src/assets/shot-mama-2.webp
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
src/assets/shot-mama-3.webp
Normal file
|
After Width: | Height: | Size: 57 KiB |
466
src/index.html
Normal file
@@ -0,0 +1,466 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
|
<title>兜爸心选 · 孕婴童好物一站购齐|官方应用官网</title>
|
||||||
|
<meta name="description" content="兜爸心选是一款专注孕婴童的购物 App。用父爱的严谨与担当,为宝妈和宝宝甄选全球优质好物。立即下载 Android 版,孕婴童好物一站购齐。">
|
||||||
|
<meta name="theme-color" content="#FBF5EC">
|
||||||
|
<link rel="canonical" href="https://shop.douba.top/app/">
|
||||||
|
<link rel="icon" type="image/png" href="/app/assets/favicon.png">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:site_name" content="兜爸心选">
|
||||||
|
<meta property="og:title" content="兜爸心选 · 孕婴童好物一站购齐">
|
||||||
|
<meta property="og:description" content="用父爱的严谨与担当,为宝妈和宝宝甄选全球优质好物。用心守护爱的每一步。">
|
||||||
|
<meta property="og:url" content="https://shop.douba.top/app/">
|
||||||
|
<meta property="og:image" content="https://shop.douba.top/app/assets/og.jpg">
|
||||||
|
<link rel="stylesheet" href="/app/styles.css">
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "SoftwareApplication",
|
||||||
|
"name": "兜爸心选",
|
||||||
|
"url": "https://shop.douba.top/app/",
|
||||||
|
"applicationCategory": "ShoppingApplication",
|
||||||
|
"operatingSystem": "Android 5.0+",
|
||||||
|
"softwareVersion": "{{version}}",
|
||||||
|
"inLanguage": "zh-CN",
|
||||||
|
"description": "兜爸心选—孕婴童好物一站购齐。用父爱的严谨与担当为宝妈和宝宝甄选全球优质好物。用心守护爱的每一步。",
|
||||||
|
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "CNY" },
|
||||||
|
"publisher": { "@type": "Organization", "name": "北京臻惠网络科技有限公司" }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="top">
|
||||||
|
<a class="skip" href="#main">跳到主要内容</a>
|
||||||
|
|
||||||
|
<header class="nav" id="nav">
|
||||||
|
<div class="nav-inner">
|
||||||
|
<a class="brand" href="#top" aria-label="兜爸心选 首页">
|
||||||
|
<img src="/app/assets/brand.webp" alt="兜爸心选" width="150" height="111">
|
||||||
|
</a>
|
||||||
|
<nav class="nav-links" aria-label="主导航">
|
||||||
|
<a href="#about">品牌理念</a>
|
||||||
|
<a href="#features">应用功能</a>
|
||||||
|
<a href="#screens">应用截图</a>
|
||||||
|
<a href="#faq">常见问题</a>
|
||||||
|
</nav>
|
||||||
|
<a class="btn btn--red btn--sm" href="#download">下载 App</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main id="main">
|
||||||
|
|
||||||
|
<!-- ============ HERO ============ -->
|
||||||
|
<section class="hero">
|
||||||
|
<div class="hero-bg" aria-hidden="true">
|
||||||
|
<span class="blob"></span>
|
||||||
|
<span class="grid"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrap hero-inner">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<p class="eyebrow"><span class="eyebrow-dot"></span>官方应用官网 · 孕婴童全品类</p>
|
||||||
|
<h1 class="hero-title">兜爸心选</h1>
|
||||||
|
<p class="hero-lede">孕婴童好物,<br><span class="hl">一站购齐。</span></p>
|
||||||
|
<p class="hero-desc">用父爱的严谨与担当,为宝妈和宝宝甄选全球优质好物。<br class="pc">用心守护爱的每一步。</p>
|
||||||
|
|
||||||
|
<div class="cta-row">
|
||||||
|
<a class="btn btn--red btn--lg" href="#download">
|
||||||
|
<svg viewBox="0 0 24 24" aria-hidden="true" class="ico"><path d="M12 3v11m0 0 4.2-4.2M12 14 7.8 9.8M5 19.5h14" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
|
下载 Android 版
|
||||||
|
</a>
|
||||||
|
<a class="btn btn--ghost btn--lg" href="#features">看看 App 能做什么</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="hero-meta">
|
||||||
|
<li>版本 v{{version}}({{channel}})</li>
|
||||||
|
<li>安装包 {{apkSize}}</li>
|
||||||
|
<li>Android 5.0 及以上</li>
|
||||||
|
<li>iOS 版即将上架</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero-art">
|
||||||
|
<div class="stamp" aria-hidden="true">
|
||||||
|
<span class="stamp-top">兜爸严选</span>
|
||||||
|
<span class="stamp-line"></span>
|
||||||
|
<span class="stamp-bottom">亲自试用</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="phone phone--hero" data-reveal><div class="phone-screen hero-slides" id="heroSlides" aria-label="应用界面自动轮播">
|
||||||
|
<img class="hs-slide is-on" src="/app/assets/shot-mama-1.webp" alt="孕育首页:孕周倒计时与数胎动、体重记录" width="600" height="1301" decoding="async">
|
||||||
|
<img class="hs-slide" src="/app/assets/shot-mama-2.webp" alt="今日孕期小知识" width="600" height="1301" loading="lazy" decoding="async">
|
||||||
|
<img class="hs-slide" src="/app/assets/shot-mama-3.webp" alt="今日脚印与兜豆兑换" width="600" height="1301" loading="lazy" decoding="async">
|
||||||
|
<img class="hs-slide" src="/app/assets/shot-mall-1.webp" alt="商城首页:今日推荐与分类入口" width="600" height="1360" loading="lazy" decoding="async">
|
||||||
|
<img class="hs-slide" src="/app/assets/shot-mall-2.webp" alt="商品分类" width="600" height="1360" loading="lazy" decoding="async">
|
||||||
|
<img class="hs-slide" src="/app/assets/shot-mall-3.webp" alt="商品详情" width="600" height="1360" loading="lazy" decoding="async">
|
||||||
|
</div></div>
|
||||||
|
|
||||||
|
<p class="hand-note">每一件,都先给<br>自家孩子用。</p>
|
||||||
|
<svg class="hand-arrow" viewBox="0 0 120 70" aria-hidden="true">
|
||||||
|
<path d="M6 8c22 30 46 44 78 48" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-dasharray="4 6"/>
|
||||||
|
<path d="M76 50l12 8-13 6" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ============ 三条承诺 ============ -->
|
||||||
|
<section class="promises" aria-label="兜爸心选的三个坚持">
|
||||||
|
<div class="wrap promises-grid">
|
||||||
|
<article class="promise" data-reveal>
|
||||||
|
<span class="p-num">01</span>
|
||||||
|
<h3>全球甄选</h3>
|
||||||
|
<p>正规渠道、品牌直供,从源头开始把第一道关。</p>
|
||||||
|
</article>
|
||||||
|
<article class="promise" data-reveal>
|
||||||
|
<span class="p-num">02</span>
|
||||||
|
<h3>严苛比对</h3>
|
||||||
|
<p>成分表、检测报告、真实口碑,逐项比对过才上架。</p>
|
||||||
|
</article>
|
||||||
|
<article class="promise" data-reveal>
|
||||||
|
<span class="p-num">03</span>
|
||||||
|
<h3>爸爸把关</h3>
|
||||||
|
<p>先给自家孩子用;不好用的东西,我们不卖。</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ============ 品牌理念 ============ -->
|
||||||
|
<section class="about" id="about">
|
||||||
|
<div class="wrap about-inner">
|
||||||
|
<div class="about-head">
|
||||||
|
<p class="kicker">01 / 品牌理念</p>
|
||||||
|
<h2 class="h2">一个爸爸的<br>购物清单</h2>
|
||||||
|
<p class="about-sub">挑宝宝的东西,标准只有一条:<br>敢不敢给自己的孩子用。</p>
|
||||||
|
<ul class="checks">
|
||||||
|
<li><span>一看</span>成分与配方,说不清楚的不上</li>
|
||||||
|
<li><span>二看</span>检测报告与资质,缺一项不上</li>
|
||||||
|
<li><span>三看</span>真实评价与售后,口碑不好不上</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="note" data-reveal>
|
||||||
|
<span class="tape tape--l" aria-hidden="true"></span>
|
||||||
|
<span class="tape tape--r" aria-hidden="true"></span>
|
||||||
|
<p class="note-label">选品笔记 · NO.001</p>
|
||||||
|
<div class="note-body">
|
||||||
|
<p>兜爸心选是一款专注孕婴童的购物 App。从孕期营养、纸尿裤、洗护用品,到辅食、玩具、绘本与出行装备——一家人从孕期到学龄前的日常所需,都能在一个 App 里买齐。</p>
|
||||||
|
<p>我们把选品当成给自家孩子挑东西:先看原料与配方,再看检测报告与真实评价,最后才谈价格。渠道不清楚的不上,成分说不明白的不上,自己用着不顺手的不上。</p>
|
||||||
|
<p>我们不追求把货架堆满,只把值得放进宝宝生活里的东西留下来。</p>
|
||||||
|
</div>
|
||||||
|
<p class="sign">—— 兜爸</p>
|
||||||
|
<svg class="note-star" viewBox="0 0 40 40" aria-hidden="true"><path d="M20 3l4 9 9 4-9 4-4 9-4-9-9-4 9-4z" fill="none" stroke="currentColor" stroke-width="1.4"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ============ 应用功能 ============ -->
|
||||||
|
<section class="features" id="features">
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="sec-head">
|
||||||
|
<p class="kicker">02 / 应用功能</p>
|
||||||
|
<h2 class="h2">打开它,<br>孕婴童的日常就够了</h2>
|
||||||
|
<p class="sec-sub">买东西、查物流、找工具,都在同一个地方。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="feature-grid">
|
||||||
|
<article class="feature" data-reveal>
|
||||||
|
<span class="f-num">01</span>
|
||||||
|
<span class="f-ico">
|
||||||
|
<svg viewBox="0 0 48 48" aria-hidden="true"><path d="M9 15h30l-3 22H12z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><path d="M18 15V11a6 6 0 0 1 12 0v4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M20 26c1.6 2 6.4 2 8 0" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||||
|
</span>
|
||||||
|
<h3>好物一站购齐</h3>
|
||||||
|
<p>奶粉、纸尿裤、洗护、辅食、玩具、绘本……按孕周和月龄挑,不用在几个 App 之间来回比价。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="feature" data-reveal>
|
||||||
|
<span class="f-num">02</span>
|
||||||
|
<span class="f-ico">
|
||||||
|
<svg viewBox="0 0 48 48" aria-hidden="true"><rect x="8" y="10" width="32" height="30" rx="4" fill="none" stroke="currentColor" stroke-width="2"/><path d="M16 6v8M32 6v8M8 20h32" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M17 28h5M26 28h5M17 34h5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||||
|
</span>
|
||||||
|
<h3>孕育工具随手用</h3>
|
||||||
|
<p>孕周计算、产检提醒、数胎动等孕育小工具,在 App 里一键直达,不用再到处收藏链接。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="feature" data-reveal>
|
||||||
|
<span class="f-num">03</span>
|
||||||
|
<span class="f-ico">
|
||||||
|
<svg viewBox="0 0 48 48" aria-hidden="true"><path d="M7 17h20v14H7z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><path d="M27 22h7l7 6v3h-14z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><circle cx="14" cy="35" r="3" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="33" cy="35" r="3" fill="none" stroke="currentColor" stroke-width="2"/></svg>
|
||||||
|
</span>
|
||||||
|
<h3>订单物流看得见</h3>
|
||||||
|
<p>下单、发货、派送、签收,每一步都能查到;退换货进度,也在同一页里。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="feature" data-reveal>
|
||||||
|
<span class="f-num">04</span>
|
||||||
|
<span class="f-ico">
|
||||||
|
<svg viewBox="0 0 48 48" aria-hidden="true"><path d="M10 11h28v20H24l-8 7v-7h-6z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><path d="M17 19h14M17 24h9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||||
|
</span>
|
||||||
|
<h3>专属客服找得到</h3>
|
||||||
|
<p>关于商品、尺码、喂养、退换的任何问题,都有人耐心回答,不是机器人绕圈。</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ============ 应用截图 ============ -->
|
||||||
|
<section class="screens" id="screens">
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="sec-head sec-head--row">
|
||||||
|
<div>
|
||||||
|
<p class="kicker">03 / 应用截图</p>
|
||||||
|
<h2 class="h2">界面一览</h2>
|
||||||
|
</div>
|
||||||
|
<p class="sec-note">截图取自 Android 版 v{{screenshotVersion}}<br>实际界面以应用内为准</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="shots-hint">左右滑动,查看更多截图 →</p>
|
||||||
|
<div class="shots">
|
||||||
|
<figure class="shot" data-reveal>
|
||||||
|
<div class="phone phone--shot">
|
||||||
|
<div class="phone-screen"><img class="shot-img" src="/app/assets/shot-mama-1.webp" alt="兜爸心选 App 孕育首页:孕周倒计时与孕育工具" width="600" height="1301" loading="lazy" decoding="async"></div>
|
||||||
|
</div>
|
||||||
|
<figcaption><b>孕育首页</b> 孕 29 周倒计时、数胎动与体重,一屏看全</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<figure class="shot" data-reveal>
|
||||||
|
<div class="phone phone--shot">
|
||||||
|
<div class="phone-screen"><img class="shot-img" src="/app/assets/shot-mama-2.webp" alt="兜爸心选 App 今日孕期小知识" width="600" height="1301" loading="lazy" decoding="async"></div>
|
||||||
|
</div>
|
||||||
|
<figcaption><b>孕期知识</b> 本周话题与今日小知识,按孕周推送</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<figure class="shot" data-reveal>
|
||||||
|
<div class="phone phone--shot">
|
||||||
|
<div class="phone-screen"><img class="shot-img" src="/app/assets/shot-mama-3.webp" alt="兜爸心选 App 今日脚印与兜豆兑换" width="600" height="1301" loading="lazy" decoding="async"></div>
|
||||||
|
</div>
|
||||||
|
<figcaption><b>今日脚印</b> 一天的记录收成一条时间轴,兜豆还能换实物</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<figure class="shot" data-reveal>
|
||||||
|
<div class="phone phone--shot">
|
||||||
|
<div class="phone-screen">
|
||||||
|
<div class="statusbar"><span>9:41</span><span class="sb-right"><i class="sig"></i><i class="wifi"></i><i class="batt"></i></span></div>
|
||||||
|
<div class="app-top">
|
||||||
|
<img class="mini-logo" src="/app/assets/brand.webp" alt="">
|
||||||
|
<div class="search"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="6.5"/><path d="m16 16 4 4"/></svg><span>搜「纸尿裤」</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="promo">
|
||||||
|
<p class="promo-k">孕婴童好物节</p>
|
||||||
|
<p class="promo-t">从孕期到学龄前<br>一个 App 买齐</p>
|
||||||
|
<span class="promo-tag">0–3 岁 · 全品类</span>
|
||||||
|
</div>
|
||||||
|
<div class="chips"><span class="chip chip--on">奶粉</span><span class="chip">纸尿裤</span><span class="chip">洗护</span><span class="chip">玩具</span></div>
|
||||||
|
<div class="sect-head"><b>兜爸今日推荐</b><span>换一批</span></div>
|
||||||
|
<div class="pgrid pgrid--2">
|
||||||
|
<div class="pcard">
|
||||||
|
<div class="pimg"><img src="/app/assets/p1.webp" alt=""></div>
|
||||||
|
<p class="pname">大王光之羽 环贴式纸尿裤</p>
|
||||||
|
<p class="pprice"><em>¥220</em><s>¥338</s></p>
|
||||||
|
</div>
|
||||||
|
<div class="pcard">
|
||||||
|
<div class="pimg"><img src="/app/assets/p2.webp" alt=""></div>
|
||||||
|
<p class="pname">海龟爸爸 婴童物理防晒乳</p>
|
||||||
|
<p class="pprice"><em>¥99</em><s>¥129</s></p>
|
||||||
|
</div>
|
||||||
|
<div class="pcard">
|
||||||
|
<div class="pimg"><img src="/app/assets/p3.webp" alt=""></div>
|
||||||
|
<p class="pname">纽强 婴幼儿保湿面霜</p>
|
||||||
|
<p class="pprice"><em>¥198</em></p>
|
||||||
|
</div>
|
||||||
|
<div class="pcard">
|
||||||
|
<div class="pimg"><img src="/app/assets/p5.webp" alt=""></div>
|
||||||
|
<p class="pname">贝肽斯 宝宝防晒遮阳帽</p>
|
||||||
|
<p class="pprice"><em>¥35.9</em></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tabbar">
|
||||||
|
<span class="tab tab--on"><svg viewBox="0 0 24 24"><path d="M4 11 12 4l8 7v8.5H4z"/></svg>首页</span>
|
||||||
|
<span class="tab"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="7" height="7"/><rect x="13" y="4" width="7" height="7"/><rect x="4" y="13" width="7" height="7"/><rect x="13" y="13" width="7" height="7"/></svg>分类</span>
|
||||||
|
<span class="tab"><svg viewBox="0 0 24 24"><path d="M4 5h2l2.5 10h9L20 8H7"/><circle cx="9" cy="19" r="1.4"/><circle cx="17" cy="19" r="1.4"/></svg>购物车</span>
|
||||||
|
<span class="tab"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="3.6"/><path d="M5 20c0-3.6 3.1-5.6 7-5.6s7 2 7 5.6"/></svg>我的</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<figcaption><b>商城首页</b> 今日推荐与分类入口,想买的都在第一屏</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<figure class="shot" data-reveal>
|
||||||
|
<div class="phone phone--shot">
|
||||||
|
<div class="phone-screen">
|
||||||
|
<div class="statusbar"><span>9:41</span><span class="sb-right"><i class="sig"></i><i class="wifi"></i><i class="batt"></i></span></div>
|
||||||
|
<div class="subpage-head"><svg class="back" viewBox="0 0 24 24"><path d="m14 6-6 6 6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg><b>全部分类</b><span></span></div>
|
||||||
|
<div class="cat">
|
||||||
|
<ul class="cat-rail">
|
||||||
|
<li class="on">奶粉</li><li>纸尿裤</li><li>洗护</li><li>辅食</li><li>玩具</li><li>绘本</li><li>出行</li><li>妈妈</li>
|
||||||
|
</ul>
|
||||||
|
<div class="cat-list">
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p1.webp" alt=""></div><div class="rt"><p>大王光之羽 环贴式纸尿裤</p><p class="rtag">品牌直供</p><em>¥220</em></div></div>
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p3.webp" alt=""></div><div class="rt"><p>纽强 婴幼儿保湿面霜</p><p class="rtag">敏感肌可用</p><em>¥198</em></div></div>
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p5.webp" alt=""></div><div class="rt"><p>贝肽斯 宝宝防晒遮阳帽</p><p class="rtag">夏季上新</p><em>¥35.9</em></div></div>
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p2.webp" alt=""></div><div class="rt"><p>海龟爸爸 婴童物理防晒乳</p><p class="rtag">纯物理配方</p><em>¥99</em></div></div>
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p4.webp" alt=""></div><div class="rt"><p>沃隆 每日坚果妈妈款</p><p class="rtag">孕期零食</p><em>¥118</em></div></div>
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p1.webp" alt=""></div><div class="rt"><p>大王 短裤式成长裤</p><p class="rtag">学步期</p><em>¥228</em></div></div>
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p3.webp" alt=""></div><div class="rt"><p>纽强 婴儿身体乳</p><p class="rtag">秋冬保湿</p><em>¥168</em></div></div>
|
||||||
|
<div class="row"><div class="rimg"><img src="/app/assets/p2.webp" alt=""></div><div class="rt"><p>海龟爸爸 防晒喷雾</p><p class="rtag">户外补涂</p><em>¥89</em></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tabbar">
|
||||||
|
<span class="tab"><svg viewBox="0 0 24 24"><path d="M4 11 12 4l8 7v8.5H4z"/></svg>首页</span>
|
||||||
|
<span class="tab tab--on"><svg viewBox="0 0 24 24"><rect x="4" y="4" width="7" height="7"/><rect x="13" y="4" width="7" height="7"/><rect x="4" y="13" width="7" height="7"/><rect x="13" y="13" width="7" height="7"/></svg>分类</span>
|
||||||
|
<span class="tab"><svg viewBox="0 0 24 24"><path d="M4 5h2l2.5 10h9L20 8H7"/><circle cx="9" cy="19" r="1.4"/><circle cx="17" cy="19" r="1.4"/></svg>购物车</span>
|
||||||
|
<span class="tab"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="3.6"/><path d="M5 20c0-3.6 3.1-5.6 7-5.6s7 2 7 5.6"/></svg>我的</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<figcaption><b>分类</b> 按品类、孕周与月龄,筛到合适的那款</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<figure class="shot" data-reveal>
|
||||||
|
<div class="phone phone--shot">
|
||||||
|
<div class="phone-screen">
|
||||||
|
<div class="statusbar"><span>9:41</span><span class="sb-right"><i class="sig"></i><i class="wifi"></i><i class="batt"></i></span></div>
|
||||||
|
<div class="subpage-head"><svg class="back" viewBox="0 0 24 24"><path d="m14 6-6 6 6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg><b>商品详情</b><span class="share">···</span></div>
|
||||||
|
<div class="dimg"><img src="/app/assets/p1.webp" alt=""></div>
|
||||||
|
<div class="dbox">
|
||||||
|
<p class="dprice"><em>¥220</em><s>¥338</s><span>已售 2352</span></p>
|
||||||
|
<p class="dname">大王光之羽系列 干爽超薄柔透双护 环贴式纸尿裤</p>
|
||||||
|
<div class="dtags"><span>品牌直供</span><span>正品保障</span><span>7 天无理由</span></div>
|
||||||
|
<div class="dline"><span>尺码</span><b>S / M / L / XL</b></div>
|
||||||
|
<div class="dline"><span>发货</span><b>48 小时内 · 顺丰</b></div>
|
||||||
|
<div class="dnote"><span class="dnote-k">兜爸说</span>夏天用很省心:薄、透气,夜里也不容易闷。</div>
|
||||||
|
</div>
|
||||||
|
<div class="dbuy">
|
||||||
|
<span class="dico"><svg viewBox="0 0 24 24"><path d="M4 5h16v11H9l-5 4z" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>客服</span>
|
||||||
|
<span class="dico"><svg viewBox="0 0 24 24"><path d="M12 20s-7-4.4-7-9a4 4 0 0 1 7-2.3A4 4 0 0 1 19 11c0 4.6-7 9-7 9z" fill="none" stroke="currentColor" stroke-width="2"/></svg>收藏</span>
|
||||||
|
<span class="dbtn">加入购物车</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<figcaption><b>商品详情</b> 成分、尺码、发货与爸爸的试用笔记</figcaption>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ============ 下载 ============ -->
|
||||||
|
<section class="download" id="download">
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="dl-card" data-reveal>
|
||||||
|
<span class="dl-star dl-star--1" aria-hidden="true">✦</span>
|
||||||
|
<span class="dl-star dl-star--2" aria-hidden="true">✧</span>
|
||||||
|
<div class="dl-left">
|
||||||
|
<p class="kicker kicker--light">04 / 下载安装</p>
|
||||||
|
<h2 class="dl-title">把严选,<br>装进口袋</h2>
|
||||||
|
<p class="dl-desc">支持 Android 手机。下载后按提示允许「安装未知来源应用」即可完成安装,安装包不含任何捆绑。</p>
|
||||||
|
|
||||||
|
<div class="dl-actions">
|
||||||
|
<a class="btn btn--cream btn--lg" href="/app/download/{{apkFile}}" download>
|
||||||
|
<svg viewBox="0 0 24 24" aria-hidden="true" class="ico"><path d="M12 3v11m0 0 4.2-4.2M12 14 7.8 9.8M5 19.5h14" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
|
下载 Android 版 <span class="btn-note">{{apkSize}} · {{channel}}版</span>
|
||||||
|
</a>
|
||||||
|
<span class="btn btn--outline btn--lg is-disabled" aria-disabled="true">iOS 版即将上架</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="dl-tip"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 7.5v6M12 16.4v.2" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>微信内打开时,请点右上角「···」→「在浏览器打开」再下载。</p>
|
||||||
|
|
||||||
|
<dl class="dl-meta">
|
||||||
|
<div><dt>当前版本</dt><dd>v{{version}}({{channel}})</dd></div>
|
||||||
|
<div><dt>更新时间</dt><dd>{{releaseDate}}</dd></div>
|
||||||
|
<div><dt>系统要求</dt><dd>Android 5.0+</dd></div>
|
||||||
|
<div><dt>安装包大小</dt><dd>{{apkSize}}</dd></div>
|
||||||
|
<div><dt>应用类别</dt><dd>购物</dd></div>
|
||||||
|
<div><dt>应用包名</dt><dd>com.yizhezhe.douba</dd></div>
|
||||||
|
<div><dt>语言</dt><dd>简体中文</dd></div>
|
||||||
|
<div><dt>开发者</dt><dd>北京臻惠网络科技有限公司</dd></div>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<p class="dl-legal">下载安装即表示你已阅读并同意 <a href="/app/terms.html">《用户协议》</a> 与 <a href="/protocol.html">《隐私政策》</a>。我们仅收集提供服务所必需的信息。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dl-right">
|
||||||
|
<div class="qr-card">
|
||||||
|
<img class="qr" src="/app/assets/qr.svg" alt="扫码打开兜爸心选官网" width="176" height="176">
|
||||||
|
<p class="qr-t">扫码在手机上打开</p>
|
||||||
|
<p class="qr-url">shop.douba.top/app</p>
|
||||||
|
</div>
|
||||||
|
<p class="qr-hint">电脑访问时,扫码可把下载页发到手机</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ============ FAQ ============ -->
|
||||||
|
<section class="faq" id="faq">
|
||||||
|
<div class="wrap faq-inner">
|
||||||
|
<div class="faq-head">
|
||||||
|
<p class="kicker">05 / 常见问题</p>
|
||||||
|
<h2 class="h2">下载之前,<br>你可能想知道</h2>
|
||||||
|
<p class="faq-contact">还有别的疑问?<br>请在 App 内「我的 → 联系客服」找我们<br>工作日 9:00–18:00</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="faq-list">
|
||||||
|
<details class="qa" open>
|
||||||
|
<summary>怎么下载安装兜爸心选?<i></i></summary>
|
||||||
|
<div class="qa-body"><p>当前提供的是 Android {{channel}}版(v{{version}})。点击页面上的「下载 Android 版」按钮,下载完成后在通知栏或文件管理里点击安装包;若手机提示「禁止安装未知来源应用」,在系统设置里允许浏览器或文件管理器安装应用即可。正式版上架后会在本页同步更新。</p></div>
|
||||||
|
</details>
|
||||||
|
<details class="qa">
|
||||||
|
<summary>iPhone 可以用吗?<i></i></summary>
|
||||||
|
<div class="qa-body"><p>iOS 版本正在准备上架 App Store,上架后会在本页更新下载入口。目前 iPhone 用户可以先用微信小程序「兜爸心选」购物,体验与 App 一致。</p></div>
|
||||||
|
</details>
|
||||||
|
<details class="qa">
|
||||||
|
<summary>App 里卖的东西是正品吗?<i></i></summary>
|
||||||
|
<div class="qa-body"><p>我们只与品牌方或品牌授权渠道合作,商品页会标注货源与保障说明。收到货后如有疑问,可在 App 内联系客服,支持 7 天无理由退换(生鲜及特殊商品除外)。</p></div>
|
||||||
|
</details>
|
||||||
|
<details class="qa">
|
||||||
|
<summary>App 会收集哪些个人信息?<i></i></summary>
|
||||||
|
<div class="qa-body"><p>为完成下单与配送,我们会收集必要的账号、收货与支付信息;具体范围、用途与第三方 SDK 清单,请见<a href="/protocol.html">《隐私政策》</a>与<a href="/app/permissions.html">《权限说明》</a>。未经同意,我们不会向他人提供你的个人信息。</p></div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="wrap footer-top">
|
||||||
|
<div class="foot-brand">
|
||||||
|
<p class="foot-logo">兜爸心选</p>
|
||||||
|
<p class="foot-slogan">孕婴童好物,一站购齐。<br>用心守护爱的每一步。</p>
|
||||||
|
</div>
|
||||||
|
<nav class="foot-cols" aria-label="页脚导航">
|
||||||
|
<div>
|
||||||
|
<h4>产品</h4>
|
||||||
|
<a href="#features">应用功能</a>
|
||||||
|
<a href="#screens">应用截图</a>
|
||||||
|
<a href="#download">下载安装</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>支持</h4>
|
||||||
|
<a href="#faq">常见问题</a>
|
||||||
|
<a href="/protocol.html">隐私政策</a>
|
||||||
|
<a href="/app/terms.html">用户协议</a>
|
||||||
|
<a href="/app/permissions.html">权限说明</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4>联系我们</h4>
|
||||||
|
<span class="foot-plain">App 内:我的 → 联系客服</span>
|
||||||
|
<span class="foot-plain">工作日 9:00–18:00</span>
|
||||||
|
<a href="/protocol.html">隐私政策与联系方式</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrap foot-legal">
|
||||||
|
<p>
|
||||||
|
北京臻惠网络科技有限公司 ·
|
||||||
|
<a class="foot-icp" href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">京ICP备17065521号</a>
|
||||||
|
</p>
|
||||||
|
<p>© 2026 兜爸心选 · 本页面为「兜爸心选」移动应用的官方介绍与下载页面</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="/app/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
50
src/legal.css
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* 兜爸心选官网 · 合规文本页 */
|
||||||
|
:root{
|
||||||
|
--paper:#FBF5EC;--card:#FFFCF7;--ink:#231C18;--ink-2:#4B3F37;--muted:#7E7064;
|
||||||
|
--red:#CF152C;--line:#E6D7C3;
|
||||||
|
--serif:"Songti SC","STSong","Noto Serif CJK SC","Noto Serif SC","Source Han Serif SC","SimSun",serif;
|
||||||
|
--sans:"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans CJK SC",sans-serif;
|
||||||
|
}
|
||||||
|
*,*::before,*::after{box-sizing:border-box}
|
||||||
|
body{
|
||||||
|
margin:0;background:var(--paper);color:var(--ink);font-family:var(--sans);
|
||||||
|
font-size:16px;line-height:1.9;-webkit-font-smoothing:antialiased;
|
||||||
|
background-image:radial-gradient(rgba(35,28,24,.07) 1px,transparent 1px);
|
||||||
|
background-size:26px 26px;
|
||||||
|
}
|
||||||
|
a{color:var(--red);text-decoration:none;border-bottom:1px solid rgba(207,21,44,.28)}
|
||||||
|
a:hover{border-bottom-color:var(--red)}
|
||||||
|
.wrap{width:min(820px,calc(100% - 40px));margin-inline:auto}
|
||||||
|
.top{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:22px 0}
|
||||||
|
.top img{height:44px;width:auto}
|
||||||
|
.top a.back{font-size:13.5px;color:var(--ink-2);border:0;border-bottom:1px solid transparent;padding-bottom:2px}
|
||||||
|
.top a.back:hover{color:var(--red);border-bottom-color:var(--red)}
|
||||||
|
.paper{
|
||||||
|
background:var(--card);border:1px solid var(--line);border-radius:6px;
|
||||||
|
padding:64px 64px 56px;margin:10px 0 60px;
|
||||||
|
box-shadow:0 40px 70px -55px rgba(35,28,24,.5);
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
.paper::before{content:"";position:absolute;left:0;right:0;top:0;height:4px;background:var(--red);border-radius:6px 6px 0 0;opacity:.85}
|
||||||
|
h1{font-family:var(--serif);font-size:40px;line-height:1.3;margin:0 0 10px;letter-spacing:.02em}
|
||||||
|
.meta{font-size:13px;color:var(--muted);letter-spacing:.02em;margin-bottom:38px}
|
||||||
|
h2{font-family:var(--serif);font-size:21px;margin:38px 0 10px;letter-spacing:.03em}
|
||||||
|
h3{font-size:16px;margin:22px 0 6px;font-weight:600}
|
||||||
|
p{margin:10px 0}
|
||||||
|
ul{margin:8px 0 8px;padding-left:1.3em}
|
||||||
|
li{margin:6px 0}
|
||||||
|
.note{background:rgba(207,21,44,.06);border-left:3px solid rgba(207,21,44,.5);padding:14px 18px;border-radius:0 8px 8px 0;font-size:14.5px;color:var(--ink-2)}
|
||||||
|
.table{border-top:1px solid var(--line);margin-top:14px}
|
||||||
|
.row{display:grid;grid-template-columns:170px 1fr;gap:18px;padding:14px 0;border-bottom:1px solid var(--line)}
|
||||||
|
.row dt{font-weight:600;color:var(--ink)}
|
||||||
|
.row dd{margin:0;color:var(--ink-2);font-size:15px}
|
||||||
|
.foot{font-size:12.5px;color:var(--muted);padding:0 0 50px;line-height:2}
|
||||||
|
.foot a{color:var(--muted);border-bottom:1px solid rgba(126,112,100,.3)}
|
||||||
|
@media (max-width:640px){
|
||||||
|
.paper{padding:38px 22px 34px;border-radius:4px;margin-bottom:36px}
|
||||||
|
h1{font-size:30px}
|
||||||
|
h2{font-size:19px;margin-top:30px}
|
||||||
|
body{font-size:15px}
|
||||||
|
.row{grid-template-columns:1fr;gap:4px}
|
||||||
|
.top img{height:38px}
|
||||||
|
}
|
||||||
71
src/main.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/* 兜爸心选官网 · 轻交互(无依赖) */
|
||||||
|
(function () {
|
||||||
|
document.documentElement.classList.add('js');
|
||||||
|
|
||||||
|
var nav = document.getElementById('nav');
|
||||||
|
var onScroll = function () {
|
||||||
|
if (!nav) return;
|
||||||
|
nav.classList.toggle('is-stuck', window.scrollY > 24);
|
||||||
|
};
|
||||||
|
onScroll();
|
||||||
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||||||
|
|
||||||
|
var items = document.querySelectorAll('[data-reveal]');
|
||||||
|
if ('IntersectionObserver' in window) {
|
||||||
|
var io = new IntersectionObserver(function (entries) {
|
||||||
|
entries.forEach(function (e) {
|
||||||
|
if (e.isIntersecting) {
|
||||||
|
e.target.classList.add('is-in');
|
||||||
|
io.unobserve(e.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { rootMargin: '0px 0px -12% 0px', threshold: 0.12 });
|
||||||
|
items.forEach(function (el) { io.observe(el); });
|
||||||
|
} else {
|
||||||
|
items.forEach(function (el) { el.classList.add('is-in'); });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同一时间只展开一个 FAQ
|
||||||
|
var qas = document.querySelectorAll('.qa');
|
||||||
|
qas.forEach(function (d) {
|
||||||
|
d.addEventListener('toggle', function () {
|
||||||
|
if (!d.open) return;
|
||||||
|
qas.forEach(function (o) { if (o !== d) o.open = false; });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 首屏手机屏:6 张界面截图自动轮换(悬停暂停 / 切后台暂停 / 尊重"减少动效")
|
||||||
|
(function () {
|
||||||
|
var box = document.getElementById('heroSlides');
|
||||||
|
if (!box) return;
|
||||||
|
var slides = Array.prototype.slice.call(box.querySelectorAll('.hs-slide'));
|
||||||
|
if (slides.length < 2) return;
|
||||||
|
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||||
|
var idx = 0, timer = null, hover = false;
|
||||||
|
|
||||||
|
function show(n) {
|
||||||
|
slides[idx].classList.remove('is-on');
|
||||||
|
idx = (n + slides.length) % slides.length;
|
||||||
|
slides[idx].classList.add('is-on');
|
||||||
|
}
|
||||||
|
function stop() { if (timer) { clearInterval(timer); timer = null; } }
|
||||||
|
function start() {
|
||||||
|
stop();
|
||||||
|
if (reduce.matches) return;
|
||||||
|
timer = setInterval(function () {
|
||||||
|
if (hover || document.hidden) return;
|
||||||
|
show(idx + 1);
|
||||||
|
}, 4200);
|
||||||
|
}
|
||||||
|
box.addEventListener('mouseenter', function () { hover = true; });
|
||||||
|
box.addEventListener('mouseleave', function () { hover = false; });
|
||||||
|
document.addEventListener('visibilitychange', function () { if (!document.hidden) start(); });
|
||||||
|
if (reduce.addEventListener) reduce.addEventListener('change', start);
|
||||||
|
start();
|
||||||
|
})();
|
||||||
|
|
||||||
|
// 外链统一安全属性
|
||||||
|
document.querySelectorAll('a[href^="http"]').forEach(function (a) {
|
||||||
|
a.rel = 'noopener';
|
||||||
|
});
|
||||||
|
})();
|
||||||
82
src/permissions.html
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
|
<title>权限说明 · 兜爸心选</title>
|
||||||
|
<meta name="description" content="兜爸心选 Android 版申请的权限及用途说明,以及关闭权限的方式。">
|
||||||
|
<meta name="theme-color" content="#FBF5EC">
|
||||||
|
<link rel="icon" type="image/png" href="assets/favicon.png">
|
||||||
|
<link rel="stylesheet" href="legal.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="top">
|
||||||
|
<a href="/app/" aria-label="返回兜爸心选官网"><img src="assets/brand.webp" alt="兜爸心选"></a>
|
||||||
|
<a class="back" href="/app/">← 返回官网</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article class="paper">
|
||||||
|
<h1>兜爸心选 · 权限说明</h1>
|
||||||
|
<p class="meta">适用版本:Android 版 v{{permissions.version}}({{channel}}) 更新日期:{{permissions.updatedCn}}</p>
|
||||||
|
|
||||||
|
<p class="note">我们只会在实现具体功能所必需的场景下申请权限,并在您使用对应功能时向您说明。您可以在手机「设置 → 应用 → 兜爸心选 → 权限」中随时开启或关闭;关闭后相关功能可能无法使用,但不影响浏览商品等其他功能。</p>
|
||||||
|
|
||||||
|
<h2>一、权限清单与用途</h2>
|
||||||
|
<dl class="table">
|
||||||
|
<div class="row">
|
||||||
|
<dt>相机</dt>
|
||||||
|
<dd>用于扫一扫(扫码进入活动/商品)、拍照上传评价晒图与头像。仅在您主动点击拍照或扫码时调用。</dd>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<dt>相册与存储</dt>
|
||||||
|
<dd>用于选择图片上传(头像、评价)、保存商品图与活动海报、下载并安装应用更新包。</dd>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<dt>麦克风</dt>
|
||||||
|
<dd>用于客服会话中的语音消息、语音搜索等需要录音的功能。不会在后台悄悄录音。</dd>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<dt>位置信息</dt>
|
||||||
|
<dd>用于定位所在城市、展示附近门店与配送范围、计算运费与预计送达时间。您也可以手动选择城市而不授权定位。</dd>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<dt>电话与设备信息</dt>
|
||||||
|
<dd>用于设备识别与账号安全风控,以及在客服页一键拨打客服电话。我们不会读取您的通话内容与通讯录。</dd>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<dt>通知与桌面角标</dt>
|
||||||
|
<dd>用于发送订单状态、物流进度、活动提醒;桌面角标用于提示未读消息。可在系统设置中关闭通知。</dd>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<dt>安装应用</dt>
|
||||||
|
<dd>用于 App 内检测到新版本后下载并安装更新包。安装前系统会再次向您确认。</dd>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<dt>网络与基础运行</dt>
|
||||||
|
<dd>用于联网、判断网络状态、保持消息接收、振动提醒与蓝牙设备连接(如使用相关外设)。</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2>二、关于第三方 SDK</h2>
|
||||||
|
<p>应用基于 DCloud uni-app 构建;微信登录、支付与分享使用微信开放平台 SDK,支付宝支付使用支付宝 SDK,定位能力使用高德地图 SDK。上述 SDK 可能在其功能运行时申请相应权限或收集必要的设备信息,具体处理规则请见<a href="/protocol.html">《兜爸心选隐私保护政策》</a>第十节「第三方服务提供商清单」。</p>
|
||||||
|
|
||||||
|
<h2>三、如何关闭权限</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Android:设置 → 应用(或「应用管理」)→ 兜爸心选 → 权限,逐项关闭。</li>
|
||||||
|
<li>关闭相机/相册后,扫码、晒图与头像上传将不可用;关闭定位后,需手动选择城市;关闭通知后,将收不到订单与物流提醒。</li>
|
||||||
|
<li>如您希望撤回全部授权或注销账号,可通过 App 内「我的 → 联系客服」提出,我们会在 15 个工作日内处理。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>四、联系我们</h2>
|
||||||
|
<p>客服入口:App 内「我的 → 联系客服」。<br>
|
||||||
|
隐私与个人信息相关事项,请见<a href="/protocol.html">《兜爸心选隐私保护政策》</a>第九节联系方式。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<p class="foot">
|
||||||
|
北京臻惠网络科技有限公司 · <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">京ICP备17065521号</a><br>
|
||||||
|
© 2026 兜爸心选 · <a href="/app/">返回官网</a> · <a href="terms.html">用户协议</a> · <a href="/protocol.html">隐私政策</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
656
src/styles.css
Normal file
@@ -0,0 +1,656 @@
|
|||||||
|
/* ============================================================
|
||||||
|
兜爸心选 · 官方应用官网
|
||||||
|
视觉方向:品牌手账 —— 纸感底、印章红、宋体标题、手写批注
|
||||||
|
============================================================ */
|
||||||
|
|
||||||
|
:root{
|
||||||
|
--paper:#FBF5EC;
|
||||||
|
--paper-2:#F4E9D8;
|
||||||
|
--card:#FFFCF7;
|
||||||
|
--ink:#231C18;
|
||||||
|
--ink-2:#4B3F37;
|
||||||
|
--muted:#7E7064;
|
||||||
|
--red:#CF152C;
|
||||||
|
--red-deep:#A60F21;
|
||||||
|
--red-soft:rgba(207,21,44,.08);
|
||||||
|
--line:#E6D7C3;
|
||||||
|
--cream:#FFF7EC;
|
||||||
|
|
||||||
|
--serif:"Songti SC","STSong","Noto Serif CJK SC","Noto Serif SC","Source Han Serif SC","SimSun",serif;
|
||||||
|
--sans:"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans CJK SC","Noto Sans SC",sans-serif;
|
||||||
|
--hand:"Kaiti SC","STKaiti","KaiTi","Kaiti TC","Yuanti SC",cursive;
|
||||||
|
|
||||||
|
--wrap:1240px;
|
||||||
|
--ease:cubic-bezier(.16,1,.3,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
*,*::before,*::after{box-sizing:border-box}
|
||||||
|
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
|
||||||
|
body{
|
||||||
|
margin:0;
|
||||||
|
background:var(--paper);
|
||||||
|
color:var(--ink);
|
||||||
|
font-family:var(--sans);
|
||||||
|
font-size:16px;
|
||||||
|
line-height:1.75;
|
||||||
|
-webkit-font-smoothing:antialiased;
|
||||||
|
overflow-x:hidden;
|
||||||
|
}
|
||||||
|
img{max-width:100%;display:block}
|
||||||
|
a{color:inherit;text-decoration:none}
|
||||||
|
ul,ol,dl,dd{margin:0;padding:0;list-style:none}
|
||||||
|
p{margin:0}
|
||||||
|
h1,h2,h3,h4{margin:0;font-weight:700;line-height:1.2}
|
||||||
|
svg{display:block}
|
||||||
|
::selection{background:rgba(207,21,44,.16)}
|
||||||
|
|
||||||
|
/* 纸纹 */
|
||||||
|
body::after{
|
||||||
|
content:"";position:fixed;inset:0;z-index:9;pointer-events:none;opacity:.045;
|
||||||
|
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
|
||||||
|
mix-blend-mode:multiply;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap{width:min(var(--wrap),calc(100% - 56px));margin-inline:auto}
|
||||||
|
section[id]{scroll-margin-top:96px}
|
||||||
|
.skip{position:absolute;left:-9999px;top:0;background:var(--ink);color:#fff;padding:10px 16px;z-index:99}
|
||||||
|
.skip:focus{left:12px;top:12px}
|
||||||
|
|
||||||
|
/* ---------- 通用文字 ---------- */
|
||||||
|
.kicker{
|
||||||
|
font-size:11px;letter-spacing:.22em;text-transform:uppercase;
|
||||||
|
color:var(--red);font-weight:600;margin-bottom:22px;
|
||||||
|
}
|
||||||
|
.kicker--light{color:rgba(255,247,236,.7)}
|
||||||
|
.h2{
|
||||||
|
font-family:var(--serif);
|
||||||
|
font-size:clamp(34px,4.2vw,56px);
|
||||||
|
line-height:1.22;letter-spacing:.01em;font-weight:700;
|
||||||
|
}
|
||||||
|
.sec-sub{margin-top:18px;color:var(--muted);font-size:16px}
|
||||||
|
|
||||||
|
/* ---------- 按钮 ---------- */
|
||||||
|
.btn{
|
||||||
|
--btn-bg:var(--ink);--btn-fg:#fff;
|
||||||
|
display:inline-flex;align-items:center;justify-content:center;gap:9px;
|
||||||
|
background:var(--btn-bg);color:var(--btn-fg);
|
||||||
|
border:1px solid transparent;border-radius:999px;
|
||||||
|
font-size:15px;font-weight:600;line-height:1;
|
||||||
|
padding:14px 24px;cursor:pointer;white-space:nowrap;
|
||||||
|
transition:transform .35s var(--ease),box-shadow .35s var(--ease),background .25s,color .25s,border-color .25s;
|
||||||
|
}
|
||||||
|
.btn .ico{width:18px;height:18px;flex:none}
|
||||||
|
.btn--red{--btn-bg:var(--red);--btn-fg:#fff;box-shadow:0 12px 26px -14px rgba(207,21,44,.9)}
|
||||||
|
.btn--red:hover{--btn-bg:var(--red-deep);transform:translateY(-2px);box-shadow:0 18px 30px -14px rgba(207,21,44,.85)}
|
||||||
|
.btn--ghost{background:transparent;color:var(--ink);border-color:rgba(35,28,24,.22)}
|
||||||
|
.btn--ghost:hover{border-color:var(--ink);transform:translateY(-2px)}
|
||||||
|
.btn--cream{background:var(--cream);color:var(--red);box-shadow:0 16px 32px -20px rgba(0,0,0,.6)}
|
||||||
|
.btn--cream:hover{transform:translateY(-2px);background:#fff}
|
||||||
|
.btn--outline{background:transparent;color:rgba(255,247,236,.92);border-color:rgba(255,247,236,.38)}
|
||||||
|
.btn--outline.is-disabled{cursor:default;opacity:.8}
|
||||||
|
.btn--sm{padding:11px 20px;font-size:13.5px}
|
||||||
|
.btn--lg{padding:18px 30px;font-size:16px}
|
||||||
|
.btn-note{font-size:12px;font-weight:400;opacity:.62;letter-spacing:.02em}
|
||||||
|
|
||||||
|
/* ---------- 导航 ---------- */
|
||||||
|
.nav{
|
||||||
|
position:fixed;inset:0 0 auto;z-index:50;
|
||||||
|
padding:14px 0;transition:padding .35s var(--ease),background .35s,border-color .35s,box-shadow .35s;
|
||||||
|
border-bottom:1px solid transparent;
|
||||||
|
}
|
||||||
|
.nav-inner{
|
||||||
|
width:min(var(--wrap),calc(100% - 56px));margin-inline:auto;
|
||||||
|
display:flex;align-items:center;gap:40px;
|
||||||
|
}
|
||||||
|
.nav.is-stuck{
|
||||||
|
padding:8px 0;background:rgba(251,245,236,.86);
|
||||||
|
backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
|
||||||
|
border-bottom-color:rgba(230,215,195,.9);
|
||||||
|
}
|
||||||
|
/* logo:白色圆角卡片 + 柔和阴影 + 缓动(hover 上浮 / 按下回弹 / 首屏淡入) */
|
||||||
|
.brand{
|
||||||
|
flex:none;display:flex;align-items:center;
|
||||||
|
padding:8px 12px;border:0;border-radius:16px;background:#fff;
|
||||||
|
box-shadow:0 1px 2px rgba(35,28,24,.05),0 10px 24px -14px rgba(35,28,24,.34);
|
||||||
|
transition:padding .45s var(--ease),border-radius .45s var(--ease),
|
||||||
|
box-shadow .45s var(--ease),transform .45s var(--ease);
|
||||||
|
animation:brandIn .9s var(--ease) both;
|
||||||
|
}
|
||||||
|
.brand img{height:56px;width:auto;transition:height .45s var(--ease)}
|
||||||
|
.nav.is-stuck .brand{padding:6px 10px;border-radius:13px}
|
||||||
|
.nav.is-stuck .brand img{height:44px}
|
||||||
|
.brand:hover{
|
||||||
|
transform:translateY(-3px);
|
||||||
|
box-shadow:0 2px 4px rgba(35,28,24,.06),0 18px 34px -16px rgba(35,28,24,.45);
|
||||||
|
}
|
||||||
|
.brand:active{transform:translateY(-1px) scale(.985);transition-duration:.18s}
|
||||||
|
.brand:focus-visible{outline:2px solid var(--red);outline-offset:3px}
|
||||||
|
@keyframes brandIn{from{opacity:0;transform:translateY(-10px) scale(.94)}to{opacity:1;transform:none}}
|
||||||
|
@media (prefers-reduced-motion:reduce){
|
||||||
|
.brand{animation:none;transition:none}
|
||||||
|
}
|
||||||
|
.nav-links{display:flex;gap:34px;margin-left:auto;font-size:14.5px;color:var(--ink-2)}
|
||||||
|
.nav-links a{position:relative;padding:4px 0;transition:color .25s}
|
||||||
|
.nav-links a::after{
|
||||||
|
content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
|
||||||
|
background:var(--red);transform:scaleX(0);transform-origin:left;transition:transform .4s var(--ease);
|
||||||
|
}
|
||||||
|
.nav-links a:hover{color:var(--red)}
|
||||||
|
.nav-links a:hover::after{transform:scaleX(1)}
|
||||||
|
|
||||||
|
/* ---------- HERO ---------- */
|
||||||
|
.hero{position:relative;padding:168px 0 78px;overflow:hidden}
|
||||||
|
.hero-bg{position:absolute;inset:0;pointer-events:none}
|
||||||
|
.hero-bg .blob{
|
||||||
|
position:absolute;right:-8%;top:-16%;width:760px;height:760px;border-radius:50%;
|
||||||
|
background:radial-gradient(circle at 50% 50%,rgba(207,21,44,.16),rgba(207,21,44,.05) 42%,transparent 68%);
|
||||||
|
filter:blur(6px);
|
||||||
|
}
|
||||||
|
.hero-bg .grid{
|
||||||
|
position:absolute;inset:0;
|
||||||
|
background-image:radial-gradient(rgba(35,28,24,.16) 1px,transparent 1px);
|
||||||
|
background-size:24px 24px;
|
||||||
|
-webkit-mask-image:radial-gradient(120% 80% at 78% 8%,#000 0%,transparent 62%);
|
||||||
|
mask-image:radial-gradient(120% 80% at 78% 8%,#000 0%,transparent 62%);
|
||||||
|
opacity:.7;
|
||||||
|
}
|
||||||
|
.hero-inner{position:relative;display:grid;grid-template-columns:1.02fr .98fr;align-items:center;gap:40px}
|
||||||
|
|
||||||
|
.eyebrow{
|
||||||
|
display:inline-flex;align-items:center;gap:10px;
|
||||||
|
font-size:12.5px;letter-spacing:.16em;color:var(--ink-2);
|
||||||
|
border:1px solid var(--line);border-radius:999px;padding:8px 18px;background:rgba(255,252,247,.6);
|
||||||
|
}
|
||||||
|
.eyebrow-dot{width:6px;height:6px;border-radius:50%;background:var(--red);box-shadow:0 0 0 4px rgba(207,21,44,.12)}
|
||||||
|
|
||||||
|
.hero-title{
|
||||||
|
font-family:var(--serif);
|
||||||
|
font-size:clamp(64px,8.6vw,124px);
|
||||||
|
line-height:1.02;letter-spacing:.02em;
|
||||||
|
margin:26px 0 8px;font-weight:700;
|
||||||
|
}
|
||||||
|
.hero-lede{
|
||||||
|
font-family:var(--serif);
|
||||||
|
font-size:clamp(28px,3.2vw,42px);
|
||||||
|
line-height:1.5;color:var(--ink);margin-top:6px;font-weight:700;
|
||||||
|
}
|
||||||
|
.hero-lede .hl{position:relative;display:inline-block;color:var(--red)}
|
||||||
|
.hero-lede .hl::after{
|
||||||
|
content:"";position:absolute;left:-2%;right:-2%;bottom:2px;height:12px;
|
||||||
|
background:linear-gradient(90deg,rgba(207,21,44,.26),rgba(207,21,44,.14));
|
||||||
|
border-radius:60% 40% 55% 45% / 100% 100% 0 0;
|
||||||
|
transform:rotate(-.6deg);z-index:-1;
|
||||||
|
}
|
||||||
|
.hero-desc{margin-top:24px;font-size:16.5px;line-height:1.95;color:var(--muted);max-width:32em;text-wrap:balance}
|
||||||
|
.about-sub,.about-sub,.feature p,.promise p,.dl-desc,.sec-sub{text-wrap:pretty}
|
||||||
|
.cta-row{display:flex;flex-wrap:wrap;gap:14px;margin-top:36px}
|
||||||
|
.hero-meta{
|
||||||
|
display:flex;flex-wrap:wrap;gap:0 18px;margin-top:30px;
|
||||||
|
font-size:12.5px;letter-spacing:.04em;color:var(--muted);
|
||||||
|
}
|
||||||
|
.hero-meta li{position:relative;padding-right:18px}
|
||||||
|
.hero-meta li:not(:last-child)::after{
|
||||||
|
content:"";position:absolute;right:7px;top:50%;width:3px;height:3px;border-radius:50%;background:var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 手机模型 */
|
||||||
|
.hero-art{position:relative;display:flex;justify-content:center;align-items:center;min-height:640px}
|
||||||
|
.phone{
|
||||||
|
position:relative;width:328px;padding:var(--bezel,8px);border-radius:48px;
|
||||||
|
background:linear-gradient(160deg,#3A302A,#17120F 46%,#241D19);
|
||||||
|
box-shadow:
|
||||||
|
0 2px 0 rgba(255,255,255,.14) inset,
|
||||||
|
0 50px 90px -50px rgba(35,28,24,.75),
|
||||||
|
0 20px 40px -30px rgba(35,28,24,.5);
|
||||||
|
flex:none;
|
||||||
|
}
|
||||||
|
.phone::after{
|
||||||
|
content:"";position:absolute;inset:0;border-radius:48px;pointer-events:none;
|
||||||
|
background:linear-gradient(120deg,rgba(255,255,255,.16),transparent 32%,transparent 70%,rgba(255,255,255,.05));
|
||||||
|
-webkit-mask:linear-gradient(#000,#000) content-box,linear-gradient(#000,#000);
|
||||||
|
-webkit-mask-composite:xor;mask-composite:exclude;padding:1px;
|
||||||
|
}
|
||||||
|
.phone-screen{
|
||||||
|
position:relative;border-radius:39px;overflow:hidden;background:#FCFAF6;
|
||||||
|
height:632px;display:flex;flex-direction:column;
|
||||||
|
}
|
||||||
|
.phone-screen > *{flex:none}
|
||||||
|
.phone--hero{transform:rotate(-3.4deg)}
|
||||||
|
.phone--hero .phone-screen{height:680px}
|
||||||
|
|
||||||
|
/* 首屏手机屏:6 张界面截图自动轮换(mama-box 3 张 + 商城 3 张) */
|
||||||
|
.hero-slides{position:relative;overflow:hidden;background:#fff}
|
||||||
|
.hs-slide{
|
||||||
|
position:absolute;inset:0;display:block;width:100%;height:100%;
|
||||||
|
object-fit:cover;object-position:top center;
|
||||||
|
opacity:0;transition:opacity .9s var(--ease);will-change:opacity;
|
||||||
|
}
|
||||||
|
.hs-slide.is-on{opacity:1;animation:hsKen 8.4s linear both}
|
||||||
|
@keyframes hsKen{from{transform:scale(1)}to{transform:scale(1.055)}}
|
||||||
|
@media (prefers-reduced-motion:reduce){
|
||||||
|
.hs-slide{transition:none}
|
||||||
|
.hs-slide.is-on{animation:none}
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusbar{display:flex;justify-content:space-between;align-items:center;padding:8px 18px 2px;font-size:10px;font-weight:700;color:#2B231E;letter-spacing:.02em}
|
||||||
|
.sb-right{display:flex;align-items:center;gap:4px}
|
||||||
|
.sb-right i{display:block;background:#2B231E;border-radius:1px}
|
||||||
|
.sb-right .sig{width:12px;height:8px;clip-path:polygon(0 100%,100% 0,100% 100%)}
|
||||||
|
.sb-right .wifi{width:10px;height:8px;clip-path:polygon(50% 100%,0 25%,100% 25%)}
|
||||||
|
.sb-right .batt{width:16px;height:8px;border-radius:2px;opacity:.9}
|
||||||
|
|
||||||
|
.app-top{display:flex;align-items:center;gap:8px;padding:4px 14px 8px}
|
||||||
|
.mini-logo{height:26px;width:auto;flex:none}
|
||||||
|
.search{
|
||||||
|
flex:1;display:flex;align-items:center;gap:5px;
|
||||||
|
height:30px;padding:0 10px;border-radius:999px;
|
||||||
|
background:#F2E9DC;color:#9A8B7C;font-size:10px;
|
||||||
|
}
|
||||||
|
.search svg{width:12px;height:12px;fill:none;stroke:#9A8B7C;stroke-width:2;stroke-linecap:round;flex:none}
|
||||||
|
|
||||||
|
.promo{
|
||||||
|
position:relative;margin:0 14px;border-radius:15px;padding:10px 14px 11px;
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 120% at 90% 0%,rgba(255,255,255,.18),transparent 55%),
|
||||||
|
linear-gradient(150deg,#D9192F,#A60F21);
|
||||||
|
color:#FFEEE6;overflow:hidden;
|
||||||
|
box-shadow:0 12px 22px -16px rgba(166,15,33,.9);
|
||||||
|
}
|
||||||
|
.promo-k{font-size:9.5px;letter-spacing:.16em;opacity:.82}
|
||||||
|
.promo-t{font-family:var(--serif);font-size:16px;font-weight:700;line-height:1.38;margin-top:4px}
|
||||||
|
.promo-tag{display:inline-block;margin-top:8px;padding:2px 8px;border-radius:999px;background:rgba(255,255,255,.16);font-size:8.5px;letter-spacing:.04em}
|
||||||
|
.promo-doodle{position:absolute;right:8px;top:10px;width:44px;height:44px;color:#fff;opacity:.32}
|
||||||
|
|
||||||
|
.chips{display:flex;gap:6px;padding:10px 14px 2px;overflow:hidden}
|
||||||
|
.chip{flex:none;font-size:9.5px;padding:5px 10px;border-radius:999px;background:#F2E9DC;color:#6E6156}
|
||||||
|
.chip--on{background:var(--red);color:#fff}
|
||||||
|
|
||||||
|
.sect-head{display:flex;justify-content:space-between;align-items:baseline;padding:7px 15px 4px;font-size:11px;color:#2B231E}
|
||||||
|
.sect-head b{font-size:12px;letter-spacing:.02em}
|
||||||
|
.sect-head span{font-size:9px;color:#A6988A}
|
||||||
|
|
||||||
|
.pgrid{display:grid;grid-template-columns:1fr 1fr;gap:6px;padding:0 14px}
|
||||||
|
.pcard{background:#fff;border-radius:11px;padding:5px;box-shadow:0 6px 14px -12px rgba(35,28,24,.5)}
|
||||||
|
.pimg{height:118px;border-radius:8px;overflow:hidden;background:#F6F0E7}
|
||||||
|
.pimg img{width:100%;height:100%;object-fit:cover}
|
||||||
|
.pname{
|
||||||
|
margin:5px 3px 2px;font-size:9px;line-height:1.4;color:#4B3F37;
|
||||||
|
display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;height:2.9em;
|
||||||
|
}
|
||||||
|
.pprice{margin:0 3px 3px;font-size:10px;color:var(--red);display:flex;align-items:baseline;gap:4px}
|
||||||
|
.pprice em{font-style:normal;font-weight:700;font-size:11px}
|
||||||
|
.pprice s{color:#A6988A;font-size:9px}
|
||||||
|
|
||||||
|
.tabbar{
|
||||||
|
margin-top:auto;display:flex;border-top:1px solid #F0E6D9;background:#FFFDFA;
|
||||||
|
padding:6px 4px 9px;
|
||||||
|
}
|
||||||
|
.tab{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;font-size:8.5px;color:#A6988A}
|
||||||
|
.tab svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
|
||||||
|
.tab--on{color:var(--red)}
|
||||||
|
|
||||||
|
/* 印章 */
|
||||||
|
.stamp{
|
||||||
|
position:absolute;left:-6px;top:12px;z-index:3;
|
||||||
|
width:126px;height:126px;border-radius:50%;
|
||||||
|
border:2px solid rgba(207,21,44,.72);
|
||||||
|
display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;
|
||||||
|
color:rgba(207,21,44,.86);transform:rotate(-11deg);
|
||||||
|
background:rgba(255,252,247,.36);
|
||||||
|
mix-blend-mode:multiply;
|
||||||
|
box-shadow:0 0 0 6px rgba(207,21,44,.06) inset;
|
||||||
|
}
|
||||||
|
.stamp-top{font-family:var(--serif);font-size:20px;font-weight:700;letter-spacing:.14em;text-indent:.14em}
|
||||||
|
.stamp-line{width:52px;height:1px;background:rgba(207,21,44,.5)}
|
||||||
|
.stamp-bottom{font-family:var(--hand);font-size:10.5px;letter-spacing:.14em;text-indent:.14em}
|
||||||
|
|
||||||
|
.hand-note{
|
||||||
|
position:absolute;left:-4px;bottom:44px;
|
||||||
|
font-family:var(--hand);font-size:19px;line-height:1.6;color:var(--red);
|
||||||
|
transform:rotate(-4deg);
|
||||||
|
}
|
||||||
|
.hand-arrow{
|
||||||
|
position:absolute;left:118px;bottom:16px;width:96px;color:rgba(207,21,44,.5);
|
||||||
|
transform:rotate(-22deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 三条承诺 ---------- */
|
||||||
|
.promises{border-top:1px solid var(--line);border-bottom:1px solid var(--line);background:rgba(255,252,247,.5)}
|
||||||
|
.promises-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:48px;padding:46px 0}
|
||||||
|
.promise{position:relative;padding-left:0}
|
||||||
|
.p-num{font-family:var(--serif);font-size:12px;letter-spacing:.2em;color:var(--red)}
|
||||||
|
.promise h3{font-family:var(--serif);font-size:23px;margin:8px 0 6px;letter-spacing:.04em}
|
||||||
|
.promise p{font-size:14.5px;line-height:1.8;color:var(--muted)}
|
||||||
|
|
||||||
|
/* ---------- 品牌理念 ---------- */
|
||||||
|
.about{padding:118px 0 110px}
|
||||||
|
.about-inner{display:grid;grid-template-columns:.86fr 1.14fr;gap:80px;align-items:start}
|
||||||
|
.about-head{position:sticky;top:120px}
|
||||||
|
.about-sub{margin-top:26px;font-size:16px;line-height:1.95;color:var(--muted)}
|
||||||
|
|
||||||
|
.note{
|
||||||
|
position:relative;background:var(--card);
|
||||||
|
border:1px solid var(--line);border-radius:4px;
|
||||||
|
padding:56px 54px 44px;
|
||||||
|
box-shadow:0 40px 70px -50px rgba(35,28,24,.55),0 2px 0 rgba(255,255,255,.8) inset;
|
||||||
|
transform:rotate(-.55deg);
|
||||||
|
}
|
||||||
|
.note::before{
|
||||||
|
content:"";position:absolute;inset:0;border-radius:4px;pointer-events:none;
|
||||||
|
background-image:repeating-linear-gradient(to bottom,transparent 0 33px,rgba(35,28,24,.045) 33px 34px);
|
||||||
|
opacity:.9;
|
||||||
|
}
|
||||||
|
.tape{
|
||||||
|
position:absolute;width:112px;height:30px;background:rgba(226,196,148,.55);
|
||||||
|
box-shadow:0 2px 6px rgba(35,28,24,.08);backdrop-filter:blur(1px);
|
||||||
|
}
|
||||||
|
.tape--l{left:-22px;top:26px;transform:rotate(-38deg)}
|
||||||
|
.tape--r{right:-18px;bottom:40px;transform:rotate(-32deg)}
|
||||||
|
.note-label{
|
||||||
|
position:relative;font-size:10.5px;letter-spacing:.24em;color:var(--muted);
|
||||||
|
margin-bottom:26px;text-transform:uppercase;
|
||||||
|
}
|
||||||
|
.note-body{position:relative}
|
||||||
|
.note-body p{font-size:17px;line-height:2.02;color:var(--ink-2);letter-spacing:.01em}
|
||||||
|
.note-body p + p{margin-top:18px}
|
||||||
|
.note-body p:first-child::first-letter{
|
||||||
|
float:left;font-family:var(--serif);font-size:56px;line-height:.9;color:var(--red);
|
||||||
|
margin:6px 12px 0 0;
|
||||||
|
}
|
||||||
|
.sign{position:relative;margin-top:26px;text-align:right;font-family:var(--hand);font-size:21px;color:var(--red);letter-spacing:.06em}
|
||||||
|
.checks{margin-top:34px;border-top:1px solid var(--line)}
|
||||||
|
.checks li{
|
||||||
|
display:flex;align-items:baseline;gap:14px;padding:15px 0;
|
||||||
|
border-bottom:1px dashed var(--line);font-size:14px;line-height:1.7;color:var(--muted);
|
||||||
|
}
|
||||||
|
.checks li span{flex:none;font-family:var(--serif);font-size:12px;letter-spacing:.18em;color:var(--red)}
|
||||||
|
|
||||||
|
.note-star{position:absolute;right:30px;bottom:24px;width:34px;color:rgba(207,21,44,.35)}
|
||||||
|
|
||||||
|
/* ---------- 应用功能 ---------- */
|
||||||
|
.features{padding:104px 0 110px;background:var(--paper-2);border-top:1px solid rgba(230,215,195,.7)}
|
||||||
|
.sec-head{max-width:720px}
|
||||||
|
.feature-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px;margin-top:56px}
|
||||||
|
.feature{
|
||||||
|
position:relative;background:var(--card);border:1px solid rgba(230,215,195,.9);
|
||||||
|
border-radius:22px;padding:36px 38px 38px;
|
||||||
|
transition:transform .5s var(--ease),box-shadow .5s var(--ease),border-color .5s;
|
||||||
|
}
|
||||||
|
.feature:hover{transform:translateY(-5px);border-color:rgba(207,21,44,.35);box-shadow:0 30px 50px -40px rgba(35,28,24,.55)}
|
||||||
|
.feature .f-num{
|
||||||
|
position:absolute;right:36px;top:30px;
|
||||||
|
font-family:var(--serif);font-size:13px;letter-spacing:.2em;color:rgba(35,28,24,.2);
|
||||||
|
}
|
||||||
|
.feature::after{
|
||||||
|
content:"";position:absolute;left:38px;right:38px;top:0;height:2px;border-radius:2px;
|
||||||
|
background:linear-gradient(90deg,var(--red),rgba(207,21,44,0));
|
||||||
|
transform:scaleX(0);transform-origin:left;transition:transform .6s var(--ease);
|
||||||
|
}
|
||||||
|
.feature:hover::after{transform:scaleX(1)}
|
||||||
|
.f-ico{
|
||||||
|
width:56px;height:56px;border-radius:50%;border:1px dashed rgba(207,21,44,.4);
|
||||||
|
display:grid;place-items:center;color:var(--red);background:var(--red-soft);
|
||||||
|
}
|
||||||
|
.f-ico svg{width:28px;height:28px}
|
||||||
|
.feature h3{font-family:var(--serif);font-size:23px;margin:22px 0 10px;letter-spacing:.03em}
|
||||||
|
.feature p{font-size:15px;line-height:1.85;color:var(--muted)}
|
||||||
|
|
||||||
|
/* ---------- 应用截图 ---------- */
|
||||||
|
.screens{padding:104px 0 118px;background:var(--paper);border-top:1px solid var(--line)}
|
||||||
|
.sec-head--row{display:flex;justify-content:space-between;align-items:flex-end;max-width:none;gap:40px}
|
||||||
|
.sec-note{font-size:12.5px;line-height:1.9;color:var(--muted);text-align:right;letter-spacing:.02em}
|
||||||
|
.shots-hint{display:none;font-size:12px;letter-spacing:.06em;color:var(--muted);margin-top:10px}
|
||||||
|
.shots{display:grid;grid-template-columns:repeat(3,1fr);gap:38px;row-gap:78px;margin-top:64px;justify-items:center}
|
||||||
|
.shot{width:100%;display:flex;flex-direction:column;align-items:center}
|
||||||
|
.phone--shot{--bezel:6px;width:300px;padding:var(--bezel);border-radius:44px}
|
||||||
|
.phone--shot .phone-screen{height:680px;border-radius:36px}
|
||||||
|
/* 真机截图(mama-box 首页):铺满屏幕区,顶部对齐 */
|
||||||
|
.phone--shot .phone-screen .shot-img{width:100%;height:100%;object-fit:cover;object-position:top center;display:block}
|
||||||
|
.phone--shot .statusbar{padding-top:8px}
|
||||||
|
.phone--shot .promo-t{font-size:16px}
|
||||||
|
.phone--shot .pgrid{gap:7px}
|
||||||
|
.shot:nth-child(1) .phone--shot{transform:rotate(-2.2deg)}
|
||||||
|
.shot:nth-child(2) .phone--shot{transform:translateY(-18px)}
|
||||||
|
.shot:nth-child(3) .phone--shot{transform:rotate(2.2deg)}
|
||||||
|
.shot:nth-child(4) .phone--shot{transform:rotate(-2.2deg)}
|
||||||
|
.shot:nth-child(5) .phone--shot{transform:translateY(-18px)}
|
||||||
|
.shot:nth-child(6) .phone--shot{transform:rotate(2.2deg)}
|
||||||
|
.shot .phone--shot{transition:transform .6s var(--ease),box-shadow .6s}
|
||||||
|
.shot:hover .phone--shot{transform:rotate(0) translateY(-6px)}
|
||||||
|
.shot figcaption{margin-top:26px;font-size:13.5px;line-height:1.7;color:var(--muted);text-align:center;max-width:300px}
|
||||||
|
.shot figcaption b{color:var(--ink);font-weight:600}
|
||||||
|
|
||||||
|
/* 分类页 / 详情页 mock */
|
||||||
|
.subpage-head{display:flex;align-items:center;justify-content:space-between;padding:6px 14px 12px;font-size:12px;color:#2B231E}
|
||||||
|
.subpage-head b{font-weight:600}
|
||||||
|
.subpage-head .back{width:18px;height:18px}
|
||||||
|
.subpage-head .share{color:#A6988A;letter-spacing:2px}
|
||||||
|
.cat{display:flex;flex:1;overflow:hidden;border-top:1px solid #F0E6D9}
|
||||||
|
.cat-rail{width:78px;background:#F6F0E7;padding-top:4px;overflow:hidden}
|
||||||
|
.cat-rail li{font-size:10px;color:#7E7064;text-align:center;padding:9px 0;position:relative}
|
||||||
|
.cat-rail li.on{background:#FCFAF6;color:var(--red);font-weight:600}
|
||||||
|
.cat-rail li.on::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);width:3px;height:16px;background:var(--red);border-radius:0 3px 3px 0}
|
||||||
|
.cat-list{flex:1;padding:10px 10px 0;overflow:hidden}
|
||||||
|
.row{display:flex;gap:8px;margin-bottom:11px}
|
||||||
|
.rimg{width:58px;height:58px;border-radius:9px;overflow:hidden;flex:none;background:#F6F0E7}
|
||||||
|
.rimg img{width:100%;height:100%;object-fit:cover}
|
||||||
|
.rt{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
|
||||||
|
.rt p{margin:0;font-size:9.5px;line-height:1.4;color:#4B3F37;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
|
||||||
|
.rt .rtag{display:inline-block;font-size:8px;color:var(--red);border:1px solid rgba(207,21,44,.3);border-radius:3px;padding:0 4px;width:max-content}
|
||||||
|
.rt em{font-style:normal;font-size:11px;font-weight:700;color:var(--red);margin-top:auto}
|
||||||
|
|
||||||
|
.dimg{width:100%;aspect-ratio:1/1;background:#F6F0E7}
|
||||||
|
.dimg img{width:100%;height:100%;object-fit:cover}
|
||||||
|
.dbox{padding:12px 14px 0;flex:1;overflow:hidden}
|
||||||
|
.dprice{display:flex;align-items:baseline;gap:6px;color:var(--red)}
|
||||||
|
.dprice em{font-style:normal;font-family:var(--sans);font-size:19px;font-weight:700}
|
||||||
|
.dprice s{color:#A6988A;font-size:9px}
|
||||||
|
.dprice span{margin-left:auto;color:#A6988A;font-size:9px}
|
||||||
|
.dname{margin-top:6px;font-size:11px;line-height:1.5;color:#2B231E}
|
||||||
|
.dtags{display:flex;gap:5px;margin-top:8px}
|
||||||
|
.dtags span{font-size:8px;padding:2px 5px;border-radius:3px;background:rgba(207,21,44,.07);color:var(--red)}
|
||||||
|
.dline{display:flex;gap:12px;font-size:9px;padding:8px 0;border-top:1px dashed #EDE2D3;color:#A6988A}
|
||||||
|
.dline b{font-weight:500;color:#4B3F37}
|
||||||
|
.dnote{margin-top:6px;background:#FBF1E7;border-radius:8px;padding:8px 10px;font-size:9px;line-height:1.6;color:#6E6156}
|
||||||
|
.dnote-k{display:inline-block;font-size:8px;background:var(--red);color:#fff;border-radius:3px;padding:1px 5px;margin-right:4px}
|
||||||
|
.dbuy{margin-top:auto;display:flex;align-items:center;gap:10px;border-top:1px solid #F0E6D9;padding:8px 12px 12px;background:#FFFDFA}
|
||||||
|
.dico{display:flex;flex-direction:column;align-items:center;gap:1px;font-size:7.5px;color:#7E7064}
|
||||||
|
.dico svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.6}
|
||||||
|
.dbtn{margin-left:auto;background:var(--red);color:#fff;font-size:10.5px;font-weight:600;border-radius:999px;padding:9px 22px}
|
||||||
|
|
||||||
|
/* ---------- 下载 ---------- */
|
||||||
|
.download{padding:0 0 104px}
|
||||||
|
.dl-card{
|
||||||
|
position:relative;overflow:hidden;color:var(--cream);
|
||||||
|
border-radius:32px;padding:66px 64px;
|
||||||
|
background:
|
||||||
|
radial-gradient(90% 120% at 88% 8%,rgba(255,255,255,.16),transparent 55%),
|
||||||
|
radial-gradient(120% 100% at 0% 100%,rgba(0,0,0,.22),transparent 60%),
|
||||||
|
linear-gradient(140deg,#D2152C,#A30E20 70%);
|
||||||
|
display:grid;grid-template-columns:1.16fr .84fr;gap:56px;align-items:center;
|
||||||
|
box-shadow:0 50px 80px -60px rgba(166,15,33,.9);
|
||||||
|
}
|
||||||
|
.dl-card::before{
|
||||||
|
content:"";position:absolute;inset:0;pointer-events:none;opacity:.55;
|
||||||
|
background-image:radial-gradient(rgba(255,255,255,.14) 1px,transparent 1px);
|
||||||
|
background-size:22px 22px;
|
||||||
|
-webkit-mask-image:radial-gradient(80% 100% at 100% 0%,#000,transparent 70%);
|
||||||
|
mask-image:radial-gradient(80% 100% at 100% 0%,#000,transparent 70%);
|
||||||
|
}
|
||||||
|
.dl-star{position:absolute;color:rgba(255,247,236,.35);font-size:22px}
|
||||||
|
.dl-star--1{left:46%;top:34px}
|
||||||
|
.dl-star--2{left:52%;bottom:48px;font-size:15px}
|
||||||
|
.dl-left{position:relative}
|
||||||
|
.dl-title{font-family:var(--serif);font-size:clamp(38px,4.4vw,62px);line-height:1.24;letter-spacing:.01em}
|
||||||
|
.dl-desc{margin-top:20px;font-size:15px;line-height:1.9;color:rgba(255,247,236,.8);max-width:34em}
|
||||||
|
.dl-actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:32px;align-items:center}
|
||||||
|
.dl-meta{display:grid;grid-template-columns:1fr 1fr;gap:16px 24px;margin-top:38px;max-width:440px}
|
||||||
|
.dl-meta dt{font-size:10.5px;letter-spacing:.18em;color:rgba(255,247,236,.55);margin-bottom:3px}
|
||||||
|
.dl-meta dd{font-size:14.5px;color:var(--cream)}
|
||||||
|
.tbd{color:inherit;border-bottom:1px dashed currentColor;opacity:.55;cursor:help}
|
||||||
|
.dl-tip{display:flex;align-items:center;gap:8px;margin-top:22px;font-size:12.5px;line-height:1.7;color:rgba(255,247,236,.72)}
|
||||||
|
.dl-tip svg{width:15px;height:15px;flex:none;opacity:.8}
|
||||||
|
.dl-legal{margin-top:22px;font-size:12.5px;line-height:1.8;color:rgba(255,247,236,.76);max-width:34em}
|
||||||
|
.dl-legal a{color:rgba(255,247,236,.9);border-bottom:1px solid rgba(255,247,236,.35)}
|
||||||
|
|
||||||
|
.dl-right{position:relative;display:flex;flex-direction:column;align-items:center;gap:14px}
|
||||||
|
.qr-card{background:var(--card);color:var(--ink);border-radius:20px;padding:20px 20px 18px;text-align:center;box-shadow:0 30px 60px -40px rgba(0,0,0,.6);transform:rotate(1.6deg)}
|
||||||
|
.qr{width:176px;height:176px}
|
||||||
|
.qr-t{margin-top:12px;font-size:13px;color:var(--ink-2)}
|
||||||
|
.qr-url{margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;letter-spacing:.02em;color:var(--muted)}
|
||||||
|
.qr-hint{font-size:11.5px;color:rgba(255,247,236,.55);text-align:center}
|
||||||
|
|
||||||
|
/* ---------- FAQ ---------- */
|
||||||
|
.faq{padding:20px 0 130px}
|
||||||
|
.faq-inner{display:grid;grid-template-columns:.82fr 1.18fr;gap:80px;align-items:start}
|
||||||
|
.faq-head{position:sticky;top:120px}
|
||||||
|
.faq-contact{margin-top:30px;font-size:14px;line-height:2;color:var(--muted)}
|
||||||
|
.faq-contact a{color:var(--red);border-bottom:1px solid rgba(207,21,44,.35);padding-bottom:1px}
|
||||||
|
.faq-list{border-top:1px solid var(--line)}
|
||||||
|
.qa{border-bottom:1px solid var(--line)}
|
||||||
|
.qa summary{
|
||||||
|
list-style:none;cursor:pointer;display:flex;justify-content:space-between;align-items:center;gap:24px;
|
||||||
|
padding:26px 2px;font-family:var(--serif);font-size:20px;letter-spacing:.02em;color:var(--ink);
|
||||||
|
transition:color .3s;
|
||||||
|
}
|
||||||
|
.qa summary::-webkit-details-marker{display:none}
|
||||||
|
.qa summary:hover{color:var(--red)}
|
||||||
|
.qa summary i{position:relative;width:16px;height:16px;flex:none;transition:transform .4s var(--ease)}
|
||||||
|
.qa summary i::before,.qa summary i::after{content:"";position:absolute;background:currentColor;border-radius:2px}
|
||||||
|
.qa summary i::before{left:0;right:0;top:7px;height:1.5px}
|
||||||
|
.qa summary i::after{top:0;bottom:0;left:7px;width:1.5px;transition:opacity .3s}
|
||||||
|
.qa[open] summary i{transform:rotate(180deg)}
|
||||||
|
.qa[open] summary i::after{opacity:0}
|
||||||
|
.qa-body{padding:0 44px 28px 2px;color:var(--muted);font-size:15px;line-height:1.95}
|
||||||
|
.qa-body a{color:var(--red);border-bottom:1px solid rgba(207,21,44,.3)}
|
||||||
|
|
||||||
|
/* ---------- 页脚 ---------- */
|
||||||
|
.footer{background:var(--ink);color:#EADFD3;padding:74px 0 34px}
|
||||||
|
.footer-top{display:grid;grid-template-columns:1fr 1.25fr;gap:64px}
|
||||||
|
.foot-logo{font-family:var(--serif);font-size:32px;letter-spacing:.06em;color:var(--cream)}
|
||||||
|
.foot-slogan{margin-top:14px;font-size:14px;line-height:1.95;color:rgba(234,223,211,.6)}
|
||||||
|
.foot-cols{display:grid;grid-template-columns:repeat(3,1fr);gap:28px}
|
||||||
|
.foot-cols h4{font-size:11px;letter-spacing:.2em;color:rgba(234,223,211,.45);margin-bottom:16px;font-weight:600}
|
||||||
|
.foot-cols a,.foot-plain{display:block;font-size:13.5px;color:rgba(234,223,211,.82);padding:5px 0;transition:color .25s}
|
||||||
|
.foot-cols a:hover{color:#fff}
|
||||||
|
.foot-legal{margin-top:54px;padding-top:22px;border-top:1px solid rgba(234,223,211,.14);font-size:12px;line-height:2;color:rgba(234,223,211,.45)}
|
||||||
|
|
||||||
|
/* ---------- 动效 ---------- */
|
||||||
|
.js [data-reveal]{opacity:0;transform:translateY(26px);transition:opacity .9s var(--ease),transform .9s var(--ease)}
|
||||||
|
.js [data-reveal].is-in{opacity:1;transform:none}
|
||||||
|
.hero-copy > *{opacity:0;transform:translateY(22px);animation:rise .95s var(--ease) forwards}
|
||||||
|
.hero-copy > *:nth-child(1){animation-delay:.05s}
|
||||||
|
.hero-copy > *:nth-child(2){animation-delay:.14s}
|
||||||
|
.hero-copy > *:nth-child(3){animation-delay:.23s}
|
||||||
|
.hero-copy > *:nth-child(4){animation-delay:.32s}
|
||||||
|
.hero-copy > *:nth-child(5){animation-delay:.41s}
|
||||||
|
.hero-copy > *:nth-child(6){animation-delay:.5s}
|
||||||
|
@keyframes rise{to{opacity:1;transform:none}}
|
||||||
|
.hero-art{opacity:0;animation:rise 1.1s .3s var(--ease) forwards}
|
||||||
|
.phone--hero{animation:float 7s ease-in-out infinite}
|
||||||
|
@keyframes float{
|
||||||
|
0%,100%{transform:rotate(-3.4deg) translateY(0)}
|
||||||
|
50%{transform:rotate(-3deg) translateY(-10px)}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- 响应式 ---------- */
|
||||||
|
@media (max-width:1080px){
|
||||||
|
.hero-inner{gap:20px}
|
||||||
|
.hero-art{min-height:auto;transform:scale(.94)}
|
||||||
|
.about-inner,.faq-inner{grid-template-columns:1fr;gap:52px}
|
||||||
|
.about-head,.faq-head{position:static}
|
||||||
|
.dl-card{padding:56px 46px;gap:40px}
|
||||||
|
.dl-meta{grid-template-columns:1fr 1fr}
|
||||||
|
}
|
||||||
|
@media (max-width:900px){
|
||||||
|
.wrap,.nav-inner{width:calc(100% - 40px)}
|
||||||
|
.hero{padding:132px 0 72px}
|
||||||
|
.hero-inner{grid-template-columns:1fr;gap:54px}
|
||||||
|
.hero-art{order:2;justify-content:center;transform:none;min-height:0;margin-top:8px}
|
||||||
|
.stamp{display:none}
|
||||||
|
.hand-note{right:4%;bottom:0;font-size:17px}
|
||||||
|
.hand-arrow{display:none}
|
||||||
|
.stamp{left:0;top:-6px;width:104px;height:104px}
|
||||||
|
.promises-grid{grid-template-columns:1fr;gap:26px;padding:38px 0}
|
||||||
|
.promise{display:grid;grid-template-columns:44px 1fr;gap:0 16px;align-items:baseline}
|
||||||
|
.promise h3{margin:0}
|
||||||
|
.promise p{grid-column:2}
|
||||||
|
.hero-meta{display:grid;grid-template-columns:1fr 1fr;gap:6px 12px}
|
||||||
|
.feature{padding:28px 26px 30px;border-radius:18px}
|
||||||
|
.f-ico{width:48px;height:48px}
|
||||||
|
.f-ico svg{width:24px;height:24px}
|
||||||
|
.feature h3{font-size:20px;margin:16px 0 8px}
|
||||||
|
.feature .f-num{right:24px;top:24px}
|
||||||
|
.about{padding:84px 0 78px}
|
||||||
|
.note{padding:44px 34px 38px}
|
||||||
|
.note-body p{font-size:16px}
|
||||||
|
.features{padding:78px 0 84px}
|
||||||
|
.feature-grid{grid-template-columns:1fr;gap:16px;margin-top:40px}
|
||||||
|
.screens{padding:78px 0 92px}
|
||||||
|
.sec-head--row{flex-direction:column;align-items:flex-start;gap:18px}
|
||||||
|
.sec-note{text-align:left}
|
||||||
|
.shots-hint{display:block}
|
||||||
|
.shots{
|
||||||
|
grid-template-columns:none;display:flex;overflow-x:auto;gap:22px;
|
||||||
|
margin:44px -20px 0;padding:0 20px 18px;scroll-snap-type:x mandatory;
|
||||||
|
-webkit-overflow-scrolling:touch;scrollbar-width:none;
|
||||||
|
}
|
||||||
|
.shots::-webkit-scrollbar{display:none}
|
||||||
|
.shot{flex:none;width:300px;scroll-snap-align:center}
|
||||||
|
.shot:nth-child(n) .phone--shot{transform:none}
|
||||||
|
.download{padding-bottom:84px}
|
||||||
|
.dl-card{grid-template-columns:1fr;padding:44px 30px;gap:36px;border-radius:26px}
|
||||||
|
.dl-actions{flex-direction:column;align-items:stretch}
|
||||||
|
.dl-actions .btn{width:100%}
|
||||||
|
.dl-right{align-items:center;text-align:center}
|
||||||
|
.dl-right .qr-hint{text-align:center}
|
||||||
|
.qr-card{transform:none}
|
||||||
|
.faq{padding-bottom:92px}
|
||||||
|
.footer-top{grid-template-columns:1fr;gap:40px}
|
||||||
|
.foot-cols{grid-template-columns:1fr 1fr;gap:24px 20px}
|
||||||
|
}
|
||||||
|
@media (max-width:760px){
|
||||||
|
.nav-links{display:none}
|
||||||
|
.brand{padding:6px 9px;border-radius:13px}
|
||||||
|
.brand img{height:44px}
|
||||||
|
.nav.is-stuck .brand{padding:5px 8px;border-radius:11px}
|
||||||
|
.nav.is-stuck .brand img{height:36px}
|
||||||
|
}
|
||||||
|
@media (max-width:560px){
|
||||||
|
.wrap,.nav-inner{width:calc(100% - 32px)}
|
||||||
|
.hero{padding-top:118px}
|
||||||
|
.hero-title{font-size:clamp(52px,15vw,78px)}
|
||||||
|
.hero-lede{font-size:27px}
|
||||||
|
.hero-desc{font-size:15px}
|
||||||
|
.cta-row{flex-direction:column;align-items:stretch;gap:10px}
|
||||||
|
.cta-row .btn{width:100%}
|
||||||
|
.hero-meta{gap:6px 0;flex-direction:column;font-size:12px}
|
||||||
|
.hero-meta li{padding-right:0}
|
||||||
|
.hero-meta li:not(:last-child)::after{display:none}
|
||||||
|
.hand-note{display:none}
|
||||||
|
.stamp{width:92px;height:92px}
|
||||||
|
.stamp-top{font-size:16px}
|
||||||
|
.stamp-bottom{font-size:9px}
|
||||||
|
.promises-grid{padding:32px 0}
|
||||||
|
.about-sub{font-size:15px}
|
||||||
|
.note{padding:38px 22px 30px}
|
||||||
|
.note-body p{font-size:15.3px;line-height:1.95}
|
||||||
|
.note-body p:first-child::first-letter{font-size:44px}
|
||||||
|
.tape{display:none}
|
||||||
|
.dl-card{padding:36px 22px}
|
||||||
|
.dl-meta{grid-template-columns:1fr 1fr;gap:14px}
|
||||||
|
.dl-meta dd{font-size:13px}
|
||||||
|
.qa summary{font-size:17.5px;padding:22px 0;gap:16px}
|
||||||
|
.qa-body{padding-right:8px;font-size:14.5px}
|
||||||
|
.foot-cols{grid-template-columns:1fr}
|
||||||
|
.foot-legal{margin-top:38px;font-size:11.5px}
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion:reduce){
|
||||||
|
*{animation:none!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
|
||||||
|
.js [data-reveal]{opacity:1;transform:none}
|
||||||
|
.hero-copy > *,.hero-art{opacity:1;transform:none}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页脚备案链接 */
|
||||||
|
.foot-icp{color:rgba(234,223,211,.82);border-bottom:1px solid rgba(234,223,211,.28)}
|
||||||
|
.foot-icp:hover{color:#fff}
|
||||||
95
src/terms.html
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
|
<title>用户协议 · 兜爸心选</title>
|
||||||
|
<meta name="description" content="兜爸心选用户服务协议:账号、下单、支付、配送、退换货与用户行为规范。">
|
||||||
|
<meta name="theme-color" content="#FBF5EC">
|
||||||
|
<link rel="icon" type="image/png" href="assets/favicon.png">
|
||||||
|
<link rel="stylesheet" href="legal.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="top">
|
||||||
|
<a href="/app/" aria-label="返回兜爸心选官网"><img src="assets/brand.webp" alt="兜爸心选"></a>
|
||||||
|
<a class="back" href="/app/">← 返回官网</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article class="paper">
|
||||||
|
<h1>兜爸心选用户服务协议</h1>
|
||||||
|
<p class="meta">更新日期:2026 年 10 月 27 日 生效日期:2026 年 10 月 27 日</p>
|
||||||
|
|
||||||
|
<p class="note">本协议是您与北京臻惠网络科技有限公司(以下简称「我们」)之间,就您下载、安装、注册和使用「兜爸心选」移动应用及相关服务所订立的协议。请您在注册或使用前完整阅读;您勾选同意或实际使用服务,即视为已阅读并接受本协议。</p>
|
||||||
|
|
||||||
|
<h2>一、协议范围</h2>
|
||||||
|
<p>本协议适用于「兜爸心选」移动应用(Android / iOS,应用包名 com.yizhezhe.douba)及通过该应用提供的商品浏览、下单、支付、配送查询与售后等服务。</p>
|
||||||
|
<p>《兜爸心选隐私保护政策》是本协议不可分割的组成部分,与本协议具有同等效力。如本协议与隐私政策存在不一致,就个人信息处理事项以隐私政策为准。</p>
|
||||||
|
|
||||||
|
<h2>二、账号注册与使用</h2>
|
||||||
|
<ul>
|
||||||
|
<li>您可以使用手机号验证码或微信授权方式注册、登录。您应保证所提供的手机号、收货信息真实、准确、有效。</li>
|
||||||
|
<li>账号仅限您本人使用,不得出借、转让、售卖或以其他方式提供给他人使用。</li>
|
||||||
|
<li>您应妥善保管账号及验证码。因您保管不善导致的损失,由您自行承担;发现账号异常时,请及时通过 App 内客服联系我们。</li>
|
||||||
|
<li>未满 14 周岁的未成年人应在监护人陪同下阅读本协议并使用本服务;监护人应对其使用行为进行指导与监督。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>三、商品信息与下单</h2>
|
||||||
|
<ul>
|
||||||
|
<li>商品名称、规格、价格、库存、优惠等信息以您下单时应用内展示为准。因系统延迟、价格标注错误或库存变动导致订单无法履行的,我们会及时通知您并办理退款。</li>
|
||||||
|
<li>您提交订单并完成支付后,订单成立。预售、跨境等特殊商品的发货时间以商品页说明为准。</li>
|
||||||
|
<li>跨境商品可能需要您提供真实姓名与身份证信息用于海关清关,具体见隐私政策。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>四、支付、配送与发票</h2>
|
||||||
|
<ul>
|
||||||
|
<li>我们支持微信支付、支付宝等第三方支付渠道。支付过程由相应支付机构完成,我们不保存您的银行卡号、支付密码等信息。</li>
|
||||||
|
<li>配送范围、时效与运费以下单页展示为准。因地址填写错误、无人签收等原因导致的退回或二次配送费用,由您承担。</li>
|
||||||
|
<li>您可在订单完成后按应用内指引申请电子发票,具体以实际支持情况为准。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>五、退换货与售后</h2>
|
||||||
|
<ul>
|
||||||
|
<li>除生鲜、定制、拆封后影响二次销售等依法不适用无理由退货的商品外,您可在收货后 7 日内申请无理由退货。</li>
|
||||||
|
<li>商品存在质量问题、错发、漏发的,请在签收后及时联系客服并提供必要凭证,我们将按实际情况为您办理退换、补发或退款。</li>
|
||||||
|
<li>退换货商品的完好标准、运费承担及退款到账时间,以应用内售后规则与客服说明为准。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>六、用户行为规范</h2>
|
||||||
|
<p>您承诺不利用本服务从事下列行为:</p>
|
||||||
|
<ul>
|
||||||
|
<li>发布违法、侵权、虚假、骚扰性或违背公序良俗的内容;</li>
|
||||||
|
<li>恶意刷单、套取优惠、利用技术手段干扰系统正常运行;</li>
|
||||||
|
<li>侵犯他人知识产权、商业秘密或个人隐私;</li>
|
||||||
|
<li>其他违反法律法规或损害平台、商家、其他用户合法权益的行为。</li>
|
||||||
|
</ul>
|
||||||
|
<p>如您违反上述约定,我们有权视情节采取限制功能、取消订单、冻结或注销账号等措施,并保留追究法律责任的权利。</p>
|
||||||
|
|
||||||
|
<h2>七、知识产权</h2>
|
||||||
|
<p>本应用内的软件、界面设计、文字、图片、商标及「兜爸心选」品牌标识,其知识产权归我们或相关权利人所有。未经书面许可,任何人不得复制、修改、传播或用于商业用途。</p>
|
||||||
|
|
||||||
|
<h2>八、服务变更、中断与责任限制</h2>
|
||||||
|
<ul>
|
||||||
|
<li>我们可能因系统维护、升级或不可抗力暂停部分服务,并尽可能提前公告。</li>
|
||||||
|
<li>因网络故障、设备故障、第三方支付或物流服务异常等非我们可控原因造成的损失,我们将协助处理,但在法律允许范围内不承担赔偿责任。</li>
|
||||||
|
<li>本协议中任何条款不免除我们因故意或重大过失造成您人身、财产损害依法应承担的责任。</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>九、协议变更与终止</h2>
|
||||||
|
<p>我们可能根据法律法规或业务调整更新本协议,更新后会在应用内或本页面公示。重大变更将再次征得您的同意。您可随时停止使用服务并申请注销账号,注销后的信息处理方式见隐私政策。</p>
|
||||||
|
|
||||||
|
<h2>十、法律适用与争议解决</h2>
|
||||||
|
<p>本协议适用中华人民共和国大陆地区法律。因本协议产生的争议,双方应友好协商;协商不成的,任一方可向被告住所地有管辖权的人民法院提起诉讼。</p>
|
||||||
|
|
||||||
|
<h2>十一、联系我们</h2>
|
||||||
|
<p>客服入口:App 内「我的 → 联系客服」。<br>
|
||||||
|
隐私与个人信息相关事项,请见<a href="/protocol.html">《兜爸心选隐私保护政策》</a>第九节联系方式。</p>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<p class="foot">
|
||||||
|
北京臻惠网络科技有限公司 · <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">京ICP备17065521号</a><br>
|
||||||
|
© 2026 兜爸心选 · <a href="/app/">返回官网</a> · <a href="permissions.html">权限说明</a> · <a href="/protocol.html">隐私政策</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||