init
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"weapp": {
|
||||||
|
"appid": "wx5008ec49a5dba8f9",
|
||||||
|
"privateKeyPath": ".auth/private.wx5008ec49a5dba8f9.key"
|
||||||
|
},
|
||||||
|
"tt": {
|
||||||
|
"appid": "",
|
||||||
|
"token": ""
|
||||||
|
},
|
||||||
|
"alipay": {
|
||||||
|
"appid": "",
|
||||||
|
"identityKeyPath": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEA6pDyEkG4lgI7aGYIy5mRa9QPdOF9NZ8jx++i9QbNSWPU8dnw
|
||||||
|
Ak2IdbIRK9nDk4yKcYjdg7aJe0oW7RVBLaJDmjJoG9knQove81wsyRkZJSiHH+be
|
||||||
|
uxxgw7BSLugsg1qIoEae0A3GDVeAJ3lRHif9Tbml4sjDyKifKONtfUdWdmyayFzu
|
||||||
|
5TLQ+w5lbkGfrgd9ZndSn2uCpQ2yIl3FgZJ9wVuppQmNBiaPLuhonsHA2eVcswD+
|
||||||
|
FLaw1Al5K/hY19LGJVpuvZoH9waHAhlZYo3ffqPkBc4wNNO1JLn5lmmnfiQEA5aA
|
||||||
|
LMNiGDJowU3WpUOt6HRuVk9t5qmhfXgOHGWIQwIDAQABAoIBAQCzWOINvXxiDhDY
|
||||||
|
UPO2oJOE655p0qMGpcgY7gwd5vZ9f7xosycEy71jqCPi8FzOay3Lg0dDlwTlZI/E
|
||||||
|
9HRibOfddV8Os+mFwyZT0o1XsT39oFA4vzBbxmXiGeWsgc7PHCDM01JIZ8+fkeCl
|
||||||
|
zeeM9CyECkdg7/pqaStQexvTJwFgB1ESXphIjCHGcdrfaJzjV0FAPwG6qfoaAg42
|
||||||
|
1aRb4i5C+BFAPS/VzixK9Bf1LOCXe8C3to/6IpOSz2eStbRiiSk9POIeO+Tq1zI/
|
||||||
|
QpWrvgqaU53Ltqbx0yjtndoaTcyDSev4Z/3YSiIl4lAL4j9oxXJFAbLDpHKz3GDH
|
||||||
|
vPIF42epAoGBAP4wLUSd0T7iZRhF/n9grReWU2j9j165/ByWX07AZvcTtjqAbHiI
|
||||||
|
J9SXFfAlWm5ZRn3jvJZKY+QEqtQG1zj4sDmlhe4pjKGVmu+dP+4zaBWwSs/fAYbn
|
||||||
|
4fFpNTg8+DOlKfkPMd2yBvnd9w+f0gmTdMyQBu95v0OPThqtCF0RlhddAoGBAOw8
|
||||||
|
9suJa9kbSLjKGSkUVRYpz0ogAmwWCyvhfId5Iy1uSh9Qwxwru2n8Gh9zb/J9Xp16
|
||||||
|
8FsjIMKdqmr0WomT71AtTQdayXtfzNktrfaKxC02YOzgx7unfkualTZcqtivk9Ap
|
||||||
|
Amz8+z5xJlX1CkPqvHz21ALbhmPv3ewFKpCU1EQfAoGAK8P3x1y07nLknS1QCHaI
|
||||||
|
1wrXCbi+uryjH/j0KAcQs3H9ak06X/ZxhTUOXe7Qhzdv37Uaf3YHhPcYwrD61aBc
|
||||||
|
F1Dcookc4aV0q9UTcNwBC9ryxp/LD4NVb8+BjlFRGvNRKsTm/RjuAo+pPlNyQpvU
|
||||||
|
/HO//fOkbul5tTYdvoiMozECgYAfqN/uUSFp/DUXxsXucnIgwUOtjHKmp6GhpNt6
|
||||||
|
kGp9eS1n2vv694VrY8TgeCkFl3Wpp0M1A5UtX9Hp+Yt0qqXE2f1bwfgEl8ctR+jr
|
||||||
|
hJdb89CzjkBWTtEnMrVSjsK6vXUSzZwsnQ7SxHk9xdQ1W+0c1jt9kowFMq1MJzkY
|
||||||
|
HUoBQwKBgQCX/I1sl06daEIBsya/UEhUwCoKFC2GzLZyJuD1uaPJK6ha4ZtXEWij
|
||||||
|
woAdgoyarmn/np/iiflJQN0xg7Nog/Hp+Jiljn7bShT72s1glauIhtZdXAAAUuEr
|
||||||
|
Pe2MrpbKZi0sgTIm2ZvlaajJQL9aeiY6LFZb8VKK5INuof8d7cy3eg==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"pid":84892,"port":53402}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"generate-mini-app": {
|
||||||
|
"lastCheck": 1781395151320,
|
||||||
|
"checkedAt": "2026-06-14T00:07:00.913Z",
|
||||||
|
"status": "skipped",
|
||||||
|
"reason": "skipped",
|
||||||
|
"skill_builtin_version": "1.0.0",
|
||||||
|
"skill_local_version": "UNKNOWN",
|
||||||
|
"updatedAt": "",
|
||||||
|
"nextCheckAt": "2026-06-14T02:59:11.320Z"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# 医院预约挂号小程序
|
||||||
|
|
||||||
|
基于 **Taro 4.x + React + TypeScript** 的医院预约挂号小程序,配套 **Node.js + Express** 后端 API。
|
||||||
|
|
||||||
|
## 功能概览
|
||||||
|
|
||||||
|
- 医院简介(轮播 Banner + 详细介绍 + 联系方式)
|
||||||
|
- 分栏展示:医院简介 / 科室设置 / 医院荣誉
|
||||||
|
- 预约挂号:选择科室 → 选择医生 → 选择日期时段 → 填写姓名电话
|
||||||
|
- 我的预约:查看列表 / 查看详情 / 取消预约
|
||||||
|
- 预约成功页与温馨提示
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── src/ # 小程序前端(Taro + React + TS)
|
||||||
|
│ ├── pages/ # 5 个页面(3 tabBar + 2 二级页)
|
||||||
|
│ ├── components/ # 通用组件
|
||||||
|
│ ├── services/ # API 请求封装
|
||||||
|
│ ├── store/ # Zustand 状态
|
||||||
|
│ ├── data/ # Mock 数据
|
||||||
|
│ ├── types/ # TS 类型定义
|
||||||
|
│ ├── styles/ # 全局样式
|
||||||
|
│ └── utils/ # 工具函数
|
||||||
|
├── server/ # Node.js 后端 API
|
||||||
|
│ ├── src/
|
||||||
|
│ │ ├── routes/ # 业务路由
|
||||||
|
│ │ ├── data.js # Mock 数据
|
||||||
|
│ │ └── index.js # 入口
|
||||||
|
│ ├── package.json
|
||||||
|
│ └── README.md
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 1. 小程序预览
|
||||||
|
|
||||||
|
项目根目录已配置 Taro 模板,可直接通过 IDE 内的预览服务打开二维码,在微信开发者工具中扫码体验。
|
||||||
|
|
||||||
|
### 2. 启动后端
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd server
|
||||||
|
npm install
|
||||||
|
npm start
|
||||||
|
# 监听 http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
## 后端 API
|
||||||
|
|
||||||
|
详见 [server/README.md](server/README.md)。
|
||||||
|
|
||||||
|
主要接口:
|
||||||
|
- `GET /api/hospitals` — 医院列表
|
||||||
|
- `GET /api/departments` — 科室列表
|
||||||
|
- `GET /api/doctors?departmentId=` — 医生列表
|
||||||
|
- `POST /api/appointments` — 创建预约
|
||||||
|
- `GET /api/appointments?phone=` — 我的预约
|
||||||
|
- `PUT /api/appointments/:id/cancel` — 取消预约
|
||||||
|
|
||||||
|
## 小程序接入真实后端
|
||||||
|
|
||||||
|
修改 `src/services/request.ts` 中的 `BASE_URL`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const BASE_URL = 'http://localhost:3000';
|
||||||
|
```
|
||||||
|
|
||||||
|
然后把 `src/services/*.ts` 中返回 mock 数据的函数改为调用 `request()`,并把 `src/data/*.ts` 删除即可完成对接。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- 前端:Taro 4.1.9、React 18、TypeScript 5、Sass
|
||||||
|
- 后端:Node.js、Express 4、CORS
|
||||||
|
|
||||||
|
## 数据存储
|
||||||
|
|
||||||
|
当前为内存 Mock,重启服务后预约数据会清空。生产环境请替换为 MySQL / PostgreSQL / MongoDB 等持久化方案。
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>苏州肛泰中医院 · 运营管理后台</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" href="./styles.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- 登录页 -->
|
||||||
|
<div id="loginPage" class="login-page">
|
||||||
|
<div class="login-bg-decor">
|
||||||
|
<span class="orb orb-1"></span>
|
||||||
|
<span class="orb orb-2"></span>
|
||||||
|
<span class="orb orb-3"></span>
|
||||||
|
</div>
|
||||||
|
<div class="login-card">
|
||||||
|
<div class="login-brand">
|
||||||
|
<div class="login-logo">🏥</div>
|
||||||
|
<h1 class="login-title">苏州肛泰中医院</h1>
|
||||||
|
<p class="login-subtitle">运营管理后台 · Internal Console</p>
|
||||||
|
</div>
|
||||||
|
<form id="loginForm" class="login-form" autocomplete="off">
|
||||||
|
<div class="form-field">
|
||||||
|
<label for="loginUsername">账号</label>
|
||||||
|
<input id="loginUsername" type="text" placeholder="请输入管理员账号" required />
|
||||||
|
</div>
|
||||||
|
<div class="form-field">
|
||||||
|
<label for="loginPassword">密码</label>
|
||||||
|
<input id="loginPassword" type="password" placeholder="请输入登录密码" required />
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">登 录</button>
|
||||||
|
<p class="login-hint">默认账号 <code>admin</code>,首次登录后请尽快修改密码</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主控制台 -->
|
||||||
|
<div id="appPage" class="app-page hidden">
|
||||||
|
<!-- 顶栏 -->
|
||||||
|
<header class="app-header">
|
||||||
|
<div class="app-header-left">
|
||||||
|
<div class="app-logo">🏥</div>
|
||||||
|
<div>
|
||||||
|
<div class="app-title">苏州肛泰中医院</div>
|
||||||
|
<div class="app-subtitle">运营管理后台 · v2.0</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="app-header-right">
|
||||||
|
<a class="header-link" href="/api/v1/hospitals" target="_blank" rel="noreferrer">API 健康</a>
|
||||||
|
<div class="user-chip" id="userChip">
|
||||||
|
<span class="user-avatar">A</span>
|
||||||
|
<span class="user-name" id="userName">管理员</span>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-ghost btn-sm" id="logoutBtn">退出</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="app-body">
|
||||||
|
<!-- 侧栏 -->
|
||||||
|
<aside class="app-side">
|
||||||
|
<nav class="side-nav" id="sideNav">
|
||||||
|
<a class="side-link" data-route="dashboard"><span class="side-icon">📊</span><span>概览</span></a>
|
||||||
|
<a class="side-link" data-route="homeContent"><span class="side-icon">🏠</span><span>首页内容</span></a>
|
||||||
|
<a class="side-link" data-route="hospitalIntro"><span class="side-icon">🏥</span><span>医院简介</span></a>
|
||||||
|
<a class="side-link" data-route="siteConfig"><span class="side-icon">⚙️</span><span>系统设置</span></a>
|
||||||
|
<a class="side-link" data-route="appointments"><span class="side-icon">📅</span><span>预约管理</span></a>
|
||||||
|
<a class="side-link" data-route="leads"><span class="side-icon">📨</span><span>意向客户</span></a>
|
||||||
|
<a class="side-link" data-route="account"><span class="side-icon">🔐</span><span>账号设置</span></a>
|
||||||
|
</nav>
|
||||||
|
<div class="side-foot">
|
||||||
|
<div class="side-foot-line">© 2026 苏州肛泰中医院</div>
|
||||||
|
<div class="side-foot-line muted">管理后台 v2.0</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<!-- 主区 -->
|
||||||
|
<main class="app-main" id="appMain">
|
||||||
|
<div class="page-loading">加载中…</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 通用 Toast -->
|
||||||
|
<div id="toast" class="toast"></div>
|
||||||
|
|
||||||
|
<!-- 通用 Modal 容器 -->
|
||||||
|
<div id="modal" class="modal hidden">
|
||||||
|
<div class="modal-mask" data-modal-close></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 id="modalTitle">标题</h3>
|
||||||
|
<button class="modal-close" data-modal-close>×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" id="modalBody"></div>
|
||||||
|
<div class="modal-footer" id="modalFooter"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="./app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,616 @@
|
|||||||
|
/*
|
||||||
|
* styles.css
|
||||||
|
* 苏州肛泰中医院 · 运营管理后台视觉系统
|
||||||
|
* 设计原则:医疗专业感 · 克制留白 · 蓝绿主色 · 8pt 间距
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--color-primary: #1f7ae0;
|
||||||
|
--color-primary-light: #4f9bff;
|
||||||
|
--color-primary-dark: #0d5fc4;
|
||||||
|
--color-primary-50: #eaf3ff;
|
||||||
|
--color-accent: #15b9a3;
|
||||||
|
--color-accent-50: #e6faf7;
|
||||||
|
--color-success: #15b9a3;
|
||||||
|
--color-success-bg: #e6faf7;
|
||||||
|
--color-warning: #ff8a00;
|
||||||
|
--color-warning-bg: #fff3e0;
|
||||||
|
--color-error: #e5454b;
|
||||||
|
--color-error-bg: #fdecec;
|
||||||
|
--color-info-bg: #eaf3ff;
|
||||||
|
|
||||||
|
--color-bg-page: #f4f6fa;
|
||||||
|
--color-bg-card: #ffffff;
|
||||||
|
--color-bg-hover: #f0f3f8;
|
||||||
|
--color-bg-elevated: #ffffff;
|
||||||
|
|
||||||
|
--color-text-primary: #0f172a;
|
||||||
|
--color-text-secondary: #475569;
|
||||||
|
--color-text-tertiary: #94a3b8;
|
||||||
|
--color-text-disabled: #cbd5e1;
|
||||||
|
--color-text-white: #ffffff;
|
||||||
|
|
||||||
|
--color-border: #e2e8f0;
|
||||||
|
--color-border-light: #eef1f6;
|
||||||
|
--color-divider: #eef1f6;
|
||||||
|
|
||||||
|
--shadow-xs: 0 1px 2px rgba(15, 23, 42, .04);
|
||||||
|
--shadow-sm: 0 2px 8px rgba(15, 23, 42, .06);
|
||||||
|
--shadow-md: 0 4px 16px rgba(15, 23, 42, .08);
|
||||||
|
--shadow-lg: 0 8px 28px rgba(15, 23, 42, .10);
|
||||||
|
--shadow-xl: 0 16px 48px rgba(15, 23, 42, .14);
|
||||||
|
|
||||||
|
--radius-xs: 4px;
|
||||||
|
--radius-sm: 8px;
|
||||||
|
--radius-md: 12px;
|
||||||
|
--radius-lg: 16px;
|
||||||
|
--radius-xl: 20px;
|
||||||
|
--radius-2xl: 24px;
|
||||||
|
--radius-pill: 999px;
|
||||||
|
|
||||||
|
--spacing-1: 4px;
|
||||||
|
--spacing-2: 8px;
|
||||||
|
--spacing-3: 12px;
|
||||||
|
--spacing-4: 16px;
|
||||||
|
--spacing-5: 20px;
|
||||||
|
--spacing-6: 24px;
|
||||||
|
--spacing-7: 32px;
|
||||||
|
--spacing-8: 40px;
|
||||||
|
--spacing-9: 48px;
|
||||||
|
|
||||||
|
--transition-fast: 0.15s cubic-bezier(.4,0,.2,1);
|
||||||
|
--transition-base: 0.25s cubic-bezier(.4,0,.2,1);
|
||||||
|
|
||||||
|
--gradient-primary: linear-gradient(135deg, #1f7ae0 0%, #15b9a3 100%);
|
||||||
|
--gradient-hero: linear-gradient(160deg, #1f7ae0 0%, #2b80f5 45%, #15b9a3 100%);
|
||||||
|
--gradient-card: linear-gradient(180deg, #ffffff 0%, #fafbfd 100%);
|
||||||
|
|
||||||
|
--font-display: 'Plus Jakarta Sans', 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
--font-body: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
html, body { margin: 0; padding: 0; }
|
||||||
|
body {
|
||||||
|
font-family: var(--font-body);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
button { font-family: inherit; cursor: pointer; }
|
||||||
|
a { color: inherit; text-decoration: none; }
|
||||||
|
code { font-family: 'SF Mono', Menlo, Consolas, monospace; font-size: 12px; background: var(--color-bg-hover); padding: 1px 6px; border-radius: 4px; color: var(--color-primary); }
|
||||||
|
|
||||||
|
.hidden { display: none !important; }
|
||||||
|
|
||||||
|
/* ============== 登录页 ============== */
|
||||||
|
.login-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--gradient-hero);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.login-bg-decor { position: absolute; inset: 0; pointer-events: none; }
|
||||||
|
.orb {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(60px);
|
||||||
|
opacity: .55;
|
||||||
|
animation: float 16s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
.orb-1 { width: 360px; height: 360px; background: #4f9bff; top: -120px; left: -80px; }
|
||||||
|
.orb-2 { width: 280px; height: 280px; background: #15b9a3; bottom: -100px; right: -60px; animation-delay: -4s; }
|
||||||
|
.orb-3 { width: 200px; height: 200px; background: #7ad6ff; top: 40%; right: 20%; animation-delay: -8s; opacity: .35; }
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||||
|
33% { transform: translate(30px, -20px) scale(1.05); }
|
||||||
|
66% { transform: translate(-20px, 30px) scale(.95); }
|
||||||
|
}
|
||||||
|
.login-card {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 420px;
|
||||||
|
margin: 24px;
|
||||||
|
background: rgba(255, 255, 255, .96);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
border-radius: var(--radius-2xl);
|
||||||
|
padding: 40px 36px;
|
||||||
|
box-shadow: 0 30px 60px rgba(13, 95, 196, .25);
|
||||||
|
animation: fadeInUp .5s var(--transition-base) both;
|
||||||
|
}
|
||||||
|
@keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
||||||
|
.login-brand { text-align: center; margin-bottom: 28px; }
|
||||||
|
.login-logo {
|
||||||
|
width: 64px; height: 64px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--gradient-primary);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 32px;
|
||||||
|
border-radius: 18px;
|
||||||
|
box-shadow: 0 8px 24px rgba(31, 122, 224, .35);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.login-title { font-size: 22px; font-weight: 700; margin: 0 0 4px; color: var(--color-text-primary); }
|
||||||
|
.login-subtitle { font-size: 13px; color: var(--color-text-tertiary); margin: 0; }
|
||||||
|
.login-form { display: flex; flex-direction: column; gap: 18px; }
|
||||||
|
.form-field { display: flex; flex-direction: column; gap: 6px; }
|
||||||
|
.form-field label { font-size: 13px; color: var(--color-text-secondary); font-weight: 500; }
|
||||||
|
.form-field input, .form-field select, .form-field textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border: 1.5px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
background: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: inherit;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.form-field input:focus, .form-field select:focus, .form-field textarea:focus {
|
||||||
|
border-color: var(--color-primary);
|
||||||
|
box-shadow: 0 0 0 3px rgba(31, 122, 224, .15);
|
||||||
|
}
|
||||||
|
.form-field textarea { min-height: 80px; resize: vertical; }
|
||||||
|
.login-hint { text-align: center; font-size: 12px; color: var(--color-text-tertiary); margin: 0; }
|
||||||
|
|
||||||
|
/* ============== 按钮 ============== */
|
||||||
|
.btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
background: var(--color-bg-hover);
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.btn:hover { background: var(--color-border-light); }
|
||||||
|
.btn:active { transform: scale(.97); }
|
||||||
|
.btn-primary {
|
||||||
|
background: var(--gradient-primary);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 4px 12px rgba(31, 122, 224, .25);
|
||||||
|
}
|
||||||
|
.btn-primary:hover { box-shadow: 0 6px 18px rgba(31, 122, 224, .35); }
|
||||||
|
.btn-ghost { background: transparent; color: var(--color-text-secondary); }
|
||||||
|
.btn-ghost:hover { background: var(--color-bg-hover); }
|
||||||
|
.btn-danger { background: var(--color-error-bg); color: var(--color-error); }
|
||||||
|
.btn-danger:hover { background: #f9d4d5; }
|
||||||
|
.btn-success { background: var(--color-success-bg); color: var(--color-success); }
|
||||||
|
.btn-warning { background: var(--color-warning-bg); color: var(--color-warning); }
|
||||||
|
.btn-sm { padding: 6px 12px; font-size: 12px; }
|
||||||
|
.btn-block { width: 100%; }
|
||||||
|
.btn-icon { padding: 6px 8px; background: transparent; color: var(--color-text-tertiary); }
|
||||||
|
.btn-icon:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
|
||||||
|
|
||||||
|
/* ============== 主控制台 ============== */
|
||||||
|
.app-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
}
|
||||||
|
.app-header {
|
||||||
|
height: 64px;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 24px;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 50;
|
||||||
|
box-shadow: var(--shadow-xs);
|
||||||
|
}
|
||||||
|
.app-header-left { display: flex; align-items: center; gap: 12px; }
|
||||||
|
.app-logo {
|
||||||
|
width: 40px; height: 40px;
|
||||||
|
background: var(--gradient-primary);
|
||||||
|
color: #fff;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 22px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 12px rgba(31, 122, 224, .25);
|
||||||
|
}
|
||||||
|
.app-title { font-size: 15px; font-weight: 700; color: var(--color-text-primary); }
|
||||||
|
.app-subtitle { font-size: 11px; color: var(--color-text-tertiary); margin-top: 2px; }
|
||||||
|
.app-header-right { display: flex; align-items: center; gap: 16px; }
|
||||||
|
.header-link { font-size: 13px; color: var(--color-text-secondary); }
|
||||||
|
.header-link:hover { color: var(--color-primary); }
|
||||||
|
.user-chip { display: flex; align-items: center; gap: 8px; padding: 4px 12px 4px 4px; background: var(--color-bg-hover); border-radius: 999px; }
|
||||||
|
.user-avatar {
|
||||||
|
width: 28px; height: 28px;
|
||||||
|
background: var(--gradient-primary);
|
||||||
|
color: #fff;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.user-name { font-size: 13px; font-weight: 500; }
|
||||||
|
|
||||||
|
.app-body { display: flex; flex: 1; min-height: 0; }
|
||||||
|
.app-side {
|
||||||
|
width: 220px;
|
||||||
|
background: #fff;
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.side-nav { padding: 16px 12px; flex: 1; display: flex; flex-direction: column; gap: 2px; }
|
||||||
|
.side-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.side-link:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
|
||||||
|
.side-link.active {
|
||||||
|
background: var(--color-primary-50);
|
||||||
|
color: var(--color-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.side-icon { font-size: 16px; width: 20px; text-align: center; }
|
||||||
|
.side-foot { padding: 16px 20px; border-top: 1px solid var(--color-border-light); }
|
||||||
|
.side-foot-line { font-size: 11px; color: var(--color-text-tertiary); }
|
||||||
|
.side-foot-line.muted { color: var(--color-text-disabled); margin-top: 2px; }
|
||||||
|
|
||||||
|
.app-main {
|
||||||
|
flex: 1;
|
||||||
|
padding: 24px 32px;
|
||||||
|
overflow-y: auto;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.page-loading { text-align: center; color: var(--color-text-tertiary); padding: 60px 0; font-size: 14px; }
|
||||||
|
|
||||||
|
/* ============== 页面通用 ============== */
|
||||||
|
.page { animation: fadeIn .35s var(--transition-base) both; }
|
||||||
|
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||||||
|
|
||||||
|
.subtab-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background: #f1f5f9;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
.subtab-bar .subtab {
|
||||||
|
padding: 8px 18px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: all .2s;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.subtab-bar .subtab.active {
|
||||||
|
background: #fff;
|
||||||
|
color: var(--color-primary);
|
||||||
|
font-weight: 600;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
}
|
||||||
|
.subtab-bar .subtab:hover:not(.active) { color: var(--color-text-primary); }
|
||||||
|
|
||||||
|
.page-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.page-title { font-size: 22px; font-weight: 700; margin: 0 0 4px; }
|
||||||
|
.page-desc { font-size: 13px; color: var(--color-text-tertiary); margin: 0; }
|
||||||
|
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||||
|
|
||||||
|
/* ============== 卡片 ============== */
|
||||||
|
.card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 20px 24px;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
border: 1px solid var(--color-border-light);
|
||||||
|
}
|
||||||
|
.card + .card { margin-top: 16px; }
|
||||||
|
.card-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.card-title { font-size: 16px; font-weight: 600; margin: 0; }
|
||||||
|
.card-subtitle { font-size: 12px; color: var(--color-text-tertiary); margin: 2px 0 0; }
|
||||||
|
|
||||||
|
/* ============== 统计卡 ============== */
|
||||||
|
.stats {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.stat-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
border: 1px solid var(--color-border-light);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.stat-card::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0; right: 0;
|
||||||
|
width: 80px; height: 80px;
|
||||||
|
background: var(--color-primary-50);
|
||||||
|
border-radius: 50%;
|
||||||
|
transform: translate(30px, -30px);
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
.stat-label { font-size: 13px; color: var(--color-text-tertiary); margin-bottom: 6px; }
|
||||||
|
.stat-value { font-size: 28px; font-weight: 700; color: var(--color-text-primary); font-family: var(--font-display); }
|
||||||
|
.stat-foot { font-size: 12px; color: var(--color-text-tertiary); margin-top: 6px; }
|
||||||
|
|
||||||
|
/* ============== 工具栏 ============== */
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.toolbar .form-field { flex-direction: row; align-items: center; gap: 8px; }
|
||||||
|
.toolbar input, .toolbar select {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1.5px solid var(--color-border);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
font-size: 13px;
|
||||||
|
outline: none;
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.toolbar input:focus, .toolbar select:focus { border-color: var(--color-primary); }
|
||||||
|
.toolbar input { min-width: 220px; }
|
||||||
|
|
||||||
|
/* ============== 表格 ============== */
|
||||||
|
.table-wrap {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
border: 1px solid var(--color-border-light);
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
|
}
|
||||||
|
table.data-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.data-table thead th {
|
||||||
|
text-align: left;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--color-bg-page);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.data-table tbody td {
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-bottom: 1px solid var(--color-border-light);
|
||||||
|
vertical-align: middle;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
}
|
||||||
|
.data-table tbody tr:last-child td { border-bottom: none; }
|
||||||
|
.data-table tbody tr:hover { background: var(--color-bg-page); }
|
||||||
|
.data-table .avatar-cell { display: flex; align-items: center; gap: 10px; }
|
||||||
|
.data-table .avatar {
|
||||||
|
width: 40px; height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--color-bg-hover);
|
||||||
|
object-fit: cover;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.data-table .name-cell { font-weight: 600; }
|
||||||
|
.data-table .sub { font-size: 12px; color: var(--color-text-tertiary); margin-top: 2px; }
|
||||||
|
.data-table .actions { display: flex; gap: 6px; justify-content: flex-end; }
|
||||||
|
.empty-state { text-align: center; padding: 60px 20px; color: var(--color-text-tertiary); }
|
||||||
|
|
||||||
|
/* ============== 状态标签 ============== */
|
||||||
|
.tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 2px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--color-bg-hover);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
.tag-primary { background: var(--color-primary-50); color: var(--color-primary); }
|
||||||
|
.tag-success { background: var(--color-success-bg); color: var(--color-success); }
|
||||||
|
.tag-warning { background: var(--color-warning-bg); color: var(--color-warning); }
|
||||||
|
.tag-error { background: var(--color-error-bg); color: var(--color-error); }
|
||||||
|
|
||||||
|
/* ============== Toast ============== */
|
||||||
|
.toast {
|
||||||
|
position: fixed;
|
||||||
|
top: 24px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%) translateY(-100%);
|
||||||
|
background: var(--color-text-primary);
|
||||||
|
color: #fff;
|
||||||
|
padding: 10px 18px;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
font-size: 13px;
|
||||||
|
z-index: 9999;
|
||||||
|
transition: transform var(--transition-base), opacity var(--transition-base);
|
||||||
|
opacity: 0;
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
max-width: 80vw;
|
||||||
|
}
|
||||||
|
.toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
|
||||||
|
.toast.success { background: var(--color-success); }
|
||||||
|
.toast.error { background: var(--color-error); }
|
||||||
|
|
||||||
|
/* ============== Modal ============== */
|
||||||
|
.modal {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.modal-mask {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(15, 23, 42, .55);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
animation: fadeIn .2s both;
|
||||||
|
}
|
||||||
|
.modal-card {
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: var(--radius-xl);
|
||||||
|
width: 90%;
|
||||||
|
max-width: 560px;
|
||||||
|
max-height: 90vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-shadow: var(--shadow-xl);
|
||||||
|
animation: modalIn .3s var(--transition-base) both;
|
||||||
|
}
|
||||||
|
@keyframes modalIn { from { opacity: 0; transform: scale(.92) translateY(20px); } to { opacity: 1; transform: scale(1) translateY(0); } }
|
||||||
|
.modal-card.modal-lg { max-width: 760px; }
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20px 24px;
|
||||||
|
border-bottom: 1px solid var(--color-border-light);
|
||||||
|
}
|
||||||
|
.modal-header h3 { font-size: 16px; font-weight: 600; margin: 0; }
|
||||||
|
.modal-close {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
color: var(--color-text-tertiary);
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
width: 28px; height: 28px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
}
|
||||||
|
.modal-close:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
|
||||||
|
.modal-body { padding: 20px 24px; overflow-y: auto; flex: 1; }
|
||||||
|
.modal-body .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
|
||||||
|
.modal-body .form-grid .full { grid-column: 1 / -1; }
|
||||||
|
.modal-footer {
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-top: 1px solid var(--color-border-light);
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============== 开关 ============== */
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 36px; height: 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.switch input { display: none; }
|
||||||
|
.switch .slider {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: var(--color-border);
|
||||||
|
border-radius: 999px;
|
||||||
|
transition: background var(--transition-fast);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.switch .slider::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 2px; left: 2px;
|
||||||
|
width: 16px; height: 16px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: transform var(--transition-fast);
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
.switch input:checked + .slider { background: var(--color-primary); }
|
||||||
|
.switch input:checked + .slider::before { transform: translateX(16px); }
|
||||||
|
|
||||||
|
/* ============== 响应式 ============== */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.app-side { width: 64px; }
|
||||||
|
.side-link span:not(.side-icon) { display: none; }
|
||||||
|
.side-link { justify-content: center; padding: 12px; }
|
||||||
|
.side-foot { display: none; }
|
||||||
|
.app-main { padding: 16px; }
|
||||||
|
.modal-body .form-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============== Leads 问卷答案(Phase 3) ============== */
|
||||||
|
.lead-q {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px dashed var(--color-border-light);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.lead-q:last-child { border-bottom: none; }
|
||||||
|
.lead-qi {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--color-text-tertiary);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.lead-qtext {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.lead-qv {
|
||||||
|
color: var(--color-primary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-ellipsis-2 {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// babel-preset-taro 更多选项和默认值:
|
||||||
|
// https://github.com/NervJS/taro/blob/next/packages/babel-preset-taro/README.md
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'taro',
|
||||||
|
{
|
||||||
|
framework: 'react',
|
||||||
|
ts: 'true',
|
||||||
|
compiler: 'webpack5',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
plugins: [],
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import type { UserConfigExport } from '@tarojs/cli';
|
||||||
|
export default {
|
||||||
|
logger: {
|
||||||
|
quiet: false,
|
||||||
|
stats: true,
|
||||||
|
},
|
||||||
|
mini: {},
|
||||||
|
h5: {
|
||||||
|
devServer: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 53402, // 与 Trae 预览代理的 ws=ws://localhost:53402 对齐
|
||||||
|
open: false,
|
||||||
|
// 允许 Trae 平台公网代理
|
||||||
|
allowedHosts: 'all',
|
||||||
|
client: { overlay: false },
|
||||||
|
// 把 /api/* 反向代理到腾讯云后端,避免 H5 跨域 + 公网代理 IP 直连
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://124.221.67.199:3000',
|
||||||
|
changeOrigin: true,
|
||||||
|
secure: false,
|
||||||
|
logLevel: 'debug',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies UserConfigExport<'webpack5'>;
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { defineConfig, type UserConfigExport } from '@tarojs/cli';
|
||||||
|
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
|
||||||
|
import devConfig from './dev';
|
||||||
|
import prodConfig from './prod';
|
||||||
|
import vitePluginImp from 'vite-plugin-imp';
|
||||||
|
// https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数
|
||||||
|
export default defineConfig<'webpack5'>(async (merge, { command, mode }) => {
|
||||||
|
const baseConfig: UserConfigExport<'webpack5'> = {
|
||||||
|
projectName: 'taro_template',
|
||||||
|
date: '2025-12-10',
|
||||||
|
designWidth: 375,
|
||||||
|
deviceRatio: {
|
||||||
|
640: 2.34 / 2,
|
||||||
|
750: 1,
|
||||||
|
375: 2,
|
||||||
|
828: 1.81 / 2,
|
||||||
|
},
|
||||||
|
sourceRoot: 'src',
|
||||||
|
outputRoot: process.env.TARO_OUTPUT_DIR || 'dist',
|
||||||
|
plugins: ['@tarojs/plugin-html'],
|
||||||
|
defineConstants: {},
|
||||||
|
copy: {
|
||||||
|
patterns: [],
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
framework: 'react',
|
||||||
|
compiler: {
|
||||||
|
type: 'webpack5',
|
||||||
|
prebundle: {
|
||||||
|
enable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cache: {
|
||||||
|
enable: false, // Webpack 持久化缓存配置,建议开启。默认配置请参考:https://docs.taro.zone/docs/config-detail#cache
|
||||||
|
},
|
||||||
|
mini: {
|
||||||
|
postcss: {
|
||||||
|
pxtransform: {
|
||||||
|
enable: true,
|
||||||
|
config: {
|
||||||
|
selectorBlackList: ['nut-'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cssModules: {
|
||||||
|
enable: true, // 开启 CSS Modules
|
||||||
|
config: {
|
||||||
|
namingPattern: 'module', // 仅 *.module.scss 生效
|
||||||
|
generateScopedName: '[name]__[local]___[hash:base64:5]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
webpackChain(chain) {
|
||||||
|
chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
h5: {
|
||||||
|
publicPath: '/',
|
||||||
|
staticDirectory: 'static',
|
||||||
|
output: {
|
||||||
|
filename: 'js/[name].[hash:8].js',
|
||||||
|
chunkFilename: 'js/[name].[chunkhash:8].js',
|
||||||
|
},
|
||||||
|
miniCssExtractPluginOption: {
|
||||||
|
ignoreOrder: true,
|
||||||
|
filename: 'css/[name].[hash].css',
|
||||||
|
chunkFilename: 'css/[name].[chunkhash].css',
|
||||||
|
},
|
||||||
|
postcss: {
|
||||||
|
autoprefixer: {
|
||||||
|
enable: true,
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
cssModules: {
|
||||||
|
enable: true, // 开启 CSS Modules
|
||||||
|
config: {
|
||||||
|
namingPattern: 'module', // 仅 *.module.scss 生效
|
||||||
|
generateScopedName: '[name]__[local]___[hash:base64:5]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
pxtransform: {
|
||||||
|
enable: true,
|
||||||
|
config: {
|
||||||
|
selectorBlackList: ['body'],
|
||||||
|
baseFontSize: 37.5,
|
||||||
|
unitPrecision: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
webpackChain(chain) {
|
||||||
|
chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rn: {
|
||||||
|
appName: 'taroDemo',
|
||||||
|
postcss: {
|
||||||
|
cssModules: {
|
||||||
|
enable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
// 本地开发构建配置(不混淆压缩)
|
||||||
|
return merge({}, baseConfig, devConfig);
|
||||||
|
}
|
||||||
|
// 生产构建配置(默认开启压缩混淆等)
|
||||||
|
return merge({}, baseConfig, prodConfig);
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import type { UserConfigExport } from '@tarojs/cli';
|
||||||
|
export default {
|
||||||
|
mini: {},
|
||||||
|
h5: {},
|
||||||
|
} satisfies UserConfigExport<'webpack5'>;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react-reconciler-constants.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react-reconciler.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* scheduler.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"pages":["pages/home/index","pages/hospital/index","pages/appointment/index","pages/self-test/index","pages/phone-consult/index","pages/mine/index","pages/success/index","pages/center/index"],"window":{"backgroundTextStyle":"light","navigationBarBackgroundColor":"#1f7ae0","navigationBarTitleText":"苏州肛泰中医院","navigationBarTextStyle":"white","backgroundColor":"#f4f6fa"},"tabBar":{"custom":true,"color":"#94a3b8","selectedColor":"#1f7ae0","backgroundColor":"#ffffff","borderStyle":"white","list":[{"pagePath":"pages/home/index","text":"首页","iconPath":"assets/tabbar/home.png","selectedIconPath":"assets/tabbar/home_selected.png"},{"pagePath":"pages/hospital/index","text":"医院简介","iconPath":"assets/tabbar/hospital.png","selectedIconPath":"assets/tabbar/hospital_selected.png"},{"pagePath":"pages/appointment/index","text":"自助预约","iconPath":"assets/tabbar/appointment.png","selectedIconPath":"assets/tabbar/appointment_selected.png"},{"pagePath":"pages/self-test/index","text":"在线自测","iconPath":"assets/tabbar/self-test.png","selectedIconPath":"assets/tabbar/self-test_selected.png"},{"pagePath":"pages/phone-consult/index","text":"电话咨询","iconPath":"assets/tabbar/phone.png","selectedIconPath":"assets/tabbar/phone_selected.png"}]}}
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
@@ -0,0 +1,749 @@
|
|||||||
|
<wxs module="xs" src="./utils.wxs" />
|
||||||
|
<template name="taro_tmpl">
|
||||||
|
<template is="{{xs.a(0, item.nn, '')}}" data="{{i:item,c:1,l:xs.f('',item.nn)}}" wx:for="{{root.cn}}" wx:key="sid" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_5">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_14">
|
||||||
|
<button size="{{i.p18||'default'}}" type="{{i.p19}}" plain="{{xs.b(i.p12,!1)}}" disabled="{{i.p2}}" loading="{{xs.b(i.p9,!1)}}" form-type="{{i.p3}}" open-type="{{i.p11}}" hover-class="{{i.p4||'button-hover'}}" hover-stop-propagation="{{xs.b(i.p7,!1)}}" hover-start-time="{{xs.b(i.p5,20)}}" hover-stay-time="{{xs.b(i.p6,70)}}" name="{{i.p10}}" bindagreeprivacyauthorization="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" lang="{{i.p8||en}}" session-from="{{i.p16}}" send-message-title="{{i.p15}}" send-message-path="{{i.p14}}" send-message-img="{{i.p13}}" app-parameter="{{i.p0}}" show-message-card="{{xs.b(i.p17,false)}}" business-id="{{i.p1}}" bindgetuserinfo="eh" bindcontact="eh" bindgetphonenumber="eh" bindgetrealtimephonenumber="eh" bindchooseavatar="eh" binderror="eh" bindopensetting="eh" bindlaunchapp="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_33">
|
||||||
|
<template is="{{xs.c(i, 'tmpl_0_')}}" data="{{i:i,c:c}}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_33_focus">
|
||||||
|
<input value="{{i.p25}}" type="{{i.p24||''}}" password="{{xs.b(i.p12,!1)}}" placeholder="{{i.p13}}" placeholder-style="{{i.p15}}" placeholder-class="{{i.p14||'input-placeholder'}}" disabled="{{i.p8}}" maxlength="{{xs.b(i.p10,140)}}" cursor-spacing="{{xs.b(i.p7,0)}}" focus="{{xs.b(i.focus,!1)}}" confirm-type="{{i.p4||'done'}}" confirm-hold="{{xs.b(i.p3,!1)}}" cursor="{{xs.b(i.p5,-1)}}" selection-start="{{xs.b(i.p23,-1)}}" selection-end="{{xs.b(i.p22,-1)}}" bindinput="eh" bindfocus="eh" bindblur="eh" bindconfirm="eh" name="{{i.p11}}" always-embed="{{xs.b(i.p1,false)}}" adjust-position="{{xs.b(i.p0,true)}}" hold-keyboard="{{xs.b(i.p9,false)}}" safe-password-cert-path="{{i.p16}}" safe-password-length="{{i.p18}}" safe-password-time-stamp="{{i.p21}}" safe-password-nonce="{{i.p19}}" safe-password-salt="{{i.p20}}" safe-password-custom-hash="{{i.p17}}" auto-fill="{{i.p2}}" cursor-color="{{i.p6}}" bindkeyboardheightchange="eh" bindnicknamereview="eh" bindselectionchange="eh" bindkeyboardcompositionstart="eh" bindkeyboardcompositionupdate="eh" bindkeyboardcompositionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}"></input>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_33_blur">
|
||||||
|
<input value="{{i.p25}}" type="{{i.p24||''}}" password="{{xs.b(i.p12,!1)}}" placeholder="{{i.p13}}" placeholder-style="{{i.p15}}" placeholder-class="{{i.p14||'input-placeholder'}}" disabled="{{i.p8}}" maxlength="{{xs.b(i.p10,140)}}" cursor-spacing="{{xs.b(i.p7,0)}}" confirm-type="{{i.p4||'done'}}" confirm-hold="{{xs.b(i.p3,!1)}}" cursor="{{xs.b(i.p5,-1)}}" selection-start="{{xs.b(i.p23,-1)}}" selection-end="{{xs.b(i.p22,-1)}}" bindinput="eh" bindfocus="eh" bindblur="eh" bindconfirm="eh" name="{{i.p11}}" always-embed="{{xs.b(i.p1,false)}}" adjust-position="{{xs.b(i.p0,true)}}" hold-keyboard="{{xs.b(i.p9,false)}}" safe-password-cert-path="{{i.p16}}" safe-password-length="{{i.p18}}" safe-password-time-stamp="{{i.p21}}" safe-password-nonce="{{i.p19}}" safe-password-salt="{{i.p20}}" safe-password-custom-hash="{{i.p17}}" auto-fill="{{i.p2}}" cursor-color="{{i.p6}}" bindkeyboardheightchange="eh" bindnicknamereview="eh" bindselectionchange="eh" bindkeyboardcompositionstart="eh" bindkeyboardcompositionupdate="eh" bindkeyboardcompositionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}"></input>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_35">
|
||||||
|
<label for="{{i.p0}}" name="{{i.p1}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_56">
|
||||||
|
<picker mode="{{i.p6||'selector'}}" disabled="{{i.p1}}" range="{{i.p8}}" range-key="{{i.p9}}" value="{{i.p11}}" start="{{i.p10}}" end="{{i.p2}}" fields="{{i.p3||'day'}}" custom-item="{{i.p0}}" name="{{i.p7}}" bindcancel="eh" bindchange="eh" bindcolumnchange="eh" header-text="{{i.p4}}" level="{{i.p5||region}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</picker>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_79">
|
||||||
|
<template is="{{xs.c(i, 'tmpl_0_')}}" data="{{i:i,c:c}}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_79_focus">
|
||||||
|
<textarea value="{{i.p20}}" placeholder="{{i.p14}}" placeholder-style="{{i.p16}}" placeholder-class="{{i.p15||'textarea-placeholder'}}" disabled="{{i.p9}}" maxlength="{{xs.b(i.p12,140)}}" auto-focus="{{xs.b(i.p2,!1)}}" focus="{{xs.b(i.focus,!1)}}" auto-height="{{xs.b(i.p3,!1)}}" fixed="{{xs.b(i.p10,!1)}}" cursor-spacing="{{xs.b(i.p7,0)}}" cursor="{{xs.b(i.p6,-1)}}" selection-start="{{xs.b(i.p18,-1)}}" selection-end="{{xs.b(i.p17,-1)}}" bindfocus="eh" bindblur="eh" bindlinechange="eh" bindinput="eh" bindconfirm="eh" name="{{i.p13}}" show-confirm-bar="{{xs.b(i.p19,true)}}" adjust-position="{{xs.b(i.p1,true)}}" hold-keyboard="{{xs.b(i.p11,false)}}" disable-default-padding="{{xs.b(i.p8,false)}}" confirm-type="{{i.p5||'return'}}" confirm-hold="{{xs.b(i.p4,false)}}" adjust-keyboard-to="{{i.p0||'cursor'}}" bindkeyboardheightchange="eh" bindselectionchange="eh" bindkeyboardcompositionstart="eh" bindkeyboardcompositionupdate="eh" bindkeyboardcompositionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}"></textarea>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_79_blur">
|
||||||
|
<textarea value="{{i.p20}}" placeholder="{{i.p14}}" placeholder-style="{{i.p16}}" placeholder-class="{{i.p15||'textarea-placeholder'}}" disabled="{{i.p9}}" maxlength="{{xs.b(i.p12,140)}}" auto-focus="{{xs.b(i.p2,!1)}}" auto-height="{{xs.b(i.p3,!1)}}" fixed="{{xs.b(i.p10,!1)}}" cursor-spacing="{{xs.b(i.p7,0)}}" cursor="{{xs.b(i.p6,-1)}}" selection-start="{{xs.b(i.p18,-1)}}" selection-end="{{xs.b(i.p17,-1)}}" bindfocus="eh" bindblur="eh" bindlinechange="eh" bindinput="eh" bindconfirm="eh" name="{{i.p13}}" show-confirm-bar="{{xs.b(i.p19,true)}}" adjust-position="{{xs.b(i.p1,true)}}" hold-keyboard="{{xs.b(i.p11,false)}}" disable-default-padding="{{xs.b(i.p8,false)}}" confirm-type="{{i.p5||'return'}}" confirm-hold="{{xs.b(i.p4,false)}}" adjust-keyboard-to="{{i.p0||'cursor'}}" bindkeyboardheightchange="eh" bindselectionchange="eh" bindkeyboardcompositionstart="eh" bindkeyboardcompositionupdate="eh" bindkeyboardcompositionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}"></textarea>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_66">
|
||||||
|
<scroll-view scroll-x="{{xs.b(i.p34,!1)}}" scroll-y="{{xs.b(i.p35,!1)}}" upper-threshold="{{xs.b(i.p38,50)}}" lower-threshold="{{xs.b(i.p10,50)}}" scroll-top="{{i.p32}}" scroll-left="{{i.p31}}" scroll-into-view="{{i.p28}}" scroll-with-animation="{{xs.b(i.p33,!1)}}" enable-back-to-top="{{xs.b(i.p5,false)}}" bindscrolltoupper="eh" bindscrolltolower="eh" bindscroll="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" enable-flex="{{xs.b(i.p6,false)}}" scroll-anchoring="{{xs.b(i.p27,false)}}" enhanced="{{xs.b(i.p8,false)}}" using-sticky="{{xs.b(i.p39,false)}}" paging-enabled="{{xs.b(i.p13,false)}}" enable-passive="{{xs.b(i.p7,false)}}" refresher-enabled="{{xs.b(i.p17,false)}}" refresher-threshold="{{xs.b(i.p18,45)}}" refresher-default-style="{{i.p16||'black'}}" refresher-background="{{i.p14||'#FFF'}}" refresher-triggered="{{xs.b(i.p19,false)}}" bounces="{{xs.b(i.p2,true)}}" show-scrollbar="{{xs.b(i.p36,true)}}" fast-deceleration="{{xs.b(i.p9,false)}}" type="{{i.p37||'list'}}" associative-container="{{i.p1||''}}" reverse="{{xs.b(i.p26,false)}}" clip="{{xs.b(i.p4,true)}}" cache-extent="{{i.p3}}" min-drag-distance="{{xs.b(i.p11,18)}}" scroll-into-view-within-extent="{{xs.b(i.p30,false)}}" scroll-into-view-alignment="{{i.p29||'start'}}" padding="{{i.p12||[0,0,0,0]}}" refresher-two-level-enabled="{{xs.b(i.p21,false)}}" refresher-two-level-triggered="{{xs.b(i.p25,false)}}" refresher-two-level-threshold="{{xs.b(i.p24,150)}}" refresher-two-level-close-threshold="{{xs.b(i.p20,80)}}" refresher-two-level-scroll-enabled="{{xs.b(i.p23,false)}}" refresher-ballistic-refresh-enabled="{{xs.b(i.p15,false)}}" refresher-two-level-pinned="{{xs.b(i.p22,false)}}" binddragstart="eh" binddragging="eh" binddragend="eh" bindrefresherpulling="eh" bindrefresherrefresh="eh" bindrefresherrestore="eh" bindrefresherabort="eh" bindscrollstart="eh" bindscrollend="eh" bindrefresherwillrefresh="eh" bindrefresherstatuschange="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</scroll-view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_75">
|
||||||
|
<swiper indicator-dots="{{xs.b(i.p10,!1)}}" indicator-color="{{i.p9||'rgba(0, 0, 0, .3)'}}" indicator-active-color="{{i.p7||'#000000'}}" autoplay="{{xs.b(i.p0,!1)}}" current="{{xs.b(i.p3,0)}}" interval="{{xs.b(i.p18,5000)}}" duration="{{xs.b(i.p5,500)}}" circular="{{xs.b(i.p2,!1)}}" vertical="{{xs.b(i.p25,!1)}}" previous-margin="{{i.p21||'0px'}}" next-margin="{{i.p20||'0px'}}" display-multiple-items="{{xs.b(i.p4,1)}}" bindchange="eh" bindtransition="eh" bindanimationfinish="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" snap-to-edge="{{xs.b(i.p23,false)}}" easing-function="{{i.p6||'default'}}" layout-type="{{i.p19||'normal'}}" transformer-type="{{i.p24||'scaleAndFade'}}" indicator-type="{{i.p16||'normal'}}" indicator-margin="{{xs.b(i.p12,10)}}" indicator-spacing="{{xs.b(i.p15,4)}}" indicator-radius="{{xs.b(i.p14,4)}}" indicator-width="{{xs.b(i.p17,8)}}" indicator-height="{{xs.b(i.p11,8)}}" indicator-alignment="{{i.p8||'auto'}}" indicator-offset="{{i.p13||[0, 0]}}" scroll-with-animation="{{xs.b(i.p22,true)}}" cache-extent="{{xs.b(i.p1,0)}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_76">
|
||||||
|
<swiper-item item-id="{{i.p0}}" skip-hidden-item-layout="{{xs.b(i.p1,false)}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_4">
|
||||||
|
<image src="{{i.p4}}" mode="{{i.p2||'scaleToFill'}}" lazy-load="{{xs.b(i.p1,!1)}}" webp="{{xs.b(i.p5,false)}}" show-menu-by-longpress="{{xs.b(i.p3,false)}}" fade-in="{{xs.b(i.p0,false)}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</image>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_2">
|
||||||
|
<image src="{{i.p4}}" mode="{{i.p2||'scaleToFill'}}" lazy-load="{{xs.b(i.p1,!1)}}" binderror="eh" bindload="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" webp="{{xs.b(i.p5,false)}}" show-menu-by-longpress="{{xs.b(i.p3,false)}}" fade-in="{{xs.b(i.p0,false)}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</image>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_0_9">
|
||||||
|
<block>{{i.v}}</block>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_5">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_35">
|
||||||
|
<label for="{{i.p0}}" name="{{i.p1}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_66">
|
||||||
|
<scroll-view scroll-x="{{xs.b(i.p34,!1)}}" scroll-y="{{xs.b(i.p35,!1)}}" upper-threshold="{{xs.b(i.p38,50)}}" lower-threshold="{{xs.b(i.p10,50)}}" scroll-top="{{i.p32}}" scroll-left="{{i.p31}}" scroll-into-view="{{i.p28}}" scroll-with-animation="{{xs.b(i.p33,!1)}}" enable-back-to-top="{{xs.b(i.p5,false)}}" bindscrolltoupper="eh" bindscrolltolower="eh" bindscroll="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" enable-flex="{{xs.b(i.p6,false)}}" scroll-anchoring="{{xs.b(i.p27,false)}}" enhanced="{{xs.b(i.p8,false)}}" using-sticky="{{xs.b(i.p39,false)}}" paging-enabled="{{xs.b(i.p13,false)}}" enable-passive="{{xs.b(i.p7,false)}}" refresher-enabled="{{xs.b(i.p17,false)}}" refresher-threshold="{{xs.b(i.p18,45)}}" refresher-default-style="{{i.p16||'black'}}" refresher-background="{{i.p14||'#FFF'}}" refresher-triggered="{{xs.b(i.p19,false)}}" bounces="{{xs.b(i.p2,true)}}" show-scrollbar="{{xs.b(i.p36,true)}}" fast-deceleration="{{xs.b(i.p9,false)}}" type="{{i.p37||'list'}}" associative-container="{{i.p1||''}}" reverse="{{xs.b(i.p26,false)}}" clip="{{xs.b(i.p4,true)}}" cache-extent="{{i.p3}}" min-drag-distance="{{xs.b(i.p11,18)}}" scroll-into-view-within-extent="{{xs.b(i.p30,false)}}" scroll-into-view-alignment="{{i.p29||'start'}}" padding="{{i.p12||[0,0,0,0]}}" refresher-two-level-enabled="{{xs.b(i.p21,false)}}" refresher-two-level-triggered="{{xs.b(i.p25,false)}}" refresher-two-level-threshold="{{xs.b(i.p24,150)}}" refresher-two-level-close-threshold="{{xs.b(i.p20,80)}}" refresher-two-level-scroll-enabled="{{xs.b(i.p23,false)}}" refresher-ballistic-refresh-enabled="{{xs.b(i.p15,false)}}" refresher-two-level-pinned="{{xs.b(i.p22,false)}}" binddragstart="eh" binddragging="eh" binddragend="eh" bindrefresherpulling="eh" bindrefresherrefresh="eh" bindrefresherrestore="eh" bindrefresherabort="eh" bindscrollstart="eh" bindscrollend="eh" bindrefresherwillrefresh="eh" bindrefresherstatuschange="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</scroll-view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_75">
|
||||||
|
<swiper indicator-dots="{{xs.b(i.p10,!1)}}" indicator-color="{{i.p9||'rgba(0, 0, 0, .3)'}}" indicator-active-color="{{i.p7||'#000000'}}" autoplay="{{xs.b(i.p0,!1)}}" current="{{xs.b(i.p3,0)}}" interval="{{xs.b(i.p18,5000)}}" duration="{{xs.b(i.p5,500)}}" circular="{{xs.b(i.p2,!1)}}" vertical="{{xs.b(i.p25,!1)}}" previous-margin="{{i.p21||'0px'}}" next-margin="{{i.p20||'0px'}}" display-multiple-items="{{xs.b(i.p4,1)}}" bindchange="eh" bindtransition="eh" bindanimationfinish="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" snap-to-edge="{{xs.b(i.p23,false)}}" easing-function="{{i.p6||'default'}}" layout-type="{{i.p19||'normal'}}" transformer-type="{{i.p24||'scaleAndFade'}}" indicator-type="{{i.p16||'normal'}}" indicator-margin="{{xs.b(i.p12,10)}}" indicator-spacing="{{xs.b(i.p15,4)}}" indicator-radius="{{xs.b(i.p14,4)}}" indicator-width="{{xs.b(i.p17,8)}}" indicator-height="{{xs.b(i.p11,8)}}" indicator-alignment="{{i.p8||'auto'}}" indicator-offset="{{i.p13||[0, 0]}}" scroll-with-animation="{{xs.b(i.p22,true)}}" cache-extent="{{xs.b(i.p1,0)}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_1_76">
|
||||||
|
<swiper-item item-id="{{i.p0}}" skip-hidden-item-layout="{{xs.b(i.p1,false)}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_5">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_35">
|
||||||
|
<label for="{{i.p0}}" name="{{i.p1}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_66">
|
||||||
|
<scroll-view scroll-x="{{xs.b(i.p34,!1)}}" scroll-y="{{xs.b(i.p35,!1)}}" upper-threshold="{{xs.b(i.p38,50)}}" lower-threshold="{{xs.b(i.p10,50)}}" scroll-top="{{i.p32}}" scroll-left="{{i.p31}}" scroll-into-view="{{i.p28}}" scroll-with-animation="{{xs.b(i.p33,!1)}}" enable-back-to-top="{{xs.b(i.p5,false)}}" bindscrolltoupper="eh" bindscrolltolower="eh" bindscroll="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" enable-flex="{{xs.b(i.p6,false)}}" scroll-anchoring="{{xs.b(i.p27,false)}}" enhanced="{{xs.b(i.p8,false)}}" using-sticky="{{xs.b(i.p39,false)}}" paging-enabled="{{xs.b(i.p13,false)}}" enable-passive="{{xs.b(i.p7,false)}}" refresher-enabled="{{xs.b(i.p17,false)}}" refresher-threshold="{{xs.b(i.p18,45)}}" refresher-default-style="{{i.p16||'black'}}" refresher-background="{{i.p14||'#FFF'}}" refresher-triggered="{{xs.b(i.p19,false)}}" bounces="{{xs.b(i.p2,true)}}" show-scrollbar="{{xs.b(i.p36,true)}}" fast-deceleration="{{xs.b(i.p9,false)}}" type="{{i.p37||'list'}}" associative-container="{{i.p1||''}}" reverse="{{xs.b(i.p26,false)}}" clip="{{xs.b(i.p4,true)}}" cache-extent="{{i.p3}}" min-drag-distance="{{xs.b(i.p11,18)}}" scroll-into-view-within-extent="{{xs.b(i.p30,false)}}" scroll-into-view-alignment="{{i.p29||'start'}}" padding="{{i.p12||[0,0,0,0]}}" refresher-two-level-enabled="{{xs.b(i.p21,false)}}" refresher-two-level-triggered="{{xs.b(i.p25,false)}}" refresher-two-level-threshold="{{xs.b(i.p24,150)}}" refresher-two-level-close-threshold="{{xs.b(i.p20,80)}}" refresher-two-level-scroll-enabled="{{xs.b(i.p23,false)}}" refresher-ballistic-refresh-enabled="{{xs.b(i.p15,false)}}" refresher-two-level-pinned="{{xs.b(i.p22,false)}}" binddragstart="eh" binddragging="eh" binddragend="eh" bindrefresherpulling="eh" bindrefresherrefresh="eh" bindrefresherrestore="eh" bindrefresherabort="eh" bindscrollstart="eh" bindscrollend="eh" bindrefresherwillrefresh="eh" bindrefresherstatuschange="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</scroll-view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_75">
|
||||||
|
<swiper indicator-dots="{{xs.b(i.p10,!1)}}" indicator-color="{{i.p9||'rgba(0, 0, 0, .3)'}}" indicator-active-color="{{i.p7||'#000000'}}" autoplay="{{xs.b(i.p0,!1)}}" current="{{xs.b(i.p3,0)}}" interval="{{xs.b(i.p18,5000)}}" duration="{{xs.b(i.p5,500)}}" circular="{{xs.b(i.p2,!1)}}" vertical="{{xs.b(i.p25,!1)}}" previous-margin="{{i.p21||'0px'}}" next-margin="{{i.p20||'0px'}}" display-multiple-items="{{xs.b(i.p4,1)}}" bindchange="eh" bindtransition="eh" bindanimationfinish="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" snap-to-edge="{{xs.b(i.p23,false)}}" easing-function="{{i.p6||'default'}}" layout-type="{{i.p19||'normal'}}" transformer-type="{{i.p24||'scaleAndFade'}}" indicator-type="{{i.p16||'normal'}}" indicator-margin="{{xs.b(i.p12,10)}}" indicator-spacing="{{xs.b(i.p15,4)}}" indicator-radius="{{xs.b(i.p14,4)}}" indicator-width="{{xs.b(i.p17,8)}}" indicator-height="{{xs.b(i.p11,8)}}" indicator-alignment="{{i.p8||'auto'}}" indicator-offset="{{i.p13||[0, 0]}}" scroll-with-animation="{{xs.b(i.p22,true)}}" cache-extent="{{xs.b(i.p1,0)}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_2_76">
|
||||||
|
<swiper-item item-id="{{i.p0}}" skip-hidden-item-layout="{{xs.b(i.p1,false)}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_5">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_35">
|
||||||
|
<label for="{{i.p0}}" name="{{i.p1}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_66">
|
||||||
|
<scroll-view scroll-x="{{xs.b(i.p34,!1)}}" scroll-y="{{xs.b(i.p35,!1)}}" upper-threshold="{{xs.b(i.p38,50)}}" lower-threshold="{{xs.b(i.p10,50)}}" scroll-top="{{i.p32}}" scroll-left="{{i.p31}}" scroll-into-view="{{i.p28}}" scroll-with-animation="{{xs.b(i.p33,!1)}}" enable-back-to-top="{{xs.b(i.p5,false)}}" bindscrolltoupper="eh" bindscrolltolower="eh" bindscroll="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" enable-flex="{{xs.b(i.p6,false)}}" scroll-anchoring="{{xs.b(i.p27,false)}}" enhanced="{{xs.b(i.p8,false)}}" using-sticky="{{xs.b(i.p39,false)}}" paging-enabled="{{xs.b(i.p13,false)}}" enable-passive="{{xs.b(i.p7,false)}}" refresher-enabled="{{xs.b(i.p17,false)}}" refresher-threshold="{{xs.b(i.p18,45)}}" refresher-default-style="{{i.p16||'black'}}" refresher-background="{{i.p14||'#FFF'}}" refresher-triggered="{{xs.b(i.p19,false)}}" bounces="{{xs.b(i.p2,true)}}" show-scrollbar="{{xs.b(i.p36,true)}}" fast-deceleration="{{xs.b(i.p9,false)}}" type="{{i.p37||'list'}}" associative-container="{{i.p1||''}}" reverse="{{xs.b(i.p26,false)}}" clip="{{xs.b(i.p4,true)}}" cache-extent="{{i.p3}}" min-drag-distance="{{xs.b(i.p11,18)}}" scroll-into-view-within-extent="{{xs.b(i.p30,false)}}" scroll-into-view-alignment="{{i.p29||'start'}}" padding="{{i.p12||[0,0,0,0]}}" refresher-two-level-enabled="{{xs.b(i.p21,false)}}" refresher-two-level-triggered="{{xs.b(i.p25,false)}}" refresher-two-level-threshold="{{xs.b(i.p24,150)}}" refresher-two-level-close-threshold="{{xs.b(i.p20,80)}}" refresher-two-level-scroll-enabled="{{xs.b(i.p23,false)}}" refresher-ballistic-refresh-enabled="{{xs.b(i.p15,false)}}" refresher-two-level-pinned="{{xs.b(i.p22,false)}}" binddragstart="eh" binddragging="eh" binddragend="eh" bindrefresherpulling="eh" bindrefresherrefresh="eh" bindrefresherrestore="eh" bindrefresherabort="eh" bindscrollstart="eh" bindscrollend="eh" bindrefresherwillrefresh="eh" bindrefresherstatuschange="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</scroll-view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_75">
|
||||||
|
<swiper indicator-dots="{{xs.b(i.p10,!1)}}" indicator-color="{{i.p9||'rgba(0, 0, 0, .3)'}}" indicator-active-color="{{i.p7||'#000000'}}" autoplay="{{xs.b(i.p0,!1)}}" current="{{xs.b(i.p3,0)}}" interval="{{xs.b(i.p18,5000)}}" duration="{{xs.b(i.p5,500)}}" circular="{{xs.b(i.p2,!1)}}" vertical="{{xs.b(i.p25,!1)}}" previous-margin="{{i.p21||'0px'}}" next-margin="{{i.p20||'0px'}}" display-multiple-items="{{xs.b(i.p4,1)}}" bindchange="eh" bindtransition="eh" bindanimationfinish="eh" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" snap-to-edge="{{xs.b(i.p23,false)}}" easing-function="{{i.p6||'default'}}" layout-type="{{i.p19||'normal'}}" transformer-type="{{i.p24||'scaleAndFade'}}" indicator-type="{{i.p16||'normal'}}" indicator-margin="{{xs.b(i.p12,10)}}" indicator-spacing="{{xs.b(i.p15,4)}}" indicator-radius="{{xs.b(i.p14,4)}}" indicator-width="{{xs.b(i.p17,8)}}" indicator-height="{{xs.b(i.p11,8)}}" indicator-alignment="{{i.p8||'auto'}}" indicator-offset="{{i.p13||[0, 0]}}" scroll-with-animation="{{xs.b(i.p22,true)}}" cache-extent="{{xs.b(i.p1,0)}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_3_76">
|
||||||
|
<swiper-item item-id="{{i.p0}}" skip-hidden-item-layout="{{xs.b(i.p1,false)}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</swiper-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_5">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_4_35">
|
||||||
|
<label for="{{i.p0}}" name="{{i.p1}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_5">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_5_35">
|
||||||
|
<label for="{{i.p0}}" name="{{i.p1}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</label>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_6_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_6_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_6_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_6_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_6_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_6_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_7_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_7_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_7_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_7_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_7_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_7_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_8_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_8_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_8_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_8_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_8_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_8_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_9_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_9_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_9_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_9_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_9_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_9_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_10_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_10_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_10_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_10_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_10_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_10_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_11_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_11_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_11_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_11_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_11_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_11_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_12_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_12_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_12_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_12_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_12_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_12_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_13_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_13_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_13_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_13_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_13_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_13_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.a(c, item.nn, l)}}" data="{{i:item,c:c+1,l:xs.f(l,item.nn)}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_14_0">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" catchtouchmove="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.e(15)}}" data="{{i:item,c:c,l:l}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_14_6">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" animation="{{i.p0}}" style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.e(15)}}" data="{{i:item,c:c,l:l}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_14_3">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.e(15)}}" data="{{i:item,c:c,l:l}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_14_1">
|
||||||
|
<view style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.e(15)}}" data="{{i:item,c:c,l:l}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_14_8">
|
||||||
|
<view hover-class="{{i.p1||'none'}}" hover-stop-propagation="{{xs.b(i.p4,!1)}}" hover-start-time="{{xs.b(i.p2,50)}}" hover-stay-time="{{xs.b(i.p3,400)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" animation="{{i.p0}}" bindanimationstart="eh" bindanimationiteration="eh" bindanimationend="eh" bindtransitionend="eh" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.e(15)}}" data="{{i:item,c:c,l:l}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_14_7">
|
||||||
|
<text selectable="{{xs.b(i.p3,!1)}}" space="{{i.p4}}" decode="{{xs.b(i.p0,!1)}}" bindtouchstart="eh" bindtouchmove="eh" bindtouchend="eh" bindtouchcancel="eh" bindlongpress="eh" user-select="{{xs.b(i.p5,false)}}" overflow="{{i.p2||visible}}" max-lines="{{i.p1}}" style="{{i.st}}" class="{{i.cl}}" bindtap="eh" id="{{i.uid||i.sid}}" data-sid="{{i.sid}}">
|
||||||
|
<template is="{{xs.e(15)}}" data="{{i:item,c:c,l:l}}" wx:for="{{i.cn}}" wx:key="sid" />
|
||||||
|
</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="tmpl_15_container">
|
||||||
|
<block wx:if="{{i.nn === '9'}}">
|
||||||
|
<template is="tmpl_0_9" data="{{i:i}}" />
|
||||||
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<comp i="{{i}}" l="{{l}}" />
|
||||||
|
</block>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[367],{},function(n){var t=function(t){return n(n.s=t)};n.O(0,[107,216],function(){return t(4560)});n.O()}]);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"component":true,"styleIsolation":"apply-shared","usingComponents":{"comp":"./comp"}}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<import src="./base.wxml" />
|
||||||
|
<wxs module="xs" src="./utils.wxs" />
|
||||||
|
<template is="{{'tmpl_0_' + i.nn}}" data="{{i:i,c:1,l:xs.f('',i.nn)}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.index-module__tabBar___szdYb{background:#fff;border-top:1rpx solid #e5e5e5;bottom:0;left:0;position:fixed;right:0;transform:translateZ(0);-webkit-transform:translateZ(0);z-index:100}.index-module__tabBarContent___tufCc{-webkit-align-items:stretch;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:stretch;align-items:stretch;height:100rpx}.index-module__tabItem___QdbrH{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding-bottom:4rpx;padding-top:8rpx}.index-module__tabItem___QdbrH::after{border:none}.index-module__tabItemHover___pbWEa{opacity:.7}.index-module__tabIcon___R3FEb{display:block;height:48rpx;margin-bottom:4rpx;width:48rpx}.index-module__tabText___swdWb{color:#999;font-size:20rpx;line-height:1}.index-module__tabTextActive___l3A3y{color:#07c160;font-size:20rpx;font-weight:500;line-height:1}.index-module__safeArea____quwO{background:#fff;height:env(safe-area-inset-bottom)}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"navigationBarTitleText":"自助预约","navigationBarBackgroundColor":"#2b80f5","navigationBarTextStyle":"white","enablePullDownRefresh":false,"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes index-module__fadeInUp___cBwGo{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes index-module__fadeInUp___cBwGo{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes index-module__fadeIn___mO7Wt{from{opacity:0}to{opacity:1}}@keyframes index-module__fadeIn___mO7Wt{from{opacity:0}to{opacity:1}}@-webkit-keyframes index-module__shimmer____xi8_{0%{background-position:-200% 0}100%{background-position:200% 0}}@keyframes index-module__shimmer____xi8_{0%{background-position:-200% 0}100%{background-position:200% 0}}@-webkit-keyframes index-module__pulse___gylow{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@keyframes index-module__pulse___gylow{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@-webkit-keyframes index-module__slideInRight___VAcYF{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes index-module__slideInRight___VAcYF{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.index-module__aptPage___fQPEd{background:#fafbfc;min-height:100vh;padding-bottom:48rpx}.index-module__cellArrow___ml9QE::after{border-right:4rpx solid #94a3b8;border-top:4rpx solid #94a3b8;content:"";display:inline-block;height:16rpx;margin-left:8rpx;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);width:16rpx}.index-module__input___VJmUb{color:#0f172a;font-size:28rpx;width:100%}.index-module__textareaRow___LOZ3E{-webkit-align-items:stretch;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch}.index-module__textarea___FzlGD{color:#0f172a;font-size:28rpx;line-height:1.5;width:100%}.index-module__textareaCounter___FQUmb{color:#94a3b8;font-size:22rpx;margin-top:8rpx;text-align:right}.index-module__aptDeptGroup___yU9yI{background:#fff;border-bottom:1rpx solid #eef1f6;border-top:1rpx solid #eef1f6;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:24rpx;padding:16rpx 24rpx}.index-module__aptDeptItem___O6SEn{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;background:#fafbfc;border:2rpx solid #e2e8f0;border-radius:8rpx;color:#475569;font-size:28rpx;height:72rpx;justify-content:center;-webkit-transition:all .15s cubic-bezier(.4,0,.2,1);transition:all .15s cubic-bezier(.4,0,.2,1)}.index-module__aptDeptItem___O6SEn:active{opacity:.85}.index-module__aptDeptItemActive___vUzis{background:#eef4ff;border-color:#0a6dff;color:#0a6dff;font-weight:500}.index-module__btnArea___cKIXR{padding:32rpx 24rpx 16rpx}.index-module__aptFooter___poHou{background:#fff;border-radius:16rpx;-webkit-box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);margin:32rpx 24rpx;padding:24rpx}.index-module__footerText___JsS2L{color:#475569;font-size:26rpx;line-height:1.5;margin-bottom:8rpx}.index-module__footerText___JsS2L:last-child{margin-bottom:0}.index-module__aptHotline___FhyxW{color:#0a6dff;font-weight:500}.index-module__aptNotice___cdSHH{color:#94a3b8;font-size:22rpx;line-height:1.75;margin-top:12rpx}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[332],{4720:function(e,n,a){var i=a(8774),c=a(2688),t=a(5861),s=a(9439),r=a(7294),l=a(1515),o=a(2954),d=a.n(o),_={centerPage:"index-module__centerPage___Wi3HO",centerImageWrap:"index-module__centerImageWrap___JQ9Bl",centerImage:"index-module__centerImage___gzVA1",msgContent:"index-module__msgContent___Hj1Se",msgTitle:"index-module__msgTitle___5W8aw",articleH1:"index-module__articleH1___WpsUO",articleSection:"index-module__articleSection___jhswY",articleP:"index-module__articleP___lURoA",centerActions:"index-module__centerActions___xWU2A",fadeInUp:"index-module__fadeInUp___y5COA",fadeIn:"index-module__fadeIn___GPkA4",shimmer:"index-module__shimmer___Q78uK",pulse:"index-module__pulse___s3DYc",slideInRight:"index-module__slideInRight___tzkTe"},u=a(6799),m=a(6931),h=a(5893),x=function(){var e,n=(0,o.useRouter)(),a=(null===(e=n.params)||void 0===e?void 0:e.slug)||"",i=(0,r.useState)(null),x=(0,s.Z)(i,2),g=x[0],f=x[1],p=(0,r.useState)(!0),j=(0,s.Z)(p,2),v=j[0],N=j[1];(0,r.useEffect)(function(){(0,t.Z)((0,c.Z)().m(function e(){var n,i,t;return(0,c.Z)().w(function(e){while(1)switch(e.p=e.n){case 0:return e.p=0,e.n=1,(0,u.l)().catch(function(){return[]});case 1:n=e.v,i=n.find(function(e){return e.slug===a})||null,f(i),i&&d().setNavigationBarTitle({title:i.name}),e.n=3;break;case 2:e.p=2,t=e.v,console.error("[CenterPage] load failed",t);case 3:return e.p=3,N(!1),e.f(3);case 4:return e.a(2)}},e,null,[[0,2,3,4]])}))()},[a]);var w=function(){(0,m.o)().then(function(e){if(e.phone){var n=String(e.phone).replace(/[^\d+]/g,"");d().makePhoneCall({phoneNumber:n,fail:function(n){console.error("[CenterPage] call failed",n),d().showToast({title:"\u62e8\u53f7\u5931\u8d25, \u8bf7\u624b\u52a8\u62e8\u6253 "+e.phone,icon:"none"})}})}else d().showToast({title:"\u8bf7\u5728\u7ba1\u7406\u540e\u53f0\u914d\u7f6e\u7535\u8bdd\u53f7\u7801",icon:"none"})}).catch(function(e){console.error("[CenterPage] fetchSiteConfig failed",e),d().showToast({title:"\u83b7\u53d6\u7535\u8bdd\u53f7\u7801\u5931\u8d25",icon:"none"})})};return v?(0,h.jsx)(l.G7,{className:_.centerPage,children:(0,h.jsx)(l.G7,{className:"page-loading",children:(0,h.jsx)(l.xv,{children:"\u52a0\u8f7d\u4e2d\u2026"})})}):g?(0,h.jsxs)(l.pf,{scrollY:!0,className:_.centerPage,enhanced:!0,showScrollbar:!1,children:[(0,h.jsxs)(l.G7,{className:"card",children:[(0,h.jsx)(l.G7,{className:_.articleH1,children:g.name}),g.intro&&(0,h.jsx)(l.G7,{className:_.articleSection,children:(0,h.jsx)(l.G7,{className:_.articleP,children:(0,h.jsx)(l.xv,{children:g.intro})})})]}),(0,h.jsxs)(l.G7,{className:_.centerActions,children:[(0,h.jsx)(l.G7,{className:"btn btn--primary",onClick:function(){return d().switchTab({url:"/pages/appointment/index"})},children:(0,h.jsx)(l.xv,{children:"\u7acb\u5373\u9884\u7ea6"})}),(0,h.jsx)(l.G7,{className:"btn btn--default",onClick:w,children:(0,h.jsx)(l.xv,{children:"\u7535\u8bdd\u54a8\u8be2"})})]}),g.image&&(0,h.jsx)(l.G7,{className:_.centerImageWrap,children:(0,h.jsx)(l.Ee,{className:_.centerImage,src:g.image,mode:"widthFix"})})]}):(0,h.jsx)(l.G7,{className:_.centerPage,children:(0,h.jsx)(l.G7,{className:"card",children:(0,h.jsx)(l.G7,{className:_.msgContent,children:(0,h.jsx)(l.xv,{className:_.msgTitle,children:"\u4e2d\u5fc3\u4e0d\u5b58\u5728"})})})})},g=x,f={navigationBarTitleText:"\u4e2d\u5fc3\u7b80\u4ecb",enablePullDownRefresh:!1},p=(0,i.R4)(g,"pages/center/index",{root:{cn:[]}},f||{});g&&g.behaviors&&(p.behaviors=(p.behaviors||[]).concat(g.behaviors));Page(p)}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[107,216,592],function(){return n(4720)});e.O()}]);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"navigationBarTitleText":"中心简介","enablePullDownRefresh":false,"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes index-module__fadeInUp___y5COA{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes index-module__fadeInUp___y5COA{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes index-module__fadeIn___GPkA4{from{opacity:0}to{opacity:1}}@keyframes index-module__fadeIn___GPkA4{from{opacity:0}to{opacity:1}}@-webkit-keyframes index-module__shimmer___Q78uK{0%{background-position:-200% 0}100%{background-position:200% 0}}@keyframes index-module__shimmer___Q78uK{0%{background-position:-200% 0}100%{background-position:200% 0}}@-webkit-keyframes index-module__pulse___s3DYc{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@keyframes index-module__pulse___s3DYc{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@-webkit-keyframes index-module__slideInRight___tzkTe{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes index-module__slideInRight___tzkTe{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.index-module__centerPage___Wi3HO{background:#fafbfc;min-height:100vh}.index-module__centerImageWrap___JQ9Bl{padding:0 24rpx 48rpx}.index-module__centerImage___gzVA1{border-radius:16rpx;display:block;width:100%}.index-module__msgContent___Hj1Se{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:48rpx 24rpx}.index-module__msgTitle___5W8aw{color:#475569;font-size:32rpx;font-weight:500}.index-module__articleH1___WpsUO{color:#0f172a;font-size:36rpx;font-weight:600;letter-spacing:-.01em;margin-bottom:16rpx}.index-module__articleSection___jhswY{margin-top:16rpx}.index-module__articleP___lURoA{color:#475569;font-size:28rpx;line-height:1.75}.index-module__centerActions___xWU2A{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:16rpx;padding:24rpx 24rpx 48rpx}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"navigationBarTitleText":"苏州肛泰中医院","navigationBarBackgroundColor":"#2b80f5","navigationBarTextStyle":"white","enablePullDownRefresh":false,"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes index-module__fadeInUp___wANem{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes index-module__fadeInUp___wANem{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes index-module__fadeIn___H2ZP9{from{opacity:0}to{opacity:1}}@keyframes index-module__fadeIn___H2ZP9{from{opacity:0}to{opacity:1}}@-webkit-keyframes index-module__shimmer___hwkGw{0%{background-position:-200% 0}100%{background-position:200% 0}}@keyframes index-module__shimmer___hwkGw{0%{background-position:-200% 0}100%{background-position:200% 0}}@-webkit-keyframes index-module__pulse___ZIm50{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@keyframes index-module__pulse___ZIm50{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@-webkit-keyframes index-module__slideInRight___qayOv{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes index-module__slideInRight___qayOv{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.index-module__page___QaRYa{background:#fafbfc;min-height:100vh;padding-bottom:32rpx}.index-module__banner___qgRyP{background:#f4f6fa;height:480rpx;width:100%}.index-module__bannerImg___BBhQb{display:block;height:100%;width:100%}.index-module__bannerEmpty___bsBgN{-webkit-align-items:center;background:#f4f6fa;display:-webkit-flex;display:-ms-flexbox;display:flex;height:480rpx;width:100%;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center}.index-module__bannerEmptyText___Yoj3D{color:#94a3b8;font-size:26rpx;padding:0 48rpx;text-align:center}.index-module__centerGrid___YmfE9{display:-webkit-flex;display:-ms-flexbox;display:flex;gap:16rpx;padding:24rpx}.index-module__centerCard___JmIJa{-webkit-align-items:center;background:#fff;border-radius:16rpx;-webkit-box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:24rpx 16rpx;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .15s cubic-bezier(.4,0,.2,1),-webkit-transform .15s cubic-bezier(.4,0,.2,1);transition:opacity .15s cubic-bezier(.4,0,.2,1),-webkit-transform .15s cubic-bezier(.4,0,.2,1);transition:transform .15s cubic-bezier(.4,0,.2,1),opacity .15s cubic-bezier(.4,0,.2,1);transition:transform .15s cubic-bezier(.4,0,.2,1),opacity .15s cubic-bezier(.4,0,.2,1),-webkit-transform .15s cubic-bezier(.4,0,.2,1)}.index-module__centerCard___JmIJa:active{opacity:.85;-webkit-transform:scale(.97);-ms-transform:scale(.97);transform:scale(.97)}.index-module__centerIconWrap___mUhSK{-webkit-align-items:center;background:-webkit-linear-gradient(315deg,#eef4ff,#e6faf7);background:linear-gradient(135deg,#eef4ff,#e6faf7);border-radius:12rpx;display:-webkit-flex;display:-ms-flexbox;display:flex;height:96rpx;overflow:hidden;width:96rpx;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;margin-bottom:12rpx}.index-module__centerIconImg___Wx0SZ{display:block;height:100%;width:100%}.index-module__centerIconText___ltpzQ{font-size:44rpx}.index-module__centerName___HiaLB{color:#0f172a;font-size:28rpx;font-weight:500;margin-bottom:4rpx;text-align:center}.index-module__centerAction___oNMMD{color:#0a6dff;font-size:22rpx}.index-module__introWrap___BrHrC{background:#fff;border-radius:16rpx;-webkit-box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);margin:16rpx 24rpx 0;overflow:hidden}.index-module__introImg___QRC1B{display:block;width:100%}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[327],{5809:function(e,n,a){var i=a(8774),s=a(2688),t=a(5861),c=a(9439),l=a(7294),o=a(1515),_=a(2954),r=a.n(_),m={page:"index-module__page___xz6un",loadmore:"index-module__loadmore___mImAp",loadmoreTips:"index-module__loadmoreTips___NSqHE",emptyMsg:"index-module__emptyMsg___Ig2x0",emptyIconArea:"index-module__emptyIconArea___GcMIo",emptyIcon:"index-module__emptyIcon___TRWmy",emptyTextArea:"index-module__emptyTextArea___OoIuM",emptyTitle:"index-module__emptyTitle___CSRmg",emptyDesc:"index-module__emptyDesc___c5zoj",article:"index-module__article___h9mzb",articleSection:"index-module__articleSection___A5apg",imgItem:"index-module__imgItem___NCtfK",img:"index-module__img___SlC_3",articleP:"index-module__articleP___OVRfJ",caption:"index-module__caption___YQXuv",fadeInUp:"index-module__fadeInUp___mBjvU",fadeIn:"index-module__fadeIn___W16OU",shimmer:"index-module__shimmer___i8QRD",pulse:"index-module__pulse___xsvfB",slideInRight:"index-module__slideInRight___XDtx0"},d=a(2284),u=function(){var e=(0,t.Z)((0,s.Z)().m(function e(n){var a,i;return(0,s.Z)().w(function(e){while(1)switch(e.n){case 0:return a=["enabled=true",n?"hospitalId=".concat(encodeURIComponent(n)):""].filter(Boolean).join("&"),e.n=1,(0,d.W)({url:"/api/v1/hospital-images".concat(a?"?"+a:"")});case 1:return i=e.v,e.a(2,i.data||[])}},e)}));return function(n){return e.apply(this,arguments)}}(),p=a(5893),x=function(){var e=(0,l.useState)([]),n=(0,c.Z)(e,2),a=n[0],i=n[1],_=(0,l.useState)(!0),d=(0,c.Z)(_,2),x=d[0],h=d[1];return(0,l.useEffect)(function(){(0,t.Z)((0,s.Z)().m(function e(){var n,a;return(0,s.Z)().w(function(e){while(1)switch(e.p=e.n){case 0:return e.p=0,e.n=1,u();case 1:n=e.v,i(n),e.n=3;break;case 2:e.p=2,a=e.v,console.error("[HospitalPage] load failed",a),r().showToast({title:"\u52a0\u8f7d\u5931\u8d25",icon:"none"});case 3:return e.p=3,h(!1),e.f(3);case 4:return e.a(2)}},e,null,[[0,2,3,4]])}))()},[]),x?(0,p.jsx)(o.G7,{className:m.page,children:(0,p.jsx)(o.G7,{className:m.loadmore,children:(0,p.jsx)(o.xv,{className:m.loadmoreTips,children:"\u52a0\u8f7d\u4e2d\u2026"})})}):0===a.length?(0,p.jsx)(o.G7,{className:m.page,children:(0,p.jsxs)(o.G7,{className:m.emptyMsg,children:[(0,p.jsx)(o.G7,{className:m.emptyIconArea,children:(0,p.jsx)(o.xv,{className:m.emptyIcon,children:"\ud83c\udfde"})}),(0,p.jsxs)(o.G7,{className:m.emptyTextArea,children:[(0,p.jsx)(o.xv,{className:m.emptyTitle,children:"\u6682\u65e0\u533b\u9662\u7b80\u4ecb"}),(0,p.jsx)(o.xv,{className:m.emptyDesc,children:'\u8bf7\u5728\u7ba1\u7406\u540e\u53f0"\u533b\u9662\u56fe\u7247"\u4e2d\u4e0a\u4f20'})]})]})}):(0,p.jsx)(o.pf,{scrollY:!0,className:m.page,enhanced:!0,showScrollbar:!1,children:(0,p.jsx)(o.G7,{className:m.article,children:(0,p.jsx)(o.G7,{className:m.articleSection,children:a.map(function(e){return(0,p.jsxs)(o.G7,{className:m.imgItem,children:[(0,p.jsx)(o.Ee,{className:m.img,src:e.image,mode:"widthFix",showMenuByLongpress:!0,onClick:function(){return r().previewImage({urls:a.map(function(e){return e.image}),current:e.image})}}),e.caption&&(0,p.jsx)(o.G7,{className:m.articleP,children:(0,p.jsx)(o.xv,{className:m.caption,children:e.caption})})]},e.id)})})})})},h=x,g={navigationBarTitleText:"\u533b\u9662\u7b80\u4ecb",enablePullDownRefresh:!1},f=(0,i.R4)(h,"pages/hospital/index",{root:{cn:[]}},g||{});h&&h.behaviors&&(f.behaviors=(f.behaviors||[]).concat(h.behaviors));Page(f)}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[107,216,592],function(){return n(5809)});e.O()}]);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"navigationBarTitleText":"医院简介","enablePullDownRefresh":false,"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes index-module__fadeInUp___mBjvU{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes index-module__fadeInUp___mBjvU{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes index-module__fadeIn___W16OU{from{opacity:0}to{opacity:1}}@keyframes index-module__fadeIn___W16OU{from{opacity:0}to{opacity:1}}@-webkit-keyframes index-module__shimmer___i8QRD{0%{background-position:-200% 0}100%{background-position:200% 0}}@keyframes index-module__shimmer___i8QRD{0%{background-position:-200% 0}100%{background-position:200% 0}}@-webkit-keyframes index-module__pulse___xsvfB{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@keyframes index-module__pulse___xsvfB{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@-webkit-keyframes index-module__slideInRight___XDtx0{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes index-module__slideInRight___XDtx0{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.index-module__page___xz6un{background:#fafbfc;min-height:100vh}.index-module__loadmore___mImAp{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding:48rpx 0}.index-module__loadmoreTips___NSqHE{color:#94a3b8;font-size:26rpx}.index-module__emptyMsg___Ig2x0{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;justify-content:center;padding:64rpx 24rpx}.index-module__emptyIconArea___GcMIo{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;margin-bottom:24rpx}.index-module__emptyIcon___TRWmy{display:block;font-size:100rpx;opacity:.5}.index-module__emptyTextArea___OoIuM{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;justify-content:center}.index-module__emptyTitle___CSRmg{color:#0f172a;font-size:32rpx;font-weight:500;margin-bottom:8rpx}.index-module__emptyDesc___c5zoj{color:#94a3b8;font-size:26rpx}.index-module__article___h9mzb{padding:16rpx}.index-module__articleSection___A5apg{padding:0 8rpx}.index-module__imgItem___NCtfK{margin-bottom:16rpx;width:100%}.index-module__img___SlC_3{border-radius:12rpx;display:block;width:100%}.index-module__articleP___OVRfJ{padding:8rpx 16rpx}.index-module__caption___YQXuv{color:#475569;font-size:26rpx;text-align:center}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"navigationBarTitleText":"我的","enablePullDownRefresh":true,"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes index-module__fadeInUp___av8UX{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes index-module__fadeInUp___av8UX{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes index-module__fadeIn___MEM7l{from{opacity:0}to{opacity:1}}@keyframes index-module__fadeIn___MEM7l{from{opacity:0}to{opacity:1}}@-webkit-keyframes index-module__shimmer___YUAOa{0%{background-position:-200% 0}100%{background-position:200% 0}}@keyframes index-module__shimmer___YUAOa{0%{background-position:-200% 0}100%{background-position:200% 0}}@-webkit-keyframes index-module__pulse___QNmyE{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@keyframes index-module__pulse___QNmyE{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@-webkit-keyframes index-module__slideInRight___yR1mQ{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes index-module__slideInRight___yR1mQ{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.index-module__minePage___tG3Jx{background:#fafbfc;min-height:100vh;padding-bottom:48rpx}.index-module__mineStat___KMdi5{background:#fff;-webkit-box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);display:-webkit-flex;display:-ms-flexbox;display:flex;margin-bottom:16rpx;padding:32rpx 0}.index-module__mineStatItem___mV2Pi{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex:1;-ms-flex:1;flex:1;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center}.index-module__mineStatValue___SsgQl{color:#0a6dff;font-size:36rpx;font-weight:600}.index-module__mineStatLabel___MLoeH{color:#94a3b8;font-size:22rpx;margin-top:4rpx}.index-module__mineList___iB4HW{padding:0 24rpx}.index-module__mineCard___kQlYB{margin-bottom:24rpx;overflow:hidden}.index-module__mineCardHeader___pAMNF{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:16rpx 16rpx 0}.index-module__mineCardBody___IbchM{-webkit-flex:1;-ms-flex:1;flex:1}.index-module__mineCardFt___VJMMu{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.index-module__mineHospital____c8tQ{color:#0f172a;font-size:32rpx;font-weight:500}.index-module__mineStatusPending___LEMjM{background:#fff3e0;border-radius:8rpx;color:#ff8a00;font-size:22rpx;padding:4rpx 12rpx}.index-module__mineStatusConfirmed___JYvmR{background:#e6faf7;border-radius:8rpx;color:#15b9a3;font-size:22rpx;padding:4rpx 12rpx}.index-module__mineStatusCompleted___KTZBm{background:#f4f6fa;border-radius:8rpx;color:#94a3b8;font-size:22rpx;padding:4rpx 12rpx}.index-module__mineStatusCancelled___zU4bY{background:#f4f6fa;border-radius:8rpx;color:#94a3b8;font-size:22rpx;padding:4rpx 12rpx;text-decoration:line-through}.index-module__mineCardDetail___EbMBm{padding:8rpx 16rpx}.index-module__mineInfoRow___ZoaEn{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;color:#475569;font-size:26rpx;padding:4rpx 0}.index-module__mineInfoLabel___c1vCT{color:#94a3b8;margin-right:16rpx;min-width:80rpx}.index-module__mineInfoPhone___J_M4p{color:#0a6dff}.index-module__mineCardFooter___FlPBa{padding:8rpx 16rpx 16rpx}.index-module__mineCardActions___GcdXE{display:-webkit-flex;display:-ms-flexbox;display:flex;gap:16rpx;-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.index-module__mineEmpty___CeqXC{padding:48rpx 24rpx}.index-module__mineEmptyContent___NhLTN{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center}.index-module__mineEmptyIcon___ayxOI{display:block;font-size:80rpx;opacity:.5;text-align:center}.index-module__mineEmptyText___Ge1Yb{color:#94a3b8;display:block;font-size:28rpx;margin-top:16rpx;text-align:center}.index-module__mineEmptyBtn___Z2O0E{margin-top:32rpx}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"use strict";(wx["webpackJsonp"]=wx["webpackJsonp"]||[]).push([[787],{9963:function(e,n,t){var i=t(8774),o=t(7294),r=t(1515),c=t(2954),s=t.n(c),a=t(5893),l=function(){return(0,o.useEffect)(function(){s().setNavigationBarTitle({title:"\u7535\u8bdd\u54a8\u8be2"})},[]),(0,a.jsxs)(r.G7,{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",height:"100vh",padding:"0 24rpx",textAlign:"center"},children:[(0,a.jsx)(r.xv,{style:{fontSize:"36rpx",color:"#0f172a",marginBottom:"16rpx"},children:"\ud83d\udcde \u7535\u8bdd\u54a8\u8be2"}),(0,a.jsx)(r.xv,{style:{fontSize:"26rpx",color:"#94a3b8"},children:'\u8bf7\u70b9\u51fb\u5e95\u680f"\u7535\u8bdd\u54a8\u8be2"\u6309\u94ae\u76f4\u63a5\u62e8\u6253'})]})},u=l,x={},f=(0,i.R4)(u,"pages/phone-consult/index",{root:{cn:[]}},x||{});u&&u.behaviors&&(f.behaviors=(f.behaviors||[]).concat(u.behaviors));Page(f)}},function(e){var n=function(n){return e(e.s=n)};e.O(0,[107,216],function(){return n(9963)});e.O()}]);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"navigationBarTitleText":"在线自测","enablePullDownRefresh":false,"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes index-module__fadeInUp___c0G1s{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes index-module__fadeInUp___c0G1s{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes index-module__fadeIn___WKtj8{from{opacity:0}to{opacity:1}}@keyframes index-module__fadeIn___WKtj8{from{opacity:0}to{opacity:1}}@-webkit-keyframes index-module__shimmer___cyJaC{0%{background-position:-200% 0}100%{background-position:200% 0}}@keyframes index-module__shimmer___cyJaC{0%{background-position:-200% 0}100%{background-position:200% 0}}@-webkit-keyframes index-module__pulse___zdSkP{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@keyframes index-module__pulse___zdSkP{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@-webkit-keyframes index-module__slideInRight___p_JAa{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes index-module__slideInRight___p_JAa{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.index-module__st-page___nFriu{background:#fafbfc;min-height:100vh}.index-module__st-page-inner___xwPgF{padding:0 24rpx 48rpx}.index-module__st-notice___YDWJB{color:#475569;font-size:26rpx;line-height:1.75;white-space:pre-line}.index-module__st-progress___Gdk2G{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;background:#fff;border-radius:8rpx;-webkit-box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);box-shadow:0 1rpx 4rpx rgba(15,23,42,.04);margin:16rpx 0;padding:16rpx 24rpx}.index-module__st-progress-bar___zh2oF{background:#f4f6fa;border-radius:9999rpx;-webkit-flex:1;-ms-flex:1;flex:1;height:12rpx;overflow:hidden}.index-module__st-progress-fill___B6xdz{background:-webkit-linear-gradient(315deg,#0a6dff,#15b9a3);background:linear-gradient(135deg,#0a6dff,#15b9a3);border-radius:9999rpx;height:100%;-webkit-transition:width .25s cubic-bezier(.4,0,.2,1);transition:width .25s cubic-bezier(.4,0,.2,1)}.index-module__st-progress-text___nzP70{color:#94a3b8;font-size:22rpx;margin-left:16rpx;min-width:60rpx;text-align:right}.index-module__st-qnum___dVsr3{color:#0a6dff;font-weight:500}.index-module__st-option___gwZgs{-webkit-transition:background .15s cubic-bezier(.4,0,.2,1);transition:background .15s cubic-bezier(.4,0,.2,1)}.index-module__st-option___gwZgs:active{background:#f0f3f8}.index-module__st-check___u0p5k{color:#0a6dff;font-size:32rpx;font-weight:500}.index-module__st-input___MEbcf{color:#0f172a;font-size:28rpx;line-height:1.5;width:100%}.index-module__st-textarea___H8tO7{color:#0f172a;font-size:28rpx;line-height:1.5;width:100%}.index-module__st-textarea-counter___PebEy{color:#94a3b8;font-size:22rpx;margin-top:8rpx;text-align:right}.index-module__st-error___BmrdU{color:#e5454b;font-size:22rpx;padding:8rpx 24rpx}.index-module__st-actions___KCI8l{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:24rpx;padding:24rpx 0}.index-module__st-bottom-tip___HF7jZ{margin:16rpx 0 40rpx}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"navigationBarTitleText":"预约成功","enablePullDownRefresh":false,"usingComponents":{"comp":"../../comp"}}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<import src="../../base.wxml"/>
|
||||||
|
<template is="taro_tmpl" data="{{root:root}}" />
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
@-webkit-keyframes index-module__fadeInUp___XK76i{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes index-module__fadeInUp___XK76i{from{opacity:0;-webkit-transform:translateY(16rpx);transform:translateY(16rpx)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes index-module__fadeIn___Tr5j1{from{opacity:0}to{opacity:1}}@keyframes index-module__fadeIn___Tr5j1{from{opacity:0}to{opacity:1}}@-webkit-keyframes index-module__shimmer___n9tRH{0%{background-position:-200% 0}100%{background-position:200% 0}}@keyframes index-module__shimmer___n9tRH{0%{background-position:-200% 0}100%{background-position:200% 0}}@-webkit-keyframes index-module__pulse___DxlO7{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@keyframes index-module__pulse___DxlO7{0%,100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:.7;-webkit-transform:scale(1.05);transform:scale(1.05)}}@-webkit-keyframes index-module__slideInRight___kHKDB{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes index-module__slideInRight___kHKDB{from{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}}.index-module__succ-page____x2TM{background:#fafbfc;min-height:100vh;padding:0 24rpx}.index-module__succ-icon-area____jgp_{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;padding-bottom:24rpx;padding-top:48rpx}.index-module__succ-icon___km9gr{-webkit-align-items:center;display:-webkit-flex;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-justify-content:center;-ms-flex-pack:center;background:#15b9a3;border-radius:50%;color:#fff;font-size:72rpx;font-weight:500;height:128rpx;justify-content:center;width:128rpx}.index-module__succ-icon--warn___CVDqV{background:#ff8a00}.index-module__succ-text-area___PKs5X{padding:0 24rpx 24rpx;text-align:center}.index-module__succ-title___f8GzC{color:#0f172a;display:block;font-size:36rpx;font-weight:600;margin-bottom:12rpx}.index-module__succ-desc___iTLTf{color:#475569;display:block;font-size:28rpx;line-height:1.5}.index-module__succ-opr-area____zcT9{padding:24rpx 0}.index-module__succ-detail-cells___xGc3q{border-radius:12rpx;margin:0;overflow:hidden}.index-module__succ-cell-ft___GE2m5{color:#0f172a;font-size:28rpx;text-align:right}.index-module__succ-score___xv3RZ{color:#0a6dff;font-size:32rpx;font-weight:500}.index-module__succ-strong___b3GjQ{color:#0a6dff;font-weight:500}.index-module__succ-id___a3D_N{color:#94a3b8;font-family:monospace;font-size:22rpx}.index-module__succ-btn-area___RSVB3{padding:0}.index-module__succ-btn-row___ZTkyE{display:-webkit-flex;display:-ms-flexbox;display:flex;gap:24rpx}.index-module__succ-tip___H_Mke{margin-top:24rpx;padding-bottom:48rpx}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"miniprogramRoot": "./",
|
||||||
|
"projectname": "taro_template",
|
||||||
|
"description": "苏州肛泰中医院预约挂号小程序",
|
||||||
|
"appid": "wx1e964c6f7f8009ad",
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": false,
|
||||||
|
"es6": true,
|
||||||
|
"enhance": true,
|
||||||
|
"compileHotReLoad": false,
|
||||||
|
"postcss": false,
|
||||||
|
"preloadBackgroundData": false,
|
||||||
|
"minified": true,
|
||||||
|
"newFeature": true,
|
||||||
|
"autoAudits": false,
|
||||||
|
"coverView": true,
|
||||||
|
"showShadowRootInWxmlPanel": false,
|
||||||
|
"scopeDataCheck": false,
|
||||||
|
"useCompilerModule": false,
|
||||||
|
"compileWorklet": false,
|
||||||
|
"uglifyFileName": false,
|
||||||
|
"uploadWithSourceMap": true,
|
||||||
|
"packNpmManually": false,
|
||||||
|
"packNpmRelationList": [],
|
||||||
|
"minifyWXSS": true,
|
||||||
|
"minifyWXML": true,
|
||||||
|
"localPlugins": false,
|
||||||
|
"disableUseStrict": false,
|
||||||
|
"useCompilerPlugins": false,
|
||||||
|
"condition": false,
|
||||||
|
"swc": false,
|
||||||
|
"disableSWC": true,
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"simulatorType": "wechat",
|
||||||
|
"simulatorPluginLibVersion": {},
|
||||||
|
"condition": {},
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [],
|
||||||
|
"include": []
|
||||||
|
},
|
||||||
|
"editorSetting": {},
|
||||||
|
"libVersion": "3.16.1"
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
(function(){"use strict";var n={},t={};function r(e){var o=t[e];if(void 0!==o)return o.exports;var u=t[e]={exports:{}};return n[e].call(u.exports,u,u.exports,r),u.exports}r.m=n,function(){var n=[];r.O=function(t,e,o,u){if(!e){var i=1/0;for(l=0;l<n.length;l++){e=n[l][0],o=n[l][1],u=n[l][2];for(var f=!0,c=0;c<e.length;c++)(!1&u||i>=u)&&Object.keys(r.O).every(function(n){return r.O[n](e[c])})?e.splice(c--,1):(f=!1,u<i&&(i=u));if(f){n.splice(l--,1);var a=o();void 0!==a&&(t=a)}}return t}u=u||0;for(var l=n.length;l>0&&n[l-1][2]>u;l--)n[l]=n[l-1];n[l]=[e,o,u]}}(),function(){r.n=function(n){var t=n&&n.__esModule?function(){return n["default"]}:function(){return n};return r.d(t,{a:t}),t}}(),function(){var n,t=Object.getPrototypeOf?function(n){return Object.getPrototypeOf(n)}:function(n){return n.__proto__};r.t=function(e,o){if(1&o&&(e=this(e)),8&o)return e;if("object"===typeof e&&e){if(4&o&&e.__esModule)return e;if(16&o&&"function"===typeof e.then)return e}var u=Object.create(null);r.r(u);var i={};n=n||[null,t({}),t([]),t(t)];for(var f=2&o&&e;"object"==typeof f&&!~n.indexOf(f);f=t(f))Object.getOwnPropertyNames(f).forEach(function(n){i[n]=function(){return e[n]}});return i["default"]=function(){return e},r.d(u,i),u}}(),function(){r.d=function(n,t){for(var e in t)r.o(t,e)&&!r.o(n,e)&&Object.defineProperty(n,e,{enumerable:!0,get:t[e]})}}(),function(){r.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(n){if("object"===typeof window)return window}}()}(),function(){r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)}}(),function(){r.r=function(n){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})}}(),function(){r.p="/"}(),function(){var n={666:0};r.O.j=function(t){return 0===n[t]};var t=function(t,e){var o,u,i=e[0],f=e[1],c=e[2],a=0;if(i.some(function(t){return 0!==n[t]})){for(o in f)r.o(f,o)&&(r.m[o]=f[o]);if(c)var l=c(r)}for(t&&t(e);a<i.length;a++)u=i[a],r.o(n,u)&&n[u]&&n[u][0](),n[u]=0;return r.O(l)},e=wx["webpackJsonp"]=wx["webpackJsonp"]||[];e.forEach(t.bind(null,0)),e.push=t.bind(null,e.push.bind(e))}()})();
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
module.exports = {
|
||||||
|
a: function (l, n, s) {
|
||||||
|
var a = ["8","0","22","6","3","1","13","7","5","69","70","35","27","66","75","76","63"]
|
||||||
|
var b = ["5","69","70","35","27","66","75","76","63"]
|
||||||
|
if (a.indexOf(n) === -1) {
|
||||||
|
l = 0
|
||||||
|
}
|
||||||
|
if (b.indexOf(n) > -1) {
|
||||||
|
var u = s.split(',')
|
||||||
|
var depth = 0
|
||||||
|
for (var i = 0; i < u.length; i++) {
|
||||||
|
if (u[i] === n) depth++
|
||||||
|
}
|
||||||
|
l = depth
|
||||||
|
}
|
||||||
|
if (l >= 15) {
|
||||||
|
return 'tmpl_15_container'
|
||||||
|
}
|
||||||
|
return 'tmpl_' + l + '_' + n
|
||||||
|
},
|
||||||
|
b: function (a, b) {
|
||||||
|
return a === undefined ? b : a
|
||||||
|
},
|
||||||
|
c: function(i, prefix) {
|
||||||
|
var s = i.focus !== undefined ? 'focus' : 'blur'
|
||||||
|
return prefix + i.nn + '_' + s
|
||||||
|
},
|
||||||
|
d: function (a) {
|
||||||
|
return a === undefined ? {} : a
|
||||||
|
},
|
||||||
|
e: function (n) {
|
||||||
|
return 'tmpl_' + n + '_container'
|
||||||
|
},
|
||||||
|
f: function (l, n) {
|
||||||
|
var b = ["5","69","70","35","27","66","75","76","63"]
|
||||||
|
if (b.indexOf(n) > -1) {
|
||||||
|
if (l) l += ','
|
||||||
|
l += n
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react-jsx-runtime.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* react.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* use-sync-external-store-shim.production.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @license React
|
||||||
|
* use-sync-external-store-shim/with-selector.production.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# API 变更日志
|
||||||
|
|
||||||
|
所有非破坏性变更记录在此,**重大变更必须先经过设计评审**。
|
||||||
|
|
||||||
|
## [1.2.0] - 2026-06-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- ✨ **Phase 3**:新增 `leads` 表(`phone + source` 唯一索引)
|
||||||
|
- ✨ **Phase 3**:`POST /api/v1/leads` 公开提交意向客户(自主问卷)
|
||||||
|
- ✨ **Phase 3**:`GET /api/v1/leads/stats` 鉴权统计
|
||||||
|
- ✨ **Phase 3**:`GET /api/v1/admin/leads` 鉴权列表(phone/source/keyword/时间过滤 + 分页)
|
||||||
|
- ✨ **Phase 3**:`GET /api/v1/admin/leads/:id` 详情
|
||||||
|
- ✨ **Phase 3**:`PUT /api/v1/admin/leads/:id/remark` 改备注
|
||||||
|
- ✨ **Phase 3**:`DELETE /api/v1/admin/leads/:id` 删除
|
||||||
|
|
||||||
|
## [1.1.0] - 2026-06-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- ✨ **Phase 1**:后端按业务域重构为 `modules/{route,service,dto,README}` 四件套
|
||||||
|
- ✨ **Phase 1**:所有接口统一加 `/api/v1` 前缀,URL 路径升级
|
||||||
|
- ✨ **Phase 2**:Swagger UI 文档(`/api/docs`)和 OpenAPI 3.0 JSON 端点
|
||||||
|
- ✨ **Phase 2**:Appointment 模块新增 `GET /api/v1/appointments/stats` 鉴权接口
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- 修改:所有接口路径前缀从 `/api/...` 改为 `/api/v1/...`
|
||||||
|
- 修改:业务错误响应中,**资源不存在** 仍使用 HTTP 404,但响应体保持 `{code, message, data}` 结构
|
||||||
|
- 修改:管理后台自动给 `/api/` 路径加 `/v1` 前缀,调用方无需修改
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- 删除:`/api/hospitals` `/api/departments` 等无版本前缀的接口
|
||||||
|
|
||||||
|
## [1.0.0] - 2026-06-13
|
||||||
|
|
||||||
|
- 初始版本
|
||||||
|
- 7 个业务域:hospital / department / doctor / appointment / expert / banner / config
|
||||||
|
- 1 个鉴权域:adminAuth
|
||||||
|
- 同进程静态托管 `/admin` 管理后台
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# API 接口文档
|
||||||
|
|
||||||
|
> **在线浏览**:http://124.221.67.199:3000/api/docs/
|
||||||
|
> **OpenAPI JSON**:http://124.221.67.199:3000/api/docs.json
|
||||||
|
|
||||||
|
## 基础约定
|
||||||
|
|
||||||
|
| 项 | 约定 |
|
||||||
|
|---|---|
|
||||||
|
| **基地址** | `http://<host>:3000/api/v1` |
|
||||||
|
| **版本** | `v1`(Phase 1 起所有接口) |
|
||||||
|
| **请求方法** | GET / POST / PUT / DELETE |
|
||||||
|
| **请求格式** | `Content-Type: application/json` |
|
||||||
|
| **字符集** | UTF-8 |
|
||||||
|
|
||||||
|
## 统一响应结构
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"code": 0, // 0 = 成功,其他 = 业务错误
|
||||||
|
"message": "ok", // 业务消息
|
||||||
|
"data": { ... } // 业务数据
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 状态码
|
||||||
|
|
||||||
|
| 状态码 | 含义 | 出现场景 |
|
||||||
|
|---|---|---|
|
||||||
|
| 200 | 成功 | 接口正常返回 |
|
||||||
|
| 400 | 参数错误 | 缺字段、格式不对、校验失败 |
|
||||||
|
| 401 | 鉴权失败 | token 缺失/失效/密码错误 |
|
||||||
|
| 404 | 资源不存在 | 找不到 ID 对应的资源 |
|
||||||
|
| 500 | 服务器内部错误 | 异常抛出 |
|
||||||
|
|
||||||
|
> 业务错误统一用 HTTP 200 + `code !== 0` 表示,**仅在资源未找到时使用 404**。
|
||||||
|
|
||||||
|
## 鉴权
|
||||||
|
|
||||||
|
管理后台接口需要 JWT Bearer Token:
|
||||||
|
|
||||||
|
```
|
||||||
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
|
||||||
|
```
|
||||||
|
|
||||||
|
通过 `POST /api/v1/admin/auth/login` 获得 token。
|
||||||
|
|
||||||
|
## 业务模块
|
||||||
|
|
||||||
|
| 模块 | 路径前缀 | 文档 |
|
||||||
|
|---|---|---|
|
||||||
|
| Hospital | `/hospitals` | [hospital.md](v1/hospital.md) |
|
||||||
|
| Department | `/departments` | [department.md](v1/department.md) |
|
||||||
|
| Doctor | `/doctors` | [doctor.md](v1/doctor.md) |
|
||||||
|
| Appointment | `/appointments` | [appointment.md](v1/appointment.md) |
|
||||||
|
| Expert | `/experts` | [expert.md](v1/expert.md) |
|
||||||
|
| Banner | `/banners` | [banner.md](v1/banner.md) |
|
||||||
|
| Config | `/config` | [config.md](v1/config.md) |
|
||||||
|
| AdminAuth | `/admin/auth` | [admin-auth.md](v1/admin-auth.md) |
|
||||||
|
| Lead | `/leads` · `/admin/leads` | [lead.md](v1/lead.md) |
|
||||||
|
|
||||||
|
## 变更日志
|
||||||
|
|
||||||
|
详见 [CHANGELOG.md](CHANGELOG.md)
|
||||||
|
|
||||||
|
## 同步机制
|
||||||
|
|
||||||
|
后端改接口 → 见 [SYNC.md](SYNC.md) 工作流(Phase 5 实施)
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# AdminAuth · 管理员鉴权
|
||||||
|
|
||||||
|
JWT (jsonwebtoken)。请求时 Header `Authorization: Bearer <token>`。
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| POST | `/api/v1/admin/auth/login` | - | 登录 |
|
||||||
|
| GET | `/api/v1/admin/auth/me` | ✅ | 当前账号 |
|
||||||
|
| POST | `/api/v1/admin/auth/change-password` | ✅ | 修改密码 |
|
||||||
|
|
||||||
|
## POST /api/v1/admin/auth/login
|
||||||
|
|
||||||
|
**请求体**
|
||||||
|
```json
|
||||||
|
{ "username": "admin", "password": "Yygh@2026#Admin" }
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "登录成功",
|
||||||
|
"data": {
|
||||||
|
"token": "eyJhbGc...",
|
||||||
|
"admin": { "id": "u-001", "username": "admin", "nickname": "系统管理员", "role": "super" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**错误码**
|
||||||
|
- 400 用户名 / 密码必填
|
||||||
|
- 401 用户名或密码错误
|
||||||
|
- 500 服务器内部错误
|
||||||
|
|
||||||
|
## POST /api/v1/admin/auth/change-password
|
||||||
|
|
||||||
|
**请求体**
|
||||||
|
```json
|
||||||
|
{ "oldPassword": "...", "newPassword": "新密码至少 8 位" }
|
||||||
|
```
|
||||||
|
|
||||||
|
**错误码**
|
||||||
|
- 400 原密码 / 新密码必填
|
||||||
|
- 400 新密码至少 8 位
|
||||||
|
- 400 原密码错误
|
||||||
|
- 404 账号不存在
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# Appointment · 预约挂号
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/v1/appointments` | - | 预约列表 |
|
||||||
|
| GET | `/api/v1/appointments/stats` | ✅ | 统计 |
|
||||||
|
| GET | `/api/v1/appointments/:id` | - | 详情 |
|
||||||
|
| POST | `/api/v1/appointments` | - | 创建 |
|
||||||
|
| PUT | `/api/v1/appointments/:id/cancel` | - | 取消 |
|
||||||
|
| PUT | `/api/v1/appointments/:id/confirm` | ✅ | 确认(管理后台) |
|
||||||
|
| PUT | `/api/v1/appointments/:id/complete` | ✅ | 完成(管理后台) |
|
||||||
|
| PUT | `/api/v1/appointments/:id` | ✅ | 更新备注 |
|
||||||
|
| DELETE | `/api/v1/appointments/admin/:id` | ✅ | 删除(管理后台) |
|
||||||
|
|
||||||
|
## GET /api/v1/appointments
|
||||||
|
|
||||||
|
**Query**
|
||||||
|
- `phone` - 按手机号过滤
|
||||||
|
- `status` - 'pending' / 'confirmed' / 'completed' / 'cancelled'
|
||||||
|
|
||||||
|
## POST /api/v1/appointments
|
||||||
|
|
||||||
|
**请求体**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"patientName": "张三",
|
||||||
|
"patientAge": 30,
|
||||||
|
"patientPhone": "13800138000",
|
||||||
|
"date": "2026-06-14",
|
||||||
|
"departmentName": "肛肠",
|
||||||
|
"doctorId": "doc-001",
|
||||||
|
"doctorName": "李医生",
|
||||||
|
"timeSlot": "上午",
|
||||||
|
"symptom": "便血"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**校验规则**
|
||||||
|
- `patientName` 必填,长度 1-20
|
||||||
|
- `patientAge` 必填,1-149
|
||||||
|
- `patientPhone` 必填,匹配 `^1[3-9]\d{9}$`
|
||||||
|
- `date` 必填,ISO 日期 `YYYY-MM-DD`
|
||||||
|
- `departmentName` 必填,仅支持 `肛肠` / `胃肠`
|
||||||
|
- `doctorId` / `doctorName` / `timeSlot` / `symptom` 可选
|
||||||
|
|
||||||
|
**错误码**
|
||||||
|
- 400 缺少必填参数
|
||||||
|
- 400 手机号格式不正确
|
||||||
|
- 400 年龄参数错误
|
||||||
|
- 400 科室参数仅支持:肛肠 / 胃肠
|
||||||
|
- 500 服务器内部错误
|
||||||
|
|
||||||
|
## 状态机
|
||||||
|
|
||||||
|
```
|
||||||
|
pending ──confirm──► confirmed ──complete──► completed
|
||||||
|
│ │
|
||||||
|
└─cancel──► cancelled └─cancel──► cancelled
|
||||||
|
```
|
||||||
|
|
||||||
|
completed 状态不可取消;cancelled 状态不可确认/完成。
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Banner · 轮播图
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/v1/banners` | - | 列表 |
|
||||||
|
| POST | `/api/v1/banners` | ✅ | 新增 |
|
||||||
|
| PUT | `/api/v1/banners/:id` | ✅ | 更新 |
|
||||||
|
| DELETE | `/api/v1/banners/:id` | ✅ | 删除 |
|
||||||
|
|
||||||
|
## 字段
|
||||||
|
|
||||||
|
`id` / `title` / `subtitle` / `image` / `link` / `sort` / `enabled` / `createdAt` / `updatedAt`
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Config · 首页整体配置
|
||||||
|
|
||||||
|
存储在 `home_config.data` JSON 列。**单行单列,固定 `id=1`**。
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/v1/config/home` | - | 读取首页配置 |
|
||||||
|
| PUT | `/api/v1/config/home` | ✅ | 整体更新 |
|
||||||
|
| PUT | `/api/v1/config/home/hero` | ✅ | 更新 Hero 区 |
|
||||||
|
| PUT | `/api/v1/config/home/features` | ✅ | 整体替换功能卡 |
|
||||||
|
| PUT | `/api/v1/config/home/expert-team` | ✅ | 整体替换专家团队 |
|
||||||
|
| PUT | `/api/v1/config/home/info-banner` | ✅ | 更新信息条 |
|
||||||
|
| PUT | `/api/v1/config/home/hero-experts` | ✅ | 整体替换 Hero 专家 |
|
||||||
|
|
||||||
|
## GET /api/v1/config/home
|
||||||
|
|
||||||
|
**响应** `data` 形态:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hero": {
|
||||||
|
"title": "...",
|
||||||
|
"subtitle": "...",
|
||||||
|
"bgImage": "...",
|
||||||
|
"primaryCta": { "text": "...", "link": "/pages/appointment/index" }
|
||||||
|
},
|
||||||
|
"features": [
|
||||||
|
{ "icon": "🩺", "title": "..." , "link": "..." }
|
||||||
|
],
|
||||||
|
"expertTeam": [
|
||||||
|
{ "id": "he-001", "name": "...", "title": "...", "avatar": "..." }
|
||||||
|
],
|
||||||
|
"infoBanner": { "enabled": true, "texts": ["..."] },
|
||||||
|
"heroExperts": [
|
||||||
|
{ "id": "he-001", "name": "...", "title": "...", "avatar": "..." }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Department · 科室
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/v1/departments` | - | 科室列表 |
|
||||||
|
|
||||||
|
## GET /api/v1/departments
|
||||||
|
|
||||||
|
**Query 参数**
|
||||||
|
- `hospitalId` (string, 可选) - 按医院过滤
|
||||||
|
- `enabled` ('true' | 'false', 可选) - 按启用状态过滤
|
||||||
|
|
||||||
|
**响应示例**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "d-001",
|
||||||
|
"name": "肛肠中心",
|
||||||
|
"icon": "🩺",
|
||||||
|
"description": "肛肠疾病专科",
|
||||||
|
"doctorCount": 5,
|
||||||
|
"sort": 1,
|
||||||
|
"enabled": true,
|
||||||
|
"createdAt": "...",
|
||||||
|
"updatedAt": "..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Doctor · 医生
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/v1/doctors` | - | 医生列表 |
|
||||||
|
| GET | `/api/v1/doctors/:id` | - | 医生详情 |
|
||||||
|
| POST | `/api/v1/doctors/admin` | ✅ | 新增 |
|
||||||
|
| PUT | `/api/v1/doctors/admin/:id` | ✅ | 更新 |
|
||||||
|
| DELETE | `/api/v1/doctors/admin/:id` | ✅ | 删除 |
|
||||||
|
|
||||||
|
## GET /api/v1/doctors
|
||||||
|
|
||||||
|
**Query 参数**
|
||||||
|
- `departmentId` (string) - 按科室 ID
|
||||||
|
- `departmentName` (string) - 按科室名
|
||||||
|
- `enabled` (string) - 'true' / 'false'
|
||||||
|
|
||||||
|
**响应** - `data` 是 `Doctor[]`
|
||||||
|
|
||||||
|
## Doctor 字段
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| id | string | 医生 ID |
|
||||||
|
| name | string | 姓名 |
|
||||||
|
| title | string | 职称 |
|
||||||
|
| departmentId | string \| null | 所属科室 ID |
|
||||||
|
| departmentName | string \| null | 所属科室名 |
|
||||||
|
| avatar | string | 头像 URL |
|
||||||
|
| specialty | string | 专长 |
|
||||||
|
| intro | string | 简介 |
|
||||||
|
| fee | number | 挂号费 |
|
||||||
|
| rating | number | 评分 |
|
||||||
|
| availableDates | string[] | 可预约日期(ISO) |
|
||||||
|
| enabled | boolean | 启用状态 |
|
||||||
|
| createdAt | string | ISO datetime |
|
||||||
|
| updatedAt | string | ISO datetime |
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Expert · 专家资源
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/v1/experts` | - | 列表(?enabled=true) |
|
||||||
|
| GET | `/api/v1/experts/:id` | - | 详情 |
|
||||||
|
| POST | `/api/v1/experts` | ✅ | 新增 |
|
||||||
|
| PUT | `/api/v1/experts/:id` | ✅ | 更新 |
|
||||||
|
| DELETE | `/api/v1/experts/:id` | ✅ | 删除 |
|
||||||
|
| POST | `/api/v1/experts/upload` | ✅ | 上传(url / base64) |
|
||||||
|
|
||||||
|
## 字段
|
||||||
|
|
||||||
|
`id` / `name` / `title` / `avatar` / `department` / `intro` / `sort` / `enabled` / `createdAt` / `updatedAt`
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Hospital · 医院信息
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/api/v1/hospitals` | - | 医院列表 |
|
||||||
|
| GET | `/api/v1/hospitals/:id` | - | 医院详情 |
|
||||||
|
|
||||||
|
## GET /api/v1/hospitals
|
||||||
|
|
||||||
|
**响应示例**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": "h-001",
|
||||||
|
"name": "苏州肛泰中医院",
|
||||||
|
"level": "三甲",
|
||||||
|
"address": "苏州市姑苏区吴中西路 888 号",
|
||||||
|
"phone": "0512-6586-3999",
|
||||||
|
"intro": "胃肠肛肠专科医院 · 三甲名医亲诊",
|
||||||
|
"description": "...",
|
||||||
|
"banner": "https://...",
|
||||||
|
"logo": "https://...",
|
||||||
|
"established": "1998",
|
||||||
|
"departments": 12,
|
||||||
|
"doctors": 35,
|
||||||
|
"beds": 200,
|
||||||
|
"createdAt": "2024-01-01T00:00:00.000Z",
|
||||||
|
"updatedAt": "2024-01-01T00:00:00.000Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## GET /api/v1/hospitals/:id
|
||||||
|
|
||||||
|
**路径参数**
|
||||||
|
- `id` (string, 必填) - 医院 ID
|
||||||
|
|
||||||
|
**错误响应**
|
||||||
|
- 404 医院不存在
|
||||||
|
- 500 服务器内部错误
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# HospitalImage · 医院图片
|
||||||
|
|
||||||
|
维护医院"简介"栏目展示的图片 (轮播/单图)。小程序 `hospital` 页"医院简介" tab 直接拉取启用项展示。
|
||||||
|
|
||||||
|
## 接口
|
||||||
|
|
||||||
|
| 方法 | 路径 | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | /api/v1/hospital-images | 否 | 列表 (支持 `?enabled=true` 过滤) |
|
||||||
|
| GET | /api/v1/hospital-images/:id | 否 | 详情 |
|
||||||
|
| POST | /api/v1/hospital-images | 是 | 新增 |
|
||||||
|
| PUT | /api/v1/hospital-images/:id | 是 | 更新 |
|
||||||
|
| DELETE | /api/v1/hospital-images/:id | 是 | 删除 |
|
||||||
|
| POST | /api/v1/uploads/image | 是 | 通用图片上传 (base64 → dataURL) |
|
||||||
|
|
||||||
|
## DTO 字段
|
||||||
|
|
||||||
|
- `hospitalId` 关联医院 id (默认 h-001)
|
||||||
|
- `image` 图片 URL 或 dataURL
|
||||||
|
- `caption` 图片说明
|
||||||
|
- `sort` 排序 (升序)
|
||||||
|
- `enabled` 是否启用
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
# Lead · 意向客户(Phase 3)
|
||||||
|
|
||||||
|
> 自主问卷用户信息采集的统一入口,落到 `leads` 表,供管理后台跟进。
|
||||||
|
|
||||||
|
## 接口表
|
||||||
|
|
||||||
|
| Method | Path | 鉴权 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| POST | `/api/v1/leads` | - | 提交(小程序自测问卷、首页落地等) |
|
||||||
|
| GET | `/api/v1/leads/stats` | ✅ | 统计:总数 / 24h / 按 source 分组 |
|
||||||
|
| GET | `/api/v1/admin/leads` | ✅ | 列表,支持 phone / source / keyword / 时间过滤 |
|
||||||
|
| GET | `/api/v1/admin/leads/:id` | ✅ | 详情 |
|
||||||
|
| PUT | `/api/v1/admin/leads/:id/remark` | ✅ | 修改备注 |
|
||||||
|
| DELETE | `/api/v1/admin/leads/:id` | ✅ | 删除 |
|
||||||
|
|
||||||
|
## POST /api/v1/leads
|
||||||
|
|
||||||
|
**请求体**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "张三",
|
||||||
|
"phone": "13800138000",
|
||||||
|
"symptom": "便血近 1 周,伴有肛门坠胀",
|
||||||
|
"questionnaire": {
|
||||||
|
"total": 5,
|
||||||
|
"answers": { "0": "sometimes", "1": "no" },
|
||||||
|
"createdAt": "2026-06-14T08:30:00.000Z"
|
||||||
|
},
|
||||||
|
"source": "self-test",
|
||||||
|
"score": 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**校验规则**
|
||||||
|
- `name` 必填,1-20 字符
|
||||||
|
- `phone` 必填,匹配 `^1[3-9]\d{9}$`
|
||||||
|
- `symptom` 可选,≤ 500 字
|
||||||
|
- `questionnaire` 必填,任意 JSON 对象
|
||||||
|
- `source` 可选,枚举 `self-test` / `home` / `appointment` / `other`,默认 `self-test`
|
||||||
|
- `score` 可选,0-100
|
||||||
|
|
||||||
|
**响应**
|
||||||
|
```json
|
||||||
|
{ "code": 0, "message": "提交成功", "data": { "id": "lead-1781398800000", "createdAt": "2026-06-14 16:30:00" } }
|
||||||
|
```
|
||||||
|
|
||||||
|
**错误码**
|
||||||
|
| HTTP | code | message |
|
||||||
|
|---|---|---|
|
||||||
|
| 400 | 1 | 姓名必填 / 姓名长度需在 1-20 字符 |
|
||||||
|
| 400 | 1 | 手机号必填 / 手机号格式不正确 |
|
||||||
|
| 400 | 1 | 症状描述不超过 500 字 |
|
||||||
|
| 400 | 1 | 问卷答案 questionnaire 必填且为对象 |
|
||||||
|
| 400 | 1 | source 仅支持:self-test / home / appointment / other |
|
||||||
|
| 400 | 1 | 该手机号在同渠道已提交过,请勿重复 |
|
||||||
|
| 500 | 500 | 服务器内部错误 |
|
||||||
|
|
||||||
|
## GET /api/v1/admin/leads
|
||||||
|
|
||||||
|
**Query**
|
||||||
|
- `phone` 手机号精确匹配
|
||||||
|
- `source` 渠道
|
||||||
|
- `keyword` 姓名模糊匹配
|
||||||
|
- `startDate` / `endDate` 时间范围(`YYYY-MM-DD`)
|
||||||
|
- `limit` 默认 50,最大 200
|
||||||
|
- `offset` 默认 0
|
||||||
|
|
||||||
|
**响应**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "ok",
|
||||||
|
"data": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"id": "lead-1781398800000",
|
||||||
|
"name": "张三",
|
||||||
|
"phone": "13800138000",
|
||||||
|
"symptom": "便血近 1 周",
|
||||||
|
"questionnaire": { "total": 5, "answers": {} },
|
||||||
|
"source": "self-test",
|
||||||
|
"score": 5,
|
||||||
|
"remark": "",
|
||||||
|
"createdAt": "2026-06-14 16:30:00",
|
||||||
|
"updatedAt": "2026-06-14 16:30:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"total": 1,
|
||||||
|
"limit": 50,
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据表
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE leads (
|
||||||
|
id VARCHAR(32) PRIMARY KEY,
|
||||||
|
name VARCHAR(50) NOT NULL,
|
||||||
|
phone VARCHAR(20) NOT NULL,
|
||||||
|
symptom TEXT,
|
||||||
|
questionnaire JSON NOT NULL,
|
||||||
|
source VARCHAR(20) NOT NULL DEFAULT 'self-test',
|
||||||
|
score INT DEFAULT 0,
|
||||||
|
remark VARCHAR(500),
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY uniq_phone_source (phone, source)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
唯一约束 `(phone, source)`:同手机号在同一渠道只保留一条。
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
# 苏州肛泰中医院 · v2 平台化升级实施计划
|
||||||
|
|
||||||
|
> **For agentic workers:** 按 Phase 顺序执行,每个 Phase 都是可独立交付的 milestone,用户可在任意 Phase 完成后暂停/调整方向。
|
||||||
|
> **执行策略**:Phase 内逐步交付,每个 bite-sized 任务完成后等待用户确认再继续。
|
||||||
|
|
||||||
|
**Goal**:把当前"医院小程序 + 后端 + 管理后台"从"能跑"升级到"企业级可维护",覆盖 4 大需求:API 标准化、视觉重塑、问卷增强、模块化重构。
|
||||||
|
|
||||||
|
**Architecture**:
|
||||||
|
- 后端:Express + MySQL,新增 Swagger/OpenAPI 自动文档 + Markdown 接口规范 + `/api/leads` 新表 + 业务域 service 拆分
|
||||||
|
- 前端:Taro 4 + React 18 + TS 5,新增 `modules/lead` 业务域模块 + 全局 design tokens 重塑(低饱和度专业色系)
|
||||||
|
- 管理后台:原生 SPA 风格不变,新增 leads 客户列表 + 接口版本号展示
|
||||||
|
|
||||||
|
**Tech Stack**:
|
||||||
|
- 后端:Express 4 / mysql2 / dayjs / **新增** swagger-ui-express + swagger-jsdoc + apidoc
|
||||||
|
- 前端:Taro 4.1 / React 18 / TypeScript 5 / Sass / Zustand / **新增** modules/lead 域
|
||||||
|
- 数据库:MariaDB 10.x,新增 `leads` 表
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 总览
|
||||||
|
|
||||||
|
| Phase | 主题 | 涉及文件数 | 估时 | 依赖 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| **P1** | 业务域 service 拆分(模块化基础) | 14 改 + 6 新增 | 1.5h | 无 |
|
||||||
|
| **P2** | Swagger + Markdown 接口文档 | 4 改 + 3 新增 | 1h | P1 |
|
||||||
|
| **P3** | 问卷 / 自主测试 + 用户信息采集 + leads 表 | 1 改 + 2 新增 | 1.5h | P1, P2 |
|
||||||
|
| **P4** | 全局设计 tokens 重塑 + 主流程 6 页视觉升级 | 1 改 + 6 改 | 1.5h | P1 |
|
||||||
|
| **P5** | 接口版本控制 / 同步机制 | 2 改 + 1 新增 | 0.5h | P2 |
|
||||||
|
|
||||||
|
**总估时**:~6h(4 个 milestone 验收点,可分多次完成)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1:业务域 service 拆分(高内聚低耦合)
|
||||||
|
|
||||||
|
**目标**:把 `server/src/routes/*` 按业务域重组,添加 README,建立模块化骨架。
|
||||||
|
|
||||||
|
### 任务清单
|
||||||
|
|
||||||
|
- [ ] **Task 1.1** 新建 `server/src/modules/hospital/` 目录,迁移 `routes/hospital.js` → `modules/hospital/route.js` + 新增 `modules/hospital/service.js`(查询逻辑)+ `modules/hospital/README.md`
|
||||||
|
- [ ] **Task 1.2** 同样模式处理 `department` / `doctor` / `appointment` / `expert` / `banner` / `config` 6 个域
|
||||||
|
- [ ] **Task 1.3** 新建 `server/src/modules/index.js` 统一注册 router
|
||||||
|
- [ ] **Task 1.4** 修改 `server/src/index.js`:把 `app.use('/api/...', router)` 改为 `app.use('/api/v1/...', router)`(**v1 是版本号起点**)
|
||||||
|
- [ ] **Task 1.5** 写 `server/src/modules/README.md`:描述每个模块的 `route.js`(HTTP 层)/`service.js`(业务逻辑)/`dto.js`(数据转换)`README.md`(接口说明)规范
|
||||||
|
- [ ] **Task 1.6** 验证:PM2 重启后 `curl /api/v1/hospitals` 仍返回 `code:0, data:[...]`
|
||||||
|
|
||||||
|
**验收标准**:
|
||||||
|
- 每个业务域目录包含 route/service/dto/README 四件套
|
||||||
|
- 服务启动日志接口列表全部以 `/api/v1` 开头
|
||||||
|
- 前端 services/*.ts 调用的 URL 由 `/api/...` 改为 `/api/v1/...`(同时**前端 BASE_URL 配置新增版本号**)
|
||||||
|
- 数据库交互全部经过 service.js,route.js 不再直接写 SQL
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2:Swagger UI + Markdown 接口文档
|
||||||
|
|
||||||
|
**目标**:自动生成 OpenAPI 3.0 规范 + Markdown 业务说明,浏览器可访问 `/api/docs`。
|
||||||
|
|
||||||
|
### 任务清单
|
||||||
|
|
||||||
|
- [ ] **Task 2.1** 安装依赖:`cd server && npm i swagger-ui-express swagger-jsdoc`
|
||||||
|
- [ ] **Task 2.2** 新建 `server/src/swagger/spec.js`:配置 swagger-jsdoc,扫描 `modules/*/route.js` 的 JSDoc 注释,生成 OpenAPI 3.0 spec
|
||||||
|
- [ ] **Task 2.3** 在 `server/src/index.js` 注册 `app.use('/api/docs', swaggerUi.serve, swaggerUi.setup(spec))` + `app.get('/api/docs.json', ...)` 输出原始 spec
|
||||||
|
- [ ] **Task 2.4** 给 7 个 module 的 route.js 关键接口加 JSDoc:`@swagger` 路径,包含 path/method/parameters/responses
|
||||||
|
- [ ] **Task 2.5** 新建 `docs/api/README.md`:API 总览(基地址、版本、认证、错误码约定)
|
||||||
|
- [ ] **Task 2.6** 新建 `docs/api/v1/hospital.md`、`department.md`、`doctor.md`、`appointment.md`、`expert.md`、`banner.md`、`config.md`、`admin-auth.md`、`lead.md`(lead 是 P3 的)
|
||||||
|
- [ ] **Task 2.7** 新建 `docs/api/CHANGELOG.md`:版本变更记录
|
||||||
|
|
||||||
|
**验收标准**:
|
||||||
|
- 浏览器访问 `http://124.221.67.199:3000/api/docs/` 显示完整 API 文档
|
||||||
|
- 8 个 markdown 文档,每个包含:接口路径 / 方法 / 请求参数表 / 响应示例 / 错误码 / 业务说明
|
||||||
|
- CHANGELOG 记录 v1.0.0 → v1.1.0 的接口变更
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3:自主问卷用户信息采集 + leads 表
|
||||||
|
|
||||||
|
**目标**:问卷底部新增姓名/手机号/症状采集区,前后端校验,提交到 `/api/v1/leads`。
|
||||||
|
|
||||||
|
### 任务清单
|
||||||
|
|
||||||
|
- [ ] **Task 3.1** 数据库:在 `server/src/schema.sql` 末尾追加 `CREATE TABLE leads (...)`:id / name / phone / symptom / questionnaire JSON / source / created_at,加唯一索引 `(phone, source)`
|
||||||
|
- [ ] **Task 3.2** 后端:新建 `server/src/modules/lead/route.js`(POST 提交 / GET 列表 / GET 详情)
|
||||||
|
- [ ] **Task 3.3** 后端:新建 `server/src/modules/lead/service.js`:手机号正则、问卷 JSON 解析、source 枚举校验
|
||||||
|
- [ ] **Task 3.4** 后端:新建 `server/src/modules/lead/dto.js` + `README.md`
|
||||||
|
- [ ] **Task 3.5** 前端:新建 `src/modules/lead/types.ts`(Lead / LeadForm TS 类型)
|
||||||
|
- [ ] **Task 3.6** 前端:新建 `src/modules/lead/api.ts`(submitLead / fetchLeads)
|
||||||
|
- [ ] **Task 3.7** 前端:修改 `src/pages/self-test/index.tsx`:底部加 `<View className={styles.userInfoSection}>`,包含姓名 Input / 手机 Input / 症状 Textarea,"提交问卷结果"按钮
|
||||||
|
- [ ] **Task 3.8** 前端:表单校验(姓名 1-20 字符 / 手机 `^1[3-9]\d{9}$` / 症状 ≤500 字 / 必填),错误内联展示
|
||||||
|
- [ ] **Task 3.9** 前端:成功后调 `submitLead`,后端返回 leadId,跳 `/pages/success/index?type=lead&id=...`
|
||||||
|
- [ ] **Task 3.10** 管理后台:在 `admin/index.html` 加 `/admin/leads` 标签页,列表展示姓名/手机/来源/时间/问卷结果 JSON 折叠
|
||||||
|
- [ ] **Task 3.11** 后端:新增 `GET /api/v1/admin/leads`(authRequired)给管理后台用
|
||||||
|
|
||||||
|
**验收标准**:
|
||||||
|
- `curl -X POST /api/v1/leads -d '{"name":"...","phone":"...","questionnaire":{...}}'` 返回 200 + leadId
|
||||||
|
- 手机号不合法 → 后端 400 `{code:400, message:"手机号格式不正确"}`
|
||||||
|
- 数据库 `SELECT * FROM leads` 看到刚提交的行
|
||||||
|
- 小程序端提交 → 管理后台 `/admin/leads` 立即看到
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4:设计 tokens 重塑 + 主流程 6 页视觉升级
|
||||||
|
|
||||||
|
**目标**:低饱和度专业色系(去掉原 #1f7ae0 高饱蓝),升级 6 个主流程页视觉。
|
||||||
|
|
||||||
|
### 任务清单
|
||||||
|
|
||||||
|
- [ ] **Task 4.1** 重构 `src/styles/theme.scss`:主色改为 `#0f766e`(低饱和度医绿)或 `#475569`(深石板蓝),辅色 `border-radius` 提升到 12-16rpx,阴影由硬阴影改为柔阴影 `0 2px 8px rgba(15,23,42,.04) → 0 1px 3px rgba(15,23,42,.06), 0 4px 16px rgba(15,23,42,.04)`
|
||||||
|
- [ ] **Task 4.2** 重构 `src/styles/variables.scss`:间距 8pt 网格(`$spacing-1: 4rpx; $spacing-2: 8rpx; ...`),字号阶梯
|
||||||
|
- [ ] **Task 4.3** 新建 `src/styles/mixins.scss`:`@mixin card` / `@mixin btn-primary` / `@mixin section-title`,统一卡片/按钮/章节头样式
|
||||||
|
- [ ] **Task 4.4** 首页:使用 mixins 重写 `home/index.module.scss`,增大 Hero 留白,专家头像由 64rpx → 80rpx
|
||||||
|
- [ ] **Task 4.5** 医院页:科室网格由 4 列 → 3 列,卡片高度 220rpx → 240rpx,加 hover 状态
|
||||||
|
- [ ] **Task 4.6** 预约页:表单分组由密集 → 留白充足,提交按钮加 24rpx 圆角
|
||||||
|
- [ ] **Task 4.7** 问卷页:题目卡片加大内边距,选项 hover 加 border 高亮
|
||||||
|
- [ ] **Task 4.8** 成功页:成功图标由 emoji → SVG,结果列表用左侧色条
|
||||||
|
- [ ] **Task 4.9** 我的页:菜单项由 2 列 → 1 列 + 右侧箭头,更接近企业级
|
||||||
|
- [ ] **Task 4.10** 全站 6 个页面 `pages.config.json` 标题统一"苏州肛泰中医院 - X"
|
||||||
|
|
||||||
|
**验收标准**:
|
||||||
|
- 全站色系用 `<kbd>ColorPick</kbd>` 取色,所有页面主色都从 tokens 派生(无硬编码颜色)
|
||||||
|
- 阴影统一两层:近阴影(按钮/输入框) + 远阴影(卡片/弹层)
|
||||||
|
- 6 个页面对比之前截图,整体更"沉稳专业"(非"活泼可爱")
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5:接口版本控制与同步机制
|
||||||
|
|
||||||
|
**目标**:建立 `/api/v1` 之后到 `/api/v2` 的兼容/弃用/移除规范。
|
||||||
|
|
||||||
|
### 任务清单
|
||||||
|
|
||||||
|
- [ ] **Task 5.1** 后端:新增 `server/src/middleware/apiVersion.js`:响应头加 `X-API-Version: v1` 和 `Sunset` 头(如果 deprecated)
|
||||||
|
- [ ] **Task 5.2** 后端:新增 `server/src/middleware/changelogBroadcast.js`:每次启动时把当前版本号 + CHANGELOG.md 摘要写入 `server_runtime.log`
|
||||||
|
- [ ] **Task 5.3** 前端:新增 `src/services/apiVersion.ts`:请求时带 `X-Client-Version` 头,响应时检查 `Sunset` 头并 toast 提示
|
||||||
|
- [ ] **Task 5.4** 新建 `docs/api/SYNC.md`:描述后端接口变更 → 前端同步流程
|
||||||
|
1. 后端开发改 route.js + swagger JSDoc
|
||||||
|
2. `npm run docs:gen` 自动更新 markdown
|
||||||
|
3. 在 `docs/api/CHANGELOG.md` 加一行
|
||||||
|
4. 前端 `pnpm sync-api` 拉取 `/api/docs.json` 生成 `types/api/*.d.ts`
|
||||||
|
5. 前端 IDE 报类型错误 → 定位 + 修改
|
||||||
|
- [ ] **Task 5.5** 新建 `docs/superpowers/plans/2026-06-13-api-sync-workflow.md`:详细描述开发者日常流程
|
||||||
|
|
||||||
|
**验收标准**:
|
||||||
|
- `curl -I /api/v1/hospitals` 响应头包含 `X-API-Version: v1`
|
||||||
|
- 前端 `apiVersion.ts` 在收到 Sunset 头时 `Taro.showToast({ title: '接口即将停用,请更新 APP', icon: 'none' })`
|
||||||
|
- docs/api/SYNC.md 描述的工作流可被新开发者 5 分钟内理解
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 风险与回滚
|
||||||
|
|
||||||
|
| 风险 | 缓解 |
|
||||||
|
|---|---|
|
||||||
|
| Phase 4 视觉改坏既有页面 | 保留 theme 旧版 v1 注释,可在 1 行切换 |
|
||||||
|
| Phase 1 改 URL 前缀 `/api/v1` 影响前端联调 | 同步修改 `src/services/request.ts` 的 BASE_URL 拼接逻辑 |
|
||||||
|
| Phase 3 leads 表字段缺索引 | `(phone, source)` 加唯一索引 + `created_at` 加普通索引 |
|
||||||
|
| Phase 5 Sunset 头跨域被浏览器剥 | Nginx/proxy 不应剥自定义响应头,标注到部署文档 |
|
||||||
|
|
||||||
|
## 验收里程碑(用户暂停点)
|
||||||
|
|
||||||
|
- **M1**:Phase 1 完成后,前端 `pnpm dev` + 后端 `npm start` 全栈联通,业务不变
|
||||||
|
- **M2**:Phase 2 完成后,`/api/docs` 可访问,8 个 markdown 文档齐全
|
||||||
|
- **M3**:Phase 3 完成后,问卷可提交 + 管理后台可见
|
||||||
|
- **M4**:Phase 4 完成后,6 页视觉一致、设计 tokens 单点控制
|
||||||
|
- **M5**:Phase 5 完成后,接口版本与同步流程文档化
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
# Phase 4 · 设计 tokens 重塑 + 主流程 6 页视觉升级
|
||||||
|
|
||||||
|
## 范围
|
||||||
|
|
||||||
|
- 6 个核心页面: home / hospital / appointment / phone-consult / self-test / success
|
||||||
|
- 目标: 整洁美观、提升品质感
|
||||||
|
- 手段: 设计 token 优化 + 6 页视觉重构
|
||||||
|
|
||||||
|
## 设计 Thesis(一句话)
|
||||||
|
|
||||||
|
> 用 **医疗级克制美学** + **人文摄影** + **精准排版层级**,告别卡片堆叠,改为分栏 + divider + 全宽背景区,让用户在一屏内完成 "我该做什么" 的判断。
|
||||||
|
|
||||||
|
## Visual Thesis
|
||||||
|
|
||||||
|
- **氛围**: 医疗专业 × 苏州江南温润(降低饱和、加微暖)
|
||||||
|
- **材质**: 大面积白 + 极浅米灰背景(#fafbfc),用品牌蓝绿做局部强调
|
||||||
|
- **能量**: 安静、稳定、可信赖——> 留白 + 排版权重做主节奏
|
||||||
|
|
||||||
|
## Content Plan(6 页)
|
||||||
|
|
||||||
|
| # | 页面 | 主任务 | 主导视觉 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | home 首页 | 引导用户进入预约/咨询/自测 | 真实医院外景 hero + 3 个分栏入口 + 科室速选 |
|
||||||
|
| 2 | hospital 医院详情 | 了解医院+选科室 | 医院环境图 + 实力数据 + 科室列表(无卡片) |
|
||||||
|
| 3 | appointment 预约 | 提交预约信息 | 单一表单焦点 + 步骤条 |
|
||||||
|
| 4 | phone-consult 电话咨询 | 选专家并拨号 | 专家横向滚动(行) + 拨号区 |
|
||||||
|
| 5 | self-test 自测 | 答题+留资 | 进度条主导 + 题卡 + 底部信息采集 |
|
||||||
|
| 6 | success 成功 | 确认+下一步 | 大号 ✓ 符号 + 信息行(无卡) |
|
||||||
|
|
||||||
|
## Interaction Thesis(2-3 个核心动效)
|
||||||
|
|
||||||
|
1. **入场 fadeInUp**: 首屏内容从下方 16rpx 渐入,延迟 0/80/160ms 形成节奏
|
||||||
|
2. **按下反馈**: 按钮 active 状态 `scale(0.97)` + 透明度 0.85(已有 mixin)
|
||||||
|
3. **scroll reveal**: ScrollView 内区块在视口出现时 fadeIn(用 IntersectionObserver,小程序内用 onScroll)
|
||||||
|
|
||||||
|
## Token 优化清单
|
||||||
|
|
||||||
|
### A. 颜色: 收敛与精致
|
||||||
|
|
||||||
|
- **主品牌色**: `#1f7ae0` → `#0a6dff`(更精炼的"医蓝"),加 50/100/200/300/500/600/700 完整色阶
|
||||||
|
- **辅色**: 青绿 `#15b9a3` 保留,但使用率≤15%
|
||||||
|
- **新增"米杏"色系**: `#fafbfc` 背景 / `#f4f1ec` 卡片底 / `#f0e6d6` 强调区(降低冷感、提升温度)
|
||||||
|
- **价格色**: `#ff5e3a` → `#e85a3c`(更稳重)
|
||||||
|
- 删:`$color-text-disabled` 浅灰改为 `$color-text-tertiary` 的 60% opacity
|
||||||
|
|
||||||
|
### B. 排版: 增强层级
|
||||||
|
|
||||||
|
- 引入"两套字重"原则: 标题用 $font-weight-bold,正文用 regular,**不混用 medium 太多**
|
||||||
|
- 新增 `$letter-spacing-tight: -0.01em`(标题字距)
|
||||||
|
- 新增 `$letter-spacing-loose: 0.04em`(小标签字距)
|
||||||
|
|
||||||
|
### C. 阴影: 收为 3 级
|
||||||
|
|
||||||
|
- 现有 5 级 → 3 级: `$shadow-1` (xs) / `$shadow-2` (md) / `$shadow-3` (lg)
|
||||||
|
- 删除 `$shadow-xs`、合并 `$shadow-sm` → 1
|
||||||
|
|
||||||
|
### D. 圆角: 收敛
|
||||||
|
|
||||||
|
- 主要用 8/12/16,删除 20/24(过圆损失专业感)
|
||||||
|
- 按钮仍用全圆角(`$radius-button: 999rpx`)
|
||||||
|
|
||||||
|
### E. 间距: 加 `$page-gutter`
|
||||||
|
|
||||||
|
- 现有 `$page-spacing: 32rpx` → 改为 `$page-gutter: 24rpx`(更紧凑、更易扫读)
|
||||||
|
|
||||||
|
### F. 新增 Z-index 标准化
|
||||||
|
|
||||||
|
- 现有 ok,不动
|
||||||
|
|
||||||
|
## 6 页视觉重做
|
||||||
|
|
||||||
|
### home 首页
|
||||||
|
- **删除**: 顶部 banner 条、三个并列卡片式入口、医生推荐卡
|
||||||
|
- **改为**:
|
||||||
|
- 全宽 hero: 医院外景图 + 品牌名 + 一句承诺
|
||||||
|
- 3 个入口: divider 分隔的 3 行(不用卡片),左 icon + 标题 + 副文 + 箭头
|
||||||
|
- 科室速选: 横向滚动 chip(去卡片)
|
||||||
|
- 专家推荐: 1 个真实人物照 + 文案段(无卡)
|
||||||
|
- 底部信息采集卡(自测入口): 全宽背景图 + 居中标题 + 1 按钮
|
||||||
|
|
||||||
|
### hospital 医院详情
|
||||||
|
- **删除**: 顶部图、卡式信息块
|
||||||
|
- **改为**:
|
||||||
|
- 医院环境照(全宽,16:9)
|
||||||
|
- 医院简介: 段落式,首字下沉
|
||||||
|
- 实力数据: 4 列数字 + 标签(无卡,divider 隔开)
|
||||||
|
- 科室列表: 折叠面板(可展开),不用卡片
|
||||||
|
- 底部固定: 立即预约 CTA
|
||||||
|
|
||||||
|
### appointment 预约
|
||||||
|
- **删除**: 多步向导里的"步骤卡"
|
||||||
|
- **改为**:
|
||||||
|
- 步骤指示器: 4 个圆点 + 连线
|
||||||
|
- 单一表单焦点: 当前步骤内容居中,信息密度大
|
||||||
|
- 字段: 大输入框(高 96rpx),label 在上方
|
||||||
|
- 提交按钮: 底部固定主色渐变按钮(高 96rpx)
|
||||||
|
|
||||||
|
### phone-consult 电话咨询
|
||||||
|
- **删除**: 9 宫格、卡片式专家列表
|
||||||
|
- **改为**:
|
||||||
|
- 顶部 hero: "24h 健康热线" + 大号电话号(可点击拨号)
|
||||||
|
- 专家列表: 横向滚动,每个专家是一行(头像 + 姓名 + 简介 + 拨号按钮)
|
||||||
|
- 底部说明: 2-3 段文字,无卡
|
||||||
|
|
||||||
|
### self-test 自测
|
||||||
|
- 已 Phase 3 改造完成,本阶段只做视觉微调
|
||||||
|
- 优化: 进度条改用更细的 4rpx,圆角降低
|
||||||
|
- 题卡从阴影改为分隔线
|
||||||
|
- 用户信息区改为无阴影背景
|
||||||
|
|
||||||
|
### success 成功
|
||||||
|
- **删除**: 卡片包裹
|
||||||
|
- **改为**:
|
||||||
|
- 顶部 1/3 高度: 大号 ✓ 居中(无背景)
|
||||||
|
- 中部信息行: divider 分隔的列表(医院/患者/电话/科室/时间)
|
||||||
|
- 底部双按钮: 圆角胶囊,主次分明
|
||||||
|
|
||||||
|
## 实施步骤
|
||||||
|
|
||||||
|
1. **Task 4.1**: 重写 [src/styles/theme.scss](file:///Users/skn/Desktop/yuyueguahao/src/styles/theme.scss),新增色阶/排版变量,精简阴影圆角
|
||||||
|
2. **Task 4.2**: 同步更新 [src/styles/variables.scss](file:///Users/skn/Desktop/yuyueguahao/src/styles/variables.scss) 转发关系(避免变量重复定义)
|
||||||
|
3. **Task 4.3**: home 页重做
|
||||||
|
4. **Task 4.4**: hospital 页重做
|
||||||
|
5. **Task 4.5**: appointment 页重做
|
||||||
|
6. **Task 4.6**: phone-consult 页重做
|
||||||
|
7. **Task 4.7**: self-test 页视觉微调
|
||||||
|
8. **Task 4.8**: success 页重做
|
||||||
|
9. **Task 4.9**: 部署 + 视觉验证(上传 taro dist 或仅改 SCSS)
|
||||||
|
|
||||||
|
## 设计原则硬约束
|
||||||
|
|
||||||
|
- ✅ 严格 1 个主品牌色 + 1 个辅色
|
||||||
|
- ✅ 卡片只在 card-as-interaction 时使用(如自测题卡、日期选择)
|
||||||
|
- ✅ 所有 hero 区是全宽,不留左右页边距
|
||||||
|
- ✅ 标题用 bold,正文用 regular,不混用 medium 太多
|
||||||
|
- ✅ 留白 ≥ 32rpx(区块之间)
|
||||||
|
- ✅ 字距: 标题 -0.01em,小标签 0.04em
|
||||||
|
|
||||||
|
## 暂缓(避免范围蔓延)
|
||||||
|
|
||||||
|
- 不做 Framer Motion 等大型动效库(小程序不友好)
|
||||||
|
- 不换字体(用系统字体)
|
||||||
|
- 不做国际化
|
||||||
|
|
||||||
|
## 风险
|
||||||
|
|
||||||
|
- 小程序 SCSS 变量是编译期,改 theme 后需要 `npm run build:weapp`
|
||||||
|
- 后端与本次重做无关,只改前端 + theme
|
||||||
|
|
||||||
|
## 验收
|
||||||
|
|
||||||
|
- 6 页均可 `npm run dev:weapp` 编译通过
|
||||||
|
- 在微信开发者工具中,6 页布局正常,无样式丢失
|
||||||
|
- 后端 API 调用与 Phase 3 保持一致(无破坏)
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
{
|
||||||
|
"name": "taro_template",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"description": "taro_template",
|
||||||
|
"templateInfo": {
|
||||||
|
"name": "react",
|
||||||
|
"typescript": true,
|
||||||
|
"css": "Sass",
|
||||||
|
"framework": "React"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build:weapp": "taro build --type weapp",
|
||||||
|
"build:swan": "taro build --type swan",
|
||||||
|
"build:alipay": "taro build --type alipay",
|
||||||
|
"build:tt": "taro build --type tt",
|
||||||
|
"build:h5": "taro build --type h5",
|
||||||
|
"build:rn": "taro build --type rn",
|
||||||
|
"build:qq": "taro build --type qq",
|
||||||
|
"build:jd": "taro build --type jd",
|
||||||
|
"build:quickapp": "taro build --type quickapp",
|
||||||
|
"dev:weapp": "npm run build:weapp -- --watch",
|
||||||
|
"dev:swan": "npm run build:swan -- --watch",
|
||||||
|
"dev:alipay": "npm run build:alipay -- --watch",
|
||||||
|
"dev:tt": "npm run build:tt -- --watch",
|
||||||
|
"dev:h5": "npm run build:h5 -- --watch",
|
||||||
|
"dev:rn": "npm run build:rn -- --watch",
|
||||||
|
"dev:qq": "npm run build:qq -- --watch",
|
||||||
|
"dev:jd": "npm run build:jd -- --watch",
|
||||||
|
"dev:quickapp": "npm run build:quickapp -- --watch"
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"last 3 versions",
|
||||||
|
"Android >= 4.1",
|
||||||
|
"ios >= 8"
|
||||||
|
],
|
||||||
|
"author": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.21.5",
|
||||||
|
"@tarojs/components": "4.1.9",
|
||||||
|
"@tarojs/helper": "4.1.9",
|
||||||
|
"@tarojs/plugin-framework-react": "4.1.9",
|
||||||
|
"@tarojs/plugin-html": "4.1.9",
|
||||||
|
"@tarojs/plugin-platform-alipay": "4.1.9",
|
||||||
|
"@tarojs/plugin-platform-h5": "4.1.9",
|
||||||
|
"@tarojs/plugin-platform-tt": "4.1.9",
|
||||||
|
"@tarojs/plugin-platform-weapp": "4.1.9",
|
||||||
|
"@tarojs/react": "4.1.9",
|
||||||
|
"@tarojs/runtime": "4.1.9",
|
||||||
|
"@tarojs/shared": "4.1.9",
|
||||||
|
"@tarojs/taro": "4.1.9",
|
||||||
|
"classnames": "^2.5.0",
|
||||||
|
"dayjs": "^1.11.10",
|
||||||
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0",
|
||||||
|
"zustand": "^4.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.8.0",
|
||||||
|
"@babel/plugin-proposal-class-properties": "7.14.5",
|
||||||
|
"@babel/preset-react": "^7.24.1",
|
||||||
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
|
||||||
|
"@tarojs/cli": "4.1.9",
|
||||||
|
"@tarojs/taro-loader": "4.1.9",
|
||||||
|
"@tarojs/webpack5-runner": "4.1.9",
|
||||||
|
"@types/node": "^18.15.11",
|
||||||
|
"@types/react": "^18.0.0",
|
||||||
|
"@types/webpack-env": "^1.13.6",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
||||||
|
"@typescript-eslint/parser": "^6.2.0",
|
||||||
|
"ajv": "^8.20.0",
|
||||||
|
"babel-plugin-import": "^1.13.8",
|
||||||
|
"babel-preset-taro": "4.1.9",
|
||||||
|
"eslint": "^8.12.0",
|
||||||
|
"eslint-config-taro": "4.1.9",
|
||||||
|
"eslint-plugin-import": "^2.12.0",
|
||||||
|
"eslint-plugin-react": "^7.8.2",
|
||||||
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
|
"minidev": "^2.2.5",
|
||||||
|
"miniprogram-ci": "^2.1.26",
|
||||||
|
"postcss": "^8.4.18",
|
||||||
|
"react-refresh": "^0.11.0",
|
||||||
|
"stylelint": "^14.4.0",
|
||||||
|
"ts-node": "^10.9.1",
|
||||||
|
"tsconfig-paths-webpack-plugin": "^4.0.1",
|
||||||
|
"tt-ide-cli": "^0.1.31",
|
||||||
|
"typescript": "^5.1.0",
|
||||||
|
"webpack": "5.78.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"miniprogramRoot": "dist/",
|
||||||
|
"projectname": "taro_template",
|
||||||
|
"description": "苏州肛泰中医院预约挂号小程序",
|
||||||
|
"appid": "wx1e964c6f7f8009ad",
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": false,
|
||||||
|
"es6": true,
|
||||||
|
"enhance": true,
|
||||||
|
"compileHotReLoad": false,
|
||||||
|
"postcss": false,
|
||||||
|
"preloadBackgroundData": false,
|
||||||
|
"minified": true,
|
||||||
|
"newFeature": true,
|
||||||
|
"autoAudits": false,
|
||||||
|
"coverView": true,
|
||||||
|
"showShadowRootInWxmlPanel": false,
|
||||||
|
"scopeDataCheck": false,
|
||||||
|
"useCompilerModule": false,
|
||||||
|
"compileWorklet": false,
|
||||||
|
"uglifyFileName": false,
|
||||||
|
"uploadWithSourceMap": true,
|
||||||
|
"packNpmManually": false,
|
||||||
|
"packNpmRelationList": [],
|
||||||
|
"minifyWXSS": true,
|
||||||
|
"minifyWXML": true,
|
||||||
|
"localPlugins": false,
|
||||||
|
"disableUseStrict": false,
|
||||||
|
"useCompilerPlugins": false,
|
||||||
|
"condition": false,
|
||||||
|
"swc": false,
|
||||||
|
"disableSWC": true,
|
||||||
|
"babelSetting": {
|
||||||
|
"ignore": [],
|
||||||
|
"disablePlugins": [],
|
||||||
|
"outputPath": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compileType": "miniprogram",
|
||||||
|
"simulatorType": "wechat",
|
||||||
|
"simulatorPluginLibVersion": {},
|
||||||
|
"condition": {},
|
||||||
|
"packOptions": {
|
||||||
|
"ignore": [],
|
||||||
|
"include": []
|
||||||
|
},
|
||||||
|
"editorSetting": {},
|
||||||
|
"libVersion": "3.16.1"
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"libVersion": "3.16.1",
|
||||||
|
"projectname": "yuyueguahao",
|
||||||
|
"condition": {},
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": true,
|
||||||
|
"coverView": true,
|
||||||
|
"lazyloadPlaceholderEnable": false,
|
||||||
|
"skylineRenderEnable": false,
|
||||||
|
"preloadBackgroundData": false,
|
||||||
|
"autoAudits": false,
|
||||||
|
"useApiHook": true,
|
||||||
|
"showShadowRootInWxmlPanel": false,
|
||||||
|
"useStaticServer": false,
|
||||||
|
"useLanDebug": false,
|
||||||
|
"showES6CompileOption": false,
|
||||||
|
"compileHotReLoad": true,
|
||||||
|
"checkInvalidKey": true,
|
||||||
|
"ignoreDevUnusedFiles": true,
|
||||||
|
"bigPackageSizeSupport": false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"miniprogramRoot": "./",
|
||||||
|
"projectname": "taro_template",
|
||||||
|
"description": "taro_template",
|
||||||
|
"appid": "touristappid",
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": true,
|
||||||
|
"es6": false,
|
||||||
|
"postcss": false,
|
||||||
|
"minified": false
|
||||||
|
},
|
||||||
|
"compileType": "miniprogram"
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "--- Check nginx processes ---"
|
||||||
|
ps -efL | grep -E "nginx|openresty" | grep -v grep
|
||||||
|
echo "--- Sleep 3s, then check again ---"
|
||||||
|
sleep 3
|
||||||
|
ps -efL | grep -E "nginx" | grep -v grep | head -5
|
||||||
|
echo "--- Find master ---"
|
||||||
|
NGINX_MASTER=$(ps -efL | grep "nginx: master" | grep -v grep | awk '{print $2}' | head -1)
|
||||||
|
echo "Master PID: $NGINX_MASTER"
|
||||||
|
if [ -n "$NGINX_MASTER" ]; then
|
||||||
|
kill -HUP "$NGINX_MASTER"
|
||||||
|
sleep 2
|
||||||
|
echo "--- TEST uploads ---"
|
||||||
|
curl -o /dev/null -s -w "HTTP %{http_code} size=%{size_download} type=%{content_type}\n" http://localhost/uploads/1781403331659-1cac3cac.png
|
||||||
|
echo "--- TEST api ---"
|
||||||
|
curl -o /dev/null -s -w "HTTP %{http_code}\n" http://localhost/api/v1/banners
|
||||||
|
fi
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 清理 home_config 表被前一次错误 absolutize 污染的数据
|
||||||
|
# - 把所有 "http://124.221.67.199:3000/" 前缀的"假URL"还原成原文本
|
||||||
|
# - 只在 home_config 表中清理,不动上传文件路径(那些是真的需要 base 的)
|
||||||
|
set -e
|
||||||
|
PASSWORD="Szgt888."
|
||||||
|
HOST="124.221.67.199"
|
||||||
|
USER="root"
|
||||||
|
|
||||||
|
sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${USER}@${HOST} "mysql -uyygh_app -p'Yygh@2026#App' yuyueguahao -e \"
|
||||||
|
SET @b = 'http://124.221.67.199:3000/';
|
||||||
|
|
||||||
|
-- 看一眼当前数据
|
||||||
|
SELECT 'BEFORE' AS phase, data FROM home_config WHERE id=1 \G
|
||||||
|
|
||||||
|
-- 清理被错误 absolutize 的非 URL 字段:把所有 BASE 前缀剔除(仅针对 home_config.data 字段)
|
||||||
|
UPDATE home_config
|
||||||
|
SET data = REPLACE(data, @b, '')
|
||||||
|
WHERE id = 1
|
||||||
|
AND data LIKE CONCAT('%', @b, '%');
|
||||||
|
|
||||||
|
-- 看一眼清理后
|
||||||
|
SELECT 'AFTER' AS phase, data FROM home_config WHERE id=1 \G
|
||||||
|
\" 2>&1"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "--- 1. Express on 3000 - direct test ---"
|
||||||
|
curl -o /dev/null -s -w "API direct 3000: HTTP %{http_code}\n" http://127.0.0.1:3000/api/v1/banners
|
||||||
|
curl -o /dev/null -s -w "Uploads direct 3000: HTTP %{http_code} size=%{size_download}\n" http://127.0.0.1:3000/uploads/1781403331659-1cac3cac.png
|
||||||
|
|
||||||
|
echo "--- 2. Nginx proxy test ---"
|
||||||
|
curl -o /dev/null -s -w "API nginx 80: HTTP %{http_code}\n" http://127.0.0.1:80/api/v1/banners
|
||||||
|
curl -o /dev/null -s -w "Uploads nginx 80: HTTP %{http_code} size=%{size_download}\n" http://127.0.0.1:80/uploads/1781403331659-1cac3cac.png
|
||||||
|
|
||||||
|
echo "--- 3. Check if Express is actually listening ---"
|
||||||
|
ss -tlnp 2>/dev/null | grep 3000
|
||||||
|
echo "--- 4. List of PM2 processes ---"
|
||||||
|
ps -ef | grep -E "pm2|node" | grep -v grep | head -5
|
||||||
|
|
||||||
|
echo "--- 5. Check what openresty config is reading ---"
|
||||||
|
cat /etc/nginx/sites-enabled/yuyueguahao | grep -A1 "location /uploads"
|
||||||
|
cat /etc/nginx/sites-enabled/yuyueguahao | grep -A1 "location /api"
|
||||||
|
echo "--- 6. Error log fresh ---"
|
||||||
|
tail -5 /var/log/nginx/error.log
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "--- Test: what does nginx see? ---"
|
||||||
|
echo "--- Express handler for unknown route ---"
|
||||||
|
curl -v http://127.0.0.1:3000/api/v1/banners 2>&1 | grep -E "HTTP|Server|Content-Type" | head -3
|
||||||
|
echo "--- Test with Host header ---"
|
||||||
|
curl -v -H "Host: 124.221.67.199" http://127.0.0.1:3000/api/v1/banners 2>&1 | grep -E "HTTP|< " | head -5
|
||||||
|
echo "--- Test with X-Forwarded-Proto header (like nginx sends) ---"
|
||||||
|
curl -v -H "Host: 124.221.67.199" -H "X-Forwarded-Proto: http" -H "X-Real-IP: 1.2.3.4" http://127.0.0.1:3000/api/v1/banners 2>&1 | grep -E "HTTP|< " | head -5
|
||||||
|
echo "--- Test Express trust proxy setting ---"
|
||||||
|
grep -E "trust.proxy|app.set" /opt/yuyueguahao/server/src/index.js | head -5
|
||||||
|
echo "--- Curl the configured express IP directly ---"
|
||||||
|
curl -v -H "Host: localhost" http://127.0.0.1:3000/api/v1/banners 2>&1 | grep -E "HTTP|< |^>" | head -8
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "--- Network namespace of openresty vs node ---"
|
||||||
|
NGINX_PID=$(ps -efL | grep "nginx" | grep -v grep | awk '{print $2}' | head -1)
|
||||||
|
NODE_PID=$(ps -efL | grep "node /opt/yuyueguahao" | grep -v grep | awk '{print $2}' | head -1)
|
||||||
|
echo "nginx: $NGINX_PID, node: $NODE_PID"
|
||||||
|
|
||||||
|
# readlink /proc/PID/ns/net
|
||||||
|
echo "nginx netns: $(readlink /proc/$NGINX_PID/ns/net)"
|
||||||
|
echo "node netns: $(readlink /proc/$NODE_PID/ns/net)"
|
||||||
|
|
||||||
|
echo "--- /etc/hosts in both contexts ---"
|
||||||
|
ls -la /proc/$NGINX_PID/root/etc/hosts 2>&1
|
||||||
|
cat /proc/$NGINX_PID/root/etc/hosts 2>&1 | head
|
||||||
|
|
||||||
|
echo "--- Test connectivity from nginx's network ns to 3000 ---"
|
||||||
|
# Run a process in nginx's netns and test
|
||||||
|
NS=$(readlink /proc/$NGINX_PID/ns/net)
|
||||||
|
echo "Testing from netns: $NS"
|
||||||
|
|
||||||
|
echo "--- Use nsenter to test ---"
|
||||||
|
nsenter -t $NGINX_PID -n -- curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 5 http://127.0.0.1:3000/api/v1/banners
|
||||||
|
nsenter -t $NGINX_PID -n -- curl -s -o /dev/null -w "HTTP %{http_code} size=%{size_download}\n" --max-time 5 http://127.0.0.1:3000/uploads/1781403331659-1cac3cac.png
|
||||||
|
|
||||||
|
echo "--- Check if /uploads is being intercepted somewhere ---"
|
||||||
|
ls -la /proc/$NGINX_PID/root/opt/yuyueguahao/uploads 2>&1
|
||||||