commit 71bc2db9856250bbe9c510c8aa6c114cdb917f2b
Author: ni ziyi <310925901@qq.com>
Date: Fri Dec 12 16:49:06 2025 +0800
前端初始化
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5f19c63
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,132 @@
+# ======================
+# 操作系统 & 编辑器
+# ======================
+.DS_Store
+Thumbs.db
+ehthumbs.db
+Icon?
+desktop.ini
+*.swp
+*.swo
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.idea/
+*.sublime-project
+*.sublime-workspace
+
+# ======================
+# 日志 & 临时文件
+# ======================
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# ======================
+# 依赖目录
+# ======================
+node_modules/
+jspm_packages/
+bower_components/
+.mvn/
+target/
+build/
+dist/
+out/
+coverage/
+
+# ======================
+# 环境变量 & 敏感配置
+# ======================
+.env
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+config/local.*
+secrets.yml
+
+# ======================
+# 构建产物(前端)
+# ======================
+/public/build
+/public/hot
+/public/dist
+/assets/*.min.js
+/assets/*.min.css
+
+# ======================
+# Python
+# ======================
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+venv/
+ENV/
+.env
+
+# ======================
+# Java / Maven / Gradle
+# ======================
+*.class
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+hs_err_pid*
+.gradle/
+build/
+!gradle/wrapper/gradle-wrapper.jar
+
+# ======================
+# Docker
+# ======================
+.dockerignore
+docker-compose.override.yml
+
+# ======================
+# 其他
+# ======================
+*.tmp
+*.bak
+*.orig
+*.rej
+*~
+.swp
+.lock
+.nyc_output/
+.grunt/
+gulpfile.js
+package-lock.json # 可选:有些团队会提交它
+yarn.lock # 可选:通常建议提交 yarn.lock
+pnpm-lock.yaml # 可选:通常建议提交
+/node_modules/
diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json
new file mode 100644
index 0000000..6dea3f8
--- /dev/null
+++ b/.hbuilderx/launch.json
@@ -0,0 +1,23 @@
+{
+ "version" : "2.0.0",
+ "configurations" : [
+ {
+ "name" : "运行到H5",
+ "request" : "launch",
+ "runtime" : "h5",
+ "type" : "uni-app",
+ "url" : "http://localhost:8080"
+ },
+ {
+ "default" : {
+ "launchtype" : "local"
+ },
+ "h5" : {
+ "launchtype" : "local"
+ },
+ "provider" : "alipay",
+ "type" : "uniCloud"
+ }
+ ]
+}
+
diff --git a/App.vue b/App.vue
new file mode 100644
index 0000000..5148124
--- /dev/null
+++ b/App.vue
@@ -0,0 +1,20 @@
+
+
+
diff --git a/DEBUG.md b/DEBUG.md
new file mode 100644
index 0000000..1717c61
--- /dev/null
+++ b/DEBUG.md
@@ -0,0 +1,82 @@
+# 调试指南 - 空白页面问题
+
+## 可能的原因和解决方案
+
+### 1. 检查浏览器控制台
+打开浏览器开发者工具(F12),查看Console标签页,看是否有JavaScript错误。
+
+### 2. 检查网络请求
+在Network标签页,查看是否有资源加载失败(红色标记)。
+
+### 3. 检查uni-app配置
+确保项目被HBuilderX识别为uni-app项目:
+- `manifest.json` 存在且配置正确
+- `pages.json` 存在且配置正确
+- `App.vue` 存在
+
+### 4. 尝试以下操作
+
+#### 方法一:使用HBuilderX的标准运行方式
+1. 关闭当前运行
+2. 在HBuilderX中:运行 → 运行到浏览器 → Chrome
+3. 不要使用命令行运行
+
+#### 方法二:检查项目类型
+确保HBuilderX识别项目类型为"uni-app项目":
+- 右键项目根目录
+- 查看项目类型
+
+#### 方法三:清除缓存
+```bash
+cd frontend
+rm -rf node_modules/.vite
+rm -rf .hbuilderx
+```
+
+#### 方法四:检查页面路由
+确保 `pages.json` 中第一个页面路径正确:
+```json
+{
+ "pages": [
+ {
+ "path": "pages/index/index", // 确保这个文件存在
+ ...
+ }
+ ]
+}
+```
+
+### 5. 常见错误
+
+#### 错误:Cannot find module 'vue'
+**解决**:执行 `npm install vue pinia`
+
+#### 错误:Failed to parse .vue files
+**解决**:已安装 `@vitejs/plugin-vue`
+
+#### 错误:空白页面
+**可能原因**:
+- main.js格式不正确
+- App.vue缺少template
+- 页面路由配置错误
+- JavaScript运行时错误
+
+### 6. 调试步骤
+
+1. **打开浏览器控制台**(F12)
+2. **查看Console错误**
+3. **查看Network请求**
+4. **检查页面元素**(Elements标签)
+5. **提供错误信息**以便进一步排查
+
+## 如果仍然空白
+
+请提供以下信息:
+1. 浏览器控制台的错误信息(Console标签)
+2. 网络请求状态(Network标签,是否有404或500错误)
+3. HBuilderX的运行日志
+4. 页面源代码(右键页面 → 查看网页源代码)
+
+
+
+
diff --git a/DIAGNOSIS.md b/DIAGNOSIS.md
new file mode 100644
index 0000000..5fbc858
--- /dev/null
+++ b/DIAGNOSIS.md
@@ -0,0 +1,74 @@
+# 诊断指南 - 页面空白问题
+
+## 当前状态
+- ✅ main.js 已加载完成
+- ❌ 页面显示空白
+- ❌ Console没有页面相关的输出
+
+## 可能的原因
+
+### 1. uni-app路由系统未初始化
+uni-app在HBuilderX中运行时,需要特殊的路由系统。如果路由系统没有正确初始化,页面就不会显示。
+
+### 2. 页面组件未加载
+如果控制台没有"登录页面加载成功"的输出,说明页面组件根本没有加载。
+
+### 3. App.vue的template是空的
+App.vue只有一个空的view标签,uni-app可能无法正确渲染。
+
+## 排查步骤
+
+### 步骤1:检查控制台输出
+请查看浏览器控制台,告诉我:
+- 是否有"登录页面加载成功"的输出?
+- 是否有"App Launch"的输出?
+- 是否有任何错误信息?
+
+### 步骤2:检查Network标签
+查看Network标签,检查:
+- `pages/login/login-simple.vue` 是否加载?
+- 是否有404错误?
+- 是否有其他失败的请求?
+
+### 步骤3:检查页面元素
+在Elements标签中,检查:
+- `#app` 元素是否存在?
+- 是否有内容被渲染?
+- 是否有uni-app的路由容器?
+
+## 解决方案
+
+### 方案1:检查HBuilderX项目类型
+确保HBuilderX识别为"uni-app项目":
+- 右键项目文件夹
+- 查看项目类型
+- 如果不是uni-app,可能需要重新创建项目
+
+### 方案2:使用HBuilderX的标准运行方式
+- 不要使用命令行运行
+- 使用HBuilderX菜单:运行 → 运行到浏览器
+- 确保选择的是"uni-app"运行方式
+
+### 方案3:检查manifest.json
+确保manifest.json配置正确:
+- vueVersion: "3"
+- 其他配置正确
+
+## 请提供以下信息
+
+1. **控制台输出**:
+ - 是否有"登录页面加载成功"?
+ - 是否有"App Launch"?
+ - 是否有任何错误?
+
+2. **Network标签**:
+ - login-simple.vue是否加载?
+ - 状态码是什么?
+
+3. **Elements标签**:
+ - #app元素的内容是什么?
+ - 是否有任何内容被渲染?
+
+
+
+
diff --git a/FILES_CHECKLIST.md b/FILES_CHECKLIST.md
new file mode 100644
index 0000000..f0f40df
--- /dev/null
+++ b/FILES_CHECKLIST.md
@@ -0,0 +1,67 @@
+# 前端文件清单
+
+## 已创建的文件
+
+### 核心配置文件
+- ✅ `package.json` - 项目依赖配置
+- ✅ `pages.json` - 页面路由配置
+- ✅ `manifest.json` - uni-app应用配置
+- ✅ `main.js` - 应用入口文件
+- ✅ `App.vue` - 应用根组件
+- ✅ `vite.config.js` - Vite构建配置
+- ✅ `tsconfig.json` - TypeScript配置
+- ✅ `uni.scss` - uni-app样式变量
+
+### 工具类文件
+- ✅ `utils/request.js` - HTTP请求封装(包含JWT token管理)
+- ✅ `utils/date.js` - 日期工具函数
+
+### 状态管理
+- ✅ `store/user.js` - 用户状态管理(Pinia store)
+
+### API接口封装
+- ✅ `api/auth.js` - 认证相关API(注册、登录)
+- ✅ `api/bill.js` - 账单相关API(CRUD操作)
+- ✅ `api/category.js` - 分类相关API
+- ✅ `api/statistics.js` - 统计相关API
+- ✅ `api/ocr.js` - OCR识别API
+
+### 页面文件
+- ✅ `pages/login/login.vue` - 登录/注册页面
+- ✅ `pages/index/index.vue` - 首页(账单列表)
+- ✅ `pages/add/add.vue` - 添加账单页面(手动+OCR)
+- ✅ `pages/statistics/statistics.vue` - 统计页面
+- ✅ `pages/category/category.vue` - 分类管理页面
+
+### 样式文件
+- ✅ `static/css/common.css` - 全局公共样式
+
+## 可选文件(需要时添加)
+
+### TabBar图标(可选)
+如果需要显示底部导航栏图标,需要添加以下图片文件:
+- `static/tabbar/home.png` - 首页图标
+- `static/tabbar/home-active.png` - 首页选中图标
+- `static/tabbar/add.png` - 记账图标
+- `static/tabbar/add-active.png` - 记账选中图标
+- `static/tabbar/statistics.png` - 统计图标
+- `static/tabbar/statistics-active.png` - 统计选中图标
+
+如果没有这些图标,tabBar会显示文字但不显示图标,功能不受影响。
+
+## 文件说明
+
+所有核心功能文件都已创建完成,项目可以直接运行。如果遇到问题,请检查:
+
+1. 是否已安装依赖:`npm install`
+2. 后端服务是否已启动
+3. API地址配置是否正确(`utils/request.js`中的BASE_URL)
+
+
+
+
+
+
+
+
+
diff --git a/ICONS_GUIDE.md b/ICONS_GUIDE.md
new file mode 100644
index 0000000..469e728
--- /dev/null
+++ b/ICONS_GUIDE.md
@@ -0,0 +1,174 @@
+# 图标文件使用指南
+
+## 📋 项目中使用的图标文件
+
+### 1. TabBar 底部导航图标(必需)
+
+在 `pages.json` 中配置的 TabBar 需要以下 6 个图标文件:
+
+| 图标名称 | 用途 | 路径 |
+|---------|------|------|
+| `home.png` | 首页(未选中) | `static/tabbar/home.png` |
+| `home-active.png` | 首页(选中) | `static/tabbar/home-active.png` |
+| `add.png` | 记账(未选中) | `static/tabbar/add.png` |
+| `add-active.png` | 记账(选中) | `static/tabbar/add-active.png` |
+| `statistics.png` | 统计(未选中) | `static/tabbar/statistics.png` |
+| `statistics-active.png` | 统计(选中) | `static/tabbar/statistics-active.png` |
+
+**图标规格**:
+- 尺寸:81px × 81px(@2x)或 40px × 40px(@1x)
+- 格式:PNG(支持透明背景)
+- 颜色:
+ - 未选中:#7A7E83(灰色)
+ - 选中:#667eea(紫色)
+
+### 2. 分类图标(使用 Emoji,无需文件)
+
+代码中使用 Emoji 作为分类图标,例如:
+- 📦 默认分类
+- 🍔 餐饮
+- 👕 服装
+- 🏠 住房
+- 🚗 交通
+- 等等...
+
+这些图标存储在数据库中,不需要图标文件。
+
+### 3. 功能图标(使用 Emoji,无需文件)
+
+- 📷 上传图片图标(在 OCR 页面)
+
+## 🚀 快速获取图标的方法
+
+### 方法1:使用在线图标库(推荐)
+
+#### IconFont(阿里巴巴图标库)
+1. 访问:https://www.iconfont.cn/
+2. 注册/登录账号
+3. 搜索关键词:
+ - "首页" 或 "home"
+ - "添加" 或 "add" 或 "plus"
+ - "统计" 或 "statistics" 或 "chart"
+4. 选择图标,点击下载
+5. 选择 PNG 格式,尺寸选择 81×81
+6. 下载后重命名并放入 `static/tabbar/` 目录
+
+#### Flaticon
+1. 访问:https://www.flaticon.com/
+2. 搜索图标
+3. 下载 PNG 格式(免费账号需要注明来源)
+
+### 方法2:使用 AI 生成图标
+
+使用 ChatGPT、Midjourney 等 AI 工具生成图标:
+
+**提示词示例**:
+```
+生成一个简单的首页图标,极简风格,紫色主题,透明背景,81x81像素,PNG格式
+```
+
+### 方法3:临时解决方案(使用文字图标)
+
+如果暂时没有图标文件,可以修改 `pages.json`,移除图标路径,只显示文字:
+
+```json
+{
+ "tabBar": {
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "text": "首页"
+ // 移除 iconPath 和 selectedIconPath
+ }
+ ]
+ }
+}
+```
+
+### 方法4:使用 uni-app 内置图标
+
+uni-app 支持使用字体图标,可以集成 iconfont:
+
+1. 访问 https://www.iconfont.cn/
+2. 创建项目,添加图标
+3. 下载字体文件
+4. 在项目中引入字体文件
+5. 使用类名引用图标
+
+## 📥 推荐的免费图标资源
+
+1. **IconFont** - https://www.iconfont.cn/
+ - 中文界面,搜索方便
+ - 免费使用,需登录
+
+2. **Flaticon** - https://www.flaticon.com/
+ - 图标丰富
+ - 免费使用需注明来源
+
+3. **Icons8** - https://icons8.com/
+ - 图标质量高
+ - 部分免费
+
+4. **Material Icons** - https://fonts.google.com/icons
+ - Google 官方图标库
+ - 完全免费
+
+5. **Font Awesome** - https://fontawesome.com/
+ - 图标库丰富
+ - 部分免费
+
+## 🎨 图标设计建议
+
+### 风格统一
+- 所有图标使用相同的设计风格
+- 线条粗细一致
+- 圆角或直角统一
+
+### 颜色方案
+- 未选中:灰色(#7A7E83)
+- 选中:紫色(#667eea,与主题色一致)
+
+### 尺寸规范
+- TabBar 图标:81px × 81px(@2x)
+- 确保图标在选中和未选中状态下清晰可辨
+
+## ⚠️ 注意事项
+
+1. **文件路径**:图标文件必须放在 `static/tabbar/` 目录下
+2. **文件命名**:文件名必须与 `pages.json` 中的配置完全一致(区分大小写)
+3. **文件格式**:使用 PNG 格式,支持透明背景
+4. **文件大小**:建议单个图标文件不超过 50KB
+5. **缺失处理**:如果图标文件不存在,TabBar 可能无法正常显示
+
+## 🔧 快速测试
+
+创建占位图标文件进行测试:
+
+1. 创建 6 个 81×81px 的纯色 PNG 图片
+2. 未选中状态使用灰色,选中状态使用紫色
+3. 放入 `static/tabbar/` 目录
+4. 运行项目查看效果
+
+## 📝 图标文件清单
+
+请确保以下文件存在:
+
+```
+frontend/static/tabbar/
+├── home.png ✅ 需要创建
+├── home-active.png ✅ 需要创建
+├── add.png ✅ 需要创建
+├── add-active.png ✅ 需要创建
+├── statistics.png ✅ 需要创建
+└── statistics-active.png ✅ 需要创建
+```
+
+## 💡 快速开始
+
+**最快的方式**:
+1. 访问 https://www.iconfont.cn/
+2. 搜索并下载 6 个图标(首页、添加、统计各 2 个)
+3. 重命名为对应文件名
+4. 放入 `static/tabbar/` 目录
+5. 完成!
+
diff --git a/QUICK_FIX.md b/QUICK_FIX.md
new file mode 100644
index 0000000..35c58b8
--- /dev/null
+++ b/QUICK_FIX.md
@@ -0,0 +1,83 @@
+# 快速修复指南 - 登录页不显示
+
+## 问题分析
+
+uni-app项目在HBuilderX中使用Vite时,可能存在路由系统不兼容的问题。
+
+## 解决方案
+
+### 方案一:使用HBuilderX标准运行方式(推荐)
+
+1. **删除或重命名 `vite.config.js`**
+ - HBuilderX有自己的构建系统,不需要Vite配置
+ - 已重命名为 `vite.config.js.bak`
+
+2. **在HBuilderX中运行**
+ - 运行 → 运行到浏览器 → Chrome
+ - 不要使用命令行运行
+
+3. **检查项目类型**
+ - 确保HBuilderX识别为"uni-app项目"
+ - 右键项目 → 查看项目类型
+
+### 方案二:检查浏览器控制台
+
+1. **打开浏览器开发者工具**(F12)
+2. **查看Console标签**,看是否有错误:
+ - 路由错误
+ - 模块加载错误
+ - JavaScript运行时错误
+
+3. **查看Network标签**,检查:
+ - `main.js` 是否加载成功
+ - `pages/login/login.vue` 是否加载成功
+ - 是否有404错误
+
+### 方案三:简化测试
+
+如果仍然不显示,创建一个最简单的测试页面:
+
+在 `pages/login/login.vue` 中,先测试最基础的内容:
+
+```vue
+
+
+ 登录页面测试
+
+
+
+
+```
+
+### 方案四:检查文件路径
+
+确保文件路径正确:
+- `pages/login/login.vue` 文件存在
+- `pages.json` 中路径配置正确:`"path": "pages/login/login"`
+
+## 常见问题
+
+### Q: 页面完全空白?
+A: 检查浏览器控制台,看是否有JavaScript错误
+
+### Q: 显示"加载中"?
+A: 检查 `index.html` 是否还有加载提示,已移除
+
+### Q: 路由不工作?
+A: 确保使用HBuilderX的标准运行方式,不要使用纯Vite
+
+## 下一步
+
+1. 删除 `vite.config.js.bak`(如果方案一不行)
+2. 检查浏览器控制台错误
+3. 提供具体的错误信息以便进一步排查
+
+
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8af346b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,158 @@
+# 强宝爱记账前端
+
+基于 uni-app + Vue 3 开发的记账应用前端项目。
+
+## 功能特性
+
+- ✅ 用户登录/注册
+- ✅ 手动记账
+- ✅ OCR识别记账(支持截图识别金额)
+- ✅ 账单列表展示(按日期分组)
+- ✅ 统计功能(按日/周/月统计)
+- ✅ 分类管理
+
+## 技术栈
+
+- **框架**: uni-app + Vue 3
+- **状态管理**: Pinia
+- **UI组件**: uni-ui
+- **HTTP请求**: uni.request 封装
+
+## 项目结构
+
+```
+frontend/
+├── pages/ # 页面
+│ ├── login/ # 登录页
+│ ├── index/ # 首页(账单列表)
+│ ├── add/ # 添加账单
+│ └── statistics/ # 统计页
+├── api/ # API接口封装
+│ ├── auth.js # 认证接口
+│ ├── bill.js # 账单接口
+│ ├── category.js # 分类接口
+│ ├── statistics.js # 统计接口
+│ └── ocr.js # OCR接口
+├── store/ # Pinia状态管理
+│ └── user.js # 用户状态
+├── utils/ # 工具函数
+│ ├── request.js # HTTP请求封装
+│ └── date.js # 日期工具
+├── static/ # 静态资源
+├── App.vue # 应用根组件
+├── main.js # 入口文件
+└── pages.json # 页面配置
+```
+
+## 开发说明
+
+### 环境要求
+
+- Node.js >= 14
+- HBuilderX(推荐)或 uni-app CLI
+
+### 安装依赖
+
+```bash
+npm install
+```
+
+### 运行项目
+
+#### HBuilderX
+
+1. 使用 HBuilderX 打开项目
+2. 选择运行 -> 运行到浏览器 -> Chrome
+
+#### CLI
+
+```bash
+npm run dev:h5
+```
+
+### 配置后端API地址
+
+修改 `utils/request.js` 中的 `BASE_URL`:
+
+```javascript
+const BASE_URL = process.env.NODE_ENV === 'development'
+ ? 'http://localhost:8080/api' // 开发环境
+ : 'https://your-api-domain.com/api' // 生产环境
+```
+
+## 页面说明
+
+### 登录页 (`pages/login/login.vue`)
+
+- 支持登录和注册
+- 自动保存token和用户信息
+- 登录成功后跳转到首页
+
+### 首页 (`pages/index/index.vue`)
+
+- 显示本月收支统计
+- 账单列表按日期分组展示
+- 支持下拉刷新
+- 点击账单可查看详情(待完善)
+
+### 添加账单页 (`pages/add/add.vue`)
+
+- **手动记账**: 手动输入分类、金额、日期、备注
+- **OCR识别**:
+ - 选择图片(相机/相册)
+ - 上传识别
+ - 自动填充金额、商户、日期
+ - 可手动修改识别结果
+
+### 统计页 (`pages/statistics/statistics.vue`)
+
+- 按日/周/月切换统计
+- 显示总收入、总支出、余额
+- 分类统计展示(带进度条)
+
+## API接口
+
+### 认证接口
+
+- `POST /api/auth/register` - 注册
+- `POST /api/auth/login` - 登录
+
+### 账单接口
+
+- `GET /api/bills` - 获取账单列表
+- `POST /api/bills` - 创建账单
+- `GET /api/bills/:id` - 获取账单详情
+- `PUT /api/bills/:id` - 更新账单
+- `DELETE /api/bills/:id` - 删除账单
+
+### 分类接口
+
+- `GET /api/categories` - 获取分类列表
+- `POST /api/categories` - 创建分类
+- `PUT /api/categories/:id` - 更新分类
+- `DELETE /api/categories/:id` - 删除分类
+
+### 统计接口
+
+- `GET /api/statistics/daily` - 按日统计
+- `GET /api/statistics/weekly` - 按周统计
+- `GET /api/statistics/monthly` - 按月统计
+
+### OCR接口
+
+- `POST /api/ocr/recognize` - OCR识别
+
+## 注意事项
+
+1. **登录状态**: 所有页面都会检查登录状态,未登录会自动跳转到登录页
+2. **Token管理**: Token存储在本地存储中,过期后会自动跳转登录
+3. **图片上传**: OCR功能需要上传图片,注意图片大小限制
+4. **平台差异**: 注意H5和App平台的API差异,部分功能可能需要平台判断
+
+## 待完善功能
+
+- [ ] 账单编辑功能
+- [ ] 账单删除功能
+- [ ] 分类管理页面
+- [ ] 账单详情页面
+- [ ] 图表展示(echarts集成)
diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md
new file mode 100644
index 0000000..eaca192
--- /dev/null
+++ b/TROUBLESHOOTING.md
@@ -0,0 +1,47 @@
+# 故障排查指南
+
+## 问题:Failed to resolve import "vue"
+
+### 解决方案
+
+1. **确保依赖已安装**
+ ```bash
+ cd frontend
+ npm install vue pinia
+ ```
+
+2. **清除缓存并重新安装**
+ ```bash
+ cd frontend
+ npm cache clean --force
+ rm -rf node_modules
+ npm install
+ ```
+
+3. **在HBuilderX中运行**
+ - 不要使用命令行运行
+ - 直接在HBuilderX中:运行 → 运行到浏览器
+ - HBuilderX会自动处理依赖
+
+4. **检查node_modules**
+ - 确保 `frontend/node_modules/vue` 目录存在
+ - 如果不存在,执行 `npm install vue`
+
+5. **如果仍然报错**
+ - 尝试删除 `vite.config.js`(HBuilderX项目可能不需要)
+ - 或者简化 `vite.config.js` 配置
+
+## 常见问题
+
+### Q: HBuilderX提示缺少index.html?
+A: 已创建 `index.html` 文件,如果还有问题,检查文件是否在根目录。
+
+### Q: 依赖安装失败?
+A: 对于HBuilderX项目,通常不需要手动安装uni-app相关依赖,只需要安装业务依赖(vue、pinia)。
+
+### Q: API请求失败?
+A: 确保后端服务已启动,检查 `utils/request.js` 中的API地址配置。
+
+
+
+
diff --git a/api/auth.js b/api/auth.js
new file mode 100644
index 0000000..1ca299a
--- /dev/null
+++ b/api/auth.js
@@ -0,0 +1,20 @@
+import { post } from '../utils/request'
+
+// 用户注册
+export function register(data) {
+ return post('/auth/register', data)
+}
+
+// 用户登录
+export function login(data) {
+ return post('/auth/login', data)
+}
+
+
+
+
+
+
+
+
+
diff --git a/api/bill.js b/api/bill.js
new file mode 100644
index 0000000..3886be7
--- /dev/null
+++ b/api/bill.js
@@ -0,0 +1,35 @@
+import { get, post, put, del } from '../utils/request'
+
+// 获取账单列表
+export function getBills(params) {
+ return get('/bills', params)
+}
+
+// 获取账单详情
+export function getBill(id) {
+ return get(`/bills/${id}`)
+}
+
+// 创建账单
+export function createBill(data) {
+ return post('/bills', data)
+}
+
+// 更新账单
+export function updateBill(id, data) {
+ return put(`/bills/${id}`, data)
+}
+
+// 删除账单
+export function deleteBill(id) {
+ return del(`/bills/${id}`)
+}
+
+
+
+
+
+
+
+
+
diff --git a/api/category.js b/api/category.js
new file mode 100644
index 0000000..feaab8b
--- /dev/null
+++ b/api/category.js
@@ -0,0 +1,30 @@
+import { get, post, put, del } from '../utils/request'
+
+// 获取分类列表
+export function getCategories(type) {
+ return get('/categories', type ? { type } : {})
+}
+
+// 创建分类
+export function createCategory(data) {
+ return post('/categories', data)
+}
+
+// 更新分类
+export function updateCategory(id, data) {
+ return put(`/categories/${id}`, data)
+}
+
+// 删除分类
+export function deleteCategory(id) {
+ return del(`/categories/${id}`)
+}
+
+
+
+
+
+
+
+
+
diff --git a/api/ocr.js b/api/ocr.js
new file mode 100644
index 0000000..fd75465
--- /dev/null
+++ b/api/ocr.js
@@ -0,0 +1,15 @@
+import { upload } from '../utils/request'
+
+// OCR识别
+export function recognizeImage(filePath) {
+ return upload('/ocr/recognize', filePath)
+}
+
+
+
+
+
+
+
+
+
diff --git a/api/statistics.js b/api/statistics.js
new file mode 100644
index 0000000..b772543
--- /dev/null
+++ b/api/statistics.js
@@ -0,0 +1,25 @@
+import { get } from '../utils/request'
+
+// 按日期范围统计
+export function getDailyStatistics(startDate, endDate) {
+ return get('/statistics/daily', { startDate, endDate })
+}
+
+// 按周统计
+export function getWeeklyStatistics(weekStart) {
+ return get('/statistics/weekly', { weekStart })
+}
+
+// 按月统计
+export function getMonthlyStatistics(year, month) {
+ return get('/statistics/monthly', { year, month })
+}
+
+
+
+
+
+
+
+
+
diff --git a/common/uni-ui.scss b/common/uni-ui.scss
new file mode 100644
index 0000000..6ba0990
--- /dev/null
+++ b/common/uni-ui.scss
@@ -0,0 +1,120 @@
+
+.uni-flex {
+ display: flex;
+}
+
+.uni-flex-row {
+ @extend .uni-flex;
+ flex-direction: row;
+ box-sizing: border-box;
+}
+
+.uni-flex-column {
+ @extend .uni-flex;
+ flex-direction: column;
+}
+
+.uni-color-gary {
+ color: #3b4144;
+}
+
+/* 标题 */
+.uni-title {
+ display: flex;
+ margin-bottom: $uni-spacing-col-base;
+ font-size: $uni-font-size-lg;
+ font-weight: bold;
+ color: #3b4144;
+}
+
+.uni-title-sub {
+ display: flex;
+ // margin-bottom: $uni-spacing-col-base;
+ font-size: $uni-font-size-base;
+ font-weight: 500;
+ color: #3b4144;
+}
+
+/* 描述 额外文本 */
+.uni-note {
+ margin-top: 10px;
+ color: #999;
+ font-size: $uni-font-size-sm;
+}
+
+/* 列表内容 */
+.uni-list-box {
+ @extend .uni-flex-row;
+ flex: 1;
+ margin-top: 10px;
+}
+
+/* 略缩图 */
+.uni-thumb {
+ flex-shrink: 0;
+ margin-right: $uni-spacing-row-base;
+ width: 125px;
+ height: 75px;
+ border-radius: $uni-border-radius-lg;
+ overflow: hidden;
+ border: 1px #f5f5f5 solid;
+ image {
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.uni-media-box {
+ @extend .uni-flex-row;
+ // margin-bottom: $uni-spacing-col-base;
+ border-radius: $uni-border-radius-lg;
+ overflow: hidden;
+ .uni-thumb {
+ margin: 0;
+ margin-left: 4px;
+ flex-shrink: 1;
+ width: 33%;
+ border-radius:0;
+ &:first-child {
+ margin: 0;
+ }
+ }
+}
+
+/* 内容 */
+.uni-content {
+ @extend .uni-flex-column;
+ justify-content: space-between;
+}
+
+/* 列表footer */
+.uni-footer {
+ @extend .uni-flex-row;
+ justify-content: space-between;
+ margin-top: $uni-spacing-col-lg;
+}
+.uni-footer-text {
+ font-size: $uni-font-size-sm;
+ color: $uni-text-color-grey;
+ margin-left: 5px;
+}
+
+/* 标签 */
+
+.uni-tag {
+ flex-shrink: 0;
+ padding: 0 5px;
+ border: 1px $uni-border-color solid;
+ margin-right: $uni-spacing-row-sm;
+ border-radius: $uni-border-radius-base;
+ background: $uni-bg-color-grey;
+ color: $uni-text-color;
+ font-size: $uni-font-size-sm;
+}
+
+/* 链接 */
+.uni-link {
+ margin-left: 10px;
+ color: $uni-text-color;
+ text-decoration: underline;
+}
diff --git a/components/uni-section/config.json b/components/uni-section/config.json
new file mode 100644
index 0000000..43d5d01
--- /dev/null
+++ b/components/uni-section/config.json
@@ -0,0 +1,12 @@
+{
+ "id": "99999",
+ "name": "Section",
+ "desc": "标题栏",
+ "edition": "0.0.1",
+ "url": "section",
+ "type": "布局组件",
+ "path": "https://ext.dcloud.net.cn/plugin?id=",
+ "hidden": true,
+ "test":true,
+ "update_log": []
+}
diff --git a/components/uni-section/readme.md b/components/uni-section/readme.md
new file mode 100644
index 0000000..c5998fa
--- /dev/null
+++ b/components/uni-section/readme.md
@@ -0,0 +1,30 @@
+### Section 标题栏
+
+标题栏,用于显示标题,组件名:``uni-section``,代码块: uSection。
+
+### 使用方式
+
+在 ``script`` 中引用组件
+
+```javascript
+import uniSection from "@/components/uni-section/uni-section.vue"
+export default {
+ components: {uniSection}
+}
+```
+
+在 ``template`` 中使用组件
+
+```html
+
+
+
+```
+
+### 属性说明
+
+|属性名 |类型 |默认值 |说明 |
+|--- |---- |--- |--- |
+|type |String |- |标题装饰类型 ,可选值:line(竖线)、circle(圆形)|
+|title |String |- |主标题 |
+|sub-title |String |- |副标题 |
diff --git a/components/uni-section/uni-section.vue b/components/uni-section/uni-section.vue
new file mode 100644
index 0000000..52a1567
--- /dev/null
+++ b/components/uni-section/uni-section.vue
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+ {{ title }}
+ {{ subTitle }}
+
+
+
+
+
+
+
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..e5515b1
--- /dev/null
+++ b/index.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ 强宝爱记账
+
+
+
+
+
+
+
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..4501e2c
--- /dev/null
+++ b/main.js
@@ -0,0 +1,12 @@
+import { createSSRApp } from 'vue'
+import { createPinia } from 'pinia'
+import App from './App.vue'
+
+export function createApp() {
+ const app = createSSRApp(App)
+ const pinia = createPinia()
+ app.use(pinia)
+ return {
+ app
+ }
+}
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..fab259f
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,71 @@
+{
+ "name": "强宝爱记账",
+ "appid": "__UNI__ACCOUNTING",
+ "description": "智能记账应用,支持OCR识别账单",
+ "versionName": "1.0.0",
+ "versionCode": "100",
+ "transformPx": false,
+ "app-plus": {
+ "usingComponents": true,
+ "nvueStyleCompiler": "uni-app",
+ "compilerVersion": 3,
+ "splashscreen": {
+ "alwaysShowBeforeRender": true,
+ "waiting": true,
+ "autoclose": true,
+ "delay": 0
+ },
+ "modules": {},
+ "distribute": {
+ "android": {
+ "permissions": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ]
+ },
+ "ios": {},
+ "sdkConfigs": {}
+ }
+ },
+ "quickapp": {},
+ "mp-weixin": {
+ "appid": "",
+ "setting": {
+ "urlCheck": false
+ },
+ "usingComponents": true
+ },
+ "mp-alipay": {
+ "usingComponents": true
+ },
+ "mp-baidu": {
+ "usingComponents": true
+ },
+ "mp-toutiao": {
+ "usingComponents": true
+ },
+ "uniStatistics": {
+ "enable": false
+ },
+ "vueVersion": "3",
+ "h5": {
+ "router": {
+ "mode": "hash"
+ }
+ }
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..79bbeea
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,906 @@
+{
+ "name": "accounting-app",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "accounting-app",
+ "version": "1.0.0",
+ "dependencies": {
+ "@dcloudio/uni-app": "^2.0.2-4080720251210002",
+ "@dcloudio/uni-h5": "^2.0.2-4080720251210002",
+ "pinia": "^2.3.1",
+ "vue": "^3.5.25"
+ },
+ "devDependencies": {
+ "@types/node": "^24.10.2",
+ "@vitejs/plugin-vue": "^4.0.0",
+ "typescript": "^5.2.2",
+ "vite": "^4.5.14"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.5.tgz",
+ "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
+ "dependencies": {
+ "@babel/types": "^7.28.5"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.5",
+ "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.28.5.tgz",
+ "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@dcloudio/uni-app": {
+ "version": "2.0.2-4080720251210002",
+ "resolved": "https://registry.npmmirror.com/@dcloudio/uni-app/-/uni-app-2.0.2-4080720251210002.tgz",
+ "integrity": "sha512-FUw/bJJwBPl/scKBog21wusICrU9T4TFwyKKVbtNbWIO98IBzjRIin0mmwzhqHNL1kZO0LbwnoRe7LtusW8LQw==",
+ "peerDependencies": {
+ "@dcloudio/types": "^3.0.15",
+ "@vue/composition-api": "^1.7.0"
+ }
+ },
+ "node_modules/@dcloudio/uni-h5": {
+ "version": "2.0.2-4080720251210002",
+ "resolved": "https://registry.npmmirror.com/@dcloudio/uni-h5/-/uni-h5-2.0.2-4080720251210002.tgz",
+ "integrity": "sha512-yBYX2rvX+03eVjkmzNfWetMW5jjhz+7B643Otjs7IOp+KXVSpslAwLO3F5kKhaBQQXGFJ9Tn7f4DEtrQZkAxKg==",
+ "dependencies": {
+ "base64-arraybuffer": "^0.2.0",
+ "intersection-observer": "^0.7.0",
+ "pako": "^1.0.11",
+ "postcss-urlrewrite": "^0.3.0",
+ "safe-area-insets": "^1.4.1"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+ "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+ "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+ "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+ "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+ "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+ "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+ "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+ "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+ "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+ "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+ "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+ "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+ "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+ "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+ "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+ "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+ "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+ "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+ "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+ "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
+ },
+ "node_modules/@types/node": {
+ "version": "24.10.2",
+ "resolved": "https://registry.npmmirror.com/@types/node/-/node-24.10.2.tgz",
+ "integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz",
+ "integrity": "sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==",
+ "dev": true,
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.25.tgz",
+ "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==",
+ "dependencies": {
+ "@babel/parser": "^7.28.5",
+ "@vue/shared": "3.5.25",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz",
+ "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.25",
+ "@vue/shared": "3.5.25"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz",
+ "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==",
+ "dependencies": {
+ "@babel/parser": "^7.28.5",
+ "@vue/compiler-core": "3.5.25",
+ "@vue/compiler-dom": "3.5.25",
+ "@vue/compiler-ssr": "3.5.25",
+ "@vue/shared": "3.5.25",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.21",
+ "postcss": "^8.5.6",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz",
+ "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.25",
+ "@vue/shared": "3.5.25"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "6.6.4",
+ "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.25.tgz",
+ "integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==",
+ "dependencies": {
+ "@vue/shared": "3.5.25"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.25.tgz",
+ "integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==",
+ "dependencies": {
+ "@vue/reactivity": "3.5.25",
+ "@vue/shared": "3.5.25"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz",
+ "integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==",
+ "dependencies": {
+ "@vue/reactivity": "3.5.25",
+ "@vue/runtime-core": "3.5.25",
+ "@vue/shared": "3.5.25",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.25.tgz",
+ "integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.25",
+ "@vue/shared": "3.5.25"
+ },
+ "peerDependencies": {
+ "vue": "3.5.25"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.25.tgz",
+ "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg=="
+ },
+ "node_modules/base64-arraybuffer": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
+ "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.18.20.tgz",
+ "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.18.20",
+ "@esbuild/android-arm64": "0.18.20",
+ "@esbuild/android-x64": "0.18.20",
+ "@esbuild/darwin-arm64": "0.18.20",
+ "@esbuild/darwin-x64": "0.18.20",
+ "@esbuild/freebsd-arm64": "0.18.20",
+ "@esbuild/freebsd-x64": "0.18.20",
+ "@esbuild/linux-arm": "0.18.20",
+ "@esbuild/linux-arm64": "0.18.20",
+ "@esbuild/linux-ia32": "0.18.20",
+ "@esbuild/linux-loong64": "0.18.20",
+ "@esbuild/linux-mips64el": "0.18.20",
+ "@esbuild/linux-ppc64": "0.18.20",
+ "@esbuild/linux-riscv64": "0.18.20",
+ "@esbuild/linux-s390x": "0.18.20",
+ "@esbuild/linux-x64": "0.18.20",
+ "@esbuild/netbsd-x64": "0.18.20",
+ "@esbuild/openbsd-x64": "0.18.20",
+ "@esbuild/sunos-x64": "0.18.20",
+ "@esbuild/win32-arm64": "0.18.20",
+ "@esbuild/win32-ia32": "0.18.20",
+ "@esbuild/win32-x64": "0.18.20"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/intersection-observer": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.7.0.tgz",
+ "integrity": "sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg==",
+ "deprecated": "The Intersection Observer polyfill is no longer needed and can safely be removed. Intersection Observer has been Baseline since 2019."
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
+ },
+ "node_modules/pinia": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.3.1.tgz",
+ "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.3",
+ "vue-demi": "^0.14.10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.4.4",
+ "vue": "^2.7.0 || ^3.5.11"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-helpers": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmmirror.com/postcss-helpers/-/postcss-helpers-0.3.3.tgz",
+ "integrity": "sha512-VumiUcrpbxGlTBNQj6fUOkb/HNRUk/xYz8bNlhgVOdvk3yWEy4B+0nlDUZZM9mTVZ5bJoxUy7WT6z/4E7oMTgw==",
+ "dependencies": {
+ "urijs": "^1.18.12"
+ },
+ "engines": {
+ "node": ">=0.12.9"
+ }
+ },
+ "node_modules/postcss-urlrewrite": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmmirror.com/postcss-urlrewrite/-/postcss-urlrewrite-0.3.0.tgz",
+ "integrity": "sha512-504S/dMa7a0n1yghE2I6fxY/DfMUM+w9qsFaoYnXE8KsCofmKLlA7PKbR+wtdEJ0N00Z1lGYxX/oFz13xArcLQ==",
+ "dependencies": {
+ "postcss-helpers": "^0.3.3"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "3.29.5",
+ "resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.29.5.tgz",
+ "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/safe-area-insets": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmmirror.com/safe-area-insets/-/safe-area-insets-1.4.1.tgz",
+ "integrity": "sha512-r/nRWTjFGhhm3w1Z6Kd/jY11srN+lHt2mNl1E/emQGW8ic7n3Avu4noibklfSM+Y34peNphHD/BSZecav0sXYQ=="
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "dev": true
+ },
+ "node_modules/urijs": {
+ "version": "1.19.11",
+ "resolved": "https://registry.npmmirror.com/urijs/-/urijs-1.19.11.tgz",
+ "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ=="
+ },
+ "node_modules/vite": {
+ "version": "4.5.14",
+ "resolved": "https://registry.npmmirror.com/vite/-/vite-4.5.14.tgz",
+ "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==",
+ "dev": true,
+ "dependencies": {
+ "esbuild": "^0.18.10",
+ "postcss": "^8.4.27",
+ "rollup": "^3.27.1"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@types/node": ">= 14",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue": {
+ "version": "3.5.25",
+ "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.25.tgz",
+ "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.25",
+ "@vue/compiler-sfc": "3.5.25",
+ "@vue/runtime-dom": "3.5.25",
+ "@vue/server-renderer": "3.5.25",
+ "@vue/shared": "3.5.25"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-demi": {
+ "version": "0.14.10",
+ "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz",
+ "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+ "hasInstallScript": true,
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..c8d1a05
--- /dev/null
+++ b/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "accounting-app",
+ "version": "1.0.0",
+ "description": "强宝爱记账",
+ "main": "main.js",
+ "scripts": {
+ "dev:h5": "npm run serve",
+ "serve": "uni serve",
+ "build:h5": "uni build"
+ },
+ "dependencies": {
+ "@dcloudio/uni-app": "^2.0.2-4080720251210002",
+ "@dcloudio/uni-h5": "^2.0.2-4080720251210002",
+ "pinia": "^2.3.1",
+ "vue": "^3.5.25"
+ },
+ "devDependencies": {
+ "@types/node": "^24.10.2",
+ "typescript": "^5.2.2"
+ }
+}
\ No newline at end of file
diff --git a/pages.json b/pages.json
new file mode 100644
index 0000000..1af33d4
--- /dev/null
+++ b/pages.json
@@ -0,0 +1,74 @@
+{
+ "easycom": {
+ "autoscan": true,
+ "custom": {
+ "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
+ }
+ },
+ "pages": [
+ {
+ "path": "pages/login/login",
+ "style": {
+ "navigationBarTitleText": "登录",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/index/index",
+ "style": {
+ "navigationBarTitleText": "首页",
+ "enablePullDownRefresh": true
+ }
+ },
+ {
+ "path": "pages/add/add",
+ "style": {
+ "navigationBarTitleText": "添加账单"
+ }
+ },
+ {
+ "path": "pages/statistics/statistics",
+ "style": {
+ "navigationBarTitleText": "统计"
+ }
+ },
+ {
+ "path": "pages/bill/detail",
+ "style": {
+ "navigationBarTitleText": "编辑账单"
+ }
+ }
+ ],
+ "tabBar": {
+ "color": "#7A7E83",
+ "selectedColor": "#667eea",
+ "borderStyle": "black",
+ "backgroundColor": "#ffffff",
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "iconPath": "static/tabbar/home.png",
+ "selectedIconPath": "static/tabbar/home-active.png",
+ "text": "首页"
+ },
+ {
+ "pagePath": "pages/add/add",
+ "iconPath": "static/tabbar/add.png",
+ "selectedIconPath": "static/tabbar/add-active.png",
+ "text": "记账"
+ },
+ {
+ "pagePath": "pages/statistics/statistics",
+ "iconPath": "static/tabbar/statistics.png",
+ "selectedIconPath": "static/tabbar/statistic-active.png",
+ "text": "统计"
+ }
+ ]
+ },
+ "globalStyle": {
+ "navigationBarTextStyle": "black",
+ "navigationBarTitleText": "强宝爱记账",
+ "navigationBarBackgroundColor": "#F8F8F8",
+ "backgroundColor": "#F8F8F8"
+ }
+}
diff --git a/pages/add/add.vue b/pages/add/add.vue
new file mode 100644
index 0000000..0471079
--- /dev/null
+++ b/pages/add/add.vue
@@ -0,0 +1,895 @@
+
+
+
+
+
+ 手动记账
+
+
+ OCR识别
+
+
+
+
+
+
+ 账单类型
+
+
+ 📤
+ 支出
+
+
+ 📥
+ 收入
+
+
+
+
+
+ 分类
+
+
+
+ {{ category.icon || '📦' }}
+
+ {{ category.name }}
+
+
+
+ 暂无分类,请先创建分类
+
+
+
+
+ 金额
+
+
+
+
+ 日期
+
+
+ {{ form.billDate || '选择日期' }}
+ >
+
+
+
+
+
+ 备注
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 📷
+ 点击选择图片
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 金额:
+ ¥{{ item.amount ? Math.abs(item.amount).toFixed(2) : '0.00' }}
+
+
+ 商户:
+ {{ item.merchant }}
+
+
+ 日期:
+ {{ formatOcrDate(item.date) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/add/list/list.vue b/pages/add/list/list.vue
new file mode 100644
index 0000000..dd62d95
--- /dev/null
+++ b/pages/add/list/list.vue
@@ -0,0 +1,158 @@
+
+
+
+
+ 为您更新了10条最新新闻动态
+
+
+
+
+
+
+
+ {{item.title}}
+
+
+
+
+
+ {{item.excerpt}}
+ {{item.user_name + ' '+item.last_modify_date}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/bill/detail.vue b/pages/bill/detail.vue
new file mode 100644
index 0000000..bbee0f9
--- /dev/null
+++ b/pages/bill/detail.vue
@@ -0,0 +1,492 @@
+
+
+
+
+
+
+
+
+ 账单类型
+
+
+ 📤
+ 支出
+
+
+ 📥
+ 收入
+
+
+
+
+
+ 分类
+
+
+
+ {{ category.icon || '📦' }}
+
+ {{ category.name }}
+
+
+
+ 暂无分类
+
+
+
+
+ 金额
+
+
+
+
+ 日期
+
+
+ {{ form.billDate || '选择日期' }}
+ >
+
+
+
+
+
+ 备注
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/category/category.vue b/pages/category/category.vue
new file mode 100644
index 0000000..5a57724
--- /dev/null
+++ b/pages/category/category.vue
@@ -0,0 +1,337 @@
+
+
+
+
+
+
+ 支出
+
+
+ 收入
+
+
+
+
+
+ {{ category.icon }}
+ {{ category.name }}
+ 系统
+
+ 编辑
+ 删除
+
+
+
+
+
+
+
+
+
+
+ 分类名称
+
+
+
+ 图标
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/index/index.vue b/pages/index/index.vue
new file mode 100644
index 0000000..d61bb85
--- /dev/null
+++ b/pages/index/index.vue
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+ {{ bill.categoryIcon || '📦' }}
+
+ {{ bill.categoryName || '未分类' }}
+ {{ bill.description }}
+
+
+ {{ bill.type > 0 ? '-' : '+' }}¥{{ Math.abs(bill.amount).toFixed(2) }}
+
+
+
+
+
+ 暂无账单记录
+ 点击下方"记账"按钮添加账单
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/login/login-simple.vue b/pages/login/login-simple.vue
new file mode 100644
index 0000000..c85ad60
--- /dev/null
+++ b/pages/login/login-simple.vue
@@ -0,0 +1,22 @@
+
+
+ 强宝爱记账
+ 登录页面测试
+ 如果能看到这个,说明路由正常
+
+
+
+
+
+
+
+
diff --git a/pages/login/login.vue b/pages/login/login.vue
new file mode 100644
index 0000000..13aa446
--- /dev/null
+++ b/pages/login/login.vue
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ isRegister ? '已有账号?去登录' : '没有账号?去注册' }}
+
+
+
+
+
+
+
+
diff --git a/pages/statistics/statistics.vue b/pages/statistics/statistics.vue
new file mode 100644
index 0000000..1ff0258
--- /dev/null
+++ b/pages/statistics/statistics.vue
@@ -0,0 +1,246 @@
+
+
+
+
+ 按日
+
+
+ 按周
+
+
+ 按月
+
+
+
+
+
+ 总收入
+ ¥{{ statistics.totalIncome?.toFixed(2) || '0.00' }}
+
+
+ 总支出
+ ¥{{ statistics.totalExpense?.toFixed(2) || '0.00' }}
+
+
+ 余额
+ ¥{{ getBalance.toFixed(2) }}
+
+
+
+
+ 分类统计
+
+
+ {{ item.categoryIcon || '📦' }}
+
+ {{ item.categoryName }}
+
+
+
+
+ ¥{{ item.amount?.toFixed(2) || '0.00' }}
+
+
+
+ 暂无统计数据
+
+
+
+
+
+
+
+
diff --git a/static/css/common.css b/static/css/common.css
new file mode 100644
index 0000000..f5a638d
--- /dev/null
+++ b/static/css/common.css
@@ -0,0 +1,80 @@
+/* 全局样式 */
+page {
+ background-color: #f5f5f5;
+ font-size: 28rpx;
+ color: #333;
+}
+
+.container {
+ padding: 20rpx;
+}
+
+.flex {
+ display: flex;
+}
+
+.flex-column {
+ display: flex;
+ flex-direction: column;
+}
+
+.flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.flex-between {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.mt-10 {
+ margin-top: 10rpx;
+}
+
+.mt-20 {
+ margin-top: 20rpx;
+}
+
+.mb-10 {
+ margin-bottom: 10rpx;
+}
+
+.mb-20 {
+ margin-bottom: 20rpx;
+}
+
+.p-20 {
+ padding: 20rpx;
+}
+
+.text-center {
+ text-align: center;
+}
+
+.text-primary {
+ color: #3c9cff;
+}
+
+.text-success {
+ color: #19be6b;
+}
+
+.text-warning {
+ color: #ff9900;
+}
+
+.text-error {
+ color: #fa3534;
+}
+
+
+
+
+
+
+
+
+
diff --git a/static/tabbar/README.md b/static/tabbar/README.md
new file mode 100644
index 0000000..6013f71
--- /dev/null
+++ b/static/tabbar/README.md
@@ -0,0 +1,111 @@
+# TabBar 图标文件说明
+
+## 需要的图标文件
+
+本项目需要以下 6 个图标文件用于底部导航栏(TabBar):
+
+### 1. 首页图标
+- `home.png` - 未选中状态的首页图标
+- `home-active.png` - 选中状态的首页图标
+
+### 2. 记账图标
+- `add.png` - 未选中状态的记账图标
+- `add-active.png` - 选中状态的记账图标
+
+### 3. 统计图标
+- `statistics.png` - 未选中状态的统计图标
+- `statistics-active.png` - 选中状态的统计图标
+
+## 图标规格要求
+
+- **尺寸**: 建议 81px × 81px(@2x)或 40px × 40px(@1x)
+- **格式**: PNG(支持透明背景)
+- **颜色**:
+ - 未选中状态:灰色(#7A7E83)
+ - 选中状态:紫色(#667eea)
+
+## 如何获取图标
+
+### 方法1:使用图标库(推荐)
+
+1. **IconFont(阿里巴巴图标库)**
+ - 访问:https://www.iconfont.cn/
+ - 搜索关键词:首页、home、记账、add、统计、statistics
+ - 下载 PNG 格式,选择合适尺寸
+
+2. **Flaticon**
+ - 访问:https://www.flaticon.com/
+ - 搜索并下载免费图标
+
+3. **Icons8**
+ - 访问:https://icons8.com/
+ - 搜索并下载图标
+
+### 方法2:使用在线图标生成器
+
+1. **Canva**
+ - 访问:https://www.canva.com/
+ - 创建 81×81px 的画布
+ - 设计图标并导出为 PNG
+
+2. **Figma**
+ - 使用 Figma 设计图标
+ - 导出为 PNG 格式
+
+### 方法3:使用 AI 生成
+
+使用 AI 工具(如 Midjourney、DALL-E)生成图标:
+- 提示词示例:"simple icon home house, minimal style, purple color, transparent background, 81x81px"
+
+### 方法4:使用 Emoji(临时方案)
+
+如果暂时没有图标文件,可以:
+1. 使用系统字体图标
+2. 或者暂时移除 tabBar 配置,使用其他导航方式
+
+## 快速获取方案
+
+### 使用 uni-app 官方图标
+
+uni-app 提供了内置图标,可以修改 `pages.json` 使用文字图标:
+
+```json
+{
+ "tabBar": {
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "text": "首页",
+ "iconPath": "",
+ "selectedIconPath": ""
+ }
+ ]
+ }
+}
+```
+
+### 使用字体图标
+
+可以使用 iconfont 字体图标库,将图标转换为字体文件使用。
+
+## 图标命名规范
+
+请确保图标文件命名与 `pages.json` 中的配置一致:
+
+```
+static/tabbar/
+├── home.png
+├── home-active.png
+├── add.png
+├── add-active.png
+├── statistics.png
+└── statistics-active.png
+```
+
+## 注意事项
+
+1. 图标文件必须放在 `static/tabbar/` 目录下
+2. 文件名必须与 `pages.json` 中的配置完全一致
+3. 建议使用 @2x 尺寸(81px)以获得更好的显示效果
+4. 如果图标文件不存在,tabBar 可能无法正常显示
+
diff --git a/static/tabbar/add-active.png b/static/tabbar/add-active.png
new file mode 100644
index 0000000..7f22c25
Binary files /dev/null and b/static/tabbar/add-active.png differ
diff --git a/static/tabbar/add.png b/static/tabbar/add.png
new file mode 100644
index 0000000..5f59431
Binary files /dev/null and b/static/tabbar/add.png differ
diff --git a/static/tabbar/home-active.png b/static/tabbar/home-active.png
new file mode 100644
index 0000000..96d999c
Binary files /dev/null and b/static/tabbar/home-active.png differ
diff --git a/static/tabbar/home.png b/static/tabbar/home.png
new file mode 100644
index 0000000..ceee161
Binary files /dev/null and b/static/tabbar/home.png differ
diff --git a/static/tabbar/statistic-active.png b/static/tabbar/statistic-active.png
new file mode 100644
index 0000000..981304d
Binary files /dev/null and b/static/tabbar/statistic-active.png differ
diff --git a/static/tabbar/statistics.png b/static/tabbar/statistics.png
new file mode 100644
index 0000000..da5b889
Binary files /dev/null and b/static/tabbar/statistics.png differ
diff --git a/store/user.js b/store/user.js
new file mode 100644
index 0000000..20a4d99
--- /dev/null
+++ b/store/user.js
@@ -0,0 +1,47 @@
+import { defineStore } from 'pinia'
+
+export const useUserStore = defineStore('user', {
+ state: () => ({
+ token: uni.getStorageSync('token') || '',
+ userInfo: uni.getStorageSync('userInfo') || null
+ }),
+
+ getters: {
+ isLoggedIn: (state) => !!state.token,
+ username: (state) => state.userInfo?.username || '',
+ nickname: (state) => state.userInfo?.nickname || ''
+ },
+
+ actions: {
+ setToken(token) {
+ this.token = token
+ uni.setStorageSync('token', token)
+ },
+
+ setUserInfo(userInfo) {
+ this.userInfo = userInfo
+ uni.setStorageSync('userInfo', userInfo)
+ },
+
+ login(token, userInfo) {
+ this.setToken(token)
+ this.setUserInfo(userInfo)
+ },
+
+ logout() {
+ this.token = ''
+ this.userInfo = null
+ uni.removeStorageSync('token')
+ uni.removeStorageSync('userInfo')
+ }
+ }
+})
+
+
+
+
+
+
+
+
+
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..9876c55
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "jsx": "preserve",
+ "moduleResolution": "node",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "types": ["@dcloudio/types"]
+ },
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
+ "exclude": ["node_modules"]
+}
+
+
+
+
+
+
+
+
+
diff --git a/uni.scss b/uni.scss
new file mode 100644
index 0000000..e7b25fd
--- /dev/null
+++ b/uni.scss
@@ -0,0 +1,75 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #3c9cff;
+$uni-color-success: #19be6b;
+$uni-color-warning: #ff9900;
+$uni-color-error: #fa3534;
+
+/* 文字基本颜色 */
+$uni-text-color: #333; // 基本色
+$uni-text-color-inverse: #fff; // 反色
+$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable: #c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color: #ffffff;
+$uni-bg-color-grey: #f8f8f8;
+$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
+$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color: #c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm: 24rpx;
+$uni-font-size-base: 28rpx;
+$uni-font-size-lg: 32rpx;
+
+/* 图片尺寸 */
+$uni-img-size-sm: 40rpx;
+$uni-img-size-base: 52rpx;
+$uni-img-size-lg: 80rpx;
+
+/* Border Radius */
+$uni-border-radius-sm: 4rpx;
+$uni-border-radius-base: 6rpx;
+$uni-border-radius-lg: 12rpx;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 10rpx;
+$uni-spacing-row-base: 20rpx;
+$uni-spacing-row-lg: 30rpx;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 10rpx;
+$uni-spacing-col-base: 20rpx;
+$uni-spacing-col-lg: 30rpx;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2c405a; // 文章标题颜色
+$uni-font-size-title: 40rpx;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle: 36rpx;
+$uni-color-paragraph: #3f536e; // 文章段落颜色
+$uni-font-size-paragraph: 30rpx;
+
+
+
+
+
+
+
+
+
diff --git a/uniCloud-alipay/database/db_init.json b/uniCloud-alipay/database/db_init.json
new file mode 100644
index 0000000..ff60f6b
--- /dev/null
+++ b/uniCloud-alipay/database/db_init.json
@@ -0,0 +1,427 @@
+// 在本文件中可配置云数据库初始化,数据格式见:https://uniapp.dcloud.io/uniCloud/cf-database?id=db_init
+// 编写完毕后对本文件点右键,可按配置规则创建表和添加数据
+{
+ "opendb-news-articles": {
+ "data": [{
+ "user_id": 121375,
+ "user_name": "未来汽车日报",
+ "category_id": "223",
+ "title": "为什么自动驾驶诉讼不断?",
+ "content": "",
+ "excerpt": "没有永远的敌人,只有永远的利益。",
+ "article_status": 1,
+ "view_count": 32053,
+ "like_count": 4603,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 1204,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200410/v2_9c3331af67e64994aa97a27fffb1a380_img_png?x-oss-process=image/resize,m_mfit,w_520,h_300/crop,w_520,h_300,g_center",
+ "publish_date": "2020-04-11 17:07:48",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 17:11:09",
+ "last_modify_ip": "",
+ "mode":1
+ }, {
+ "user_id": 121374,
+ "user_name": "36氪深度服务",
+ "category_id": "0",
+ "title": "2020数字中国创新大赛-数字政府赛道21强出炉,四大赛题紧贴政府数字化发展需求",
+ "content": "",
+ "excerpt": "提升数字治理、建设“温暖渔政”——四大赛题助力政府解决治理难题",
+ "article_status": 1,
+ "view_count": 53855,
+ "like_count": 970,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 267,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200411/v2_16417a06088947debe0450950f8fc813_img_png",
+ "publish_date": "2020-04-11 16:59:15",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 17:03:18",
+ "last_modify_ip": "",
+ "mode":2
+ }, {
+ "user_id": 121373,
+ "user_name": "未来汽车日报",
+ "category_id": "223",
+ "title": "地方政府救市哪家强?广州补贴上万元,广深杭新增指标超5万",
+ "content": "",
+ "excerpt": "补贴很难落袋为安。",
+ "article_status": 1,
+ "view_count": 51662,
+ "like_count": 238,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 6217,
+ "last_comment_user_id": "",
+ "avatar": ["https://img.36krcdn.com/20200410/v2_6905947498bc4ec0af228afed409f771_img_png?x-oss-process=image/resize,m_mfit,w_520,h_300/crop,w_520,h_300,g_center","https://img.36krcdn.com/20200410/v2_6905947498bc4ec0af228afed409f771_img_png?x-oss-process=image/resize,m_mfit,w_520,h_300/crop,w_520,h_300,g_center","https://img.36krcdn.com/20200410/v2_6905947498bc4ec0af228afed409f771_img_png?x-oss-process=image/resize,m_mfit,w_520,h_300/crop,w_520,h_300,g_center"],
+ "publish_date": "2020-04-11 16:09:09",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 16:11:11",
+ "last_modify_ip": "",
+ "mode":3
+ }, {
+ "user_id": 121372,
+ "user_name": "智东西",
+ "category_id": "234",
+ "title": "救命呼吸机缺口难补!一文扒开供应链真相",
+ "content": "",
+ "excerpt": "全球疯抢国产呼吸机背后:技术有短板,产能被卡住。",
+ "article_status": 1,
+ "view_count": 77926,
+ "like_count": 2239,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 9154,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200410/v2_86bbf8245f754be79f3386a82b385093_img_000",
+ "publish_date": "2020-04-11 15:40:02",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 15:53:10",
+ "last_modify_ip": "",
+ "mode":4
+ }, {
+ "user_id": 121371,
+ "user_name": "神译局",
+ "category_id": "223",
+ "title": "每月节省32%的开支,我是怎么做到的?",
+ "content": "",
+ "excerpt": "开源节流",
+ "article_status": 1,
+ "view_count": 53577,
+ "like_count": 862,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 8073,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200408/v2_c67c3edfe4b5446992b32fad93a44a75_img_png",
+ "publish_date": "2020-04-11 14:48:02",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 15:02:22",
+ "last_modify_ip": "",
+ "mode":5
+ }, {
+ "user_id": 121369,
+ "user_name": "资本侦探",
+ "category_id": "221",
+ "title": "瓜子坚果双增长,但洽洽并不能高枕无忧",
+ "content": "",
+ "excerpt": "零食市场竞争日益激烈。",
+ "article_status": 1,
+ "view_count": 13740,
+ "like_count": 1354,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 7942,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200411/v2_2204c6132432403184e43df22485545e_img_000?x-oss-process=image/resize,m_mfit,w_432,h_288/crop,w_432,h_288,g_center",
+ "publish_date": "2020-04-11 14:23:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 14:34:13",
+ "last_modify_ip": "",
+ "mode":6
+ }, {
+ "user_id": 121367,
+ "user_name": "神译局",
+ "category_id": "103",
+ "title": "克服危机和压力,精神力量强大的人都有这5个习惯",
+ "content": "",
+ "excerpt": "学会利用好真正艰难的时刻,增强自己的精神力量",
+ "article_status": 1,
+ "view_count": 71706,
+ "like_count": 4978,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 5361,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200406/v2_d2c6a686b4074a1eb43603e67d6ba204_img_png",
+ "publish_date": "2020-04-11 13:47:01",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 13:52:12",
+ "last_modify_ip": "",
+ "mode":1
+ }, {
+ "user_id": 121365,
+ "user_name": "PingWest品玩",
+ "category_id": "221",
+ "title": "神州租车找爹记",
+ "content": "",
+ "excerpt": "一爹难求。",
+ "article_status": 1,
+ "view_count": 47794,
+ "like_count": 2397,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 9489,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200411/v2_f497b1c414d5489791569b3ea99df33d_img_000",
+ "publish_date": "2020-04-11 13:39:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 13:44:11",
+ "last_modify_ip": "",
+ "mode":2
+ }, {
+ "user_id": 121366,
+ "user_name": "明星八爪娱",
+ "category_id": "225",
+ "title": "抖音快手明星图鉴:哪个平台更适合明星“再就业”?",
+ "content": "",
+ "excerpt": "一个捧红了“十八线”明星,一个靠“偶像”获得新生",
+ "article_status": 1,
+ "view_count": 95348,
+ "like_count": 1356,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 356,
+ "last_comment_user_id": "",
+ "avatar": ["https://img.36krcdn.com/20200411/v2_da4c26244cbc494c8e0e5918518e866c_img_png","https://img.36krcdn.com/20200411/v2_da4c26244cbc494c8e0e5918518e866c_img_png","https://img.36krcdn.com/20200411/v2_da4c26244cbc494c8e0e5918518e866c_img_png"],
+ "publish_date": "2020-04-11 13:38:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 13:44:11",
+ "last_modify_ip": "",
+ "mode":3
+ }, {
+ "user_id": 121364,
+ "user_name": "神译局",
+ "category_id": "223",
+ "title": "动荡的市场中,你需要牢记巴菲特的这3个原则",
+ "content": "",
+ "excerpt": "本周股市下跌了不少——沃伦·巴菲特会作何反应?",
+ "article_status": 1,
+ "view_count": 86148,
+ "like_count": 4027,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 6620,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200406/v2_232e9248d5c74ff989db57a0b6713abe_img_png",
+ "publish_date": "2020-04-11 12:45:02",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 12:51:10",
+ "last_modify_ip": "",
+ "mode":4
+ }, {
+ "user_id": 121362,
+ "user_name": "资本侦探",
+ "category_id": "0",
+ "title": "连亏六年、股价跌破1美元,曾经的明星公司途牛怎么了?",
+ "content": "",
+ "excerpt": "携程、京东、红杉共同加持也无济于事。",
+ "article_status": 1,
+ "view_count": 83493,
+ "like_count": 1771,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 2211,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200411/v2_61c1766736df49a0b2d0213624c0ebd2_img_000?x-oss-process=image/resize,m_mfit,w_432,h_288/crop,w_432,h_288,g_center",
+ "publish_date": "2020-04-11 12:37:11",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 12:41:10",
+ "last_modify_ip": "",
+ "mode":5
+ }, {
+ "user_id": 121363,
+ "user_name": "Tech星球",
+ "category_id": "0",
+ "title": "独家 | 快手版「多闪」上线:「一甜面聊」布局视频社交",
+ "content": "",
+ "excerpt": "视频社交的时代来了。",
+ "article_status": 1,
+ "view_count": 97790,
+ "like_count": 636,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 4027,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200411/v2_b92317dfc59948cea0f3c69a0357e519_img_000?x-oss-process=image/resize,m_mfit,w_432,h_288/crop,w_432,h_288,g_center",
+ "publish_date": "2020-04-11 12:36:58",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 12:41:11",
+ "last_modify_ip": "",
+ "mode":6
+ }, {
+ "user_id": 121361,
+ "user_name": "神译局",
+ "category_id": "103",
+ "title": "2020年已经过去了四分之一,但改变自己为时不晚",
+ "content": "",
+ "excerpt": "种一棵树最好的时间是十年前,其次是现在",
+ "article_status": 1,
+ "view_count": 67302,
+ "like_count": 4148,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 286,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200404/v2_d6613223fb15414897a0ba3449d00afd_img_png",
+ "publish_date": "2020-04-11 11:44:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 11:52:11",
+ "last_modify_ip": "",
+ "mode":1
+ }, {
+ "user_id": 121360,
+ "user_name": "沈帅波",
+ "category_id": "221",
+ "title": "2020,市场部求生指南",
+ "content": "",
+ "excerpt": "短期思维的套利空间正在逐渐消失。",
+ "article_status": 1,
+ "view_count": 91108,
+ "like_count": 4029,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 7126,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200410/v2_c5997a3640f54c2c880cff0906f6896c_img_000",
+ "publish_date": "2020-04-11 11:31:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 11:33:15",
+ "last_modify_ip": "",
+ "mode":2
+ }, {
+ "user_id": 121359,
+ "user_name": "陈淑雅",
+ "category_id": "223",
+ "title": "定位新媒体整合营销服务商,「通明传媒」用“小V矩阵”打出差异化",
+ "content": "",
+ "excerpt": "近期通明传媒还成为了罗永浩抖音直播的官方授权招商服务合作伙伴。",
+ "article_status": 1,
+ "view_count": 38875,
+ "like_count": 4717,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 9477,
+ "last_comment_user_id": "",
+ "avatar": ["https://img.36krcdn.com/20200410/v2_224a699a06504292804e4bdf70ca87bb_img_png","https://img.36krcdn.com/20200410/v2_224a699a06504292804e4bdf70ca87bb_img_png","https://img.36krcdn.com/20200410/v2_224a699a06504292804e4bdf70ca87bb_img_png"],
+ "publish_date": "2020-04-11 11:09:58",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 11:21:10",
+ "last_modify_ip": "",
+ "mode":3
+ }, {
+ "user_id": 121358,
+ "user_name": "来咖智库",
+ "category_id": "0",
+ "title": "BAT的直播电商新战事",
+ "content": "",
+ "excerpt": "阿里做大、腾讯做深、百度做新。",
+ "article_status": 1,
+ "view_count": 41013,
+ "like_count": 3650,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 682,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200410/v2_747fc8a18fde4da4b1ba1080d8e6aa04_img_000",
+ "publish_date": "2020-04-11 11:06:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 11:12:11",
+ "last_modify_ip": "",
+ "mode":4
+ }, {
+ "user_id": 121357,
+ "user_name": "创业最前线",
+ "category_id": "0",
+ "title": "估值50亿美元,“种草”社区头牌,小红书如何走出商业化迷途?",
+ "content": "",
+ "excerpt": "小红书求变。",
+ "article_status": 1,
+ "view_count": 36498,
+ "like_count": 1523,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 8731,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200410/v2_18c3a78cf8be42ccb45e4daba0c87c13_img_png",
+ "publish_date": "2020-04-11 10:41:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 10:53:11",
+ "last_modify_ip": "",
+ "mode":5
+ }, {
+ "user_id": 121356,
+ "user_name": "神译局",
+ "category_id": "223",
+ "title": "在混乱和不确定的时期,你最需要的是这5个技能",
+ "content": "",
+ "excerpt": "自律就是即使你不想做某件事,但也能强迫自己去做的能力。",
+ "article_status": 1,
+ "view_count": 13776,
+ "like_count": 2214,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 9514,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200401/v2_4afb7581cb5a4c36aac96a51829c13e0_img_png",
+ "publish_date": "2020-04-11 10:40:01",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 10:41:11",
+ "last_modify_ip": "",
+ "mode":6
+ }, {
+ "user_id": 121355,
+ "user_name": "音乐先声",
+ "category_id": "0",
+ "title": "复工按下暂停键,演出报批遥遥无期,线下音乐路在何方?",
+ "content": "",
+ "excerpt": "阴霾终究会散去。",
+ "article_status": 1,
+ "view_count": 96989,
+ "like_count": 3607,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 3580,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200410/v2_41365a0f26a244fdab8e3f5be081ed2b_img_000",
+ "publish_date": "2020-04-11 10:06:00",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 10:11:12",
+ "last_modify_ip": "",
+ "mode":1
+ }, {
+ "user_id": 121354,
+ "user_name": "36氪出海",
+ "category_id": "0",
+ "title": "出海创投周报|阿里领投印度BigBasket6000万美元融资;Reliance向AI教育平台Embibe追加6600万美元投资",
+ "content": "",
+ "excerpt": "出海人的周末精选读物。",
+ "article_status": 1,
+ "view_count": 63561,
+ "like_count": 3817,
+ "is_sticky": false,
+ "is_essence": false,
+ "comment_status": 0,
+ "comment_count": 1433,
+ "last_comment_user_id": "",
+ "avatar": "https://img.36krcdn.com/20200410/v2_fb948f4c18de4b22927f0361d53f6caf_img_png",
+ "publish_date": "2020-04-11 10:00:01",
+ "publish_ip": "",
+ "last_modify_date": "2020-04-11 10:03:18",
+ "last_modify_ip": "",
+ "mode":2
+ }]
+ }
+}
diff --git a/uniCloud-alipay/database/opendb-news-articles.schema.json b/uniCloud-alipay/database/opendb-news-articles.schema.json
new file mode 100644
index 0000000..18c4f0d
--- /dev/null
+++ b/uniCloud-alipay/database/opendb-news-articles.schema.json
@@ -0,0 +1,122 @@
+{
+ "bsonType": "object",
+ "permission": {
+ "create": "auth.uid != null",
+ "delete": "doc.uid == auth.uid",
+ "read": true,
+ "update": "doc.uid == auth.uid"
+ },
+ "properties": {
+ "_id": {
+ "description": "存储文档 ID(用户 ID),系统自动生成"
+ },
+ "article_status": {
+ "bsonType": "int",
+ "description": "文章状态:0 草稿箱 1 已发布",
+ "maximum": 1,
+ "minimum": 0
+ },
+ "avatar": {
+ "bsonType": "string",
+ "description": "缩略图地址",
+ "label": "封面大图"
+ },
+ "category_id": {
+ "bsonType": "string",
+ "description": "分类 id,参考`uni-news-categories`表"
+ },
+ "comment_count": {
+ "bsonType": "int",
+ "description": "评论数量",
+ "permission": {
+ "write": false
+ }
+ },
+ "comment_status": {
+ "bsonType": "int",
+ "description": "评论状态:0 关闭 1 开放",
+ "maximum": 1,
+ "minimum": 0
+ },
+ "content": {
+ "bsonType": "string",
+ "description": "文章内容",
+ "label": "文章内容"
+ },
+ "excerpt": {
+ "bsonType": "string",
+ "description": "文章摘录",
+ "label": "摘要"
+ },
+ "is_essence": {
+ "bsonType": "bool",
+ "description": "阅读加精",
+ "permission": {
+ "write": false
+ }
+ },
+ "is_sticky": {
+ "bsonType": "bool",
+ "description": "是否置顶",
+ "permission": {
+ "write": false
+ }
+ },
+ "last_comment_user_id": {
+ "bsonType": "string",
+ "description": "最后回复用户 id,参考`uni-id-users` 表"
+ },
+ "last_modify_date": {
+ "bsonType": "timestamp",
+ "description": "最后修改时间"
+ },
+ "last_modify_ip": {
+ "bsonType": "string",
+ "description": "最后修改时 IP 地址"
+ },
+ "like_count": {
+ "bsonType": "int",
+ "description": "喜欢数、点赞数",
+ "permission": {
+ "write": false
+ }
+ },
+ "mode": {
+ "bsonType": "number",
+ "description": "排版显示模式"
+ },
+ "publish_date": {
+ "bsonType": "timestamp",
+ "defaultValue": {
+ "$env": "now"
+ },
+ "description": "发表时间"
+ },
+ "publish_ip": {
+ "bsonType": "string",
+ "description": "发表时 IP 地址",
+ "forceDefaultValue": {
+ "$env": "clientIP"
+ }
+ },
+ "title": {
+ "bsonType": "string",
+ "description": "标题",
+ "label": "标题"
+ },
+ "user_id": {
+ "bsonType": "string",
+ "description": "文章作者ID, 参考`uni-id-users` 表"
+ },
+ "view_count": {
+ "bsonType": "int",
+ "description": "阅读数量",
+ "permission": {
+ "write": false
+ }
+ }
+ },
+ "required": ["user_id", "title", "content", "article_status", "view_count", "like_count", "is_sticky", "is_essence",
+ "comment_status", "comment_count", "mode"
+ ]
+}
diff --git a/uni_modules/uni-badge/changelog.md b/uni_modules/uni-badge/changelog.md
new file mode 100644
index 0000000..550eb41
--- /dev/null
+++ b/uni_modules/uni-badge/changelog.md
@@ -0,0 +1,14 @@
+## 1.1.1(2021-05-12)
+- 新增 组件示例地址
+## 1.1.0(2021-05-12)
+- 新增 uni-badge 的 absolute 属性,支持定位
+- 新增 uni-badge 的 offset 属性,支持定位偏移
+- 新增 uni-badge 的 is-dot 属性,支持仅显示有一个小点
+- 新增 uni-badge 的 max-num 属性,支持自定义封顶的数字值,超过 99 显示99+
+- 优化 uni-badge 属性 custom-style, 支持以对象形式自定义样式
+## 1.0.7(2021-05-07)
+- 修复 uni-badge 在 App 端,数字小于10时不是圆形的bug
+- 修复 uni-badge 在父元素不是 flex 布局时,宽度缩小的bug
+- 新增 uni-badge 属性 custom-style, 支持自定义样式
+## 1.0.6(2021-02-04)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-badge/components/uni-badge/uni-badge.vue b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue
new file mode 100644
index 0000000..efe2812
--- /dev/null
+++ b/uni_modules/uni-badge/components/uni-badge/uni-badge.vue
@@ -0,0 +1,252 @@
+
+
+
+ {{displayValue}}
+
+
+
+
+
+
diff --git a/uni_modules/uni-badge/package.json b/uni_modules/uni-badge/package.json
new file mode 100644
index 0000000..4b0c851
--- /dev/null
+++ b/uni_modules/uni-badge/package.json
@@ -0,0 +1,84 @@
+{
+ "id": "uni-badge",
+ "displayName": "uni-badge 数字角标",
+ "version": "1.1.1",
+ "description": "数字角标(徽章)组件,在元素周围展示消息提醒,一般用于列表、九宫格、按钮等地方。",
+ "keywords": [
+ "",
+ "badge",
+ "uni-ui",
+ "uniui",
+ "数字角标",
+ "徽章"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "y",
+ "联盟": "y"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-badge/readme.md b/uni_modules/uni-badge/readme.md
new file mode 100644
index 0000000..e035449
--- /dev/null
+++ b/uni_modules/uni-badge/readme.md
@@ -0,0 +1,58 @@
+
+
+## Badge 数字角标
+> **组件名:uni-badge**
+> 代码块: `uBadge`
+
+
+数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景,
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+
+
+
+
+
+
+```
+
+
+## API
+
+### Badge Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|text |String |- |角标内容 |
+|type |String |default|颜色类型,可选值:default(灰色)、primary(蓝色)、success(绿色)、warning(黄色)、error(红色)|
+|size |String |normal |Badge 大小,可取值:normal、small |
+|is-dot |Boolean|false |不展示数字,只有一个小点 |
+|max-num |String/Numbuer|99 |展示封顶的数字值,超过 99 显示99+ |
+|custom-style |Object | {} |自定义 Badge 样式, 样式对象语法 |
+|inverted |Boolean|false |是否无需背景颜色,为 true 时,背景颜色将变为文字的字体颜色 |
+|absolute |String| rightTop|开启绝对定位, 角标将定位到其包裹的标签的四个角上,可选值: rightTop(右上角)、rightBottom(右下角)、leftBottom(左下角) 、leftTop(左上角) |
+|offset |Array[number]| [0, 0]|距定位角中心点的偏移量,[-10, -10] 表示向 absolute 指定的方向偏移 10px,[10, 10] 表示向 absolute 指定的反方向偏移 10px,只有存在 absolute 属性时有效,与absolute 的值一一对应(例如:值为rightTop, 对应 offset 为 [right, Top])|
+
+### Badge Events
+
+|事件名 |事件说明 |返回参数 |
+|:-: |:-: |:-: |
+|@click |点击 Badge 触发事件| - |
+
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/badge/badge](https://hellouniapp.dcloud.net.cn/pages/extUI/badge/badge)
\ No newline at end of file
diff --git a/uni_modules/uni-config-center/changelog.md b/uni_modules/uni-config-center/changelog.md
new file mode 100644
index 0000000..4d2eb92
--- /dev/null
+++ b/uni_modules/uni-config-center/changelog.md
@@ -0,0 +1,4 @@
+## 0.0.2(2021-04-16)
+- 修改插件package信息
+## 0.0.1(2021-03-15)
+- 初始化项目
diff --git a/uni_modules/uni-config-center/package.json b/uni_modules/uni-config-center/package.json
new file mode 100644
index 0000000..c5dec93
--- /dev/null
+++ b/uni_modules/uni-config-center/package.json
@@ -0,0 +1,80 @@
+{
+ "id": "uni-config-center",
+ "displayName": "uni-config-center",
+ "version": "0.0.2",
+ "description": "uniCloud 配置中心",
+ "keywords": [
+ "配置",
+ "配置中心"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "uniCloud",
+ "云函数模板"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "directories": {
+ "example": "../../../scripts/dist"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "u",
+ "app-nvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "u",
+ "Android Browser": "u",
+ "微信浏览器(Android)": "u",
+ "QQ浏览器(Android)": "u"
+ },
+ "H5-pc": {
+ "Chrome": "u",
+ "IE": "u",
+ "Edge": "u",
+ "Firefox": "u",
+ "Safari": "u"
+ },
+ "小程序": {
+ "微信": "u",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-config-center/readme.md b/uni_modules/uni-config-center/readme.md
new file mode 100644
index 0000000..03f7fc2
--- /dev/null
+++ b/uni_modules/uni-config-center/readme.md
@@ -0,0 +1,93 @@
+# 为什么使用uni-config-center
+
+实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构
+
+```bash
+cloudfunctions
+└─────common 公共模块
+ ├─plugin-a // 插件A对应的目录
+ │ ├─index.js
+ │ ├─config.json // plugin-a对应的配置文件
+ │ └─other-file.cert // plugin-a依赖的其他文件
+ └─plugin-b // plugin-b对应的目录
+ ├─index.js
+ └─config.json // plugin-b对应的配置文件
+```
+
+假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。
+
+uni-config-center就是用了统一管理这些配置文件的,使用uni-config-center后的目录结构如下
+
+```bash
+cloudfunctions
+└─────common 公共模块
+ ├─plugin-a // 插件A对应的目录
+ │ └─index.js
+ ├─plugin-b // plugin-b对应的目录
+ │ └─index.js
+ └─uni-config-center
+ ├─index.js // config-center入口文件
+ ├─plugin-a
+ │ ├─config.json // plugin-a对应的配置文件
+ │ └─other-file.cert // plugin-a依赖的其他文件
+ └─plugin-b
+ └─config.json // plugin-b对应的配置文件
+```
+
+使用uni-config-center后的优势
+
+- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便
+- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持)
+
+# 用法
+
+在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖,请参考:[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common)
+
+```js
+const createConfig = require('uni-config-center')
+
+const uniIdConfig = createConfig({
+ pluginId: 'uni-id', // 插件id
+ defaultConfig: { // 默认配置
+ tokenExpiresIn: 7200,
+ tokenExpiresThreshold: 600,
+ },
+ customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并
+ // defaudltConfig 默认配置
+ // userConfig 用户配置
+ return Object.assign(defaultConfig, userConfig)
+ }
+})
+
+
+// 以如下配置为例
+// {
+// "tokenExpiresIn": 7200,
+// "passwordErrorLimit": 6,
+// "bindTokenToDevice": false,
+// "passwordErrorRetryTime": 3600,
+// "app-plus": {
+// "tokenExpiresIn": 2592000
+// },
+// "service": {
+// "sms": {
+// "codeExpiresIn": 300
+// }
+// }
+// }
+
+// 获取配置
+uniIdConfig.config() // 获取全部配置,注意:uni-config-center内不存在对应插件目录时会返回空对象
+uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置,返回:7200
+uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置,返回:300
+uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置,如果不存在则取传入的默认值,返回:600
+
+// 获取文件绝对路径
+uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径
+
+// 引用文件(require)
+uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined,文件内有其他错误导致require失败时会抛出错误。
+
+// 判断是否包含某文件
+uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件,true: 文件存在,false: 文件不存在
+```
\ No newline at end of file
diff --git a/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js b/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js
new file mode 100644
index 0000000..e14fb3b
--- /dev/null
+++ b/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js
@@ -0,0 +1 @@
+"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=_t(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=_t(p,"Map"),J=_t(Object,"create"),K=function(){function t(){}return function(r){if(!Mt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=pt(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return pt(this,t).get(t)},Y.prototype.has=function(t){return pt(this,t).has(t)},Y.prototype.set=function(t,r){var e=pt(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return xt(t)&&ct(t)==o}function ft(t){return!(!Mt(t)||function(t){return!!U&&U in t}(t))&&(At(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!Mt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=dt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),Mt(i))!function(t,r,e,n,o,i,u){var a=yt(t,e),f=yt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=wt(f),_=!p&&mt(f),v=!p&&!_&&Ct(f);l=f,p||_||v?wt(a)?l=a:xt(j=a)&&Ot(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(R?function(t,r){return R(t,"toString",{configurable:!0,enumerable:!1,value:(e=r,function(){return e}),writable:!0});var e}:It);function bt(t,r){return t===r||t!=t&&r!=r}var jt=at(function(){return arguments}())?at:function(t){return xt(t)&&F.call(t,"callee")&&!B.call(t,"callee")},wt=Array.isArray;function Ot(t){return null!=t&&zt(t.length)&&!At(t)}var mt=G||function(){return!1};function At(t){if(!Mt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function zt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function Mt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function xt(t){return null!=t&&"object"==typeof t}var Ct=b?function(t){return function(r){return t(r)}}(b):function(t){return xt(t)&&zt(t.length)&&!!s[ct(t)]};function Ft(t){return Ot(t)?tt(t,!0):st(t)}var Ut,St=(Ut=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=Ut.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!Mt(e))return!1;var n=typeof r;return!!("number"==n?Ot(e)&&vt(r,e.length):"string"==n&&r in e)&&bt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){this._config||(this._config=(this.customMerge||u)(this.defaultConfig,this._getUserConfig()));let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;t
+
+ {{unicode}}
+
+
+
+
+
+
diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.vue b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue
new file mode 100644
index 0000000..6319565
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue
@@ -0,0 +1,71 @@
+
+ {{icons[type]}}
+
+
+
+
+
diff --git a/uni_modules/uni-icons/components/uni-icons/uni.ttf b/uni_modules/uni-icons/components/uni-icons/uni.ttf
new file mode 100644
index 0000000..60a1968
Binary files /dev/null and b/uni_modules/uni-icons/components/uni-icons/uni.ttf differ
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.css b/uni_modules/uni-icons/components/uni-icons/uniicons.css
new file mode 100644
index 0000000..0a6b6fe
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uniicons.css
@@ -0,0 +1,664 @@
+
+.uniui-cart-filled:before {
+ content: "\e6d0";
+}
+
+.uniui-gift-filled:before {
+ content: "\e6c4";
+}
+
+.uniui-color:before {
+ content: "\e6cf";
+}
+
+.uniui-wallet:before {
+ content: "\e6b1";
+}
+
+.uniui-settings-filled:before {
+ content: "\e6ce";
+}
+
+.uniui-auth-filled:before {
+ content: "\e6cc";
+}
+
+.uniui-shop-filled:before {
+ content: "\e6cd";
+}
+
+.uniui-staff-filled:before {
+ content: "\e6cb";
+}
+
+.uniui-vip-filled:before {
+ content: "\e6c6";
+}
+
+.uniui-plus-filled:before {
+ content: "\e6c7";
+}
+
+.uniui-folder-add-filled:before {
+ content: "\e6c8";
+}
+
+.uniui-color-filled:before {
+ content: "\e6c9";
+}
+
+.uniui-tune-filled:before {
+ content: "\e6ca";
+}
+
+.uniui-calendar-filled:before {
+ content: "\e6c0";
+}
+
+.uniui-notification-filled:before {
+ content: "\e6c1";
+}
+
+.uniui-wallet-filled:before {
+ content: "\e6c2";
+}
+
+.uniui-medal-filled:before {
+ content: "\e6c3";
+}
+
+.uniui-fire-filled:before {
+ content: "\e6c5";
+}
+
+.uniui-refreshempty:before {
+ content: "\e6bf";
+}
+
+.uniui-location-filled:before {
+ content: "\e6af";
+}
+
+.uniui-person-filled:before {
+ content: "\e69d";
+}
+
+.uniui-personadd-filled:before {
+ content: "\e698";
+}
+
+.uniui-arrowthinleft:before {
+ content: "\e6d2";
+}
+
+.uniui-arrowthinup:before {
+ content: "\e6d3";
+}
+
+.uniui-arrowthindown:before {
+ content: "\e6d4";
+}
+
+.uniui-back:before {
+ content: "\e6b9";
+}
+
+.uniui-forward:before {
+ content: "\e6ba";
+}
+
+.uniui-arrow-right:before {
+ content: "\e6bb";
+}
+
+.uniui-arrow-left:before {
+ content: "\e6bc";
+}
+
+.uniui-arrow-up:before {
+ content: "\e6bd";
+}
+
+.uniui-arrow-down:before {
+ content: "\e6be";
+}
+
+.uniui-arrowthinright:before {
+ content: "\e6d1";
+}
+
+.uniui-down:before {
+ content: "\e6b8";
+}
+
+.uniui-bottom:before {
+ content: "\e6b8";
+}
+
+.uniui-arrowright:before {
+ content: "\e6d5";
+}
+
+.uniui-right:before {
+ content: "\e6b5";
+}
+
+.uniui-up:before {
+ content: "\e6b6";
+}
+
+.uniui-top:before {
+ content: "\e6b6";
+}
+
+.uniui-left:before {
+ content: "\e6b7";
+}
+
+.uniui-arrowup:before {
+ content: "\e6d6";
+}
+
+.uniui-eye:before {
+ content: "\e651";
+}
+
+.uniui-eye-filled:before {
+ content: "\e66a";
+}
+
+.uniui-eye-slash:before {
+ content: "\e6b3";
+}
+
+.uniui-eye-slash-filled:before {
+ content: "\e6b4";
+}
+
+.uniui-info-filled:before {
+ content: "\e649";
+}
+
+.uniui-reload:before {
+ content: "\e6b2";
+}
+
+.uniui-micoff-filled:before {
+ content: "\e6b0";
+}
+
+.uniui-map-pin-ellipse:before {
+ content: "\e6ac";
+}
+
+.uniui-map-pin:before {
+ content: "\e6ad";
+}
+
+.uniui-location:before {
+ content: "\e6ae";
+}
+
+.uniui-starhalf:before {
+ content: "\e683";
+}
+
+.uniui-star:before {
+ content: "\e688";
+}
+
+.uniui-star-filled:before {
+ content: "\e68f";
+}
+
+.uniui-calendar:before {
+ content: "\e6a0";
+}
+
+.uniui-fire:before {
+ content: "\e6a1";
+}
+
+.uniui-medal:before {
+ content: "\e6a2";
+}
+
+.uniui-font:before {
+ content: "\e6a3";
+}
+
+.uniui-gift:before {
+ content: "\e6a4";
+}
+
+.uniui-link:before {
+ content: "\e6a5";
+}
+
+.uniui-notification:before {
+ content: "\e6a6";
+}
+
+.uniui-staff:before {
+ content: "\e6a7";
+}
+
+.uniui-vip:before {
+ content: "\e6a8";
+}
+
+.uniui-folder-add:before {
+ content: "\e6a9";
+}
+
+.uniui-tune:before {
+ content: "\e6aa";
+}
+
+.uniui-auth:before {
+ content: "\e6ab";
+}
+
+.uniui-person:before {
+ content: "\e699";
+}
+
+.uniui-email-filled:before {
+ content: "\e69a";
+}
+
+.uniui-phone-filled:before {
+ content: "\e69b";
+}
+
+.uniui-phone:before {
+ content: "\e69c";
+}
+
+.uniui-email:before {
+ content: "\e69e";
+}
+
+.uniui-personadd:before {
+ content: "\e69f";
+}
+
+.uniui-chatboxes-filled:before {
+ content: "\e692";
+}
+
+.uniui-contact:before {
+ content: "\e693";
+}
+
+.uniui-chatbubble-filled:before {
+ content: "\e694";
+}
+
+.uniui-contact-filled:before {
+ content: "\e695";
+}
+
+.uniui-chatboxes:before {
+ content: "\e696";
+}
+
+.uniui-chatbubble:before {
+ content: "\e697";
+}
+
+.uniui-upload-filled:before {
+ content: "\e68e";
+}
+
+.uniui-upload:before {
+ content: "\e690";
+}
+
+.uniui-weixin:before {
+ content: "\e691";
+}
+
+.uniui-compose:before {
+ content: "\e67f";
+}
+
+.uniui-qq:before {
+ content: "\e680";
+}
+
+.uniui-download-filled:before {
+ content: "\e681";
+}
+
+.uniui-pyq:before {
+ content: "\e682";
+}
+
+.uniui-sound:before {
+ content: "\e684";
+}
+
+.uniui-trash-filled:before {
+ content: "\e685";
+}
+
+.uniui-sound-filled:before {
+ content: "\e686";
+}
+
+.uniui-trash:before {
+ content: "\e687";
+}
+
+.uniui-videocam-filled:before {
+ content: "\e689";
+}
+
+.uniui-spinner-cycle:before {
+ content: "\e68a";
+}
+
+.uniui-weibo:before {
+ content: "\e68b";
+}
+
+.uniui-videocam:before {
+ content: "\e68c";
+}
+
+.uniui-download:before {
+ content: "\e68d";
+}
+
+.uniui-help:before {
+ content: "\e679";
+}
+
+.uniui-navigate-filled:before {
+ content: "\e67a";
+}
+
+.uniui-plusempty:before {
+ content: "\e67b";
+}
+
+.uniui-smallcircle:before {
+ content: "\e67c";
+}
+
+.uniui-minus-filled:before {
+ content: "\e67d";
+}
+
+.uniui-micoff:before {
+ content: "\e67e";
+}
+
+.uniui-closeempty:before {
+ content: "\e66c";
+}
+
+.uniui-clear:before {
+ content: "\e66d";
+}
+
+.uniui-navigate:before {
+ content: "\e66e";
+}
+
+.uniui-minus:before {
+ content: "\e66f";
+}
+
+.uniui-image:before {
+ content: "\e670";
+}
+
+.uniui-mic:before {
+ content: "\e671";
+}
+
+.uniui-paperplane:before {
+ content: "\e672";
+}
+
+.uniui-close:before {
+ content: "\e673";
+}
+
+.uniui-help-filled:before {
+ content: "\e674";
+}
+
+.uniui-paperplane-filled:before {
+ content: "\e675";
+}
+
+.uniui-plus:before {
+ content: "\e676";
+}
+
+.uniui-mic-filled:before {
+ content: "\e677";
+}
+
+.uniui-image-filled:before {
+ content: "\e678";
+}
+
+.uniui-locked-filled:before {
+ content: "\e668";
+}
+
+.uniui-info:before {
+ content: "\e669";
+}
+
+.uniui-locked:before {
+ content: "\e66b";
+}
+
+.uniui-camera-filled:before {
+ content: "\e658";
+}
+
+.uniui-chat-filled:before {
+ content: "\e659";
+}
+
+.uniui-camera:before {
+ content: "\e65a";
+}
+
+.uniui-circle:before {
+ content: "\e65b";
+}
+
+.uniui-checkmarkempty:before {
+ content: "\e65c";
+}
+
+.uniui-chat:before {
+ content: "\e65d";
+}
+
+.uniui-circle-filled:before {
+ content: "\e65e";
+}
+
+.uniui-flag:before {
+ content: "\e65f";
+}
+
+.uniui-flag-filled:before {
+ content: "\e660";
+}
+
+.uniui-gear-filled:before {
+ content: "\e661";
+}
+
+.uniui-home:before {
+ content: "\e662";
+}
+
+.uniui-home-filled:before {
+ content: "\e663";
+}
+
+.uniui-gear:before {
+ content: "\e664";
+}
+
+.uniui-smallcircle-filled:before {
+ content: "\e665";
+}
+
+.uniui-map-filled:before {
+ content: "\e666";
+}
+
+.uniui-map:before {
+ content: "\e667";
+}
+
+.uniui-refresh-filled:before {
+ content: "\e656";
+}
+
+.uniui-refresh:before {
+ content: "\e657";
+}
+
+.uniui-cloud-upload:before {
+ content: "\e645";
+}
+
+.uniui-cloud-download-filled:before {
+ content: "\e646";
+}
+
+.uniui-cloud-download:before {
+ content: "\e647";
+}
+
+.uniui-cloud-upload-filled:before {
+ content: "\e648";
+}
+
+.uniui-redo:before {
+ content: "\e64a";
+}
+
+.uniui-images-filled:before {
+ content: "\e64b";
+}
+
+.uniui-undo-filled:before {
+ content: "\e64c";
+}
+
+.uniui-more:before {
+ content: "\e64d";
+}
+
+.uniui-more-filled:before {
+ content: "\e64e";
+}
+
+.uniui-undo:before {
+ content: "\e64f";
+}
+
+.uniui-images:before {
+ content: "\e650";
+}
+
+.uniui-paperclip:before {
+ content: "\e652";
+}
+
+.uniui-settings:before {
+ content: "\e653";
+}
+
+.uniui-search:before {
+ content: "\e654";
+}
+
+.uniui-redo-filled:before {
+ content: "\e655";
+}
+
+.uniui-list:before {
+ content: "\e644";
+}
+
+.uniui-mail-open-filled:before {
+ content: "\e63a";
+}
+
+.uniui-hand-down-filled:before {
+ content: "\e63c";
+}
+
+.uniui-hand-down:before {
+ content: "\e63d";
+}
+
+.uniui-hand-up-filled:before {
+ content: "\e63e";
+}
+
+.uniui-hand-up:before {
+ content: "\e63f";
+}
+
+.uniui-heart-filled:before {
+ content: "\e641";
+}
+
+.uniui-mail-open:before {
+ content: "\e643";
+}
+
+.uniui-heart:before {
+ content: "\e639";
+}
+
+.uniui-loop:before {
+ content: "\e633";
+}
+
+.uniui-pulldown:before {
+ content: "\e632";
+}
+
+.uniui-scan:before {
+ content: "\e62a";
+}
+
+.uniui-bars:before {
+ content: "\e627";
+}
+
+.uniui-checkbox:before {
+ content: "\e62b";
+}
+
+.uniui-checkbox-filled:before {
+ content: "\e62c";
+}
+
+.uniui-shop:before {
+ content: "\e62f";
+}
+
+.uniui-headphones:before {
+ content: "\e630";
+}
+
+.uniui-cart:before {
+ content: "\e631";
+}
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.ttf b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf
new file mode 100644
index 0000000..14696d0
Binary files /dev/null and b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf differ
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
new file mode 100644
index 0000000..98e93aa
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
@@ -0,0 +1,664 @@
+
+export type IconsData = {
+ id : string
+ name : string
+ font_family : string
+ css_prefix_text : string
+ description : string
+ glyphs : Array
+}
+
+export type IconsDataItem = {
+ font_class : string
+ unicode : string
+}
+
+
+export const fontData = [
+ {
+ "font_class": "arrow-down",
+ "unicode": "\ue6be"
+ },
+ {
+ "font_class": "arrow-left",
+ "unicode": "\ue6bc"
+ },
+ {
+ "font_class": "arrow-right",
+ "unicode": "\ue6bb"
+ },
+ {
+ "font_class": "arrow-up",
+ "unicode": "\ue6bd"
+ },
+ {
+ "font_class": "auth",
+ "unicode": "\ue6ab"
+ },
+ {
+ "font_class": "auth-filled",
+ "unicode": "\ue6cc"
+ },
+ {
+ "font_class": "back",
+ "unicode": "\ue6b9"
+ },
+ {
+ "font_class": "bars",
+ "unicode": "\ue627"
+ },
+ {
+ "font_class": "calendar",
+ "unicode": "\ue6a0"
+ },
+ {
+ "font_class": "calendar-filled",
+ "unicode": "\ue6c0"
+ },
+ {
+ "font_class": "camera",
+ "unicode": "\ue65a"
+ },
+ {
+ "font_class": "camera-filled",
+ "unicode": "\ue658"
+ },
+ {
+ "font_class": "cart",
+ "unicode": "\ue631"
+ },
+ {
+ "font_class": "cart-filled",
+ "unicode": "\ue6d0"
+ },
+ {
+ "font_class": "chat",
+ "unicode": "\ue65d"
+ },
+ {
+ "font_class": "chat-filled",
+ "unicode": "\ue659"
+ },
+ {
+ "font_class": "chatboxes",
+ "unicode": "\ue696"
+ },
+ {
+ "font_class": "chatboxes-filled",
+ "unicode": "\ue692"
+ },
+ {
+ "font_class": "chatbubble",
+ "unicode": "\ue697"
+ },
+ {
+ "font_class": "chatbubble-filled",
+ "unicode": "\ue694"
+ },
+ {
+ "font_class": "checkbox",
+ "unicode": "\ue62b"
+ },
+ {
+ "font_class": "checkbox-filled",
+ "unicode": "\ue62c"
+ },
+ {
+ "font_class": "checkmarkempty",
+ "unicode": "\ue65c"
+ },
+ {
+ "font_class": "circle",
+ "unicode": "\ue65b"
+ },
+ {
+ "font_class": "circle-filled",
+ "unicode": "\ue65e"
+ },
+ {
+ "font_class": "clear",
+ "unicode": "\ue66d"
+ },
+ {
+ "font_class": "close",
+ "unicode": "\ue673"
+ },
+ {
+ "font_class": "closeempty",
+ "unicode": "\ue66c"
+ },
+ {
+ "font_class": "cloud-download",
+ "unicode": "\ue647"
+ },
+ {
+ "font_class": "cloud-download-filled",
+ "unicode": "\ue646"
+ },
+ {
+ "font_class": "cloud-upload",
+ "unicode": "\ue645"
+ },
+ {
+ "font_class": "cloud-upload-filled",
+ "unicode": "\ue648"
+ },
+ {
+ "font_class": "color",
+ "unicode": "\ue6cf"
+ },
+ {
+ "font_class": "color-filled",
+ "unicode": "\ue6c9"
+ },
+ {
+ "font_class": "compose",
+ "unicode": "\ue67f"
+ },
+ {
+ "font_class": "contact",
+ "unicode": "\ue693"
+ },
+ {
+ "font_class": "contact-filled",
+ "unicode": "\ue695"
+ },
+ {
+ "font_class": "down",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "bottom",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "download",
+ "unicode": "\ue68d"
+ },
+ {
+ "font_class": "download-filled",
+ "unicode": "\ue681"
+ },
+ {
+ "font_class": "email",
+ "unicode": "\ue69e"
+ },
+ {
+ "font_class": "email-filled",
+ "unicode": "\ue69a"
+ },
+ {
+ "font_class": "eye",
+ "unicode": "\ue651"
+ },
+ {
+ "font_class": "eye-filled",
+ "unicode": "\ue66a"
+ },
+ {
+ "font_class": "eye-slash",
+ "unicode": "\ue6b3"
+ },
+ {
+ "font_class": "eye-slash-filled",
+ "unicode": "\ue6b4"
+ },
+ {
+ "font_class": "fire",
+ "unicode": "\ue6a1"
+ },
+ {
+ "font_class": "fire-filled",
+ "unicode": "\ue6c5"
+ },
+ {
+ "font_class": "flag",
+ "unicode": "\ue65f"
+ },
+ {
+ "font_class": "flag-filled",
+ "unicode": "\ue660"
+ },
+ {
+ "font_class": "folder-add",
+ "unicode": "\ue6a9"
+ },
+ {
+ "font_class": "folder-add-filled",
+ "unicode": "\ue6c8"
+ },
+ {
+ "font_class": "font",
+ "unicode": "\ue6a3"
+ },
+ {
+ "font_class": "forward",
+ "unicode": "\ue6ba"
+ },
+ {
+ "font_class": "gear",
+ "unicode": "\ue664"
+ },
+ {
+ "font_class": "gear-filled",
+ "unicode": "\ue661"
+ },
+ {
+ "font_class": "gift",
+ "unicode": "\ue6a4"
+ },
+ {
+ "font_class": "gift-filled",
+ "unicode": "\ue6c4"
+ },
+ {
+ "font_class": "hand-down",
+ "unicode": "\ue63d"
+ },
+ {
+ "font_class": "hand-down-filled",
+ "unicode": "\ue63c"
+ },
+ {
+ "font_class": "hand-up",
+ "unicode": "\ue63f"
+ },
+ {
+ "font_class": "hand-up-filled",
+ "unicode": "\ue63e"
+ },
+ {
+ "font_class": "headphones",
+ "unicode": "\ue630"
+ },
+ {
+ "font_class": "heart",
+ "unicode": "\ue639"
+ },
+ {
+ "font_class": "heart-filled",
+ "unicode": "\ue641"
+ },
+ {
+ "font_class": "help",
+ "unicode": "\ue679"
+ },
+ {
+ "font_class": "help-filled",
+ "unicode": "\ue674"
+ },
+ {
+ "font_class": "home",
+ "unicode": "\ue662"
+ },
+ {
+ "font_class": "home-filled",
+ "unicode": "\ue663"
+ },
+ {
+ "font_class": "image",
+ "unicode": "\ue670"
+ },
+ {
+ "font_class": "image-filled",
+ "unicode": "\ue678"
+ },
+ {
+ "font_class": "images",
+ "unicode": "\ue650"
+ },
+ {
+ "font_class": "images-filled",
+ "unicode": "\ue64b"
+ },
+ {
+ "font_class": "info",
+ "unicode": "\ue669"
+ },
+ {
+ "font_class": "info-filled",
+ "unicode": "\ue649"
+ },
+ {
+ "font_class": "left",
+ "unicode": "\ue6b7"
+ },
+ {
+ "font_class": "link",
+ "unicode": "\ue6a5"
+ },
+ {
+ "font_class": "list",
+ "unicode": "\ue644"
+ },
+ {
+ "font_class": "location",
+ "unicode": "\ue6ae"
+ },
+ {
+ "font_class": "location-filled",
+ "unicode": "\ue6af"
+ },
+ {
+ "font_class": "locked",
+ "unicode": "\ue66b"
+ },
+ {
+ "font_class": "locked-filled",
+ "unicode": "\ue668"
+ },
+ {
+ "font_class": "loop",
+ "unicode": "\ue633"
+ },
+ {
+ "font_class": "mail-open",
+ "unicode": "\ue643"
+ },
+ {
+ "font_class": "mail-open-filled",
+ "unicode": "\ue63a"
+ },
+ {
+ "font_class": "map",
+ "unicode": "\ue667"
+ },
+ {
+ "font_class": "map-filled",
+ "unicode": "\ue666"
+ },
+ {
+ "font_class": "map-pin",
+ "unicode": "\ue6ad"
+ },
+ {
+ "font_class": "map-pin-ellipse",
+ "unicode": "\ue6ac"
+ },
+ {
+ "font_class": "medal",
+ "unicode": "\ue6a2"
+ },
+ {
+ "font_class": "medal-filled",
+ "unicode": "\ue6c3"
+ },
+ {
+ "font_class": "mic",
+ "unicode": "\ue671"
+ },
+ {
+ "font_class": "mic-filled",
+ "unicode": "\ue677"
+ },
+ {
+ "font_class": "micoff",
+ "unicode": "\ue67e"
+ },
+ {
+ "font_class": "micoff-filled",
+ "unicode": "\ue6b0"
+ },
+ {
+ "font_class": "minus",
+ "unicode": "\ue66f"
+ },
+ {
+ "font_class": "minus-filled",
+ "unicode": "\ue67d"
+ },
+ {
+ "font_class": "more",
+ "unicode": "\ue64d"
+ },
+ {
+ "font_class": "more-filled",
+ "unicode": "\ue64e"
+ },
+ {
+ "font_class": "navigate",
+ "unicode": "\ue66e"
+ },
+ {
+ "font_class": "navigate-filled",
+ "unicode": "\ue67a"
+ },
+ {
+ "font_class": "notification",
+ "unicode": "\ue6a6"
+ },
+ {
+ "font_class": "notification-filled",
+ "unicode": "\ue6c1"
+ },
+ {
+ "font_class": "paperclip",
+ "unicode": "\ue652"
+ },
+ {
+ "font_class": "paperplane",
+ "unicode": "\ue672"
+ },
+ {
+ "font_class": "paperplane-filled",
+ "unicode": "\ue675"
+ },
+ {
+ "font_class": "person",
+ "unicode": "\ue699"
+ },
+ {
+ "font_class": "person-filled",
+ "unicode": "\ue69d"
+ },
+ {
+ "font_class": "personadd",
+ "unicode": "\ue69f"
+ },
+ {
+ "font_class": "personadd-filled",
+ "unicode": "\ue698"
+ },
+ {
+ "font_class": "personadd-filled-copy",
+ "unicode": "\ue6d1"
+ },
+ {
+ "font_class": "phone",
+ "unicode": "\ue69c"
+ },
+ {
+ "font_class": "phone-filled",
+ "unicode": "\ue69b"
+ },
+ {
+ "font_class": "plus",
+ "unicode": "\ue676"
+ },
+ {
+ "font_class": "plus-filled",
+ "unicode": "\ue6c7"
+ },
+ {
+ "font_class": "plusempty",
+ "unicode": "\ue67b"
+ },
+ {
+ "font_class": "pulldown",
+ "unicode": "\ue632"
+ },
+ {
+ "font_class": "pyq",
+ "unicode": "\ue682"
+ },
+ {
+ "font_class": "qq",
+ "unicode": "\ue680"
+ },
+ {
+ "font_class": "redo",
+ "unicode": "\ue64a"
+ },
+ {
+ "font_class": "redo-filled",
+ "unicode": "\ue655"
+ },
+ {
+ "font_class": "refresh",
+ "unicode": "\ue657"
+ },
+ {
+ "font_class": "refresh-filled",
+ "unicode": "\ue656"
+ },
+ {
+ "font_class": "refreshempty",
+ "unicode": "\ue6bf"
+ },
+ {
+ "font_class": "reload",
+ "unicode": "\ue6b2"
+ },
+ {
+ "font_class": "right",
+ "unicode": "\ue6b5"
+ },
+ {
+ "font_class": "scan",
+ "unicode": "\ue62a"
+ },
+ {
+ "font_class": "search",
+ "unicode": "\ue654"
+ },
+ {
+ "font_class": "settings",
+ "unicode": "\ue653"
+ },
+ {
+ "font_class": "settings-filled",
+ "unicode": "\ue6ce"
+ },
+ {
+ "font_class": "shop",
+ "unicode": "\ue62f"
+ },
+ {
+ "font_class": "shop-filled",
+ "unicode": "\ue6cd"
+ },
+ {
+ "font_class": "smallcircle",
+ "unicode": "\ue67c"
+ },
+ {
+ "font_class": "smallcircle-filled",
+ "unicode": "\ue665"
+ },
+ {
+ "font_class": "sound",
+ "unicode": "\ue684"
+ },
+ {
+ "font_class": "sound-filled",
+ "unicode": "\ue686"
+ },
+ {
+ "font_class": "spinner-cycle",
+ "unicode": "\ue68a"
+ },
+ {
+ "font_class": "staff",
+ "unicode": "\ue6a7"
+ },
+ {
+ "font_class": "staff-filled",
+ "unicode": "\ue6cb"
+ },
+ {
+ "font_class": "star",
+ "unicode": "\ue688"
+ },
+ {
+ "font_class": "star-filled",
+ "unicode": "\ue68f"
+ },
+ {
+ "font_class": "starhalf",
+ "unicode": "\ue683"
+ },
+ {
+ "font_class": "trash",
+ "unicode": "\ue687"
+ },
+ {
+ "font_class": "trash-filled",
+ "unicode": "\ue685"
+ },
+ {
+ "font_class": "tune",
+ "unicode": "\ue6aa"
+ },
+ {
+ "font_class": "tune-filled",
+ "unicode": "\ue6ca"
+ },
+ {
+ "font_class": "undo",
+ "unicode": "\ue64f"
+ },
+ {
+ "font_class": "undo-filled",
+ "unicode": "\ue64c"
+ },
+ {
+ "font_class": "up",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "top",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "upload",
+ "unicode": "\ue690"
+ },
+ {
+ "font_class": "upload-filled",
+ "unicode": "\ue68e"
+ },
+ {
+ "font_class": "videocam",
+ "unicode": "\ue68c"
+ },
+ {
+ "font_class": "videocam-filled",
+ "unicode": "\ue689"
+ },
+ {
+ "font_class": "vip",
+ "unicode": "\ue6a8"
+ },
+ {
+ "font_class": "vip-filled",
+ "unicode": "\ue6c6"
+ },
+ {
+ "font_class": "wallet",
+ "unicode": "\ue6b1"
+ },
+ {
+ "font_class": "wallet-filled",
+ "unicode": "\ue6c2"
+ },
+ {
+ "font_class": "weibo",
+ "unicode": "\ue68b"
+ },
+ {
+ "font_class": "weixin",
+ "unicode": "\ue691"
+ }
+] as IconsDataItem[]
+
+// export const fontData = JSON.parse(fontDataJson)
diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
new file mode 100644
index 0000000..1cd11e1
--- /dev/null
+++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
@@ -0,0 +1,649 @@
+
+export const fontData = [
+ {
+ "font_class": "arrow-down",
+ "unicode": "\ue6be"
+ },
+ {
+ "font_class": "arrow-left",
+ "unicode": "\ue6bc"
+ },
+ {
+ "font_class": "arrow-right",
+ "unicode": "\ue6bb"
+ },
+ {
+ "font_class": "arrow-up",
+ "unicode": "\ue6bd"
+ },
+ {
+ "font_class": "auth",
+ "unicode": "\ue6ab"
+ },
+ {
+ "font_class": "auth-filled",
+ "unicode": "\ue6cc"
+ },
+ {
+ "font_class": "back",
+ "unicode": "\ue6b9"
+ },
+ {
+ "font_class": "bars",
+ "unicode": "\ue627"
+ },
+ {
+ "font_class": "calendar",
+ "unicode": "\ue6a0"
+ },
+ {
+ "font_class": "calendar-filled",
+ "unicode": "\ue6c0"
+ },
+ {
+ "font_class": "camera",
+ "unicode": "\ue65a"
+ },
+ {
+ "font_class": "camera-filled",
+ "unicode": "\ue658"
+ },
+ {
+ "font_class": "cart",
+ "unicode": "\ue631"
+ },
+ {
+ "font_class": "cart-filled",
+ "unicode": "\ue6d0"
+ },
+ {
+ "font_class": "chat",
+ "unicode": "\ue65d"
+ },
+ {
+ "font_class": "chat-filled",
+ "unicode": "\ue659"
+ },
+ {
+ "font_class": "chatboxes",
+ "unicode": "\ue696"
+ },
+ {
+ "font_class": "chatboxes-filled",
+ "unicode": "\ue692"
+ },
+ {
+ "font_class": "chatbubble",
+ "unicode": "\ue697"
+ },
+ {
+ "font_class": "chatbubble-filled",
+ "unicode": "\ue694"
+ },
+ {
+ "font_class": "checkbox",
+ "unicode": "\ue62b"
+ },
+ {
+ "font_class": "checkbox-filled",
+ "unicode": "\ue62c"
+ },
+ {
+ "font_class": "checkmarkempty",
+ "unicode": "\ue65c"
+ },
+ {
+ "font_class": "circle",
+ "unicode": "\ue65b"
+ },
+ {
+ "font_class": "circle-filled",
+ "unicode": "\ue65e"
+ },
+ {
+ "font_class": "clear",
+ "unicode": "\ue66d"
+ },
+ {
+ "font_class": "close",
+ "unicode": "\ue673"
+ },
+ {
+ "font_class": "closeempty",
+ "unicode": "\ue66c"
+ },
+ {
+ "font_class": "cloud-download",
+ "unicode": "\ue647"
+ },
+ {
+ "font_class": "cloud-download-filled",
+ "unicode": "\ue646"
+ },
+ {
+ "font_class": "cloud-upload",
+ "unicode": "\ue645"
+ },
+ {
+ "font_class": "cloud-upload-filled",
+ "unicode": "\ue648"
+ },
+ {
+ "font_class": "color",
+ "unicode": "\ue6cf"
+ },
+ {
+ "font_class": "color-filled",
+ "unicode": "\ue6c9"
+ },
+ {
+ "font_class": "compose",
+ "unicode": "\ue67f"
+ },
+ {
+ "font_class": "contact",
+ "unicode": "\ue693"
+ },
+ {
+ "font_class": "contact-filled",
+ "unicode": "\ue695"
+ },
+ {
+ "font_class": "down",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "bottom",
+ "unicode": "\ue6b8"
+ },
+ {
+ "font_class": "download",
+ "unicode": "\ue68d"
+ },
+ {
+ "font_class": "download-filled",
+ "unicode": "\ue681"
+ },
+ {
+ "font_class": "email",
+ "unicode": "\ue69e"
+ },
+ {
+ "font_class": "email-filled",
+ "unicode": "\ue69a"
+ },
+ {
+ "font_class": "eye",
+ "unicode": "\ue651"
+ },
+ {
+ "font_class": "eye-filled",
+ "unicode": "\ue66a"
+ },
+ {
+ "font_class": "eye-slash",
+ "unicode": "\ue6b3"
+ },
+ {
+ "font_class": "eye-slash-filled",
+ "unicode": "\ue6b4"
+ },
+ {
+ "font_class": "fire",
+ "unicode": "\ue6a1"
+ },
+ {
+ "font_class": "fire-filled",
+ "unicode": "\ue6c5"
+ },
+ {
+ "font_class": "flag",
+ "unicode": "\ue65f"
+ },
+ {
+ "font_class": "flag-filled",
+ "unicode": "\ue660"
+ },
+ {
+ "font_class": "folder-add",
+ "unicode": "\ue6a9"
+ },
+ {
+ "font_class": "folder-add-filled",
+ "unicode": "\ue6c8"
+ },
+ {
+ "font_class": "font",
+ "unicode": "\ue6a3"
+ },
+ {
+ "font_class": "forward",
+ "unicode": "\ue6ba"
+ },
+ {
+ "font_class": "gear",
+ "unicode": "\ue664"
+ },
+ {
+ "font_class": "gear-filled",
+ "unicode": "\ue661"
+ },
+ {
+ "font_class": "gift",
+ "unicode": "\ue6a4"
+ },
+ {
+ "font_class": "gift-filled",
+ "unicode": "\ue6c4"
+ },
+ {
+ "font_class": "hand-down",
+ "unicode": "\ue63d"
+ },
+ {
+ "font_class": "hand-down-filled",
+ "unicode": "\ue63c"
+ },
+ {
+ "font_class": "hand-up",
+ "unicode": "\ue63f"
+ },
+ {
+ "font_class": "hand-up-filled",
+ "unicode": "\ue63e"
+ },
+ {
+ "font_class": "headphones",
+ "unicode": "\ue630"
+ },
+ {
+ "font_class": "heart",
+ "unicode": "\ue639"
+ },
+ {
+ "font_class": "heart-filled",
+ "unicode": "\ue641"
+ },
+ {
+ "font_class": "help",
+ "unicode": "\ue679"
+ },
+ {
+ "font_class": "help-filled",
+ "unicode": "\ue674"
+ },
+ {
+ "font_class": "home",
+ "unicode": "\ue662"
+ },
+ {
+ "font_class": "home-filled",
+ "unicode": "\ue663"
+ },
+ {
+ "font_class": "image",
+ "unicode": "\ue670"
+ },
+ {
+ "font_class": "image-filled",
+ "unicode": "\ue678"
+ },
+ {
+ "font_class": "images",
+ "unicode": "\ue650"
+ },
+ {
+ "font_class": "images-filled",
+ "unicode": "\ue64b"
+ },
+ {
+ "font_class": "info",
+ "unicode": "\ue669"
+ },
+ {
+ "font_class": "info-filled",
+ "unicode": "\ue649"
+ },
+ {
+ "font_class": "left",
+ "unicode": "\ue6b7"
+ },
+ {
+ "font_class": "link",
+ "unicode": "\ue6a5"
+ },
+ {
+ "font_class": "list",
+ "unicode": "\ue644"
+ },
+ {
+ "font_class": "location",
+ "unicode": "\ue6ae"
+ },
+ {
+ "font_class": "location-filled",
+ "unicode": "\ue6af"
+ },
+ {
+ "font_class": "locked",
+ "unicode": "\ue66b"
+ },
+ {
+ "font_class": "locked-filled",
+ "unicode": "\ue668"
+ },
+ {
+ "font_class": "loop",
+ "unicode": "\ue633"
+ },
+ {
+ "font_class": "mail-open",
+ "unicode": "\ue643"
+ },
+ {
+ "font_class": "mail-open-filled",
+ "unicode": "\ue63a"
+ },
+ {
+ "font_class": "map",
+ "unicode": "\ue667"
+ },
+ {
+ "font_class": "map-filled",
+ "unicode": "\ue666"
+ },
+ {
+ "font_class": "map-pin",
+ "unicode": "\ue6ad"
+ },
+ {
+ "font_class": "map-pin-ellipse",
+ "unicode": "\ue6ac"
+ },
+ {
+ "font_class": "medal",
+ "unicode": "\ue6a2"
+ },
+ {
+ "font_class": "medal-filled",
+ "unicode": "\ue6c3"
+ },
+ {
+ "font_class": "mic",
+ "unicode": "\ue671"
+ },
+ {
+ "font_class": "mic-filled",
+ "unicode": "\ue677"
+ },
+ {
+ "font_class": "micoff",
+ "unicode": "\ue67e"
+ },
+ {
+ "font_class": "micoff-filled",
+ "unicode": "\ue6b0"
+ },
+ {
+ "font_class": "minus",
+ "unicode": "\ue66f"
+ },
+ {
+ "font_class": "minus-filled",
+ "unicode": "\ue67d"
+ },
+ {
+ "font_class": "more",
+ "unicode": "\ue64d"
+ },
+ {
+ "font_class": "more-filled",
+ "unicode": "\ue64e"
+ },
+ {
+ "font_class": "navigate",
+ "unicode": "\ue66e"
+ },
+ {
+ "font_class": "navigate-filled",
+ "unicode": "\ue67a"
+ },
+ {
+ "font_class": "notification",
+ "unicode": "\ue6a6"
+ },
+ {
+ "font_class": "notification-filled",
+ "unicode": "\ue6c1"
+ },
+ {
+ "font_class": "paperclip",
+ "unicode": "\ue652"
+ },
+ {
+ "font_class": "paperplane",
+ "unicode": "\ue672"
+ },
+ {
+ "font_class": "paperplane-filled",
+ "unicode": "\ue675"
+ },
+ {
+ "font_class": "person",
+ "unicode": "\ue699"
+ },
+ {
+ "font_class": "person-filled",
+ "unicode": "\ue69d"
+ },
+ {
+ "font_class": "personadd",
+ "unicode": "\ue69f"
+ },
+ {
+ "font_class": "personadd-filled",
+ "unicode": "\ue698"
+ },
+ {
+ "font_class": "personadd-filled-copy",
+ "unicode": "\ue6d1"
+ },
+ {
+ "font_class": "phone",
+ "unicode": "\ue69c"
+ },
+ {
+ "font_class": "phone-filled",
+ "unicode": "\ue69b"
+ },
+ {
+ "font_class": "plus",
+ "unicode": "\ue676"
+ },
+ {
+ "font_class": "plus-filled",
+ "unicode": "\ue6c7"
+ },
+ {
+ "font_class": "plusempty",
+ "unicode": "\ue67b"
+ },
+ {
+ "font_class": "pulldown",
+ "unicode": "\ue632"
+ },
+ {
+ "font_class": "pyq",
+ "unicode": "\ue682"
+ },
+ {
+ "font_class": "qq",
+ "unicode": "\ue680"
+ },
+ {
+ "font_class": "redo",
+ "unicode": "\ue64a"
+ },
+ {
+ "font_class": "redo-filled",
+ "unicode": "\ue655"
+ },
+ {
+ "font_class": "refresh",
+ "unicode": "\ue657"
+ },
+ {
+ "font_class": "refresh-filled",
+ "unicode": "\ue656"
+ },
+ {
+ "font_class": "refreshempty",
+ "unicode": "\ue6bf"
+ },
+ {
+ "font_class": "reload",
+ "unicode": "\ue6b2"
+ },
+ {
+ "font_class": "right",
+ "unicode": "\ue6b5"
+ },
+ {
+ "font_class": "scan",
+ "unicode": "\ue62a"
+ },
+ {
+ "font_class": "search",
+ "unicode": "\ue654"
+ },
+ {
+ "font_class": "settings",
+ "unicode": "\ue653"
+ },
+ {
+ "font_class": "settings-filled",
+ "unicode": "\ue6ce"
+ },
+ {
+ "font_class": "shop",
+ "unicode": "\ue62f"
+ },
+ {
+ "font_class": "shop-filled",
+ "unicode": "\ue6cd"
+ },
+ {
+ "font_class": "smallcircle",
+ "unicode": "\ue67c"
+ },
+ {
+ "font_class": "smallcircle-filled",
+ "unicode": "\ue665"
+ },
+ {
+ "font_class": "sound",
+ "unicode": "\ue684"
+ },
+ {
+ "font_class": "sound-filled",
+ "unicode": "\ue686"
+ },
+ {
+ "font_class": "spinner-cycle",
+ "unicode": "\ue68a"
+ },
+ {
+ "font_class": "staff",
+ "unicode": "\ue6a7"
+ },
+ {
+ "font_class": "staff-filled",
+ "unicode": "\ue6cb"
+ },
+ {
+ "font_class": "star",
+ "unicode": "\ue688"
+ },
+ {
+ "font_class": "star-filled",
+ "unicode": "\ue68f"
+ },
+ {
+ "font_class": "starhalf",
+ "unicode": "\ue683"
+ },
+ {
+ "font_class": "trash",
+ "unicode": "\ue687"
+ },
+ {
+ "font_class": "trash-filled",
+ "unicode": "\ue685"
+ },
+ {
+ "font_class": "tune",
+ "unicode": "\ue6aa"
+ },
+ {
+ "font_class": "tune-filled",
+ "unicode": "\ue6ca"
+ },
+ {
+ "font_class": "undo",
+ "unicode": "\ue64f"
+ },
+ {
+ "font_class": "undo-filled",
+ "unicode": "\ue64c"
+ },
+ {
+ "font_class": "up",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "top",
+ "unicode": "\ue6b6"
+ },
+ {
+ "font_class": "upload",
+ "unicode": "\ue690"
+ },
+ {
+ "font_class": "upload-filled",
+ "unicode": "\ue68e"
+ },
+ {
+ "font_class": "videocam",
+ "unicode": "\ue68c"
+ },
+ {
+ "font_class": "videocam-filled",
+ "unicode": "\ue689"
+ },
+ {
+ "font_class": "vip",
+ "unicode": "\ue6a8"
+ },
+ {
+ "font_class": "vip-filled",
+ "unicode": "\ue6c6"
+ },
+ {
+ "font_class": "wallet",
+ "unicode": "\ue6b1"
+ },
+ {
+ "font_class": "wallet-filled",
+ "unicode": "\ue6c2"
+ },
+ {
+ "font_class": "weibo",
+ "unicode": "\ue68b"
+ },
+ {
+ "font_class": "weixin",
+ "unicode": "\ue691"
+ }
+]
+
+// export const fontData = JSON.parse(fontDataJson)
diff --git a/uni_modules/uni-icons/package.json b/uni_modules/uni-icons/package.json
new file mode 100644
index 0000000..c8e1224
--- /dev/null
+++ b/uni_modules/uni-icons/package.json
@@ -0,0 +1,82 @@
+{
+ "id": "uni-icons",
+ "displayName": "uni-icons 图标",
+ "version": "1.1.5",
+ "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "icon",
+ "图标"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-icons/readme.md b/uni_modules/uni-icons/readme.md
new file mode 100644
index 0000000..8d56f42
--- /dev/null
+++ b/uni_modules/uni-icons/readme.md
@@ -0,0 +1,46 @@
+
+
+## Icons 图标
+> **组件名:uni-icons**
+> 代码块: `uIcons`
+
+
+用于展示 icons 图标 。
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 基本用法
+
+在 ``template`` 中使用组件
+
+```html
+
+```
+
+
+
+## API
+
+### Icons Props
+
+|属性名 |类型 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |
+|size |Number |24 |图标大小 |
+|type |String |- |图标图案,参考示例 |
+|color |String |- |图标颜色 |
+
+
+### Icons Events
+|事件名 |说明 |返回值|
+|:-: |:-: |:-: |
+|@click|点击 Icon 触发事件|- |
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/icons/icons](https://hellouniapp.dcloud.net.cn/pages/extUI/icons/icons)
\ No newline at end of file
diff --git a/uni_modules/uni-id/changelog.md b/uni_modules/uni-id/changelog.md
new file mode 100644
index 0000000..634061e
--- /dev/null
+++ b/uni_modules/uni-id/changelog.md
@@ -0,0 +1,24 @@
+## 3.1.0(2021-04-19)
+- 增加对用户名、邮箱、密码字段的两端去空格
+- 默认忽略用户名、邮箱的大小写 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=case-sensitive)
+- 修复 customToken导出async方法报错的Bug
+## 3.0.12(2021-04-13)
+- 调整bindTokenToDevice默认值为false
+## 3.0.11(2021-04-12)
+- 修复3.0.7版本引出的多个用户访问时可能出现30201报错的Bug
+## 3.0.10(2021-04-08)
+- 优化错误提示
+## 3.0.9(2021-04-08)
+- bindMobile接口支持通过一键登录的方式绑定
+- 优化错误提示
+## 3.0.8(2021-03-19)
+- 修复 3.0.7版本某些情况下生成token报错的Bug
+## 3.0.7(2021-03-19)
+- 新增 支持uni-config-center,更新uni-id无须再担心配置被覆盖 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=uni-config-center)
+- 新增 自定义token内容,可以缓存角色权限之外的更多信息到客户端 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=custom-token)
+- 新增 支持传入context获取uni-id实例,防止单实例多并发时全局context混乱 [详情](https://uniapp.dcloud.io/uniCloud/uni-id?id=create-instance)
+## 3.0.6(2021-03-05)
+- 新增[uniID.wxBizDataCrypt](https://uniapp.dcloud.io/uniCloud/uni-id?id=%e5%be%ae%e4%bf%a1%e6%95%b0%e6%8d%ae%e8%a7%a3%e5%af%86)方法
+- 优化loginByApple方法,提高接口响应速度
+## 3.0.5(2021-02-03)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-id/package.json b/uni_modules/uni-id/package.json
new file mode 100644
index 0000000..a8db1fc
--- /dev/null
+++ b/uni_modules/uni-id/package.json
@@ -0,0 +1,80 @@
+{
+ "id": "uni-id",
+ "displayName": "uni-id公共模块",
+ "version": "3.1.0",
+ "description": "简单、统一、可扩展的用户中心",
+ "keywords": [
+ "uniid",
+ "uni-id",
+ "用户管理",
+ "用户中心",
+ "短信验证码"
+],
+ "repository": "https://gitee.com/dcloud/uni-id.git",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "uniCloud",
+ "云函数模板"
+ ],
+ "sale": {
+ "regular": {
+ "price": 0
+ },
+ "sourcecode": {
+ "price": 0
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": ""
+ },
+ "uni_modules": {
+ "dependencies": ["uni-config-center"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "u",
+ "app-nvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "u",
+ "Android Browser": "u",
+ "微信浏览器(Android)": "u",
+ "QQ浏览器(Android)": "u"
+ },
+ "H5-pc": {
+ "Chrome": "u",
+ "IE": "u",
+ "Edge": "u",
+ "Firefox": "u",
+ "Safari": "u"
+ },
+ "小程序": {
+ "微信": "u",
+ "阿里": "u",
+ "百度": "u",
+ "字节跳动": "u",
+ "QQ": "u"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-id/readme.md b/uni_modules/uni-id/readme.md
new file mode 100644
index 0000000..ea7751c
--- /dev/null
+++ b/uni_modules/uni-id/readme.md
@@ -0,0 +1,33 @@
+**文档已移至[uni-id文档](https://uniapp.dcloud.net.cn/uniCloud/uni-id)**
+
+> 一般uni-id升级大版本时为不兼容更新,从低版本迁移到高版本请参考:[uni-id迁移指南](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=migration)
+
+## 重要升级说明
+
+**uni-id 3.x版本,搭配的uniCloud admin版本需大于1.2.10。**
+
+### 缓存角色权限
+
+自`uni-id 3.0.0`起,支持在token内缓存用户的角色权限,默认开启此功能,各登录接口的needPermission参数不再生效。如需关闭请在config内配置`"removePermissionAndRoleFromToken": true`。
+
+为什么要缓存角色权限?要知道云数据库是按照读写次数来收取费用的,并且读写数据库会拖慢接口响应速度。未配置`"removePermissionAndRoleFromToken": true`的情况下,可以在调用checkToken接口时不查询数据库获取用户角色权限。
+
+详细checkToken流程如下:
+
+
+
+可以看出,旧版token(removePermissionAndRoleFromToken为true时生成的)在checkToken时如需返回权限需要进行两次数据库查询。新版token不需要查库即可返回权限信息。
+
+**注意**
+
+- 由于角色权限缓存在token内,可能会存在权限已经更新但是用户token未过期之前依然是旧版角色权限的情况。可以调短一些token过期时间来减少这种情况的影响。
+- admin角色token内不包含permission,如需自行判断用户是否有某个权限,要注意admin角色需要额外判断一下,写法如下
+ ```js
+ const {
+ role,
+ permission
+ } = await uniID.checkToken(event.uniIdToken)
+ if(role.includes('admin') || permission.includes('your permission id')) {
+ // 当前角色拥有'your permission id'对应的权限
+ }
+ ```
\ No newline at end of file
diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/LICENSE.md
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js
new file mode 100644
index 0000000..33e4758
--- /dev/null
+++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/index.js
@@ -0,0 +1 @@
+"use strict";function e(e){return e&&"object"==typeof e&&"default"in e?e.default:e}var t=e(require("fs")),r=e(require("path")),n=e(require("crypto")),i=e(require("querystring")),o=e(require("buffer")),s=e(require("stream")),a=e(require("util"));class c extends Error{constructor(e){super(e.message),this.errMsg=e.message||"",Object.defineProperties(this,{message:{get(){return`errCode: ${e.code||""} | errMsg: `+this.errMsg},set(e){this.errMsg=e}}})}}const u=Object.prototype.toString,f=Object.prototype.hasOwnProperty;function d(e,t){return f.call(e,t)}function l(e){return"[object Object]"===u.call(e)}function p(e){return"function"==typeof e}function m(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}const h=/_(\w)/g,g=/[A-Z]/g;function y(e){return e.replace(h,(e,t)=>t?t.toUpperCase():"")}function w(e){return e.replace(g,e=>"_"+e.toLowerCase())}function v(e,t){let r,n;switch(t){case"snake2camel":n=y,r=h;break;case"camel2snake":n=w,r=g}for(const i in e)if(d(e,i)&&r.test(i)){const r=n(i);e[r]=e[i],delete e[i],l(e[r])?e[r]=v(e[r],t):Array.isArray(e[r])&&(e[r]=e[r].map(e=>v(e,t)))}return e}function b(e){return v(e,"snake2camel")}function _(e){return v(e,"camel2snake")}function E(e){return function(e,t="-"){e=e||new Date;const r=[];return r.push(e.getFullYear()),r.push(("00"+(e.getMonth()+1)).substr(-2)),r.push(("00"+e.getDate()).substr(-2)),r.join(t)}(e=e||new Date)+" "+function(e,t=":"){e=e||new Date;const r=[];return r.push(("00"+e.getHours()).substr(-2)),r.push(("00"+e.getMinutes()).substr(-2)),r.push(("00"+e.getSeconds()).substr(-2)),r.join(t)}(e)}function S(){"development"===process.env.NODE_ENV&&console.log(...arguments)}function x(e=6){let t="";for(let r=0;r0:t=f,r="年";break;case u>0:t=u,r="月";break;case c>0:t=c,r="天";break;case a>0:t=a,r="小时";break;case s>0:t=s,r="分钟";break;default:t=o,r="秒"}return`${t}${r}${i}`}const I=async function(){};function P(e){return I.constructor===e.constructor?async function(){const t=await e.apply(this,arguments);return l(t)&&t.msg&&(t.message=t.msg),t}:function(){const t=e.apply(this,arguments);return l(t)&&t.msg&&(t.message=t.msg),t}}const R=uniCloud.database(),A=R.collection("uni-id-users"),O=R.collection("opendb-verify-codes"),M=R.collection("uni-id-roles"),D=R.collection("uni-id-permissions"),L=90002;async function B({name:e,url:t,data:r,options:n,defaultOptions:i}){let o={};const s=_(Object.assign({},r));s&&s.access_token&&delete s.access_token;try{n=Object.assign({},i,n,{data:s}),o=await uniCloud.httpclient.request(t,n)}catch(t){return function(e,t){throw new c({code:t.code||-2,message:t.message||e+" fail"})}(e,t)}let a=o.data;const u=o.headers["content-type"];if(!Buffer.isBuffer(a)||0!==u.indexOf("text/plain")&&0!==u.indexOf("application/json"))Buffer.isBuffer(a)&&(a={buffer:a,contentType:u});else try{a=JSON.parse(a.toString())}catch(e){a=a.toString()}return b(function(e,t){if(t.errcode)throw new c({code:t.errcode||-2,message:t.errmsg||e+" fail"});return delete t.errcode,delete t.errmsg,{...t,errMsg:e+" ok",errCode:0}}(e,a||{errCode:-2,errMsg:"Request failed"}))}function N(e,t){let r="";if(t&&t.accessToken){r=`${e.indexOf("?")>-1?"&":"?"}access_token=${t.accessToken}`}return`${e}${r}`}class ${constructor(e){this.options=Object.assign({baseUrl:"https://api.weixin.qq.com",timeout:5e3},e)}async _requestWxOpenapi({name:e,url:t,data:r,options:n}){const i={method:"GET",dataType:"json",dataAsQueryString:!0,timeout:this.options.timeout};return await B({name:"auth."+e,url:`${this.options.baseUrl}${N(t,r)}`,data:r,options:n,defaultOptions:i})}async code2Session(e){return await this._requestWxOpenapi({name:"code2Session",url:"/sns/jscode2session",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,js_code:e}})}async getOauthAccessToken(e){return await this._requestWxOpenapi({name:"getOauthAccessToken",url:"/sns/oauth2/access_token",data:{grant_type:"authorization_code",appid:this.options.appId,secret:this.options.secret,code:e}})}}const K={RSA:"RSA-SHA1",RSA2:"RSA-SHA256"};var V={code2Session:{returnValue:{openid:"userId"}}};class U extends class{constructor(e={}){if(!e.appId)throw new Error("appId required");if(!e.privateKey)throw new Error("privateKey required");const t={gateway:"https://openapi.alipay.com/gateway.do",timeout:5e3,charset:"utf-8",version:"1.0",signType:"RSA2",timeOffset:-(new Date).getTimezoneOffset()/60,keyType:"PKCS8"};e.sandbox&&(e.gateway="https://openapi.alipaydev.com/gateway.do"),this.options=Object.assign({},t,e);const r="PKCS8"===this.options.keyType?"PRIVATE KEY":"RSA PRIVATE KEY";this.options.privateKey=this._formatKey(this.options.privateKey,r),this.options.alipayPublicKey&&(this.options.alipayPublicKey=this._formatKey(this.options.alipayPublicKey,"PUBLIC KEY"))}_formatKey(e,t){return`-----BEGIN ${t}-----\n${e}\n-----END ${t}-----`}_formatUrl(e,t){let r=e;const n=["app_id","method","format","charset","sign_type","sign","timestamp","version","notify_url","return_url","auth_token","app_auth_token"];for(const e in t)if(n.indexOf(e)>-1){const n=encodeURIComponent(t[e]);r=`${r}${r.includes("?")?"&":"?"}${e}=${n}`,delete t[e]}return{execParams:t,url:r}}_getSign(e,t){const r=t.bizContent||null;delete t.bizContent;const i=Object.assign({method:e,appId:this.options.appId,charset:this.options.charset,version:this.options.version,signType:this.options.signType,timestamp:E((o=this.options.timeOffset,new Date(Date.now()+6e4*((new Date).getTimezoneOffset()+60*(o||0)))))},t);var o;r&&(i.bizContent=JSON.stringify(_(r)));const s=_(i),a=Object.keys(s).sort().map(e=>{let t=s[e];return"[object String]"!==Array.prototype.toString.call(t)&&(t=JSON.stringify(t)),`${e}=${t}`}).join("&"),c=n.createSign(K[this.options.signType]).update(a,"utf8").sign(this.options.privateKey,"base64");return Object.assign(s,{sign:c})}async _exec(e,t={},r={}){const n=this._getSign(e,t),{url:i,execParams:o}=this._formatUrl(this.options.gateway,n),{status:s,data:a}=await uniCloud.httpclient.request(i,{method:"POST",data:o,dataType:"text",timeout:this.options.timeout});if(200!==s)throw new Error("request fail");const c=JSON.parse(a),u=e.replace(/\./g,"_")+"_response",f=c[u],d=c.error_response;if(f){if(!r.validateSign||this._checkResponseSign(a,u)){if(!f.code||"10000"===f.code){return{errCode:0,errMsg:f.msg||"",...b(f)}}const e=f.sub_code?`${f.sub_code} ${f.sub_msg}`:""+(f.msg||"unkonwn error");throw new Error(e)}throw new Error("返回结果签名错误")}if(d)throw new Error(d.sub_msg||d.msg||"接口返回错误");throw new Error("request fail")}_checkResponseSign(e,t){if(!this.options.alipayPublicKey||""===this.options.alipayPublicKey)return console.warn("options.alipayPublicKey is empty"),!0;if(!e)return!1;const r=this._getSignStr(e,t),i=JSON.parse(e).sign,o=n.createVerify(K[this.options.signType]);return o.update(r,"utf8"),o.verify(this.options.alipayPublicKey,i,"base64")}_getSignStr(e,t){let r=e.trim();const n=e.indexOf(t+'"'),i=e.lastIndexOf('"sign"');return r=r.substr(n+t.length+1),r=r.substr(0,i),r=r.replace(/^[^{]*{/g,"{"),r=r.replace(/\}([^}]*)$/g,"}"),r}_notifyRSACheck(e,t,r){const i=Object.keys(e).sort().filter(e=>e).map(t=>{let r=e[t];return"[object String]"!==Array.prototype.toString.call(r)&&(r=JSON.stringify(r)),`${t}=${decodeURIComponent(r)}`}).join("&");return n.createVerify(K[r]).update(i,"utf8").verify(this.options.alipayPublicKey,t,"base64")}_checkNotifySign(e){const t=e.sign;if(!this.options.alipayPublicKey||!t)return!1;const r=e.sign_type||this.options.signType||"RSA2",n={...e};delete n.sign,n.sign_type=r;return!!this._notifyRSACheck(n,t,r)||(delete n.sign_type,this._notifyRSACheck(n,t,r))}_verifyNotify(e){if(!e.headers)throw new Error("通知格式不正确");let t;for(const r in e.headers)"content-type"===r.toLowerCase()&&(t=e.headers[r]);if(!1!==e.isBase64Encoded&&-1===t.indexOf("application/x-www-form-urlencoded"))throw new Error("通知格式不正确");const r=i.parse(e.body);if(this._checkNotifySign(r))return b(r);throw new Error("通知验签未通过")}}{constructor(e){super(e),this._protocols=V}async code2Session(e){return await this._exec("alipay.system.oauth.token",{grantType:"authorization_code",code:e})}}function q(e){var t=e[0];return t<"0"||t>"7"?"00"+e:e}function H(e){var t=e.toString(16);return t.length%2?"0"+t:t}function F(e){if(e<=127)return H(e);var t=H(e);return H(128+t.length/2)+t}function J(e,t){return e(t={exports:{}},t.exports),t.exports}var G=J((function(e,t){var r=o.Buffer;function n(e,t){for(var r in e)t[r]=e[r]}function i(e,t,n){return r(e,t,n)}r.from&&r.alloc&&r.allocUnsafe&&r.allocUnsafeSlow?e.exports=o:(n(o,t),t.Buffer=i),i.prototype=Object.create(r.prototype),n(r,i),i.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return r(e,t,n)},i.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var i=r(e);return void 0!==t?"string"==typeof n?i.fill(t,n):i.fill(t):i.fill(0),i},i.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r(e)},i.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o.SlowBuffer(e)}})),z=(G.Buffer,G.Buffer);function W(e){if(this.buffer=null,this.writable=!0,this.readable=!0,!e)return this.buffer=z.alloc(0),this;if("function"==typeof e.pipe)return this.buffer=z.alloc(0),e.pipe(this),this;if(e.length||"object"==typeof e)return this.buffer=e,this.writable=!1,process.nextTick(function(){this.emit("end",e),this.readable=!1,this.emit("close")}.bind(this)),this;throw new TypeError("Unexpected data type ("+typeof e+")")}a.inherits(W,s),W.prototype.write=function(e){this.buffer=z.concat([this.buffer,z.from(e)]),this.emit("data",e)},W.prototype.end=function(e){e&&this.write(e),this.emit("end",e),this.emit("close"),this.writable=!1,this.readable=!1};var X=W,Y=o.Buffer,Z=o.SlowBuffer,Q=ee;function ee(e,t){if(!Y.isBuffer(e)||!Y.isBuffer(t))return!1;if(e.length!==t.length)return!1;for(var r=0,n=0;n=128&&--n,n}var ue={derToJose:function(e,t){e=ae(e);var r=oe(t),n=r+1,i=e.length,o=0;if(48!==e[o++])throw new Error('Could not find expected "seq"');var s=e[o++];if(129===s&&(s=e[o++]),i-o0)return function(e){if((e=String(e)).length>100)return;var t=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!t)return;var r=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*r;case"weeks":case"week":case"w":return 6048e5*r;case"days":case"day":case"d":return r*ot;case"hours":case"hour":case"hrs":case"hr":case"h":return r*it;case"minutes":case"minute":case"mins":case"min":case"m":return r*nt;case"seconds":case"second":case"secs":case"sec":case"s":return r*rt;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}(e);if("number"===r&&isFinite(e))return t.long?function(e){var t=Math.abs(e);if(t>=ot)return at(e,t,ot,"day");if(t>=it)return at(e,t,it,"hour");if(t>=nt)return at(e,t,nt,"minute");if(t>=rt)return at(e,t,rt,"second");return e+" ms"}(e):function(e){var t=Math.abs(e);if(t>=ot)return Math.round(e/ot)+"d";if(t>=it)return Math.round(e/it)+"h";if(t>=nt)return Math.round(e/nt)+"m";if(t>=rt)return Math.round(e/rt)+"s";return e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function at(e,t,r,n){var i=t>=1.5*r;return Math.round(e/r)+" "+n+(i?"s":"")}var ct=function(e,t){var r=t||Math.floor(Date.now()/1e3);if("string"==typeof e){var n=st(e);if(void 0===n)return;return Math.floor(r+n/1e3)}return"number"==typeof e?r+e:void 0},ut=J((function(e,t){var r;t=e.exports=J,r="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},t.SEMVER_SPEC_VERSION="2.0.0";var n=Number.MAX_SAFE_INTEGER||9007199254740991,i=t.re=[],o=t.src=[],s=0,a=s++;o[a]="0|[1-9]\\d*";var c=s++;o[c]="[0-9]+";var u=s++;o[u]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var f=s++;o[f]="("+o[a]+")\\.("+o[a]+")\\.("+o[a]+")";var d=s++;o[d]="("+o[c]+")\\.("+o[c]+")\\.("+o[c]+")";var l=s++;o[l]="(?:"+o[a]+"|"+o[u]+")";var p=s++;o[p]="(?:"+o[c]+"|"+o[u]+")";var m=s++;o[m]="(?:-("+o[l]+"(?:\\."+o[l]+")*))";var h=s++;o[h]="(?:-?("+o[p]+"(?:\\."+o[p]+")*))";var g=s++;o[g]="[0-9A-Za-z-]+";var y=s++;o[y]="(?:\\+("+o[g]+"(?:\\."+o[g]+")*))";var w=s++,v="v?"+o[f]+o[m]+"?"+o[y]+"?";o[w]="^"+v+"$";var b="[v=\\s]*"+o[d]+o[h]+"?"+o[y]+"?",_=s++;o[_]="^"+b+"$";var E=s++;o[E]="((?:<|>)?=?)";var S=s++;o[S]=o[c]+"|x|X|\\*";var x=s++;o[x]=o[a]+"|x|X|\\*";var k=s++;o[k]="[v=\\s]*("+o[x]+")(?:\\.("+o[x]+")(?:\\.("+o[x]+")(?:"+o[m]+")?"+o[y]+"?)?)?";var C=s++;o[C]="[v=\\s]*("+o[S]+")(?:\\.("+o[S]+")(?:\\.("+o[S]+")(?:"+o[h]+")?"+o[y]+"?)?)?";var j=s++;o[j]="^"+o[E]+"\\s*"+o[k]+"$";var T=s++;o[T]="^"+o[E]+"\\s*"+o[C]+"$";var I=s++;o[I]="(?:^|[^\\d])(\\d{1,16})(?:\\.(\\d{1,16}))?(?:\\.(\\d{1,16}))?(?:$|[^\\d])";var P=s++;o[P]="(?:~>?)";var R=s++;o[R]="(\\s*)"+o[P]+"\\s+",i[R]=new RegExp(o[R],"g");var A=s++;o[A]="^"+o[P]+o[k]+"$";var O=s++;o[O]="^"+o[P]+o[C]+"$";var M=s++;o[M]="(?:\\^)";var D=s++;o[D]="(\\s*)"+o[M]+"\\s+",i[D]=new RegExp(o[D],"g");var L=s++;o[L]="^"+o[M]+o[k]+"$";var B=s++;o[B]="^"+o[M]+o[C]+"$";var N=s++;o[N]="^"+o[E]+"\\s*("+b+")$|^$";var $=s++;o[$]="^"+o[E]+"\\s*("+v+")$|^$";var K=s++;o[K]="(\\s*)"+o[E]+"\\s*("+b+"|"+o[k]+")",i[K]=new RegExp(o[K],"g");var V=s++;o[V]="^\\s*("+o[k]+")\\s+-\\s+("+o[k]+")\\s*$";var U=s++;o[U]="^\\s*("+o[C]+")\\s+-\\s+("+o[C]+")\\s*$";var q=s++;o[q]="(<|>)?=?\\s*\\*";for(var H=0;H<35;H++)r(H,o[H]),i[H]||(i[H]=new RegExp(o[H]));function F(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof J)return e;if("string"!=typeof e)return null;if(e.length>256)return null;if(!(t.loose?i[_]:i[w]).test(e))return null;try{return new J(e,t)}catch(e){return null}}function J(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof J){if(e.loose===t.loose)return e;e=e.version}else if("string"!=typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>256)throw new TypeError("version is longer than 256 characters");if(!(this instanceof J))return new J(e,t);r("SemVer",e,t),this.options=t,this.loose=!!t.loose;var o=e.trim().match(t.loose?i[_]:i[w]);if(!o)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+o[1],this.minor=+o[2],this.patch=+o[3],this.major>n||this.major<0)throw new TypeError("Invalid major version");if(this.minor>n||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>n||this.patch<0)throw new TypeError("Invalid patch version");o[4]?this.prerelease=o[4].split(".").map((function(e){if(/^[0-9]+$/.test(e)){var t=+e;if(t>=0&&t=0;)"number"==typeof this.prerelease[r]&&(this.prerelease[r]++,r=-2);-1===r&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},t.inc=function(e,t,r,n){"string"==typeof r&&(n=r,r=void 0);try{return new J(e,r).inc(t,n).version}catch(e){return null}},t.diff=function(e,t){if(Z(e,t))return null;var r=F(e),n=F(t),i="";if(r.prerelease.length||n.prerelease.length){i="pre";var o="prerelease"}for(var s in r)if(("major"===s||"minor"===s||"patch"===s)&&r[s]!==n[s])return i+s;return o},t.compareIdentifiers=z;var G=/^[0-9]+$/;function z(e,t){var r=G.test(e),n=G.test(t);return r&&n&&(e=+e,t=+t),e===t?0:r&&!n?-1:n&&!r?1:e0}function Y(e,t,r){return W(e,t,r)<0}function Z(e,t,r){return 0===W(e,t,r)}function Q(e,t,r){return 0!==W(e,t,r)}function ee(e,t,r){return W(e,t,r)>=0}function te(e,t,r){return W(e,t,r)<=0}function re(e,t,r,n){switch(t){case"===":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e===r;case"!==":return"object"==typeof e&&(e=e.version),"object"==typeof r&&(r=r.version),e!==r;case"":case"=":case"==":return Z(e,r,n);case"!=":return Q(e,r,n);case">":return X(e,r,n);case">=":return ee(e,r,n);case"<":return Y(e,r,n);case"<=":return te(e,r,n);default:throw new TypeError("Invalid operator: "+t)}}function ne(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof ne){if(e.loose===!!t.loose)return e;e=e.value}if(!(this instanceof ne))return new ne(e,t);r("comparator",e,t),this.options=t,this.loose=!!t.loose,this.parse(e),this.semver===ie?this.value="":this.value=this.operator+this.semver.version,r("comp",this)}t.rcompareIdentifiers=function(e,t){return z(t,e)},t.major=function(e,t){return new J(e,t).major},t.minor=function(e,t){return new J(e,t).minor},t.patch=function(e,t){return new J(e,t).patch},t.compare=W,t.compareLoose=function(e,t){return W(e,t,!0)},t.rcompare=function(e,t,r){return W(t,e,r)},t.sort=function(e,r){return e.sort((function(e,n){return t.compare(e,n,r)}))},t.rsort=function(e,r){return e.sort((function(e,n){return t.rcompare(e,n,r)}))},t.gt=X,t.lt=Y,t.eq=Z,t.neq=Q,t.gte=ee,t.lte=te,t.cmp=re,t.Comparator=ne;var ie={};function oe(e,t){if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),e instanceof oe)return e.loose===!!t.loose&&e.includePrerelease===!!t.includePrerelease?e:new oe(e.raw,t);if(e instanceof ne)return new oe(e.value,t);if(!(this instanceof oe))return new oe(e,t);if(this.options=t,this.loose=!!t.loose,this.includePrerelease=!!t.includePrerelease,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map((function(e){return this.parseRange(e.trim())}),this).filter((function(e){return e.length})),!this.set.length)throw new TypeError("Invalid SemVer Range: "+e);this.format()}function se(e){return!e||"x"===e.toLowerCase()||"*"===e}function ae(e,t,r,n,i,o,s,a,c,u,f,d,l){return((t=se(r)?"":se(n)?">="+r+".0.0":se(i)?">="+r+"."+n+".0":">="+t)+" "+(a=se(c)?"":se(u)?"<"+(+c+1)+".0.0":se(f)?"<"+c+"."+(+u+1)+".0":d?"<="+c+"."+u+"."+f+"-"+d:"<="+a)).trim()}function ce(e,t,n){for(var i=0;i0){var o=e[i].semver;if(o.major===t.major&&o.minor===t.minor&&o.patch===t.patch)return!0}return!1}return!0}function ue(e,t,r){try{t=new oe(t,r)}catch(e){return!1}return t.test(e)}function fe(e,t,r,n){var i,o,s,a,c;switch(e=new J(e,n),t=new oe(t,n),r){case">":i=X,o=te,s=Y,a=">",c=">=";break;case"<":i=Y,o=ee,s=X,a="<",c="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(ue(e,t,n))return!1;for(var u=0;u=0.0.0")),d=d||e,l=l||e,i(e.semver,d.semver,n)?d=e:s(e.semver,l.semver,n)&&(l=e)})),d.operator===a||d.operator===c)return!1;if((!l.operator||l.operator===a)&&o(e,l.semver))return!1;if(l.operator===c&&s(e,l.semver))return!1}return!0}ne.prototype.parse=function(e){var t=this.options.loose?i[N]:i[$],r=e.match(t);if(!r)throw new TypeError("Invalid comparator: "+e);this.operator=r[1],"="===this.operator&&(this.operator=""),r[2]?this.semver=new J(r[2],this.options.loose):this.semver=ie},ne.prototype.toString=function(){return this.value},ne.prototype.test=function(e){return r("Comparator.test",e,this.options.loose),this.semver===ie||("string"==typeof e&&(e=new J(e,this.options)),re(e,this.operator,this.semver,this.options))},ne.prototype.intersects=function(e,t){if(!(e instanceof ne))throw new TypeError("a Comparator is required");var r;if(t&&"object"==typeof t||(t={loose:!!t,includePrerelease:!1}),""===this.operator)return r=new oe(e.value,t),ue(this.value,r,t);if(""===e.operator)return r=new oe(this.value,t),ue(e.semver,r,t);var n=!(">="!==this.operator&&">"!==this.operator||">="!==e.operator&&">"!==e.operator),i=!("<="!==this.operator&&"<"!==this.operator||"<="!==e.operator&&"<"!==e.operator),o=this.semver.version===e.semver.version,s=!(">="!==this.operator&&"<="!==this.operator||">="!==e.operator&&"<="!==e.operator),a=re(this.semver,"<",e.semver,t)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),c=re(this.semver,">",e.semver,t)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return n||i||o&&s||a||c},t.Range=oe,oe.prototype.format=function(){return this.range=this.set.map((function(e){return e.join(" ").trim()})).join("||").trim(),this.range},oe.prototype.toString=function(){return this.range},oe.prototype.parseRange=function(e){var t=this.options.loose;e=e.trim();var n=t?i[U]:i[V];e=e.replace(n,ae),r("hyphen replace",e),e=e.replace(i[K],"$1$2$3"),r("comparator trim",e,i[K]),e=(e=(e=e.replace(i[R],"$1~")).replace(i[D],"$1^")).split(/\s+/).join(" ");var o=t?i[N]:i[$],s=e.split(" ").map((function(e){return function(e,t){return r("comp",e,t),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){r("caret",e,t);var n=t.loose?i[B]:i[L];return e.replace(n,(function(t,n,i,o,s){var a;return r("caret",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a="0"===n?">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":">="+n+"."+i+".0 <"+(+n+1)+".0.0":s?(r("replaceCaret pr",s),a="0"===n?"0"===i?">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+"-"+s+" <"+(+n+1)+".0.0"):(r("no pr"),a="0"===n?"0"===i?">="+n+"."+i+"."+o+" <"+n+"."+i+"."+(+o+1):">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0":">="+n+"."+i+"."+o+" <"+(+n+1)+".0.0"),r("caret return",a),a}))}(e,t)})).join(" ")}(e,t),r("caret",e),e=function(e,t){return e.trim().split(/\s+/).map((function(e){return function(e,t){var n=t.loose?i[O]:i[A];return e.replace(n,(function(t,n,i,o,s){var a;return r("tilde",e,t,n,i,o,s),se(n)?a="":se(i)?a=">="+n+".0.0 <"+(+n+1)+".0.0":se(o)?a=">="+n+"."+i+".0 <"+n+"."+(+i+1)+".0":s?(r("replaceTilde pr",s),a=">="+n+"."+i+"."+o+"-"+s+" <"+n+"."+(+i+1)+".0"):a=">="+n+"."+i+"."+o+" <"+n+"."+(+i+1)+".0",r("tilde return",a),a}))}(e,t)})).join(" ")}(e,t),r("tildes",e),e=function(e,t){return r("replaceXRanges",e,t),e.split(/\s+/).map((function(e){return function(e,t){e=e.trim();var n=t.loose?i[T]:i[j];return e.replace(n,(function(t,n,i,o,s,a){r("xRange",e,t,n,i,o,s,a);var c=se(i),u=c||se(o),f=u||se(s);return"="===n&&f&&(n=""),c?t=">"===n||"<"===n?"<0.0.0":"*":n&&f?(u&&(o=0),s=0,">"===n?(n=">=",u?(i=+i+1,o=0,s=0):(o=+o+1,s=0)):"<="===n&&(n="<",u?i=+i+1:o=+o+1),t=n+i+"."+o+"."+s):u?t=">="+i+".0.0 <"+(+i+1)+".0.0":f&&(t=">="+i+"."+o+".0 <"+i+"."+(+o+1)+".0"),r("xRange return",t),t}))}(e,t)})).join(" ")}(e,t),r("xrange",e),e=function(e,t){return r("replaceStars",e,t),e.trim().replace(i[q],"")}(e,t),r("stars",e),e}(e,this.options)}),this).join(" ").split(/\s+/);return this.options.loose&&(s=s.filter((function(e){return!!e.match(o)}))),s=s.map((function(e){return new ne(e,this.options)}),this)},oe.prototype.intersects=function(e,t){if(!(e instanceof oe))throw new TypeError("a Range is required");return this.set.some((function(r){return r.every((function(r){return e.set.some((function(e){return e.every((function(e){return r.intersects(e,t)}))}))}))}))},t.toComparators=function(e,t){return new oe(e,t).set.map((function(e){return e.map((function(e){return e.value})).join(" ").trim().split(" ")}))},oe.prototype.test=function(e){if(!e)return!1;"string"==typeof e&&(e=new J(e,this.options));for(var t=0;t":0===t.prerelease.length?t.patch++:t.prerelease.push(0),t.raw=t.format();case"":case">=":r&&!X(r,t)||(r=t);break;case"<":case"<=":break;default:throw new Error("Unexpected operation: "+e.operator)}}))}if(r&&e.test(r))return r;return null},t.validRange=function(e,t){try{return new oe(e,t).range||"*"}catch(e){return null}},t.ltr=function(e,t,r){return fe(e,t,"<",r)},t.gtr=function(e,t,r){return fe(e,t,">",r)},t.outside=fe,t.prerelease=function(e,t){var r=F(e,t);return r&&r.prerelease.length?r.prerelease:null},t.intersects=function(e,t,r){return e=new oe(e,r),t=new oe(t,r),e.intersects(t)},t.coerce=function(e){if(e instanceof J)return e;if("string"!=typeof e)return null;var t=e.match(i[I]);if(null==t)return null;return F(t[1]+"."+(t[2]||"0")+"."+(t[3]||"0"))}})),ft=(ut.SEMVER_SPEC_VERSION,ut.re,ut.src,ut.parse,ut.valid,ut.clean,ut.SemVer,ut.inc,ut.diff,ut.compareIdentifiers,ut.rcompareIdentifiers,ut.major,ut.minor,ut.patch,ut.compare,ut.compareLoose,ut.rcompare,ut.sort,ut.rsort,ut.gt,ut.lt,ut.eq,ut.neq,ut.gte,ut.lte,ut.cmp,ut.Comparator,ut.Range,ut.toComparators,ut.satisfies,ut.maxSatisfying,ut.minSatisfying,ut.minVersion,ut.validRange,ut.ltr,ut.gtr,ut.outside,ut.prerelease,ut.intersects,ut.coerce,ut.satisfies(process.version,"^6.12.0 || >=8.0.0")),dt=["RS256","RS384","RS512","ES256","ES384","ES512"],lt=["RS256","RS384","RS512"],pt=["HS256","HS384","HS512"];ft&&(dt.splice(3,0,"PS256","PS384","PS512"),lt.splice(3,0,"PS256","PS384","PS512"));var mt=/^\s+|\s+$/g,ht=/^[-+]0x[0-9a-f]+$/i,gt=/^0b[01]+$/i,yt=/^0o[0-7]+$/i,wt=/^(?:0|[1-9]\d*)$/,vt=parseInt;function bt(e){return e!=e}function _t(e,t){return function(e,t){for(var r=-1,n=e?e.length:0,i=Array(n);++r-1&&e%1==0&&e-1&&e%1==0&&e<=9007199254740991}(e.length)&&!function(e){var t=Dt(e)?Ct.call(e):"";return"[object Function]"==t||"[object GeneratorFunction]"==t}(e)}function Dt(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function Lt(e){return!!e&&"object"==typeof e}var Bt=function(e,t,r,n){var i;e=Mt(e)?e:(i=e)?_t(i,function(e){return Mt(e)?Pt(e):Rt(e)}(i)):[],r=r&&!n?function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||Lt(e)&&"[object Symbol]"==Ct.call(e)}(e))return NaN;if(Dt(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Dt(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(mt,"");var r=gt.test(e);return r||yt.test(e)?vt(e.slice(2),r?2:8):ht.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(r):0;var o=e.length;return r<0&&(r=It(o+r,0)),function(e){return"string"==typeof e||!Ot(e)&&Lt(e)&&"[object String]"==Ct.call(e)}(e)?r<=o&&e.indexOf(t,r)>-1:!!o&&function(e,t,r){if(t!=t)return function(e,t,r,n){for(var i=e.length,o=r+(n?1:-1);n?o--:++o-1},Nt=Object.prototype.toString;var $t=function(e){return!0===e||!1===e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Boolean]"==Nt.call(e)},Kt=/^\s+|\s+$/g,Vt=/^[-+]0x[0-9a-f]+$/i,Ut=/^0b[01]+$/i,qt=/^0o[0-7]+$/i,Ht=parseInt,Ft=Object.prototype.toString;function Jt(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var Gt=function(e){return"number"==typeof e&&e==function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==Ft.call(e)}(e))return NaN;if(Jt(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Jt(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(Kt,"");var r=Ut.test(e);return r||qt.test(e)?Ht(e.slice(2),r?2:8):Vt.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e)},zt=Object.prototype.toString;var Wt=function(e){return"number"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Number]"==zt.call(e)};var Xt=Function.prototype,Yt=Object.prototype,Zt=Xt.toString,Qt=Yt.hasOwnProperty,er=Zt.call(Object),tr=Yt.toString,rr=function(e,t){return function(r){return e(t(r))}}(Object.getPrototypeOf,Object);var nr=function(e){if(!function(e){return!!e&&"object"==typeof e}(e)||"[object Object]"!=tr.call(e)||function(e){var t=!1;if(null!=e&&"function"!=typeof e.toString)try{t=!!(e+"")}catch(e){}return t}(e))return!1;var t=rr(e);if(null===t)return!0;var r=Qt.call(t,"constructor")&&t.constructor;return"function"==typeof r&&r instanceof r&&Zt.call(r)==er},ir=Object.prototype.toString,or=Array.isArray;var sr=function(e){return"string"==typeof e||!or(e)&&function(e){return!!e&&"object"==typeof e}(e)&&"[object String]"==ir.call(e)},ar=/^\s+|\s+$/g,cr=/^[-+]0x[0-9a-f]+$/i,ur=/^0b[01]+$/i,fr=/^0o[0-7]+$/i,dr=parseInt,lr=Object.prototype.toString;function pr(e,t){var r;if("function"!=typeof t)throw new TypeError("Expected a function");return e=function(e){var t=function(e){if(!e)return 0===e?e:0;if((e=function(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==lr.call(e)}(e))return NaN;if(mr(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=mr(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(ar,"");var r=ur.test(e);return r||fr.test(e)?dr(e.slice(2),r?2:8):cr.test(e)?NaN:+e}(e))===1/0||e===-1/0){return 17976931348623157e292*(e<0?-1:1)}return e==e?e:0}(e),r=t%1;return t==t?r?t-r:t:0}(e),function(){return--e>0&&(r=t.apply(this,arguments)),e<=1&&(t=void 0),r}}function mr(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}var hr=function(e){return pr(2,e)},gr=["RS256","RS384","RS512","ES256","ES384","ES512","HS256","HS384","HS512","none"];ft&&gr.splice(3,0,"PS256","PS384","PS512");var yr={expiresIn:{isValid:function(e){return Gt(e)||sr(e)&&e},message:'"expiresIn" should be a number of seconds or string representing a timespan'},notBefore:{isValid:function(e){return Gt(e)||sr(e)&&e},message:'"notBefore" should be a number of seconds or string representing a timespan'},audience:{isValid:function(e){return sr(e)||Array.isArray(e)},message:'"audience" must be a string or array'},algorithm:{isValid:Bt.bind(null,gr),message:'"algorithm" must be a valid string enum value'},header:{isValid:nr,message:'"header" must be an object'},encoding:{isValid:sr,message:'"encoding" must be a string'},issuer:{isValid:sr,message:'"issuer" must be a string'},subject:{isValid:sr,message:'"subject" must be a string'},jwtid:{isValid:sr,message:'"jwtid" must be a string'},noTimestamp:{isValid:$t,message:'"noTimestamp" must be a boolean'},keyid:{isValid:sr,message:'"keyid" must be a string'},mutatePayload:{isValid:$t,message:'"mutatePayload" must be a boolean'}},wr={iat:{isValid:Wt,message:'"iat" should be a number of seconds'},exp:{isValid:Wt,message:'"exp" should be a number of seconds'},nbf:{isValid:Wt,message:'"nbf" should be a number of seconds'}};function vr(e,t,r,n){if(!nr(r))throw new Error('Expected "'+n+'" to be a plain object.');Object.keys(r).forEach((function(i){var o=e[i];if(o){if(!o.isValid(r[i]))throw new Error(o.message)}else if(!t)throw new Error('"'+i+'" is not allowed in "'+n+'"')}))}var br={audience:"aud",issuer:"iss",subject:"sub",jwtid:"jti"},_r=["expiresIn","notBefore","noTimestamp","audience","issuer","subject","jwtid"],Er=function(e,t,r,n){var i;if("function"!=typeof r||n||(n=r,r={}),r||(r={}),r=Object.assign({},r),i=n||function(e,t){if(e)throw e;return t},r.clockTimestamp&&"number"!=typeof r.clockTimestamp)return i(new Ye("clockTimestamp must be a number"));if(void 0!==r.nonce&&("string"!=typeof r.nonce||""===r.nonce.trim()))return i(new Ye("nonce must be a non-empty string"));var o=r.clockTimestamp||Math.floor(Date.now()/1e3);if(!e)return i(new Ye("jwt must be provided"));if("string"!=typeof e)return i(new Ye("jwt must be a string"));var s,a=e.split(".");if(3!==a.length)return i(new Ye("jwt malformed"));try{s=We(e,{complete:!0})}catch(e){return i(e)}if(!s)return i(new Ye("invalid token"));var c,u=s.header;if("function"==typeof t){if(!n)return i(new Ye("verify must be called asynchronous if secret or public key is provided as a callback"));c=t}else c=function(e,r){return r(null,t)};return c(u,(function(t,n){if(t)return i(new Ye("error in secret or public key callback: "+t.message));var c,f=""!==a[2].trim();if(!f&&n)return i(new Ye("jwt signature is required"));if(f&&!n)return i(new Ye("secret or public key must be provided"));if(f||r.algorithms||(r.algorithms=["none"]),r.algorithms||(r.algorithms=~n.toString().indexOf("BEGIN CERTIFICATE")||~n.toString().indexOf("BEGIN PUBLIC KEY")?dt:~n.toString().indexOf("BEGIN RSA PUBLIC KEY")?lt:pt),!~r.algorithms.indexOf(s.header.alg))return i(new Ye("invalid algorithm"));try{c=ze.verify(e,s.header.alg,n)}catch(e){return i(e)}if(!c)return i(new Ye("invalid signature"));var d=s.payload;if(void 0!==d.nbf&&!r.ignoreNotBefore){if("number"!=typeof d.nbf)return i(new Ye("invalid nbf value"));if(d.nbf>o+(r.clockTolerance||0))return i(new Qe("jwt not active",new Date(1e3*d.nbf)))}if(void 0!==d.exp&&!r.ignoreExpiration){if("number"!=typeof d.exp)return i(new Ye("invalid exp value"));if(o>=d.exp+(r.clockTolerance||0))return i(new tt("jwt expired",new Date(1e3*d.exp)))}if(r.audience){var l=Array.isArray(r.audience)?r.audience:[r.audience];if(!(Array.isArray(d.aud)?d.aud:[d.aud]).some((function(e){return l.some((function(t){return t instanceof RegExp?t.test(e):t===e}))})))return i(new Ye("jwt audience invalid. expected: "+l.join(" or ")))}if(r.issuer&&("string"==typeof r.issuer&&d.iss!==r.issuer||Array.isArray(r.issuer)&&-1===r.issuer.indexOf(d.iss)))return i(new Ye("jwt issuer invalid. expected: "+r.issuer));if(r.subject&&d.sub!==r.subject)return i(new Ye("jwt subject invalid. expected: "+r.subject));if(r.jwtid&&d.jti!==r.jwtid)return i(new Ye("jwt jwtid invalid. expected: "+r.jwtid));if(r.nonce&&d.nonce!==r.nonce)return i(new Ye("jwt nonce invalid. expected: "+r.nonce));if(r.maxAge){if("number"!=typeof d.iat)return i(new Ye("iat required when maxAge is specified"));var p=ct(r.maxAge,d.iat);if(void 0===p)return i(new Ye('"maxAge" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'));if(o>=p+(r.clockTolerance||0))return i(new tt("maxAge exceeded",new Date(1e3*p)))}if(!0===r.complete){var m=s.signature;return i(null,{header:u,payload:d,signature:m})}return i(null,d)}))},Sr=function(e,t,r,n){"function"==typeof r?(n=r,r={}):r=r||{};var i="object"==typeof e&&!Buffer.isBuffer(e),o=Object.assign({alg:r.algorithm||"HS256",typ:i?"JWT":void 0,kid:r.keyid},r.header);function s(e){if(n)return n(e);throw e}if(!t&&"none"!==r.algorithm)return s(new Error("secretOrPrivateKey must have a value"));if(void 0===e)return s(new Error("payload is required"));if(i){try{!function(e){vr(wr,!0,e,"payload")}(e)}catch(e){return s(e)}r.mutatePayload||(e=Object.assign({},e))}else{var a=_r.filter((function(e){return void 0!==r[e]}));if(a.length>0)return s(new Error("invalid "+a.join(",")+" option for "+typeof e+" payload"))}if(void 0!==e.exp&&void 0!==r.expiresIn)return s(new Error('Bad "options.expiresIn" option the payload already has an "exp" property.'));if(void 0!==e.nbf&&void 0!==r.notBefore)return s(new Error('Bad "options.notBefore" option the payload already has an "nbf" property.'));try{!function(e){vr(yr,!1,e,"options")}(r)}catch(e){return s(e)}var c=e.iat||Math.floor(Date.now()/1e3);if(r.noTimestamp?delete e.iat:i&&(e.iat=c),void 0!==r.notBefore){try{e.nbf=ct(r.notBefore,c)}catch(e){return s(e)}if(void 0===e.nbf)return s(new Error('"notBefore" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}if(void 0!==r.expiresIn&&"object"==typeof e){try{e.exp=ct(r.expiresIn,c)}catch(e){return s(e)}if(void 0===e.exp)return s(new Error('"expiresIn" should be a number of seconds or string representing a timespan eg: "1d", "20h", 60'))}Object.keys(br).forEach((function(t){var n=br[t];if(void 0!==r[t]){if(void 0!==e[n])return s(new Error('Bad "options.'+t+'" option. The payload already has an "'+n+'" property.'));e[n]=r[t]}}));var u=r.encoding||"utf8";if("function"!=typeof n)return ze.sign({header:o,payload:e,secret:t,encoding:u});n=n&&hr(n),ze.createSign({header:o,privateKey:t,payload:e,encoding:u}).once("error",n).once("done",(function(e){n(null,e)}))};let xr=[];class kr{constructor(e){this.fetched=!1,this.options=Object.assign({baseUrl:"https://appleid.apple.com",timeout:1e4},e)}async _fetch(e,t){const{baseUrl:r}=this.options;return uniCloud.httpclient.request(r+e,t)}async verifyIdentityToken(e){const t=e.split(".")[0],r=JSON.parse(Buffer.from(t,"base64").toString()).kid;if(!xr.length)try{xr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}let n=this.getUsedKey(xr,r);if(!Object.keys(n).length&&!this.fetched){try{xr=await this.getAuthKeys()}catch(e){return{code:10705,msg:e.message}}n=this.getUsedKey(xr,r)}let i=null;try{i=Er(e,function(e,t){var r=Buffer.from(e,"base64"),n=Buffer.from(t,"base64"),i=r.toString("hex"),o=n.toString("hex");i=q(i),o=q(o);var s=i.length/2,a=o.length/2,c=F(s),u=F(a),f="30"+F(s+a+c.length/2+u.length/2+2)+"02"+c+i+"02"+u+o;return"-----BEGIN RSA PUBLIC KEY-----\n"+Buffer.from(f,"hex").toString("base64").match(/.{1,64}/g).join("\n")+"\n-----END RSA PUBLIC KEY-----\n"}(n.n,n.e),{algorithms:n.alg})}catch(e){return{code:10705,msg:e.message}}return{code:0,msg:i}}async getAuthKeys(){const{status:e,data:t}=await this._fetch("/auth/keys",{method:"GET",dataType:"json",timeout:this.options.timeout});if(this.fetched=!0,200!==e)throw new Error("request fail");return t.keys}getUsedKey(e,t){let r={};for(let n=0;n upRes",await A.doc(e.uid).update({avatar:e.avatar})),{code:0,msg:"头像设置成功"}},updatePwd:async function(e){const t=await A.doc(e.uid).get();if(t&&t.data&&t.data.length>0){if(0===this._checkPwd(t.data[0],e.oldPassword).code){const{passwordHash:r,version:n}=this.encryptPwd(e.newPassword),i={password:r,token:[]};n&&(i.password_secret_version=n);return S("upRes",await A.doc(t.data[0]._id).update(i)),{code:0,msg:"修改成功"}}return{code:40202,msg:"旧密码错误"}}return{code:40201,msg:"用户不存在"}},updateUser:async function(e){const t=e.uid;if(!t)return{code:80101,msg:"缺少uid参数"};delete e.uid;const{username:r,email:n}=e,{usernameToLowerCase:i,emailToLowerCase:o}=this._getConfig();let s=r&&r.trim(),a=n&&n.trim();return s&&(i&&(s=s.toLowerCase()),e.username=s),a&&(o&&(a=a.toLowerCase()),e.email=a),S("update -> upRes",await A.doc(t).update(e)),{code:0,msg:"修改成功"}},_getAlipayApi:function({platform:e}={}){const t=e||this.context.PLATFORM;if(!t)throw new Error("未能获取客户端平台信息,请主动传入platform");const r=this._getConfig(t);if(!r.oauth||!r.oauth.alipay)throw new Error(`请在公用模块uni-id的config.json或init方法中添加${t}平台支付宝登录配置项`);return["appid","privateKey"].forEach(e=>{if(!r.oauth.alipay[e])throw new Error(`请在公用模块uni-id的config.json或init方法中添加配置项:${t}.oauth.alipay.${e}`)}),jr({...r.oauth.alipay,clientType:t})},_getValidInviteCode:async function({inviteCode:e}){let t,r=10;e?(r=1,t=e):t=Ir();let n=!1;try{for(;r>0&&!n;){r--;if(0===(await A.where({invite_code:t}).get()).data.length){n=!0;break}t=Ir()}return n?{code:0,inviteCode:t}:e?{code:80401,msg:"邀请码重复,设置失败"}:{code:80402,msg:"邀请码设置失败稍后再试"}}catch(e){return{code:90001,msg:"数据库读写异常"}}},_addUser:async function(e,t={}){const r=this._getConfig(),n={...e,register_date:Date.now(),register_ip:this.context.CLIENTIP},i=(await A.add(n)).id;let o;if(r.removePermissionAndRoleFromToken){const e=t.needPermission;o=await this.createToken({uid:i,needPermission:e})}else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),o=await this.createToken({uid:i,role:t,permission:r})}const{token:s,tokenExpired:a}=o;return await A.doc(i).update({token:[s]}),{token:s,tokenExpired:a,uid:i,type:"register",userInfo:Object.assign({},n,{token:s})}},_loginExec:async function(e,t={}){if(1===e.status)return{code:10001,msg:"账号已禁用"};const r=this._getConfig();let n=e.token||[];"string"==typeof n&&(n=[n]);const i=this._getExpiredToken(n);let o;if(n=n.filter(e=>-1===i.indexOf(e)),r.removePermissionAndRoleFromToken){const r=t.needPermission;o=await this.createToken({uid:e._id,needPermission:r})}else{const t=e.role||[];let r;r=0===t.length||t.includes("admin")?[]:await this._getPermissionListByRoleList(t),o=await this.createToken({uid:e._id,role:t,permission:r})}const{token:s,tokenExpired:a}=o;n.push(s),e.token=n;const c={last_login_date:Date.now(),last_login_ip:this.context.CLIENTIP,token:n,...t.extraData};await A.doc(e._id).update(c);const u=Object.assign({},e,c);return{code:0,msg:"登录成功",token:s,uid:u._id,username:u.username,type:"login",userInfo:u,tokenExpired:a}},_registerExec:async function(e,t={}){const{my_invite_code:r}=e;if(this._getConfig().autoSetInviteCode||r){const t=await this._getValidInviteCode({inviteCode:r});if(t.code>0)return t;e.my_invite_code=t.inviteCode}return{code:0,msg:"注册成功",...await this._addUser(e,t)}},_getWeixinApi:function({platform:e}={}){const t=e||this.context.PLATFORM;if(!t)throw new Error("未能获取客户端平台信息,请主动传入platform");const r=this._getConfig(t);if(!r.oauth||!r.oauth.weixin)throw new Error(`请在公用模块uni-id的config.json或init方法中添加${t}平台微信登录配置项`);return["appid","appsecret"].forEach(e=>{if(!r.oauth.weixin[e])throw new Error(`请在公用模块uni-id的config.json或init方法中添加配置项:${t}.oauth.weixin.${e}`)}),Cr({...r.oauth.weixin,clientType:t})},_getMatchedUser:function(e,t){if(0===e.length)return{code:10002,msg:"用户不存在"};let r;const n={},i={};for(let r=e.length-1;r>=0;r--){const o=e[r];for(let s=0;s0?{code:10003,msg:"匹配到多个账号,请联系管理员处理"}:{code:0,msg:"",userMatched:r,fieldMatched:s,isFallbackValueMatched:!!s&&i[s]}},acceptInvite:async function({uid:e,inviteCode:t}){const r=await A.where({_id:Pr.neq(e),inviter_uid:Pr.not(Pr.all([e])),my_invite_code:t}).get();if(1!==r.data.length)return{code:80501,msg:"邀请码无效"};const n=[r.data[0]._id].concat(r.data[0].inviter_uid||[]),i=await A.doc(e).field({my_invite_code:!0,inviter_uid:!0}).get();if(0===i.data.length)return{code:80502,msg:"uid错误用户不存在"};if(i.data[0].inviter_uid&&i.data[0].inviter_uid.length>0)return{code:80503,msg:"邀请码不可修改"};const o=Date.now();return await A.doc(e).update({inviter_uid:n,invite_time:o}),await A.where({inviter_uid:e}).update({inviter_uid:Pr.push(n)}),{code:0,msg:"邀请码填写成功"}},getInvitedUser:async function({uid:e,level:t=1,limit:r=20,offset:n=0,needTotal:i=!1}){const o={code:0,msg:"获取邀请列表成功",invitedUser:(await A.where({["inviter_uid."+(t-1)]:e}).field({_id:!0,username:!0,mobile:!0,invite_time:!0}).orderBy("invite_time","desc").skip(n).limit(r).get()).data};if(i){const r=await A.where({["inviter_uid."+(t-1)]:e}).count();o.total=r.total}return o},setUserInviteCode:async function({uid:e,myInviteCode:t}){const r=await this._getValidInviteCode({inviteCode:t});return r.code>0?r:(await A.doc(e).update({my_invite_code:r.inviteCode}),{code:0,msg:"邀请码设置成功",myInviteCode:r.inviteCode})},loginByAlipay:async function(e){let t=e;"string"==typeof e&&(t={code:e});const r=t.needPermission,n=t.platform||this.context.PLATFORM,{openid:i}=await this._getAlipayApi({platform:n}).code2Session(t.code);if(!i)return{code:10501,msg:"获取openid失败"};const o=await A.where({ali_openid:i}).get();if(o&&o.data&&o.data.length>0){const e=o.data[0],t=await this._loginExec(e,{needPermission:r});if(0!==t.code)return t;const{userInfo:n}=t;return{...t,openid:i,mobileConfirmed:1===n.mobile_confirmed,emailConfirmed:1===n.email_confirmed}}{const e={ali_openid:i};e.my_invite_code=t.myInviteCode,e.role=t.role;const n=await this._registerExec(e,{needPermission:r});return 0!==n.code?n:{...n,openid:i,mobileConfirmed:!1,emailConfirmed:!1}}},loginByEmail:async function({email:e,code:t,password:r,myInviteCode:n,type:i,needPermission:o,role:s}){if(!(e=e&&e.trim()))return{code:L,msg:"邮箱不可为空"};const{emailToLowerCase:a}=this._getConfig();let c=e;a&&(c=e.toLowerCase());const u=await this.verifyCode({email:c,code:t,type:i||"login"});if(0!==u.code)return u;let f={email:e,email_confirmed:1};const d={field:"email",value:e},l=Rr.command;c!==e&&(f=l.or(f,{email:c,email_confirmed:1}),d.fallbackValue=c);const p=await A.where(f).get();if(p&&p.data&&p.data.length>0){if("register"===i)return{code:10301,msg:"此邮箱已注册"};const e=this._getMatchedUser(p.data,[d]);if(e.code)return e;const{userMatched:t}=e,r=await this._loginExec(t,{needPermission:o});return 0!==r.code?r:{...r,email:c}}{if("login"===i)return{code:10302,msg:"此邮箱尚未注册"};const e={email:c,email_confirmed:1},t=r&&r.trim();if(t){const{passwordHash:r,version:n}=this.encryptPwd(t);e.password=r,n&&(e.password_secret_version=n)}e.my_invite_code=n,e.role=s;const a=await this._registerExec(e,{needPermission:o});return 0!==a.code?a:{...a,email:c}}},loginBySms:async function({mobile:e,code:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){if(!(e=e&&e.trim()))return{code:L,msg:"手机号码不可为空"};const c=this._getConfig();if(c.forceInviteCode&&!o)throw new Error("[loginBySms]强制使用邀请码注册时,需指明type为register还是login");const u=await this.verifyCode({mobile:e,code:t,type:o||"login"});if(0!==u.code)return u;const f={mobile:e,mobile_confirmed:1},d=await A.where(f).get();if(d&&d.data&&d.data.length>0){if("register"===o)return{code:10201,msg:"此手机号已注册"};const t=d.data[0],r=await this._loginExec(t,{needPermission:s});return 0!==r.code?r:{...r,mobile:e}}{const t=Date.now();if("login"===o)return{code:10203,msg:"此手机号尚未注册"};const u={mobile:e,mobile_confirmed:1,register_ip:this.context.CLIENTIP,register_date:t},f=r&&r.trim();if(f){const{passwordHash:e,version:t}=this.encryptPwd(f);u.password=e,t&&(u.password_secret_version=t)}if(n){const e=await A.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10202,msg:"邀请码无效"};u.inviter_uid=[e.data[0]._id].concat(e.data[0].inviter_uid||[]),u.invite_time=t}else if(c.forceInviteCode)return{code:10202,msg:"邀请码无效"};u.my_invite_code=i,u.role=a;const d=await this._registerExec(u,{needPermission:s});return 0!==d.code?d:{...d,mobile:e}}},loginByWeixin:async function(e){let t=e;"string"==typeof e&&(t={code:e});const r=t.needPermission,n=t.platform||this.context.PLATFORM,{openid:i,unionid:o,sessionKey:s}=await this._getWeixinApi({platform:n})["mp-weixin"===n?"code2Session":"getOauthAccessToken"](t.code);if(!i)return{code:10401,msg:"获取openid失败"};const a=Ar.command,c=[{wx_openid:{[n]:i}}];o&&c.push({wx_unionid:o});const u=await A.where(a.or(...c)).get();if(u&&u.data&&u.data.length>0){const e=u.data[0],t={wx_openid:{[n]:i}};o&&(t.wx_unionid=o);const a=await this._loginExec(e,{needPermission:r,extraData:t});if(0!==a.code)return a;const{userInfo:c}=a;return{...a,openid:i,unionid:o,sessionKey:s,mobileConfirmed:1===c.mobile_confirmed,emailConfirmed:1===c.email_confirmed}}{const e={wx_openid:{[n]:i},wx_unionid:o},a=t.myInviteCode;e.my_invite_code=a,e.role=t.role;const c=await this._registerExec(e,{needPermission:r});return 0!==c.code?c:{...c,openid:i,unionid:o,sessionKey:s,mobileConfirmed:!1,emailConfirmed:!1}}},loginByUniverify:async function({openid:e,access_token:t,password:r,inviteCode:n,myInviteCode:i,type:o,needPermission:s,role:a}){const c=this._getConfig(),u=c&&c.service&&c.service.univerify;if(!u)throw new Error("请在config.json中配置service.univerify下一键登录相关参数");if(c.forceInviteCode&&!o)throw new Error("[loginByUniverify] 强制使用邀请码注册时,需指明type为register还是login");const f=await Or({...u,openid:e,access_token:t});if(0!==f.code)return f;const d=String(f.phoneNumber),l=await A.where({mobile:d}).get();if(l&&l.data&&l.data.length>0){if("register"===o)return{code:10601,msg:"此手机号已注册"};const e=l.data[0],t=await this._loginExec(e,{needPermission:s});return 0!==t.code?t:{...t,mobile:d}}if("login"===o)return{code:10602,msg:"此手机号尚未注册"};const p=Date.now(),m={mobile:d,my_invite_code:i,mobile_confirmed:1,role:a},h=r&&r.trim();if(h){const{passwordHash:e,version:t}=this.encryptPwd(h);m.password=e,t&&(m.password_secret_version=t)}if(n){let e=await A.where({my_invite_code:n}).get();if(1!==e.data.length)return{code:10202,msg:"邀请码无效"};e=e.data[0],m.inviter_uid=[e._id].concat(e.inviter_uid||[]),m.invite_time=p}else if(c.forceInviteCode)return{code:10202,msg:"邀请码无效"};m.my_invite_code=i;const g=await this._registerExec(m,{needPermission:s});return 0!==g.code?g:{...g,mobile:d}},loginByApple:async function({nickName:e,fullName:t,email:r,authorizationCode:n,identityToken:i,realUserStatus:o,inviteCode:s,myInviteCode:a,type:c,needPermission:u,platform:f,role:d}){const l=this._getConfig(),p=l&&l["app-plus"]&&l["app-plus"].oauth&&l["app-plus"].oauth.apple;if(!p)throw new Error("请在config.json或init方法中,app-plus.oauth.apple 下配置相关参数");const{bundleId:m}=p;if(!m)throw new Error("请在config.json或init方法中 app-plus.oauth.apple 下配置bundleId");if(!i)throw new Error("[loginByApple] 苹果登录需要传递identityToken");const h=f||this.context.PLATFORM;t=e||(t&&Object.keys(t).length>0?t.familyName+t.givenName:"");const{code:g,msg:y}=await Tr({clientType:h}).verifyIdentityToken(i);if(0!==g)return{code:g,msg:y};const{iss:w,sub:v,aud:b,email:_}=y;if("https://appleid.apple.com"!==w)return{code:10706,msg:"签发机构检验失败"};if(!v)return{code:10701,msg:"获取用户唯一标识符失败"};if(m!==b)return{code:10702,msg:"bundleId校验失败,请确认配置后重试"};const E=t||"新用户"+_.split("@")[0],S=await A.where({apple_openid:v}).get();if(S&&S.data&&S.data.length>0){if("register"===c)return{code:10703,msg:"此账户已注册"};const e=S.data[0],t=await this._loginExec(e,{needPermission:u});return 0!==t.code?t:{...t,openid:v}}if("login"===c)return{code:10704,msg:"此账户尚未注册"};const x={nickname:E,apple_openid:v,my_invite_code:a,role:d},k=await this._registerExec(x,{needPermission:u});return 0!==k.code?k:{...k,openid:v}},login:async function({username:e,password:t,queryField:r=[],needPermission:n}){const i=Mr.command,o=[];r&&r.length||(r=["username"]),r.length>1&&console.warn("检测到当前使用queryField匹配多字段进行登录操作,需要注意:uni-id并未限制用户名不能是手机号或邮箱,需要开发者自行限制。否则可能出现用户输入abc@xx.com会同时匹配到邮箱为此值的用户和用户名为此值的用户,导致登录失败");const{usernameToLowerCase:s,emailToLowerCase:a,passwordErrorLimit:c,passwordErrorRetryTime:u}=this._getConfig(),f={email:{email_confirmed:1},mobile:{mobile_confirmed:1}},d={},l=e.trim();if(!l)return{code:L,msg:"用户名不可为空"};s&&(d.username=l.toLowerCase()),a&&(d.email=l.toLowerCase());const p=[];r.forEach(t=>{o.push({[t]:e,...f[t]});const r={field:t,value:e};"username"===t&&d.username!==e?(o.push({[t]:d.username,...f[t]}),r.fallbackValue=d.username):"email"===t&&d.email!==e&&(o.push({[t]:d.email,...f[t]}),r.fallbackValue=d.email),p.push(r)});const m=await A.where(i.or(...o)).limit(1).get(),h=this.context.CLIENTIP,g=this._getMatchedUser(m.data,p);if(g.code)return g;const{userMatched:y}=g;let w=y.login_ip_limit||[];w=w.filter(e=>e.last_error_time>Date.now()-1e3*u);let v=w.find(e=>e.ip===h);if(v&&v.error_times>=c)return{code:10103,msg:`密码错误次数过多,请${T(v.last_error_time+1e3*u)}再试。`};const b=t&&t.trim();if(!b)return{code:L,msg:"密码不可为空"};const _=this._checkPwd(y,b);if(0===_.code){const e=w.indexOf(v);e>-1&&w.splice(e,1);const t={login_ip_limit:w},{passwordHash:r,passwordVersion:i}=_;r&&i&&(t.password=r,t.password_secret_version=i);const o=await this._loginExec(y,{needPermission:n,extraData:t});return o.code,o}return v?(v.error_times++,v.last_error_time=Date.now()):(v={ip:h,error_times:1,last_error_time:Date.now()},w.push(v)),await A.doc(y._id).update({login_ip_limit:w}),{code:10102,msg:"密码错误"}},register:async function(e){const t=[],r=[{name:"username",desc:"用户名"},{name:"email",desc:"邮箱",extraCond:{email_confirmed:1}},{name:"mobile",desc:"手机号",extraCond:{mobile_confirmed:1}}],{usernameToLowerCase:n,emailToLowerCase:i}=this._getConfig(),o=e.needPermission;if(void 0!==o&&delete e.needPermission,r.forEach(r=>{const o=r.name;let s=e[o]&&e[o].trim();s?(("username"===r.name&&n||"email"===r.name&&i)&&(s=s.toLowerCase()),e[o]=s,t.push({[o]:s,...r.extraCond})):delete e[o]}),0===t.length)return{code:20101,msg:"用户名、邮箱、手机号不可同时为空"};const{username:s,email:a,mobile:c,myInviteCode:u}=e,f=Dr.command,d=await A.where(f.or(...t)).get();if(d&&d.data.length>0){const t=d.data[0];for(let n=0;nt[e]===i.extraCond[e])),t[i.name]===e[i.name]&&o)return{code:20102,msg:i.desc+"已存在"}}}const l=e.password&&e.password.trim();if(!l)return{code:L,msg:"密码不可为空"};const{passwordHash:p,version:m}=this.encryptPwd(l);e.password=p,m&&(e.password_secret_version=m),e.my_invite_code=u,delete e.myInviteCode;const h=await this._registerExec(e,{needPermission:o});return 0!==h.code?h:{...h,username:s,email:a,mobile:c}},logout:async function(e){const t=await this.checkToken(e);if(t.code&&t.code>0)return t;const r=Lr.command;return await A.doc(t.uid).update({token:r.pull(e)}),{code:0,msg:"退出成功"}},getRoleByUid:async function({uid:e}){if(!e)return{code:"PARAMETER_ERROR",msg:"用户Id不能为空"};const t=await A.doc(e).get();return 0===t.data.length?{code:"USER_NOT_EXIST",msg:"用户不存在"}:{code:0,msg:"获取角色成功",role:t.data[0].role||[]}},getPermissionByRole:async function({roleID:e}){if(!e)return{code:"PARAMETER_ERROR",msg:"角色ID不能为空"};if("admin"===e){return{code:0,msg:"获取权限成功",permission:(await D.limit(1e4).get()).data.map(e=>e.permission_id)}}const t=await M.where({role_id:e}).get();return 0===t.data.length?{code:"ROLE_NOT_EXIST",msg:"角色不存在"}:{code:0,msg:"获取权限成功",permission:t.data[0].permission||[]}},getPermissionByUid:async function({uid:e}){const t=await A.aggregate().match({_id:e}).project({role:!0}).unwind("$role").lookup({from:"uni-id-roles",localField:"role",foreignField:"role_id",as:"roleDetail"}).unwind("$roleDetail").replaceRoot({newRoot:"$roleDetail"}).end(),r=[];return t.data.forEach(e=>{Array.prototype.push.apply(r,e.permission)}),{code:0,msg:"获取权限成功",permission:k(r)}},bindRole:async function({uid:e,roleList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.role=r?t:Br.push(t),await A.doc(e).update(n),{code:0,msg:"角色绑定成功"}},bindPermission:async function({roleID:e,permissionList:t,reset:r=!1}){const n={};return"string"==typeof t&&(t=[t]),n.permission=r?t:Br.push(t),await M.where({role_id:e}).update(n),{code:0,msg:"权限绑定成功"}},unbindRole:async function({uid:e,roleList:t}){return"string"==typeof t&&(t=[t]),await A.doc(e).update({role:Br.pull(Br.in(t))}),{code:0,msg:"角色解绑成功"}},unbindPermission:async function({roleID:e,permissionList:t}){return"string"==typeof t&&(t=[t]),await M.where({role_id:e}).update({permission:Br.pull(Br.in(t))}),{code:0,msg:"权限解绑成功"}},addRole:async function({roleID:e,roleName:t,comment:r,permission:n=[]}){return e?"admin"===e?{code:"PARAMETER_ERROR",msg:"不可新增roleID为admin的角色"}:(await M.add({role_id:e,role_name:t,comment:r,permission:n,create_date:Date.now()}),{code:0,msg:"角色新增成功"}):{code:"PARAMETER_ERROR",msg:"roleID不能为空"}},addPermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.add({permission_id:e,permission_name:t,comment:r,create_date:Date.now()}),{code:0,msg:"权限新增成功"}):{code:"PARAMETER_ERROR",msg:"permissionID不能为空"}},getRoleList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"获取角色列表成功",roleList:(await M.skip(t).limit(e).get()).data};if(r){const{total:e}=await M.where({_id:Br.exists(!0)}).count();n.total=e}return n},getRoleInfo:async function(e){const t=await M.where({role_id:e}).get();return 0===t.data.length?{code:"ROLE_ID_NOT_EXISTS",msg:"角色ID不存在"}:{code:0,...t.data[0]}},updateRole:async function({roleID:e,roleName:t,comment:r,permission:n}){return e?(await M.where({role_id:e}).update({role_name:t,comment:r,permission:n}),{code:0,msg:"角色更新成功"}):{code:"PARAMETER_ERROR",msg:"参数错误,roleID不能为空"}},deleteRole:async function({roleID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("roleID只能为字符串或者数组");return await M.where({role_id:Br.in(e)}).remove(),await A.where({role:Br.elemMatch(Br.in(e))}).update({role:Br.pullAll(e)}),{code:0,msg:"角色删除成功"}},getPermissionList:async function({limit:e=20,offset:t=0,needTotal:r=!0}){const n={code:0,msg:"获取权限列表成功",permissionList:(await D.skip(t).limit(e).get()).data};if(r){const{total:e}=await D.where({_id:Br.exists(!0)}).count();n.total=e}return n},getPermissionInfo:async function(e){const t=await D.where({permission_id:e}).get();return 0===t.data.length?{code:"PERMISSION_ID_NOT_EXISTS",msg:"权限ID不存在"}:{code:0,...t.data[0]}},updatePermission:async function({permissionID:e,permissionName:t,comment:r}){return e?(await D.where({permission_id:e}).update({permission_name:t,comment:r}),{code:0,msg:"权限更新成功"}):{code:"PARAMETER_ERROR",msg:"参数错误,permissionID不能为空"}},deletePermission:async function({permissionID:e}){const t=m(e);if("string"===t)e=[e];else if("array"!==t)throw new Error("permissionID只能为字符串或者数组");return await D.where({permission_id:Br.in(e)}).remove(),await M.where({permission:Br.elemMatch(Br.in(e))}).update({permission:Br.pullAll(e)}),{code:0,msg:"权限删除成功"}},bindAlipay:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,{openid:i}=await this._getAlipayApi({platform:n}).code2Session(t);if(!i)return{code:60401,msg:"获取openid失败"};const o=await A.where({ali_openid:i}).get();return o&&o.data&&o.data.length>0?{code:60402,msg:"支付宝绑定失败,此账号已被绑定"}:(await A.doc(e).update({ali_openid:i}),{code:0,openid:i,msg:"绑定成功"})},bindEmail:async function({uid:e,email:t,code:r}){if(!(t=t&&t.trim()))return{code:L,msg:"邮箱不可为空"};const{emailToLowerCase:n}=this._getConfig();n&&(t=t.toLowerCase());const i=await A.where({email:t,email_confirmed:1}).limit(1).get();if(i&&i.data.length>0)return{code:60201,msg:"此邮箱已被绑定"};if(r){const e=await this.verifyCode({email:t,code:r,type:"bind"});if(0!==e.code)return e}return await A.doc(e).update({email:t,email_confirmed:1}),{code:0,msg:"邮箱绑定成功",email:t}},bindMobile:async function({uid:e,mobile:t,code:r,openid:n,access_token:i,type:o="sms"}){if("univerify"===o){const e=this._getConfig(),r=e&&e.service&&e.service.univerify;if(!r)throw new Error("请在config.json中配置service.univerify下一键登录相关参数");const o=await Or({...r,openid:n,access_token:i});if(0!==o.code)return o;t=""+o.phoneNumber}const s=await A.where({mobile:t,mobile_confirmed:1}).count();if(s&&s.total>0)return{code:60101,msg:"此手机号已被绑定"};if("sms"===o&&r){const e=await this.verifyCode({mobile:t,code:r,type:"bind"});if(0!==e.code)return e}return S("bindMobile -> upRes",await A.doc(e).update({mobile:t,mobile_confirmed:1})),{code:0,msg:"手机号码绑定成功",mobile:t}},bindWeixin:async function({uid:e,code:t,platform:r}){const n=r||this.context.PLATFORM,{openid:i,unionid:o}=await this._getWeixinApi({platform:n})["mp-weixin"===n?"code2Session":"getOauthAccessToken"](t);if(!i)return{code:60301,msg:"获取openid失败"};const s=Nr.command,a=[{wx_openid:{[n]:i}}];o&&a.push({wx_unionid:o});const c=await A.where(s.or(...a)).get();if(c&&c.data&&c.data.length>0)return{code:60302,msg:"微信绑定失败,此微信账号已被绑定"};const u={wx_openid:{[n]:i}};return o&&(u.wx_unionid=o),await A.doc(e).update(u),{code:0,openid:i,unionid:o,msg:"绑定成功"}},unbindAlipay:async function(e){const t=$r.command,r=await A.doc(e).update({ali_openid:t.remove()});return S("upRes:",r),1===r.updated?{code:0,msg:"支付宝解绑成功"}:{code:70401,msg:"支付宝解绑失败,请稍后再试"}},unbindEmail:async function({uid:e,email:t,code:r}){if(t=t&&t.trim(),!e||!t)return{code:L,msg:(e?"邮箱":"用户Id")+"不可为空"};const{emailToLowerCase:n}=this._getConfig();if(r){const e=await this.verifyCode({email:t,code:r,type:"unbind"});if(0!==e.code)return e}const i=Kr.command;let o={_id:e,email:t};if(n){const r=t.toLowerCase();r!==t&&(o=i.or(o,{_id:e,email:r}))}return 1===(await A.where(o).update({email:i.remove(),email_confirmed:i.remove()})).updated?{code:0,msg:"邮箱解绑成功"}:{code:70201,msg:"邮箱解绑失败,请稍后再试"}},unbindMobile:async function({uid:e,mobile:t,code:r}){if(r){const e=await this.verifyCode({mobile:t,code:r,type:"unbind"});if(0!==e.code)return e}const n=Vr.command;return 1===(await A.where({_id:e,mobile:t}).update({mobile:n.remove(),mobile_confirmed:n.remove()})).updated?{code:0,msg:"手机号解绑成功"}:{code:70101,msg:"手机号解绑失败,请稍后再试"}},unbindWeixin:async function(e){const t=Ur.command,r=await A.doc(e).update({wx_openid:t.remove(),wx_unionid:t.remove()});return S("upRes:",r),1===r.updated?{code:0,msg:"微信解绑成功"}:{code:70301,msg:"微信解绑失败,请稍后再试"}},code2SessionAlipay:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getAlipayApi({platform:e}).code2Session(t.code);return r.openid?{code:0,msg:"",...r}:{code:80701,msg:"获取openid失败"}}catch(e){return{code:80702,msg:e.message}}},code2SessionWeixin:async function(e){let t=e;"string"==typeof e&&(t={code:e});try{const e=t.platform||this.context.PLATFORM,r=await this._getWeixinApi({platform:e})["mp-weixin"===e?"code2Session":"getOauthAccessToken"](t.code);return r.openid?{code:0,msg:"",...r}:{code:80601,msg:"获取openid失败"}}catch(e){return{code:80602,msg:e.message}}},verifyAppleIdentityToken:async function({identityToken:e,platform:t}){const r=t||this.context.PLATFORM,{code:n,msg:i}=await Tr({clientType:r}).verifyIdentityToken(e);return 0!==n?{code:n,msg:i}:{code:n,msg:"验证通过",...i}},wxBizDataCrypt:async function({code:e,sessionKey:t,encryptedData:r,iv:i}){if(!r)return{code:80805,msg:"encryptedData不可为空"};if(!i)return{code:80806,msg:"iv不可为空"};if(!e&&!t)return{code:80804,msg:"code或sessionKey必须有其中一个"};const o=this._getWeixinApi();if(!t){const r=await o.code2Session(e);if(!r.sessionKey)return{code:80801,msg:"sessionKey获取失败"};t=r.sessionKey}t=Buffer.from(t,"base64"),r=Buffer.from(r,"base64"),i=Buffer.from(i,"base64");try{var s=n.createDecipheriv("aes-128-cbc",t,i);s.setAutoPadding(!0);var a=s.update(r,"binary","utf8");a+=s.final("utf8"),a=JSON.parse(a)}catch(e){return{code:80802,msg:"解密失败:"+e.message}}return a.watermark.appid!==o.options.appId?{code:80803,msg:"appid不匹配"}:{code:0,msg:"解密成功",...a}},encryptPwd:function(e,{value:t,version:r}={}){if(!(e=e&&e.trim()))throw new Error("密码不可为空");if(!t){const e=this._getConfig(),{passwordSecret:n}=e;if("array"===m(n)){const e=n.sort((e,t)=>e.version-t.version);t=e[e.length-1].value,r=e[e.length-1].version}else t=n}if(!t)throw new Error("passwordSecret不正确");const i=n.createHmac("sha1",t.toString("ascii"));return i.update(e),{passwordHash:i.digest("hex"),version:r}},checkToken:async function(e,{needPermission:t,needUserInfo:r=!0}={}){const n=this._getConfig();try{const i=this._verifyToken(e);if(i.code)return i;const{uid:o,needPermission:s,role:a,permission:c,exp:u}=i,f=a&&c;t=void 0===t?s:t;const d=n.removePermissionAndRoleFromToken||!f||r,l=!n.removePermissionAndRoleFromToken&&!f||n.removePermissionAndRoleFromToken&&f||n.tokenExpiresThreshold&&u-Date.now()/1e3-1===r.indexOf(e)),t.push(e.token),await A.doc(o).update({token:t,last_login_date:Date.now(),last_login_ip:this.context.CLIENTIP}),{...m,...e}}return m}catch(e){return{code:90001,msg:"数据库读写异常:"+e.message,err:e}}},createToken:function({uid:e,needPermission:t,role:r,permission:n}){if(!e)return{code:30101,msg:"缺少uid参数"};const i={uid:e,needPermission:t,role:r,permission:n},o=this._getConfig();if(!this.interceptorMap.has("customToken")){const e={...i};return this._createTokenInternal({signContent:e,config:o})}const s=this.interceptorMap.get("customToken");if("function"!=typeof s)throw new Error("custom-token.js应导出一个function");const a=s(i);return a instanceof Promise?a.then(e=>this._createTokenInternal({signContent:e,config:o})):this._createTokenInternal({signContent:a,config:o})},_checkPwd:function(e,t){if(!t)return{code:1,message:"密码不能为空"};const{password:r,password_secret_version:n}=e,i=this._getConfig(),{passwordSecret:o}=i,s=m(o);if("string"===s){const{passwordHash:e}=this.encryptPwd(t,{value:o});return e===r?{code:0,message:"密码校验通过"}:{code:2,message:"密码不正确"}}if("array"!==s)throw new Error("config内passwordSecret类型错误,只可设置string类型和array类型");const a=o.sort((e,t)=>e.version-t.version);let c;if(c=n?a.find(e=>e.version===n):a[0],!c)return{code:3,message:"secretVersion不正确"};const u=a[a.length-1],{passwordHash:f}=this.encryptPwd(t,c);if(f===r){const e={code:0,message:"密码校验通过"};if(c!==u){const{passwordHash:r,version:n}=this.encryptPwd(t,u);e.passwordHash=r,e.passwordVersion=n}return e}return{code:4,message:""}},_verifyToken:function(e){const t=this._getConfig();let r;try{r=Er(e,t.tokenSecret)}catch(e){return"TokenExpiredError"===e.name?{code:30203,msg:"token已过期,请重新登录",err:e}:{code:30204,msg:"非法token",err:e}}return t.bindTokenToDevice&&r.clientId&&r.clientId!==this._getClientUaHash()?{code:30201,msg:"token不合法,请重新登录"}:r},_getExpiredToken:function(e){const t=this._getConfig(),r=[];return e.forEach(e=>{try{Er(e,t.tokenSecret)}catch(t){r.push(e)}}),r},_getPermissionListByRoleList:async function(e){if(!Array.isArray(e))return[];if(0===e.length)return[];if(e.includes("admin")){return(await D.limit(500).get()).data.map(e=>e.permission_id)}const t=await M.where({role_id:qr.in(e)}).get(),r=[];return t.data.forEach(e=>{Array.prototype.push.apply(r,e.permission)}),k(r)},_getClientUaHash:function(){const e=n.createHash("md5"),t=/MicroMessenger/i.test(this.context.CLIENTUA)?this.context.CLIENTUA.replace(/(MicroMessenger\S+).*/i,"$1"):this.context.CLIENTUA;return e.update(t),e.digest("hex")},_createTokenInternal:function({signContent:e,config:t}){return"object"!==m(e)?{code:30101,msg:"token对应的payload为对象且必须包含uid"}:e.uid?(t.bindTokenToDevice&&(e.clientId=this._getClientUaHash()),{token:Sr(e,t.tokenSecret,{expiresIn:t.tokenExpiresIn}),tokenExpired:Date.now()+1e3*t.tokenExpiresIn}):{code:30101,msg:"token对应的payload必须包含uid"}},setVerifyCode:async function({mobile:e,email:t,code:r,expiresIn:n,type:i}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t||e&&t)return{code:50101,msg:"手机号和邮箱必须且只能给定其中一个"};r||(r=x()),n||(n=180);const o=Date.now(),s={mobile:e,email:t,type:i,code:r,state:0,ip:this.context.CLIENTIP,created_at:o,expired_at:o+1e3*n};return S("addRes",await O.add(s)),{code:0,mobile:e,email:t}},verifyCode:async function({mobile:e,email:t,code:r,type:n}){if(t=t&&t.trim(),e=e&&e.trim(),t){const{emailToLowerCase:e}=this._getConfig();e&&(t=t.toLowerCase())}if(!e&&!t||e&&t)return{code:50201,msg:"手机号和邮箱必须且只能给定其中一个"};const i=Hr.command,o=Date.now(),s={mobile:e,email:t,type:n,code:r,state:0,expired_at:i.gt(o)},a=await O.where(s).orderBy("created_at","desc").limit(1).get();if(S("verifyRecord:",a),a&&a.data&&a.data.length>0){const e=a.data[0];return S("upRes",await O.doc(e._id).update({state:1})),{code:0,msg:"验证通过"}}return{code:50202,msg:"验证码错误或已失效"}},sendSmsCode:async function({mobile:e,code:t,type:r,templateId:n}){if(!e)throw new Error("手机号码不可为空");if(t||(t=x()),!r)throw new Error("验证码类型不可为空");const i=this._getConfig();let o=i&&i.service&&i.service.sms;if(!o)throw new Error("请在config.json或init方法中配置service.sms下短信相关参数");o=Object.assign({codeExpiresIn:300},o);const s=["smsKey","smsSecret"];if(!n&&!o.name)throw new Error("不传入templateId时应在config.json或init方法内service.sms下配置name字段以正确使用uniID_code模板");for(let e=0,t=s.length;e=0?o:{code:0,msg:"验证码发送成功"}}catch(e){return{code:50301,msg:"验证码发送失败, "+e.message}}}});let Jr;try{Jr=require("uni-config-center")}catch(e){}const Gr="\n传入配置的方式有以下几种:\n- 在uni-config-center公共模块的uni-id目录下放置config.json文件(推荐)\n- 在uni-id公共模块的目录下放置config.json文件\n- 使用init方法传入配置\n- 如果使用uni-config-center且HBuilderX版本低于3.1.8,批量上传云函数及公共模块后需要再单独上传一次uni-id";class zr{constructor({context:e,config:t}={}){const r=Jr&&Jr({pluginId:"uni-id"});this.pluginConfig=r,this.config=t||this._getConfigContent(),Object.defineProperty(this,"context",{get:()=>e||global.__ctx__}),this.interceptorMap=new Map,r&&r.hasFile("custom-token.js")&&this.setInterceptor("customToken",require(r.resolve("custom-token.js")))}_getConfigContent(){if(this.pluginConfig&&this.pluginConfig.hasFile("config.json")){this._hasConfigFile=!0;try{return this.pluginConfig.config()}catch(e){return}}const e=r.resolve(__dirname,"config.json");this._hasConfigFile=t.existsSync(e);try{return require(e)}catch(e){}}init(e){this.config=e}setInterceptor(e,t){this.interceptorMap.set(e,t)}_getConfig(e){const t=this.config&&0!==Object.keys(this.config).length;if(this._hasConfigFile&&!t)throw new Error("请确保公用模块uni-id对应的配置文件格式正确(不可包含注释)"+Gr);if(!t)throw new Error("公用模块uni-id缺少配置信息"+Gr);const r=Object.assign(this.config,this.config[e||this.context.PLATFORM])||{},n=Object.assign({bindTokenToDevice:!1,tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600,usernameToLowerCase:!0,emailToLowerCase:!0},r);return["passwordSecret","tokenSecret","tokenExpiresIn","passwordErrorLimit","passwordErrorRetryTime"].forEach(e=>{if(!n||!n[e])throw new Error("请在公用模块uni-id的配置信息中内添加配置项:"+e)}),n}}for(const e in Fr)zr.prototype[e]=P(Fr[e]);function Wr({context:e,config:t}={}){const r=new zr({context:e,config:t}),n=new Proxy(r,{get(e,t){if(t in e)return"function"==typeof e[t]?e[t].bind(n):e[t]}});return n}zr.prototype.createInstance=Wr;var Xr=Wr();module.exports=Xr;
diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package-lock.json b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package-lock.json
new file mode 100644
index 0000000..b925303
--- /dev/null
+++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package-lock.json
@@ -0,0 +1,11 @@
+{
+ "name": "uni-id",
+ "version": "3.1.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "uni-config-center": {
+ "version": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
+ }
+ }
+}
diff --git a/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json
new file mode 100644
index 0000000..e2545bd
--- /dev/null
+++ b/uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "uni-id",
+ "version": "3.1.0",
+ "description": "uni-id for uniCloud",
+ "main": "index.js",
+ "homepage": "https:\/\/uniapp.dcloud.io\/uniCloud\/uni-id",
+ "repository": {
+ "type": "git",
+ "url": "git+https:\/\/gitee.com\/dcloud\/uni-id.git"
+ },
+ "author": "",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center"
+ },
+ "origin-plugin-dev-name": "uni-list-news-title",
+ "origin-plugin-version": "0.0.10",
+ "plugin-dev-name": "uni-list-news-title",
+ "plugin-version": "0.0.10"
+}
\ No newline at end of file
diff --git a/uni_modules/uni-list/changelog.md b/uni_modules/uni-list/changelog.md
new file mode 100644
index 0000000..e3338a9
--- /dev/null
+++ b/uni_modules/uni-list/changelog.md
@@ -0,0 +1,7 @@
+## 1.0.17(2021-05-12)
+- 新增 组件示例地址
+## 1.0.16(2021-02-05)
+- 优化 组件引用关系,通过uni_modules引用组件
+## 1.0.15(2021-02-05)
+- 调整为uni_modules目录规范
+- 修复 uni-list-chat 角标显示不正常的问题
diff --git a/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue b/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue
new file mode 100644
index 0000000..e256e4c
--- /dev/null
+++ b/uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue
@@ -0,0 +1,107 @@
+
+
+ |
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss
new file mode 100644
index 0000000..311f8d9
--- /dev/null
+++ b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.scss
@@ -0,0 +1,58 @@
+/**
+ * 这里是 uni-list 组件内置的常用样式变量
+ * 如果需要覆盖样式,这里提供了基本的组件样式变量,您可以尝试修改这里的变量,去完成样式替换,而不用去修改源码
+ *
+ */
+
+// 背景色
+$background-color : #fff;
+// 分割线颜色
+$divide-line-color : #e5e5e5;
+
+// 默认头像大小,如需要修改此值,注意同步修改 js 中的值 const avatarWidth = xx ,目前只支持方形头像
+// nvue 页面不支持修改头像大小
+$avatar-width : 45px ;
+
+// 头像边框
+$avatar-border-radius: 5px;
+$avatar-border-color: #eee;
+$avatar-border-width: 1px;
+
+// 标题文字样式
+$title-size : 16px;
+$title-color : #3b4144;
+$title-weight : normal;
+
+// 描述文字样式
+$note-size : 12px;
+$note-color : #999;
+$note-weight : normal;
+
+// 右侧额外内容默认样式
+$right-text-size : 12px;
+$right-text-color : #999;
+$right-text-weight : normal;
+
+// 角标样式
+// nvue 页面不支持修改圆点位置以及大小
+// 角标在左侧时,角标的位置,默认为 0 ,负数左/下移动,正数右/上移动
+$badge-left: 0px;
+$badge-top: 0px;
+
+// 显示圆点时,圆点大小
+$dot-width: 10px;
+$dot-height: 10px;
+
+// 显示角标时,角标大小和字体大小
+$badge-size : 18px;
+$badge-font : 12px;
+// 显示角标时,角标前景色
+$badge-color : #fff;
+// 显示角标时,角标背景色
+$badge-background-color : #ff5a5f;
+// 显示角标时,角标左右间距
+$badge-space : 6px;
+
+// 状态样式
+// 选中颜色
+$hover : #f5f5f5;
diff --git a/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue
new file mode 100644
index 0000000..a2de186
--- /dev/null
+++ b/uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue
@@ -0,0 +1,533 @@
+
+
+
+
+
+
+
+
+
+ {{ badgeText === 'dot' ? '' : badgeText }}
+
+
+
+ {{ title }}
+ {{ note }}
+
+
+
+
+
+
+ |
+
+
+
+
+
+
diff --git a/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue b/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue
new file mode 100644
index 0000000..c0ba12e
--- /dev/null
+++ b/uni_modules/uni-list/components/uni-list-item/uni-list-item.vue
@@ -0,0 +1,438 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ title }}
+ {{ note }}
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
diff --git a/uni_modules/uni-list/components/uni-list/uni-list.vue b/uni_modules/uni-list/components/uni-list/uni-list.vue
new file mode 100644
index 0000000..d478729
--- /dev/null
+++ b/uni_modules/uni-list/components/uni-list/uni-list.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-list/components/uni-list/uni-refresh.vue b/uni_modules/uni-list/components/uni-list/uni-refresh.vue
new file mode 100644
index 0000000..3b4c5a2
--- /dev/null
+++ b/uni_modules/uni-list/components/uni-list/uni-refresh.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-list/components/uni-list/uni-refresh.wxs b/uni_modules/uni-list/components/uni-list/uni-refresh.wxs
new file mode 100644
index 0000000..818a6b7
--- /dev/null
+++ b/uni_modules/uni-list/components/uni-list/uni-refresh.wxs
@@ -0,0 +1,87 @@
+var pullDown = {
+ threshold: 95,
+ maxHeight: 200,
+ callRefresh: 'onrefresh',
+ callPullingDown: 'onpullingdown',
+ refreshSelector: '.uni-refresh'
+};
+
+function ready(newValue, oldValue, ownerInstance, instance) {
+ var state = instance.getState()
+ state.canPullDown = newValue;
+ // console.log(newValue);
+}
+
+function touchStart(e, instance) {
+ var state = instance.getState();
+ state.refreshInstance = instance.selectComponent(pullDown.refreshSelector);
+ state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined);
+ if (!state.canPullDown) {
+ return
+ }
+
+ // console.log("touchStart");
+
+ state.height = 0;
+ state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY;
+ state.refreshInstance.setStyle({
+ 'height': 0
+ });
+ state.refreshInstance.callMethod("onchange", true);
+}
+
+function touchMove(e, ownerInstance) {
+ var instance = e.instance;
+ var state = instance.getState();
+ if (!state.canPullDown) {
+ return
+ }
+
+ var oldHeight = state.height;
+ var endY = e.touches[0].pageY || e.changedTouches[0].pageY;
+ var height = endY - state.touchStartY;
+ if (height > pullDown.maxHeight) {
+ return;
+ }
+
+ var refreshInstance = state.refreshInstance;
+ refreshInstance.setStyle({
+ 'height': height + 'px'
+ });
+
+ height = height < pullDown.maxHeight ? height : pullDown.maxHeight;
+ state.height = height;
+ refreshInstance.callMethod(pullDown.callPullingDown, {
+ height: height
+ });
+}
+
+function touchEnd(e, ownerInstance) {
+ var state = e.instance.getState();
+ if (!state.canPullDown) {
+ return
+ }
+
+ state.refreshInstance.callMethod("onchange", false);
+
+ var refreshInstance = state.refreshInstance;
+ if (state.height > pullDown.threshold) {
+ refreshInstance.callMethod(pullDown.callRefresh);
+ return;
+ }
+
+ refreshInstance.setStyle({
+ 'height': 0
+ });
+}
+
+function propObserver(newValue, oldValue, instance) {
+ pullDown = newValue;
+}
+
+module.exports = {
+ touchmove: touchMove,
+ touchstart: touchStart,
+ touchend: touchEnd,
+ propObserver: propObserver
+}
diff --git a/uni_modules/uni-list/package.json b/uni_modules/uni-list/package.json
new file mode 100644
index 0000000..3437e9e
--- /dev/null
+++ b/uni_modules/uni-list/package.json
@@ -0,0 +1,87 @@
+{
+ "id": "uni-list",
+ "displayName": "uni-list 列表",
+ "version": "1.0.17",
+ "description": "List 组件 ,帮助使用者快速构建列表。",
+ "keywords": [
+ "",
+ "uni-ui",
+ "uniui",
+ "列表",
+ "",
+ "list"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [
+ "uni-badge",
+ "uni-icons"
+ ],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-list/readme.md b/uni_modules/uni-list/readme.md
new file mode 100644
index 0000000..e4a5d73
--- /dev/null
+++ b/uni_modules/uni-list/readme.md
@@ -0,0 +1,347 @@
+
+
+## List 列表
+> **组件名:uni-list**
+> 代码块: `uList`、`uListItem`
+> 关联组件:`uni-list-item`、`uni-badge`、`uni-icons`、`uni-list-chat`、`uni-list-ad`
+
+
+List 列表组件,包含基本列表样式、可扩展插槽机制、长列表性能优化、多端兼容。
+
+在vue页面里,它默认使用页面级滚动。在app-nvue页面里,它默认使用原生list组件滚动。这样的长列表,在滚动出屏幕外后,系统会回收不可见区域的渲染内存资源,不会造成滚动越长手机越卡的问题。
+
+uni-list组件是父容器,里面的核心是uni-list-item子组件,它代表列表中的一个可重复行,子组件可以无限循环。
+
+uni-list-item有很多风格,uni-list-item组件通过内置的属性,满足一些常用的场景。当内置属性不满足需求时,可以通过扩展插槽来自定义列表内容。
+
+内置属性可以覆盖的场景包括:导航列表、设置列表、小图标列表、通信录列表、聊天记录列表。
+
+涉及很多大图或丰富内容的列表,比如类今日头条的新闻列表、类淘宝的电商列表,需要通过扩展插槽实现。
+
+下文均有样例给出。
+
+uni-list不包含下拉刷新和上拉翻页。上拉翻页另见组件:[uni-load-more](https://ext.dcloud.net.cn/plugin?id=29)
+
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+> **注意事项**
+> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
+> - 组件需要依赖 `sass` 插件 ,请自行手动安装
+> - 组件内部依赖 `'uni-icons'` 、`uni-badge` 组件
+> - `uni-list` 和 `uni-list-item` 需要配套使用,暂不支持单独使用 `uni-list-item`
+> - 只有开启点击反馈后,会有点击选中效果
+> - 使用插槽时,可以完全自定义内容
+> - note 、rightText 属性暂时没做限制,不支持文字溢出隐藏,使用时应该控制长度显示或通过默认插槽自行扩展
+> - 支付宝小程序平台需要在支付宝小程序开发者工具里开启 component2 编译模式,开启方式: 详情 --> 项目配置 --> 启用 component2 编译
+> - 如果需要修改 `switch`、`badge` 样式,请使用插槽自定义
+> - 在 `HBuilderX` 低版本中,可能会出现组件显示 `undefined` 的问题,请升级最新的 `HBuilderX` 或者 `cli`
+> - 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
+
+
+### 基本用法
+
+- 设置 `title` 属性,可以显示列表标题
+- 设置 `disabled` 属性,可以禁用当前项
+
+```html
+
+
+
+
+
+```
+
+### 多行内容显示
+
+- 设置 `note` 属性 ,可以在第二行显示描述文本信息
+
+```html
+
+
+
+
+
+```
+
+### 右侧显示角标、switch
+
+- 设置 `show-badge` 属性 ,可以显示角标内容
+- 设置 `show-switch` 属性,可以显示 switch 开关
+
+```html
+
+
+
+
+
+```
+
+### 左侧显示略缩图、图标
+
+- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图
+- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标
+
+```html
+
+
+
+
+```
+
+### 开启点击反馈和右侧箭头
+- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
+- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头
+- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
+
+```html
+
+
+
+
+
+
+
+```
+
+
+### 聊天列表示例
+- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
+- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
+- 设置 `to` 属性,可以跳转页面
+- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示
+- `avatar` 和 `avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效
+- 可以通过默认插槽自定义列表右侧内容
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 刚刚
+
+
+
+
+
+
+
+```
+
+```javascript
+
+export default {
+ components: {},
+ data() {
+ return {
+ avatarList: [{
+ url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
+ }, {
+ url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
+ }, {
+ url: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png'
+ }]
+ }
+ }
+}
+
+```
+
+
+```css
+
+.chat-custom-right {
+ flex: 1;
+ /* #ifndef APP-NVUE */
+ display: flex;
+ /* #endif */
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: flex-end;
+}
+
+.chat-custom-text {
+ font-size: 12px;
+ color: #999;
+}
+
+```
+
+## API
+
+### List Props
+
+属性名 |类型 |默认值 | 说明
+:-: |:-: |:-: | :-:
+border |Boolean |true | 是否显示边框
+
+
+### ListItem Props
+
+属性名 |类型 |默认值 | 说明
+:-: |:-: |:-: | :-:
+title |String |- | 标题
+note |String |- | 描述
+ellipsis |Number |0 | title 是否溢出隐藏,可选值,0:默认; 1:显示一行; 2:显示两行;【nvue 暂不支持】
+thumb |String |- | 左侧缩略图,若thumb有值,则不会显示扩展图标
+thumbSize |String |medium | 略缩图尺寸,可选值,lg:大图; medium:一般; sm:小图;
+showBadge |Boolean |false | 是否显示数字角标
+badgeText |String |- | 数字角标内容
+badgeType |String |- | 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21)
+rightText |String |- | 右侧文字内容
+disabled |Boolean |false | 是否禁用
+showArrow |Boolean |true | 是否显示箭头图标
+link |String |navigateTo | 新页面跳转方式,可选值见下表
+to |String |- | 新页面跳转地址,如填写此属性,click 会返回页面是否跳转成功
+clickable |Boolean |false | 是否开启点击反馈
+showSwitch |Boolean |false | 是否显示Switch
+switchChecked |Boolean |false | Switch是否被选中
+showExtraIcon |Boolean |false | 左侧是否显示扩展图标
+extraIcon |Object |- | 扩展图标参数,格式为 ``{color: '#4cd964',size: '22',type: 'spinner'}``,参考 [uni-icons](https://ext.dcloud.net.cn/plugin?id=28)
+direction | String |row | 排版方向,可选值,row:水平排列; column:垂直排列; 3个插槽是水平排还是垂直排,也受此属性控制
+
+
+#### Link Options
+
+属性名 | 说明
+:-: | :-:
+navigateTo | 同 uni.navigateTo()
+redirectTo | 同 uni.reLaunch()
+reLaunch | 同 uni.reLaunch()
+switchTab | 同 uni.switchTab()
+
+### ListItem Events
+
+事件称名 |说明 |返回参数
+:-: |:-: |:-:
+click |点击 uniListItem 触发事件,需开启点击反馈 |-
+switchChange |点击切换 Switch 时触发,需显示 switch |e={value:checked}
+
+
+
+### ListItem Slots
+
+名称 | 说明
+:-: | :-:
+header | 左/上内容插槽,可完全自定义默认显示
+body | 中间内容插槽,可完全自定义中间内容
+footer | 右/下内容插槽,可完全自定义右侧内容
+
+
+> **通过插槽扩展**
+> 需要注意的是当使用插槽时,内置样式将会失效,只保留排版样式,此时的样式需要开发者自己实现
+> 如果 `uni-list-item` 组件内置属性样式无法满足需求,可以使用插槽来自定义uni-list-item里的内容。
+> uni-list-item提供了3个可扩展的插槽:`header`、`body`、`footer`
+> - 当 `direction` 属性为 `row` 时表示水平排列,此时 `header` 表示列表的左边部分,`body` 表示列表的中间部分,`footer` 表示列表的右边部分
+> - 当 `direction` 属性为 `column` 时表示垂直排列,此时 `header` 表示列表的上边部分,`body` 表示列表的中间部分,`footer` 表示列表的下边部分
+> 开发者可以只用1个插槽,也可以3个一起使用。在插槽中可自主编写view标签,实现自己所需的效果。
+
+
+**示例**
+
+```html
+
+
+
+
+
+
+
+
+
+
+ 自定义插槽
+
+
+
+
+
+
+```
+
+
+
+
+
+### ListItemChat Props
+
+属性名 |类型 |默认值 | 说明
+:-: |:-: |:-: | :-:
+title |String |- | 标题
+note |String |- | 描述
+clickable |Boolean |false | 是否开启点击反馈
+badgeText |String |- | 数字角标内容,设置为 `dot` 将显示圆点
+badgePositon |String |right | 角标位置
+link |String |navigateTo | 是否展示右侧箭头并开启点击反馈,可选值见下表
+clickable |Boolean |false | 是否开启点击反馈
+to |String |- | 跳转页面地址,如填写此属性,click 会返回页面是否跳转成功
+time |String |- | 右侧时间显示
+avatarCircle |Boolean |false | 是否显示圆形头像
+avatar |String |- | 头像地址,avatarCircle 不填时生效
+avatarList |Array |- | 头像组,格式为 [{url:''}]
+
+#### Link Options
+
+属性名 | 说明
+:-: | :-:
+navigateTo | 同 uni.navigateTo()
+redirectTo | 同 uni.reLaunch()
+reLaunch | 同 uni.reLaunch()
+switchTab | 同 uni.switchTab()
+
+### ListItemChat Slots
+
+名称 | 说明
+:- | :-
+default | 自定义列表右侧内容(包括时间和角标显示)
+
+### ListItemChat Events
+事件称名 | 说明 | 返回参数
+:-: | :-: | :-:
+@click | 点击 uniListChat 触发事件 | {data:{}} ,如有 to 属性,会返回页面跳转信息
+
+
+
+
+
+
+## 基于uni-list扩展的页面模板
+
+通过扩展插槽,可实现多种常见样式的列表
+
+**新闻列表类**
+
+1. 云端一体混合布局:[https://ext.dcloud.net.cn/plugin?id=2546](https://ext.dcloud.net.cn/plugin?id=2546)
+2. 云端一体垂直布局,大图模式:[https://ext.dcloud.net.cn/plugin?id=2583](https://ext.dcloud.net.cn/plugin?id=2583)
+3. 云端一体垂直布局,多行图文混排:[https://ext.dcloud.net.cn/plugin?id=2584](https://ext.dcloud.net.cn/plugin?id=2584)
+4. 云端一体垂直布局,多图模式:[https://ext.dcloud.net.cn/plugin?id=2585](https://ext.dcloud.net.cn/plugin?id=2585)
+5. 云端一体水平布局,左图右文:[https://ext.dcloud.net.cn/plugin?id=2586](https://ext.dcloud.net.cn/plugin?id=2586)
+6. 云端一体水平布局,左文右图:[https://ext.dcloud.net.cn/plugin?id=2587](https://ext.dcloud.net.cn/plugin?id=2587)
+7. 云端一体垂直布局,无图模式,主标题+副标题:[https://ext.dcloud.net.cn/plugin?id=2588](https://ext.dcloud.net.cn/plugin?id=2588)
+
+**商品列表类**
+
+1. 云端一体列表/宫格视图互切:[https://ext.dcloud.net.cn/plugin?id=2651](https://ext.dcloud.net.cn/plugin?id=2651)
+2. 云端一体列表(宫格模式):[https://ext.dcloud.net.cn/plugin?id=2671](https://ext.dcloud.net.cn/plugin?id=2671)
+3. 云端一体列表(列表模式):[https://ext.dcloud.net.cn/plugin?id=2672](https://ext.dcloud.net.cn/plugin?id=2672)
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/list/list](https://hellouniapp.dcloud.net.cn/pages/extUI/list/list)
\ No newline at end of file
diff --git a/uni_modules/uni-load-more/changelog.md b/uni_modules/uni-load-more/changelog.md
new file mode 100644
index 0000000..42ffec1
--- /dev/null
+++ b/uni_modules/uni-load-more/changelog.md
@@ -0,0 +1,6 @@
+## 1.1.8(2021-05-12)
+- 新增 组件示例地址
+## 1.1.7(2021-03-30)
+- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug
+## 1.1.6(2021-02-05)
+- 调整为uni_modules目录规范
diff --git a/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue
new file mode 100644
index 0000000..a53a843
--- /dev/null
+++ b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue
@@ -0,0 +1,362 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ status === 'more' ? contentText.contentdown : status === 'loading' ? contentText.contentrefresh : contentText.contentnomore }}
+
+
+
+
+
+
diff --git a/uni_modules/uni-load-more/package.json b/uni_modules/uni-load-more/package.json
new file mode 100644
index 0000000..4fb6179
--- /dev/null
+++ b/uni_modules/uni-load-more/package.json
@@ -0,0 +1,82 @@
+{
+ "id": "uni-load-more",
+ "displayName": "uni-load-more 加载更多",
+ "version": "1.1.8",
+ "description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "加载更多",
+ "load-more"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+ "dcloudext": {
+ "category": [
+ "前端组件",
+ "通用组件"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "y"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-load-more/readme.md b/uni_modules/uni-load-more/readme.md
new file mode 100644
index 0000000..b781faf
--- /dev/null
+++ b/uni_modules/uni-load-more/readme.md
@@ -0,0 +1,70 @@
+
+
+### LoadMore 加载更多
+> **组件名:uni-load-more**
+> 代码块: `uLoadMore`
+
+
+用于列表中,做滚动加载使用,展示 loading 的各种状态。
+
+### 安装方式
+
+本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
+
+如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
+
+### 使用方式
+
+在 ``template`` 中使用组件
+
+```html
+
+```
+
+## API
+
+### LoadMore Props
+
+|属性名 |类型 | 可选值 |默认值 |说明 |
+|:-: |:-: |:-: |:-: |:-: |
+|iconSize |Number |- |24 |指定图标大小 |
+|status |String |more/loading/noMore |more |loading 的状态 |
+|showIcon |Boolean|- |true |是否显示 loading 图标 |
+|iconType |String |snow/circle/auto |auto |指定图标样式|
+|color |String |- |#777777 |图标和文字颜色 |
+|contentText|Object|- |{contentdown: "上拉显示更多",contentrefresh: "正在加载...",contentnomore: "没有更多数据了"}|各状态文字说明 |
+
+
+#### Status Options
+|参数名称 |说明 |
+|:-: |:-: |
+|more |loading前 |
+|loading|loading前中 |
+|more |没有更多数据 |
+
+#### IconType Options
+|参数名称 |说明 |
+|:-: |:-: |
+|snow |ios雪花加载样式 |
+|circle |安卓环形加载样式 |
+|auto |根据平台自动选择加载样式 |
+
+
+
+
+> **说明**
+> `iconType`为`snow`时,在`APP-NVUE`平台不可设置大小,在非`APP-NVUE`平台不可设置颜色
+
+
+
+### 事件说明
+
+|事件名 |说明 |返回值 |
+|:-: |:-: |:-: |
+|clickLoadMore |点击加载更多时触发 |e.detail={status:'loading'}|
+
+
+
+## 组件示例
+
+点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/load-more/load-more](https://hellouniapp.dcloud.net.cn/pages/extUI/load-more/load-more)
\ No newline at end of file
diff --git a/uni_modules/uni-scss/changelog.md b/uni_modules/uni-scss/changelog.md
new file mode 100644
index 0000000..b863bb0
--- /dev/null
+++ b/uni_modules/uni-scss/changelog.md
@@ -0,0 +1,8 @@
+## 1.0.3(2022-01-21)
+- 优化 组件示例
+## 1.0.2(2021-11-22)
+- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
+## 1.0.1(2021-11-22)
+- 修复 vue3中scss语法兼容问题
+## 1.0.0(2021-11-18)
+- init
diff --git a/uni_modules/uni-scss/index.scss b/uni_modules/uni-scss/index.scss
new file mode 100644
index 0000000..1744a5f
--- /dev/null
+++ b/uni_modules/uni-scss/index.scss
@@ -0,0 +1 @@
+@import './styles/index.scss';
diff --git a/uni_modules/uni-scss/package.json b/uni_modules/uni-scss/package.json
new file mode 100644
index 0000000..7cc0ccb
--- /dev/null
+++ b/uni_modules/uni-scss/package.json
@@ -0,0 +1,82 @@
+{
+ "id": "uni-scss",
+ "displayName": "uni-scss 辅助样式",
+ "version": "1.0.3",
+ "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。",
+ "keywords": [
+ "uni-scss",
+ "uni-ui",
+ "辅助样式"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": "^3.1.0"
+ },
+ "dcloudext": {
+ "category": [
+ "JS SDK",
+ "通用 SDK"
+ ],
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "n",
+ "联盟": "n"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-scss/readme.md b/uni_modules/uni-scss/readme.md
new file mode 100644
index 0000000..b7d1c25
--- /dev/null
+++ b/uni_modules/uni-scss/readme.md
@@ -0,0 +1,4 @@
+`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
diff --git a/uni_modules/uni-scss/styles/index.scss b/uni_modules/uni-scss/styles/index.scss
new file mode 100644
index 0000000..ffac4fe
--- /dev/null
+++ b/uni_modules/uni-scss/styles/index.scss
@@ -0,0 +1,7 @@
+@import './setting/_variables.scss';
+@import './setting/_border.scss';
+@import './setting/_color.scss';
+@import './setting/_space.scss';
+@import './setting/_radius.scss';
+@import './setting/_text.scss';
+@import './setting/_styles.scss';
diff --git a/uni_modules/uni-scss/styles/setting/_border.scss b/uni_modules/uni-scss/styles/setting/_border.scss
new file mode 100644
index 0000000..12a11c3
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_border.scss
@@ -0,0 +1,3 @@
+.uni-border {
+ border: 1px $uni-border-1 solid;
+}
\ No newline at end of file
diff --git a/uni_modules/uni-scss/styles/setting/_color.scss b/uni_modules/uni-scss/styles/setting/_color.scss
new file mode 100644
index 0000000..1ededd9
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_color.scss
@@ -0,0 +1,66 @@
+
+// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐
+// @mixin get-styles($k,$c) {
+// @if $k == size or $k == weight{
+// font-#{$k}:#{$c}
+// }@else{
+// #{$k}:#{$c}
+// }
+// }
+$uni-ui-color:(
+ // 主色
+ primary: $uni-primary,
+ primary-disable: $uni-primary-disable,
+ primary-light: $uni-primary-light,
+ // 辅助色
+ success: $uni-success,
+ success-disable: $uni-success-disable,
+ success-light: $uni-success-light,
+ warning: $uni-warning,
+ warning-disable: $uni-warning-disable,
+ warning-light: $uni-warning-light,
+ error: $uni-error,
+ error-disable: $uni-error-disable,
+ error-light: $uni-error-light,
+ info: $uni-info,
+ info-disable: $uni-info-disable,
+ info-light: $uni-info-light,
+ // 中性色
+ main-color: $uni-main-color,
+ base-color: $uni-base-color,
+ secondary-color: $uni-secondary-color,
+ extra-color: $uni-extra-color,
+ // 背景色
+ bg-color: $uni-bg-color,
+ // 边框颜色
+ border-1: $uni-border-1,
+ border-2: $uni-border-2,
+ border-3: $uni-border-3,
+ border-4: $uni-border-4,
+ // 黑色
+ black:$uni-black,
+ // 白色
+ white:$uni-white,
+ // 透明
+ transparent:$uni-transparent
+) !default;
+@each $key, $child in $uni-ui-color {
+ .uni-#{"" + $key} {
+ color: $child;
+ }
+ .uni-#{"" + $key}-bg {
+ background-color: $child;
+ }
+}
+.uni-shadow-sm {
+ box-shadow: $uni-shadow-sm;
+}
+.uni-shadow-base {
+ box-shadow: $uni-shadow-base;
+}
+.uni-shadow-lg {
+ box-shadow: $uni-shadow-lg;
+}
+.uni-mask {
+ background-color:$uni-mask;
+}
diff --git a/uni_modules/uni-scss/styles/setting/_radius.scss b/uni_modules/uni-scss/styles/setting/_radius.scss
new file mode 100644
index 0000000..9a0428b
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_radius.scss
@@ -0,0 +1,55 @@
+@mixin radius($r,$d:null ,$important: false){
+ $radius-value:map-get($uni-radius, $r) if($important, !important, null);
+ // Key exists within the $uni-radius variable
+ @if (map-has-key($uni-radius, $r) and $d){
+ @if $d == t {
+ border-top-left-radius:$radius-value;
+ border-top-right-radius:$radius-value;
+ }@else if $d == r {
+ border-top-right-radius:$radius-value;
+ border-bottom-right-radius:$radius-value;
+ }@else if $d == b {
+ border-bottom-left-radius:$radius-value;
+ border-bottom-right-radius:$radius-value;
+ }@else if $d == l {
+ border-top-left-radius:$radius-value;
+ border-bottom-left-radius:$radius-value;
+ }@else if $d == tl {
+ border-top-left-radius:$radius-value;
+ }@else if $d == tr {
+ border-top-right-radius:$radius-value;
+ }@else if $d == br {
+ border-bottom-right-radius:$radius-value;
+ }@else if $d == bl {
+ border-bottom-left-radius:$radius-value;
+ }
+ }@else{
+ border-radius:$radius-value;
+ }
+}
+
+@each $key, $child in $uni-radius {
+ @if($key){
+ .uni-radius-#{"" + $key} {
+ @include radius($key)
+ }
+ }@else{
+ .uni-radius {
+ @include radius($key)
+ }
+ }
+}
+
+@each $direction in t, r, b, l,tl, tr, br, bl {
+ @each $key, $child in $uni-radius {
+ @if($key){
+ .uni-radius-#{"" + $direction}-#{"" + $key} {
+ @include radius($key,$direction,false)
+ }
+ }@else{
+ .uni-radius-#{$direction} {
+ @include radius($key,$direction,false)
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-scss/styles/setting/_space.scss b/uni_modules/uni-scss/styles/setting/_space.scss
new file mode 100644
index 0000000..3c89528
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_space.scss
@@ -0,0 +1,56 @@
+
+@mixin fn($space,$direction,$size,$n) {
+ @if $n {
+ #{$space}-#{$direction}: #{$size*$uni-space-root}px
+ } @else {
+ #{$space}-#{$direction}: #{-$size*$uni-space-root}px
+ }
+}
+@mixin get-styles($direction,$i,$space,$n){
+ @if $direction == t {
+ @include fn($space, top,$i,$n);
+ }
+ @if $direction == r {
+ @include fn($space, right,$i,$n);
+ }
+ @if $direction == b {
+ @include fn($space, bottom,$i,$n);
+ }
+ @if $direction == l {
+ @include fn($space, left,$i,$n);
+ }
+ @if $direction == x {
+ @include fn($space, left,$i,$n);
+ @include fn($space, right,$i,$n);
+ }
+ @if $direction == y {
+ @include fn($space, top,$i,$n);
+ @include fn($space, bottom,$i,$n);
+ }
+ @if $direction == a {
+ @if $n {
+ #{$space}:#{$i*$uni-space-root}px;
+ } @else {
+ #{$space}:#{-$i*$uni-space-root}px;
+ }
+ }
+}
+
+@each $orientation in m,p {
+ $space: margin;
+ @if $orientation == m {
+ $space: margin;
+ } @else {
+ $space: padding;
+ }
+ @for $i from 0 through 16 {
+ @each $direction in t, r, b, l, x, y, a {
+ .uni-#{$orientation}#{$direction}-#{$i} {
+ @include get-styles($direction,$i,$space,true);
+ }
+ .uni-#{$orientation}#{$direction}-n#{$i} {
+ @include get-styles($direction,$i,$space,false);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uni_modules/uni-scss/styles/setting/_styles.scss b/uni_modules/uni-scss/styles/setting/_styles.scss
new file mode 100644
index 0000000..689afec
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_styles.scss
@@ -0,0 +1,167 @@
+/* #ifndef APP-NVUE */
+
+$-color-white:#fff;
+$-color-black:#000;
+@mixin base-style($color) {
+ color: #fff;
+ background-color: $color;
+ border-color: mix($-color-black, $color, 8%);
+ &:not([hover-class]):active {
+ background: mix($-color-black, $color, 10%);
+ border-color: mix($-color-black, $color, 20%);
+ color: $-color-white;
+ outline: none;
+ }
+}
+@mixin is-color($color) {
+ @include base-style($color);
+ &[loading] {
+ @include base-style($color);
+ &::before {
+ margin-right:5px;
+ }
+ }
+ &[disabled] {
+ &,
+ &[loading],
+ &:not([hover-class]):active {
+ color: $-color-white;
+ border-color: mix(darken($color,10%), $-color-white);
+ background-color: mix($color, $-color-white);
+ }
+ }
+
+}
+@mixin base-plain-style($color) {
+ color:$color;
+ background-color: mix($-color-white, $color, 90%);
+ border-color: mix($-color-white, $color, 70%);
+ &:not([hover-class]):active {
+ background: mix($-color-white, $color, 80%);
+ color: $color;
+ outline: none;
+ border-color: mix($-color-white, $color, 50%);
+ }
+}
+@mixin is-plain($color){
+ &[plain] {
+ @include base-plain-style($color);
+ &[loading] {
+ @include base-plain-style($color);
+ &::before {
+ margin-right:5px;
+ }
+ }
+ &[disabled] {
+ &,
+ &:active {
+ color: mix($-color-white, $color, 40%);
+ background-color: mix($-color-white, $color, 90%);
+ border-color: mix($-color-white, $color, 80%);
+ }
+ }
+ }
+}
+
+
+.uni-btn {
+ margin: 5px;
+ color: #393939;
+ border:1px solid #ccc;
+ font-size: 16px;
+ font-weight: 200;
+ background-color: #F9F9F9;
+ // TODO 暂时处理边框隐藏一边的问题
+ overflow: visible;
+ &::after{
+ border: none;
+ }
+
+ &:not([type]),&[type=default] {
+ color: #999;
+ &[loading] {
+ background: none;
+ &::before {
+ margin-right:5px;
+ }
+ }
+
+
+
+ &[disabled]{
+ color: mix($-color-white, #999, 60%);
+ &,
+ &[loading],
+ &:active {
+ color: mix($-color-white, #999, 60%);
+ background-color: mix($-color-white,$-color-black , 98%);
+ border-color: mix($-color-white, #999, 85%);
+ }
+ }
+
+ &[plain] {
+ color: #999;
+ background: none;
+ border-color: $uni-border-1;
+ &:not([hover-class]):active {
+ background: none;
+ color: mix($-color-white, $-color-black, 80%);
+ border-color: mix($-color-white, $-color-black, 90%);
+ outline: none;
+ }
+ &[disabled]{
+ &,
+ &[loading],
+ &:active {
+ background: none;
+ color: mix($-color-white, #999, 60%);
+ border-color: mix($-color-white, #999, 85%);
+ }
+ }
+ }
+ }
+
+ &:not([hover-class]):active {
+ color: mix($-color-white, $-color-black, 50%);
+ }
+
+ &[size=mini] {
+ font-size: 16px;
+ font-weight: 200;
+ border-radius: 8px;
+ }
+
+
+
+ &.uni-btn-small {
+ font-size: 14px;
+ }
+ &.uni-btn-mini {
+ font-size: 12px;
+ }
+
+ &.uni-btn-radius {
+ border-radius: 999px;
+ }
+ &[type=primary] {
+ @include is-color($uni-primary);
+ @include is-plain($uni-primary)
+ }
+ &[type=success] {
+ @include is-color($uni-success);
+ @include is-plain($uni-success)
+ }
+ &[type=error] {
+ @include is-color($uni-error);
+ @include is-plain($uni-error)
+ }
+ &[type=warning] {
+ @include is-color($uni-warning);
+ @include is-plain($uni-warning)
+ }
+ &[type=info] {
+ @include is-color($uni-info);
+ @include is-plain($uni-info)
+ }
+}
+/* #endif */
diff --git a/uni_modules/uni-scss/styles/setting/_text.scss b/uni_modules/uni-scss/styles/setting/_text.scss
new file mode 100644
index 0000000..a34d08f
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_text.scss
@@ -0,0 +1,24 @@
+@mixin get-styles($k,$c) {
+ @if $k == size or $k == weight{
+ font-#{$k}:#{$c}
+ }@else{
+ #{$k}:#{$c}
+ }
+}
+
+@each $key, $child in $uni-headings {
+ /* #ifndef APP-NVUE */
+ .uni-#{$key} {
+ @each $k, $c in $child {
+ @include get-styles($k,$c)
+ }
+ }
+ /* #endif */
+ /* #ifdef APP-NVUE */
+ .container .uni-#{$key} {
+ @each $k, $c in $child {
+ @include get-styles($k,$c)
+ }
+ }
+ /* #endif */
+}
diff --git a/uni_modules/uni-scss/styles/setting/_variables.scss b/uni_modules/uni-scss/styles/setting/_variables.scss
new file mode 100644
index 0000000..557d3d7
--- /dev/null
+++ b/uni_modules/uni-scss/styles/setting/_variables.scss
@@ -0,0 +1,146 @@
+// @use "sass:math";
+@import '../tools/functions.scss';
+// 间距基础倍数
+$uni-space-root: 2 !default;
+// 边框半径默认值
+$uni-radius-root:5px !default;
+$uni-radius: () !default;
+// 边框半径断点
+$uni-radius: map-deep-merge(
+ (
+ 0: 0,
+ // TODO 当前版本暂时不支持 sm 属性
+ // 'sm': math.div($uni-radius-root, 2),
+ null: $uni-radius-root,
+ 'lg': $uni-radius-root * 2,
+ 'xl': $uni-radius-root * 6,
+ 'pill': 9999px,
+ 'circle': 50%
+ ),
+ $uni-radius
+);
+// 字体家族
+$body-font-family: 'Roboto', sans-serif !default;
+// 文本
+$heading-font-family: $body-font-family !default;
+$uni-headings: () !default;
+$letterSpacing: -0.01562em;
+$uni-headings: map-deep-merge(
+ (
+ 'h1': (
+ size: 32px,
+ weight: 300,
+ line-height: 50px,
+ // letter-spacing:-0.01562em
+ ),
+ 'h2': (
+ size: 28px,
+ weight: 300,
+ line-height: 40px,
+ // letter-spacing: -0.00833em
+ ),
+ 'h3': (
+ size: 24px,
+ weight: 400,
+ line-height: 32px,
+ // letter-spacing: normal
+ ),
+ 'h4': (
+ size: 20px,
+ weight: 400,
+ line-height: 30px,
+ // letter-spacing: 0.00735em
+ ),
+ 'h5': (
+ size: 16px,
+ weight: 400,
+ line-height: 24px,
+ // letter-spacing: normal
+ ),
+ 'h6': (
+ size: 14px,
+ weight: 500,
+ line-height: 18px,
+ // letter-spacing: 0.0125em
+ ),
+ 'subtitle': (
+ size: 12px,
+ weight: 400,
+ line-height: 20px,
+ // letter-spacing: 0.00937em
+ ),
+ 'body': (
+ font-size: 14px,
+ font-weight: 400,
+ line-height: 22px,
+ // letter-spacing: 0.03125em
+ ),
+ 'caption': (
+ 'size': 12px,
+ 'weight': 400,
+ 'line-height': 20px,
+ // 'letter-spacing': 0.03333em,
+ // 'text-transform': false
+ )
+ ),
+ $uni-headings
+);
+
+
+
+// 主色
+$uni-primary: #2979ff !default;
+$uni-primary-disable:lighten($uni-primary,20%) !default;
+$uni-primary-light: lighten($uni-primary,25%) !default;
+
+// 辅助色
+// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
+$uni-success: #18bc37 !default;
+$uni-success-disable:lighten($uni-success,20%) !default;
+$uni-success-light: lighten($uni-success,25%) !default;
+
+$uni-warning: #f3a73f !default;
+$uni-warning-disable:lighten($uni-warning,20%) !default;
+$uni-warning-light: lighten($uni-warning,25%) !default;
+
+$uni-error: #e43d33 !default;
+$uni-error-disable:lighten($uni-error,20%) !default;
+$uni-error-light: lighten($uni-error,25%) !default;
+
+$uni-info: #8f939c !default;
+$uni-info-disable:lighten($uni-info,20%) !default;
+$uni-info-light: lighten($uni-info,25%) !default;
+
+// 中性色
+// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
+$uni-main-color: #3a3a3a !default; // 主要文字
+$uni-base-color: #6a6a6a !default; // 常规文字
+$uni-secondary-color: #909399 !default; // 次要文字
+$uni-extra-color: #c7c7c7 !default; // 辅助说明
+
+// 边框颜色
+$uni-border-1: #F0F0F0 !default;
+$uni-border-2: #EDEDED !default;
+$uni-border-3: #DCDCDC !default;
+$uni-border-4: #B9B9B9 !default;
+
+// 常规色
+$uni-black: #000000 !default;
+$uni-white: #ffffff !default;
+$uni-transparent: rgba($color: #000000, $alpha: 0) !default;
+
+// 背景色
+$uni-bg-color: #f7f7f7 !default;
+
+/* 水平间距 */
+$uni-spacing-sm: 8px !default;
+$uni-spacing-base: 15px !default;
+$uni-spacing-lg: 30px !default;
+
+// 阴影
+$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default;
+$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
+$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default;
+
+// 蒙版
+$uni-mask: rgba($color: #000000, $alpha: 0.4) !default;
diff --git a/uni_modules/uni-scss/styles/tools/functions.scss b/uni_modules/uni-scss/styles/tools/functions.scss
new file mode 100644
index 0000000..ac6f63e
--- /dev/null
+++ b/uni_modules/uni-scss/styles/tools/functions.scss
@@ -0,0 +1,19 @@
+// 合并 map
+@function map-deep-merge($parent-map, $child-map){
+ $result: $parent-map;
+ @each $key, $child in $child-map {
+ $parent-has-key: map-has-key($result, $key);
+ $parent-value: map-get($result, $key);
+ $parent-type: type-of($parent-value);
+ $child-type: type-of($child);
+ $parent-is-map: $parent-type == map;
+ $child-is-map: $child-type == map;
+
+ @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){
+ $result: map-merge($result, ( $key: $child ));
+ }@else {
+ $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) ));
+ }
+ }
+ @return $result;
+};
diff --git a/uni_modules/uni-scss/theme.scss b/uni_modules/uni-scss/theme.scss
new file mode 100644
index 0000000..80ee62f
--- /dev/null
+++ b/uni_modules/uni-scss/theme.scss
@@ -0,0 +1,31 @@
+// 间距基础倍数
+$uni-space-root: 2;
+// 边框半径默认值
+$uni-radius-root:5px;
+// 主色
+$uni-primary: #2979ff;
+// 辅助色
+$uni-success: #4cd964;
+// 警告色
+$uni-warning: #f0ad4e;
+// 错误色
+$uni-error: #dd524d;
+// 描述色
+$uni-info: #909399;
+// 中性色
+$uni-main-color: #303133;
+$uni-base-color: #606266;
+$uni-secondary-color: #909399;
+$uni-extra-color: #C0C4CC;
+// 背景色
+$uni-bg-color: #f5f5f5;
+// 边框颜色
+$uni-border-1: #DCDFE6;
+$uni-border-2: #E4E7ED;
+$uni-border-3: #EBEEF5;
+$uni-border-4: #F2F6FC;
+
+// 常规色
+$uni-black: #000000;
+$uni-white: #ffffff;
+$uni-transparent: rgba($color: #000000, $alpha: 0);
diff --git a/uni_modules/uni-scss/variables.scss b/uni_modules/uni-scss/variables.scss
new file mode 100644
index 0000000..1c062d4
--- /dev/null
+++ b/uni_modules/uni-scss/variables.scss
@@ -0,0 +1,62 @@
+@import './styles/setting/_variables.scss';
+// 间距基础倍数
+$uni-space-root: 2;
+// 边框半径默认值
+$uni-radius-root:5px;
+
+// 主色
+$uni-primary: #2979ff;
+$uni-primary-disable:mix(#fff,$uni-primary,50%);
+$uni-primary-light: mix(#fff,$uni-primary,80%);
+
+// 辅助色
+// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。
+$uni-success: #18bc37;
+$uni-success-disable:mix(#fff,$uni-success,50%);
+$uni-success-light: mix(#fff,$uni-success,80%);
+
+$uni-warning: #f3a73f;
+$uni-warning-disable:mix(#fff,$uni-warning,50%);
+$uni-warning-light: mix(#fff,$uni-warning,80%);
+
+$uni-error: #e43d33;
+$uni-error-disable:mix(#fff,$uni-error,50%);
+$uni-error-light: mix(#fff,$uni-error,80%);
+
+$uni-info: #8f939c;
+$uni-info-disable:mix(#fff,$uni-info,50%);
+$uni-info-light: mix(#fff,$uni-info,80%);
+
+// 中性色
+// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。
+$uni-main-color: #3a3a3a; // 主要文字
+$uni-base-color: #6a6a6a; // 常规文字
+$uni-secondary-color: #909399; // 次要文字
+$uni-extra-color: #c7c7c7; // 辅助说明
+
+// 边框颜色
+$uni-border-1: #F0F0F0;
+$uni-border-2: #EDEDED;
+$uni-border-3: #DCDCDC;
+$uni-border-4: #B9B9B9;
+
+// 常规色
+$uni-black: #000000;
+$uni-white: #ffffff;
+$uni-transparent: rgba($color: #000000, $alpha: 0);
+
+// 背景色
+$uni-bg-color: #f7f7f7;
+
+/* 水平间距 */
+$uni-spacing-sm: 8px;
+$uni-spacing-base: 15px;
+$uni-spacing-lg: 30px;
+
+// 阴影
+$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5);
+$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2);
+$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5);
+
+// 蒙版
+$uni-mask: rgba($color: #000000, $alpha: 0.4);
diff --git a/utils/date.js b/utils/date.js
new file mode 100644
index 0000000..7209486
--- /dev/null
+++ b/utils/date.js
@@ -0,0 +1,59 @@
+// 日期工具函数
+
+// 格式化日期
+export function formatDate(date, format = 'YYYY-MM-DD') {
+ if (!date) return ''
+
+ const d = new Date(date)
+ const year = d.getFullYear()
+ const month = String(d.getMonth() + 1).padStart(2, '0')
+ const day = String(d.getDate()).padStart(2, '0')
+ const hour = String(d.getHours()).padStart(2, '0')
+ const minute = String(d.getMinutes()).padStart(2, '0')
+ const second = String(d.getSeconds()).padStart(2, '0')
+
+ return format
+ .replace('YYYY', year)
+ .replace('MM', month)
+ .replace('DD', day)
+ .replace('HH', hour)
+ .replace('mm', minute)
+ .replace('ss', second)
+}
+
+// 格式化日期为中国格式 (例如: 2025年1月1日 13:40 星期三)
+export function formatChineseDate(date) {
+ if (!date) return ''
+
+ const d = new Date(date)
+ const year = d.getFullYear()
+ const month = d.getMonth() + 1
+ const day = d.getDate()
+ const hour = String(d.getHours()).padStart(2, '0')
+ const minute = String(d.getMinutes()).padStart(2, '0')
+
+ const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
+ const weekday = weekdays[d.getDay()]
+
+ return `${year}年${month}月${day}日 ${hour}:${minute} ${weekday}`
+}
+
+// 获取周的开始日期
+export function getWeekStart(date = new Date()) {
+ const d = new Date(date)
+ const day = d.getDay()
+ const diff = d.getDate() - day + (day === 0 ? -6 : 1) // 周一
+ return new Date(d.setDate(diff))
+}
+
+// 获取月的开始日期
+export function getMonthStart(date = new Date()) {
+ const d = new Date(date)
+ return new Date(d.getFullYear(), d.getMonth(), 1)
+}
+
+// 获取月的结束日期
+export function getMonthEnd(date = new Date()) {
+ const d = new Date(date)
+ return new Date(d.getFullYear(), d.getMonth() + 1, 0)
+}
diff --git a/utils/request.js b/utils/request.js
new file mode 100644
index 0000000..b8169ac
--- /dev/null
+++ b/utils/request.js
@@ -0,0 +1,185 @@
+// HTTP请求封装
+const BASE_URL = process.env.NODE_ENV === 'development'
+ ? 'http://localhost:8080/api'
+ : 'https://your-api-domain.com/api'
+
+// 获取token
+function getToken() {
+ return uni.getStorageSync('token') || ''
+}
+
+// 请求拦截器
+function request(options) {
+ return new Promise((resolve, reject) => {
+ // 显示加载提示
+ if (options.loading !== false) {
+ uni.showLoading({
+ title: '加载中...',
+ mask: true
+ })
+ }
+
+ uni.request({
+ url: BASE_URL + options.url,
+ method: options.method || 'GET',
+ data: options.data || {},
+ header: {
+ 'Content-Type': options.contentType || 'application/json',
+ 'Authorization': 'Bearer ' + getToken(),
+ ...options.header
+ },
+ success: (res) => {
+ uni.hideLoading()
+
+ if (res.statusCode === 200) {
+ if (res.data.code === 200 || res.data.code === undefined) {
+ resolve(res.data)
+ } else {
+ // 业务错误
+ if (res.data.code === 401) {
+ // token过期,跳转到登录页
+ uni.removeStorageSync('token')
+ uni.removeStorageSync('userInfo')
+ uni.reLaunch({
+ url: '/pages/login/login'
+ })
+ }
+ uni.showToast({
+ title: res.data.message || '请求失败',
+ icon: 'none'
+ })
+ reject(res.data)
+ }
+ } else if (res.statusCode === 401) {
+ // 未授权,跳转到登录页
+ uni.removeStorageSync('token')
+ uni.removeStorageSync('userInfo')
+ uni.reLaunch({
+ url: '/pages/login/login'
+ })
+ reject(res)
+ } else {
+ uni.showToast({
+ title: '请求失败',
+ icon: 'none'
+ })
+ reject(res)
+ }
+ },
+ fail: (err) => {
+ uni.hideLoading()
+ uni.showToast({
+ title: '网络错误',
+ icon: 'none'
+ })
+ reject(err)
+ }
+ })
+ })
+}
+
+// GET请求
+export function get(url, data, options = {}) {
+ return request({
+ url,
+ method: 'GET',
+ data,
+ ...options
+ })
+}
+
+// POST请求
+export function post(url, data, options = {}) {
+ return request({
+ url,
+ method: 'POST',
+ data,
+ ...options
+ })
+}
+
+// PUT请求
+export function put(url, data, options = {}) {
+ return request({
+ url,
+ method: 'PUT',
+ data,
+ ...options
+ })
+}
+
+// DELETE请求
+export function del(url, data, options = {}) {
+ return request({
+ url,
+ method: 'DELETE',
+ data,
+ ...options
+ })
+}
+
+// 文件上传
+export function upload(url, filePath, options = {}) {
+ return new Promise((resolve, reject) => {
+ uni.showLoading({
+ title: '上传中...',
+ mask: true
+ })
+
+ uni.uploadFile({
+ url: BASE_URL + url,
+ filePath: filePath,
+ name: 'file',
+ header: {
+ 'Authorization': 'Bearer ' + getToken()
+ },
+ formData: options.formData || {},
+ success: (res) => {
+ uni.hideLoading()
+ try {
+ const data = JSON.parse(res.data)
+ if (res.statusCode === 200) {
+ resolve(data)
+ } else {
+ uni.showToast({
+ title: data.message || '上传失败',
+ icon: 'none'
+ })
+ reject(data)
+ }
+ } catch (e) {
+ uni.showToast({
+ title: '上传失败',
+ icon: 'none'
+ })
+ reject(e)
+ }
+ },
+ fail: (err) => {
+ uni.hideLoading()
+ uni.showToast({
+ title: '上传失败',
+ icon: 'none'
+ })
+ reject(err)
+ }
+ })
+ })
+}
+
+export default {
+ get,
+ post,
+ put,
+ delete: del,
+ upload
+}
+
+
+
+
+
+
+
+
+