前端初始化
This commit is contained in:
commit
71bc2db985
132
.gitignore
vendored
Normal file
132
.gitignore
vendored
Normal file
@ -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/
|
||||
23
.hbuilderx/launch.json
Normal file
23
.hbuilderx/launch.json
Normal file
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
20
App.vue
Normal file
20
App.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<script>
|
||||
import { useUserStore } from './store/user'
|
||||
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/*每个页面公共css */
|
||||
@import './static/css/common.css';
|
||||
</style>
|
||||
82
DEBUG.md
Normal file
82
DEBUG.md
Normal file
@ -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. 页面源代码(右键页面 → 查看网页源代码)
|
||||
|
||||
|
||||
|
||||
|
||||
74
DIAGNOSIS.md
Normal file
74
DIAGNOSIS.md
Normal file
@ -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元素的内容是什么?
|
||||
- 是否有任何内容被渲染?
|
||||
|
||||
|
||||
|
||||
|
||||
67
FILES_CHECKLIST.md
Normal file
67
FILES_CHECKLIST.md
Normal file
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
174
ICONS_GUIDE.md
Normal file
174
ICONS_GUIDE.md
Normal file
@ -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. 完成!
|
||||
|
||||
83
QUICK_FIX.md
Normal file
83
QUICK_FIX.md
Normal file
@ -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
|
||||
<template>
|
||||
<view style="padding: 100px; text-align: center;">
|
||||
<text style="font-size: 32px;">登录页面测试</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
onLoad() {
|
||||
console.log('登录页面加载')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 方案四:检查文件路径
|
||||
|
||||
确保文件路径正确:
|
||||
- `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. 提供具体的错误信息以便进一步排查
|
||||
|
||||
|
||||
|
||||
|
||||
158
README.md
Normal file
158
README.md
Normal file
@ -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集成)
|
||||
47
TROUBLESHOOTING.md
Normal file
47
TROUBLESHOOTING.md
Normal file
@ -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地址配置。
|
||||
|
||||
|
||||
|
||||
|
||||
20
api/auth.js
Normal file
20
api/auth.js
Normal file
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
35
api/bill.js
Normal file
35
api/bill.js
Normal file
@ -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}`)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
30
api/category.js
Normal file
30
api/category.js
Normal file
@ -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}`)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
15
api/ocr.js
Normal file
15
api/ocr.js
Normal file
@ -0,0 +1,15 @@
|
||||
import { upload } from '../utils/request'
|
||||
|
||||
// OCR识别
|
||||
export function recognizeImage(filePath) {
|
||||
return upload('/ocr/recognize', filePath)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
api/statistics.js
Normal file
25
api/statistics.js
Normal file
@ -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 })
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
120
common/uni-ui.scss
Normal file
120
common/uni-ui.scss
Normal file
@ -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;
|
||||
}
|
||||
12
components/uni-section/config.json
Normal file
12
components/uni-section/config.json
Normal file
@ -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": []
|
||||
}
|
||||
30
components/uni-section/readme.md
Normal file
30
components/uni-section/readme.md
Normal file
@ -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
|
||||
<uni-section title="只有主标题"></uni-section>
|
||||
<uni-section title="竖线装饰" sub-title="副标题" type="line"></uni-section>
|
||||
<uni-section title="圆形装饰" sub-title="副标题" type="circle"></uni-section>
|
||||
```
|
||||
|
||||
### 属性说明
|
||||
|
||||
|属性名 |类型 |默认值 |说明 |
|
||||
|--- |---- |--- |--- |
|
||||
|type |String |- |标题装饰类型 ,可选值:line(竖线)、circle(圆形)|
|
||||
|title |String |- |主标题 |
|
||||
|sub-title |String |- |副标题 |
|
||||
136
components/uni-section/uni-section.vue
Normal file
136
components/uni-section/uni-section.vue
Normal file
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<view class="uni-section" nvue>
|
||||
<view v-if="type" class="uni-section__head">
|
||||
<view :class="type" class="uni-section__head-tag" />
|
||||
</view>
|
||||
<view class="uni-section__content">
|
||||
<text :class="{'distraction':!subTitle}" class="uni-section__content-title">{{ title }}</text>
|
||||
<text v-if="subTitle" class="uni-section__content-sub">{{ subTitle }}</text>
|
||||
</view>
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
/**
|
||||
* Section 标题栏
|
||||
* @description 标题栏
|
||||
* @property {String} type = [line|circle] 标题装饰类型
|
||||
* @value line 竖线
|
||||
* @value circle 圆形
|
||||
* @property {String} title 主标题
|
||||
* @property {String} subTitle 副标题
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'UniSection',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
subTitle: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
title(newVal) {
|
||||
if (uni.report && newVal !== '') {
|
||||
uni.report('title', newVal)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.uni-section {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
margin-top: 10px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
height: 50px;
|
||||
background-color: $uni-bg-color-grey;
|
||||
/* #ifdef APP-NVUE */
|
||||
// border-bottom-color: $uni-border-color;
|
||||
// border-bottom-style: solid;
|
||||
// border-bottom-width: 0.5px;
|
||||
/* #endif */
|
||||
font-weight: normal;
|
||||
}
|
||||
/* #ifndef APP-NVUE */
|
||||
// .uni-section:after {
|
||||
// position: absolute;
|
||||
// bottom: 0;
|
||||
// right: 0;
|
||||
// left: 0;
|
||||
// height: 1px;
|
||||
// content: '';
|
||||
// -webkit-transform: scaleY(.5);
|
||||
// transform: scaleY(.5);
|
||||
// background-color: $uni-border-color;
|
||||
// }
|
||||
/* #endif */
|
||||
|
||||
.uni-section__head {
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 15px;
|
||||
background-color: $uni-text-color-disable;
|
||||
border-radius: 5px;
|
||||
width: 3px;
|
||||
}
|
||||
|
||||
.circle {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-top-right-radius: 50px;
|
||||
border-top-left-radius: 50px;
|
||||
border-bottom-left-radius: 50px;
|
||||
border-bottom-right-radius: 50px;
|
||||
background-color: $uni-text-color-disable;
|
||||
}
|
||||
|
||||
.uni-section__content {
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
color: $uni-text-color;
|
||||
}
|
||||
|
||||
.uni-section__content-title {
|
||||
font-size: $uni-font-size-base;
|
||||
color: $uni-text-color;
|
||||
}
|
||||
|
||||
.distraction {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-section__content-sub {
|
||||
font-size: $uni-font-size-sm;
|
||||
color: $uni-text-color-grey;
|
||||
}
|
||||
</style>
|
||||
26
index.html
Normal file
26
index.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>强宝爱记账</title>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
#app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
12
main.js
Normal file
12
main.js
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
71
manifest.json
Normal file
71
manifest.json
Normal file
@ -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": [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>"
|
||||
]
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
906
package-lock.json
generated
Normal file
906
package-lock.json
generated
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
package.json
Normal file
21
package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
74
pages.json
Normal file
74
pages.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
895
pages/add/add.vue
Normal file
895
pages/add/add.vue
Normal file
@ -0,0 +1,895 @@
|
||||
<template>
|
||||
<scroll-view scroll-y class="page-scroll" :scroll-top="pageScrollTop">
|
||||
<view class="container">
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{ active: activeTab === 'manual' }" @click="activeTab = 'manual'">
|
||||
手动记账
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeTab === 'ocr' }" @click="activeTab = 'ocr'">
|
||||
OCR识别
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手动记账 -->
|
||||
<view v-if="activeTab === 'manual'" class="form">
|
||||
<view class="form-item">
|
||||
<text class="label">账单类型</text>
|
||||
<view class="type-selector-compact">
|
||||
<view
|
||||
class="type-option-compact"
|
||||
:class="{ active: form.type === 1 }"
|
||||
@click="form.type = 1"
|
||||
>
|
||||
<text class="type-icon-compact">📤</text>
|
||||
<text class="type-text-compact">支出</text>
|
||||
</view>
|
||||
<view
|
||||
class="type-option-compact"
|
||||
:class="{ active: form.type === 2 }"
|
||||
@click="form.type = 2"
|
||||
>
|
||||
<text class="type-icon-compact">📥</text>
|
||||
<text class="type-text-compact">收入</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">分类</text>
|
||||
<view v-if="categories.length > 0" class="category-grid">
|
||||
<view
|
||||
v-for="category in categories"
|
||||
:key="category.id"
|
||||
class="category-icon-item"
|
||||
:class="{ active: selectedCategory?.id === category.id }"
|
||||
@click="selectCategory(category)"
|
||||
>
|
||||
<view class="category-icon-circle">
|
||||
<text class="category-icon-emoji">{{ category.icon || '📦' }}</text>
|
||||
</view>
|
||||
<text class="category-icon-name">{{ category.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="category-empty">
|
||||
<text>暂无分类,请先创建分类</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">金额</text>
|
||||
<input
|
||||
v-model="form.amount"
|
||||
type="number"
|
||||
inputmode="decimal"
|
||||
placeholder="请输入金额"
|
||||
@input="onAmountInput"
|
||||
@focus="onAmountFocus"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">日期</text>
|
||||
<picker mode="date" v-model="form.billDate" @change="onDateChange">
|
||||
<view class="picker">
|
||||
<text>{{ form.billDate || '选择日期' }}</text>
|
||||
<text class="arrow">></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">备注</text>
|
||||
<textarea v-model="form.description" placeholder="请输入备注(可选)" class="textarea" />
|
||||
</view>
|
||||
|
||||
<button class="submit-btn" @click="submitBill">保存</button>
|
||||
</view>
|
||||
|
||||
<!-- OCR识别 -->
|
||||
<view v-if="activeTab === 'ocr'" class="ocr-container">
|
||||
<!-- 图片预览区域(可折叠) -->
|
||||
<view class="image-section">
|
||||
<view class="section-header" @click="toggleImageSection">
|
||||
<text class="section-title">图片预览</text>
|
||||
<text class="expand-icon">{{ imageSectionExpanded ? '▼' : '▶' }}</text>
|
||||
</view>
|
||||
<view v-if="imageSectionExpanded" class="section-content">
|
||||
<view class="upload-area" @click="chooseImage">
|
||||
<image v-if="imagePath" :src="imagePath" class="preview-image" mode="aspectFit" />
|
||||
<view v-else class="upload-placeholder">
|
||||
<text class="upload-icon">📷</text>
|
||||
<text>点击选择图片</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<button v-if="imagePath && ocrResultList.length === 0" class="recognize-btn" @click="recognizeImage" :loading="recognizing">
|
||||
识别账单
|
||||
</button>
|
||||
|
||||
<!-- OCR识别结果列表(可折叠) -->
|
||||
<view v-if="ocrResultList.length > 0" class="ocr-result-list-container">
|
||||
<view class="section-header" @click="toggleResultList">
|
||||
<text class="list-title">识别到 {{ ocrResultList.length }} 条账单记录</text>
|
||||
<text class="expand-icon">{{ resultListExpanded ? '▼' : '▶' }}</text>
|
||||
</view>
|
||||
<view v-if="resultListExpanded" class="section-content">
|
||||
<view class="result-list-wrapper">
|
||||
<view v-for="(item, index) in ocrResultList" :key="index" class="result-card" :class="{ active: selectedOcrResult === item, expanded: expandedCards.has(index) }">
|
||||
<view class="result-header" @click.stop="toggleCard(index)">
|
||||
<view class="header-left">
|
||||
<text class="result-index">#{{ index + 1 }}</text>
|
||||
<text class="result-value amount summary">¥{{ item.amount }}</text>
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<text v-if="item.confidence" class="result-confidence">置信度: {{ (item.confidence * 100).toFixed(1) }}%</text>
|
||||
<text class="expand-icon">{{ expandedCards.has(index) ? '▼' : '▶' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="expandedCards.has(index)" class="result-details">
|
||||
<view class="result-item">
|
||||
<text class="result-label">金额:</text>
|
||||
<text class="result-value amount">¥{{ item.amount ? Math.abs(item.amount).toFixed(2) : '0.00' }}</text>
|
||||
</view>
|
||||
<view v-if="item.merchant" class="result-item">
|
||||
<text class="result-label">商户:</text>
|
||||
<text class="result-value">{{ item.merchant }}</text>
|
||||
</view>
|
||||
<view v-if="item.date" class="result-item">
|
||||
<text class="result-label">日期:</text>
|
||||
<text class="result-value">{{ formatOcrDate(item.date) }}</text>
|
||||
</view>
|
||||
<button class="select-btn" @click.stop="goToManualWithOcrData(item)">选择此条</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { createBill } from '../../api/bill'
|
||||
import { getCategories } from '../../api/category'
|
||||
import { recognizeImage as ocrRecognize } from '../../api/ocr'
|
||||
import { formatDate } from '../../utils/date'
|
||||
|
||||
const activeTab = ref('manual')
|
||||
const categories = ref([])
|
||||
const selectedCategory = ref(null)
|
||||
const imagePath = ref('')
|
||||
const recognizing = ref(false)
|
||||
const ocrResultList = ref([])
|
||||
const selectedOcrResult = ref(null)
|
||||
const expandedCards = ref(new Set()) // 存储展开的卡片索引
|
||||
const imageSectionExpanded = ref(true) // 图片预览区域展开状态
|
||||
const resultListExpanded = ref(true) // 结果列表展开状态
|
||||
const pageScrollTop = ref(0) // 页面滚动位置
|
||||
|
||||
const form = ref({
|
||||
type: 1, // 1-支出,2-收入,默认支出
|
||||
categoryId: null,
|
||||
amount: '',
|
||||
description: '',
|
||||
billDate: formatDate(new Date()),
|
||||
imageUrl: ''
|
||||
})
|
||||
|
||||
const loadCategories = async () => {
|
||||
try {
|
||||
// 根据账单类型加载对应的分类(1-支出,2-收入)
|
||||
const type = form.value.type || 1
|
||||
const data = await getCategories(type)
|
||||
categories.value = data || []
|
||||
// 如果当前选中的分类不在新类型中,清空选择
|
||||
if (selectedCategory.value && selectedCategory.value.type !== type) {
|
||||
selectedCategory.value = null
|
||||
form.value.categoryId = null
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载分类失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 监听账单类型变化,重新加载分类
|
||||
watch(() => form.value.type, (newType) => {
|
||||
if (newType) {
|
||||
loadCategories()
|
||||
}
|
||||
})
|
||||
|
||||
// 监听账单类型变化,重新加载分类
|
||||
watch(() => form.value.type, (newType) => {
|
||||
if (newType) {
|
||||
loadCategories()
|
||||
}
|
||||
})
|
||||
|
||||
const chooseImage = () => {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['camera', 'album'],
|
||||
success: (res) => {
|
||||
imagePath.value = res.tempFilePaths[0]
|
||||
ocrResultList.value = []
|
||||
selectedOcrResult.value = null
|
||||
expandedCards.value.clear()
|
||||
form.value.amount = ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const recognizeImage = async () => {
|
||||
if (!imagePath.value) {
|
||||
uni.showToast({
|
||||
title: '请先选择图片',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
recognizing.value = true
|
||||
try {
|
||||
const resultList = await ocrRecognize(imagePath.value)
|
||||
// 后端返回的是数组
|
||||
ocrResultList.value = Array.isArray(resultList) ? resultList : [resultList]
|
||||
|
||||
if (ocrResultList.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: '未识别到账单信息',
|
||||
icon: 'none'
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: `识别到 ${ocrResultList.value.length} 条记录`,
|
||||
icon: 'success'
|
||||
})
|
||||
// 如果只有一条,自动选中并展开
|
||||
if (ocrResultList.value.length === 1) {
|
||||
expandedCards.value.add(0)
|
||||
selectOcrResult(ocrResultList.value[0])
|
||||
} else if (ocrResultList.value.length > 0) {
|
||||
// 多条记录时,默认展开第一条
|
||||
expandedCards.value.add(0)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('OCR识别失败:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '识别失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
recognizing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const scrollTop = ref(0)
|
||||
|
||||
const toggleImageSection = () => {
|
||||
imageSectionExpanded.value = !imageSectionExpanded.value
|
||||
}
|
||||
|
||||
const toggleResultList = () => {
|
||||
resultListExpanded.value = !resultListExpanded.value
|
||||
}
|
||||
|
||||
const toggleCard = (index) => {
|
||||
if (expandedCards.value.has(index)) {
|
||||
expandedCards.value.delete(index)
|
||||
} else {
|
||||
expandedCards.value.add(index)
|
||||
}
|
||||
}
|
||||
|
||||
const goToManualWithOcrData = (item) => {
|
||||
// 根据金额正负判断账单类型
|
||||
// 负数 -> 支出(type: 1),正数 -> 收入(type: 2)
|
||||
const amount = parseFloat(item.amount) || 0
|
||||
const billType = amount < 0 ? 1 : 2 // 1-支出,2-收入
|
||||
|
||||
// 保存OCR识别数据到本地存储
|
||||
const ocrData = {
|
||||
amount: Math.abs(amount).toString(), // 金额取绝对值
|
||||
billDate: item.date ? formatOcrDate(item.date) : formatDate(new Date()),
|
||||
description: item.merchant || '',
|
||||
type: billType, // 根据金额正负设置类型
|
||||
fromOcr: true
|
||||
}
|
||||
uni.setStorageSync('ocrFormData', ocrData)
|
||||
|
||||
// 切换到手动记账页面
|
||||
activeTab.value = 'manual'
|
||||
|
||||
// 填充表单数据
|
||||
form.value.amount = ocrData.amount
|
||||
form.value.billDate = ocrData.billDate
|
||||
form.value.description = ocrData.description
|
||||
form.value.type = billType // 根据金额正负自动设置类型
|
||||
|
||||
// 加载对应类型的分类
|
||||
loadCategories()
|
||||
|
||||
uni.showToast({
|
||||
title: `已填充到手动记账(${billType === 1 ? '支出' : '收入'})`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
const formatOcrDate = (dateStr) => {
|
||||
if (!dateStr) return formatDate(new Date())
|
||||
// 如果已经是 YYYY-MM-DD 格式,直接返回
|
||||
if (typeof dateStr === 'string' && dateStr.match(/^\d{4}-\d{2}-\d{2}/)) {
|
||||
return dateStr.split('T')[0] // 处理 LocalDateTime 格式
|
||||
}
|
||||
// 尝试解析日期
|
||||
try {
|
||||
const date = new Date(dateStr)
|
||||
return formatDate(date)
|
||||
} catch (e) {
|
||||
return formatDate(new Date())
|
||||
}
|
||||
}
|
||||
|
||||
const selectCategory = (category) => {
|
||||
selectedCategory.value = category
|
||||
form.value.categoryId = category.id
|
||||
}
|
||||
|
||||
const onDateChange = (e) => {
|
||||
form.value.billDate = e.detail.value
|
||||
}
|
||||
|
||||
const onAmountInput = (e) => {
|
||||
// 确保只能输入数字和小数点
|
||||
let value = e.detail.value || ''
|
||||
// 移除非数字和小数点的字符
|
||||
value = value.replace(/[^\d.]/g, '')
|
||||
// 确保只有一个小数点
|
||||
const parts = value.split('.')
|
||||
if (parts.length > 2) {
|
||||
value = parts[0] + '.' + parts.slice(1).join('')
|
||||
}
|
||||
// 限制小数位数为2位
|
||||
if (parts.length === 2 && parts[1].length > 2) {
|
||||
value = parts[0] + '.' + parts[1].substring(0, 2)
|
||||
}
|
||||
form.value.amount = value
|
||||
}
|
||||
|
||||
const onAmountFocus = () => {
|
||||
// 聚焦时确保输入框可交互
|
||||
console.log('金额输入框聚焦')
|
||||
}
|
||||
|
||||
const submitBill = async () => {
|
||||
if (!form.value.type) {
|
||||
uni.showToast({
|
||||
title: '请选择账单类型',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!form.value.categoryId) {
|
||||
uni.showToast({
|
||||
title: '请选择分类',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!form.value.amount || parseFloat(form.value.amount) <= 0) {
|
||||
uni.showToast({
|
||||
title: '请输入有效金额',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await createBill({
|
||||
type: form.value.type,
|
||||
categoryId: form.value.categoryId,
|
||||
amount: parseFloat(form.value.amount),
|
||||
description: form.value.description,
|
||||
billDate: form.value.billDate,
|
||||
imageUrl: form.value.imageUrl
|
||||
})
|
||||
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 重置表单
|
||||
form.value = {
|
||||
type: 1,
|
||||
categoryId: null,
|
||||
amount: '',
|
||||
description: '',
|
||||
billDate: formatDate(new Date()),
|
||||
imageUrl: ''
|
||||
}
|
||||
selectedCategory.value = null
|
||||
ocrResultList.value = []
|
||||
selectedOcrResult.value = null
|
||||
expandedCards.value.clear()
|
||||
imagePath.value = ''
|
||||
|
||||
// 重新加载分类
|
||||
loadCategories()
|
||||
|
||||
// 触发首页刷新
|
||||
uni.$emit('refreshBills')
|
||||
|
||||
// 跳转到首页
|
||||
setTimeout(() => {
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}, 1500)
|
||||
} catch (error) {
|
||||
console.error('保存失败:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '保存失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCategories()
|
||||
|
||||
// 检查是否有OCR数据需要填充
|
||||
const ocrFormData = uni.getStorageSync('ocrFormData')
|
||||
if (ocrFormData && ocrFormData.fromOcr) {
|
||||
form.value.amount = ocrFormData.amount || ''
|
||||
form.value.billDate = ocrFormData.billDate || formatDate(new Date())
|
||||
form.value.description = ocrFormData.description || ''
|
||||
// 清除临时数据
|
||||
uni.removeStorageSync('ocrFormData')
|
||||
// 切换到手动记账页面
|
||||
activeTab.value = 'manual'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-scroll {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
padding-bottom: calc(50px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.container {
|
||||
min-height: calc(100vh - 100rpx);
|
||||
background: #f5f5f5;
|
||||
padding: 20rpx;
|
||||
padding-bottom: calc(170rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.form {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.type-selector-compact {
|
||||
display: flex;
|
||||
gap: 15rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.type-option-compact {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 15rpx 30rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
min-width: 120rpx;
|
||||
}
|
||||
|
||||
.type-option-compact.active {
|
||||
background: #f0f7ff;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.type-icon-compact {
|
||||
font-size: 32rpx;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.type-text-compact {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.type-option-compact.active .type-text-compact {
|
||||
color: #667eea;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.category-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.category-icon-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: calc(25% - 15rpx);
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.category-icon-circle {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
background: #f8f8f8;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 8rpx;
|
||||
border: 3rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.category-icon-item.active .category-icon-circle {
|
||||
background: #f0f7ff;
|
||||
border-color: #667eea;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.category-icon-emoji {
|
||||
font-size: 48rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.category-icon-name {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.category-icon-item.active .category-icon-name {
|
||||
color: #667eea;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.category-empty {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
color: #999;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.input, .textarea {
|
||||
width: 100%;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
pointer-events: auto;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
min-height: 200rpx;
|
||||
}
|
||||
|
||||
.category-selector, .picker {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
margin-top: 40rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ocr-container {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.image-section {
|
||||
margin-bottom: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 12rpx;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.section-header:active {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.section-content {
|
||||
padding: 20rpx 0;
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
width: 100%;
|
||||
height: 400rpx;
|
||||
border: 2rpx dashed #ddd;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.upload-placeholder {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
font-size: 80rpx;
|
||||
display: block;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.recognize-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #19be6b;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
margin-bottom: 30rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ocr-result-list-container {
|
||||
margin-top: 30rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.result-list-wrapper {
|
||||
max-height: 600rpx;
|
||||
overflow-y: auto;
|
||||
padding: 0 20rpx 20rpx 20rpx;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
background: #fff;
|
||||
border: 2rpx solid #e0e0e0;
|
||||
border-radius: 12rpx;
|
||||
padding: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
transition: all 0.3s;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.result-card.active {
|
||||
border-color: #667eea;
|
||||
background: #f0f7ff;
|
||||
}
|
||||
|
||||
.result-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15rpx;
|
||||
}
|
||||
|
||||
.result-index {
|
||||
font-size: 24rpx;
|
||||
color: #667eea;
|
||||
font-weight: bold;
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.result-value.amount.summary {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #fa3534;
|
||||
}
|
||||
|
||||
.result-confidence {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
font-size: 24rpx;
|
||||
color: #667eea;
|
||||
transition: transform 0.3s;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.result-card.expanded .expand-icon {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.result-details {
|
||||
margin-top: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
max-height: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
max-height: 500rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.result-item {
|
||||
display: flex;
|
||||
padding: 10rpx 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
width: 100rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.result-value.amount {
|
||||
font-weight: bold;
|
||||
color: #fa3534;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.select-btn {
|
||||
width: 100%;
|
||||
height: 70rpx;
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
font-size: 26rpx;
|
||||
margin-top: 20rpx;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ocr-result {
|
||||
margin-top: 30rpx;
|
||||
padding-top: 30rpx;
|
||||
border-top: 2rpx solid #667eea;
|
||||
}
|
||||
|
||||
</style>
|
||||
158
pages/add/list/list.vue
Normal file
158
pages/add/list/list.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<!--
|
||||
本页面模板教程:https://ext.dcloud.net.cn/plugin?id=2588
|
||||
uni-list 文档:https://ext.dcloud.net.cn/plugin?id=24
|
||||
uniCloud 文档:https://uniapp.dcloud.io/uniCloud/README
|
||||
unicloud-db 组件文档:https://uniapp.dcloud.io/uniCloud/unicloud-db
|
||||
DB Schema 规范:https://uniapp.dcloud.net.cn/uniCloud/schema
|
||||
-->
|
||||
<view>
|
||||
<!-- 刷新页面后的顶部提示框 -->
|
||||
<view class="tips" :class="{ 'tips-ani': tipShow }">为您更新了10条最新新闻动态</view>
|
||||
<unicloud-db ref="udb" v-slot:default="{data, loading, error, options}" :options="formData" :collection="collection"
|
||||
:field="field" @load="load">
|
||||
<!-- 基于 uni-list 的页面布局 -->
|
||||
<uni-list>
|
||||
<!-- to 属性携带参数跳转详情页面,当前只为参考 -->
|
||||
<uni-list-item direction="column" v-for="item in data" :key="item.id" :to="'/pages/detail/detail?id='+item._id+'&title='+item.title">
|
||||
<!-- 通过header插槽定义列表的标题 -->
|
||||
<template v-slot:header>
|
||||
<view class="uni-title">{{item.title}}</view>
|
||||
</template>
|
||||
<!-- 通过body插槽定义列表内容显示 -->
|
||||
<template v-slot:body>
|
||||
<view class="uni-list-box">
|
||||
<view class="uni-content">
|
||||
<view class="uni-title-sub uni-ellipsis-2">{{item.excerpt}}</view>
|
||||
<view class="uni-note">{{item.user_name + ' '+item.last_modify_date}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<!-- 同步footer插槽定义列表底部的显示效果 -->
|
||||
<template v-slot:footer>
|
||||
<view class="uni-footer">
|
||||
<text class="uni-footer-text">评论</text>
|
||||
<text class="uni-footer-text">点赞</text>
|
||||
<text class="uni-footer-text">分享</text>
|
||||
</view>
|
||||
</template>
|
||||
</uni-list-item>
|
||||
</uni-list>
|
||||
<!-- 通过 loadMore 组件实现上拉加载效果,如需自定义显示内容,可参考:https://ext.dcloud.net.cn/plugin?id=29 -->
|
||||
<uni-load-more v-if="loading || options.status === 'noMore' " :status="options.status" />
|
||||
</unicloud-db>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
// 数据表名
|
||||
collection: 'opendb-news-articles',
|
||||
// 查询字段,多个字段用 , 分割
|
||||
field: '_id,mode,avatar,title,user_name,excerpt,last_modify_date',
|
||||
formData: {
|
||||
status: 'loading' // 加载状态
|
||||
},
|
||||
tipShow: false // 是否显示顶部提示框
|
||||
};
|
||||
},
|
||||
onLoad() {},
|
||||
methods: {
|
||||
load(data, ended) {
|
||||
if (ended) {
|
||||
this.formData.status = 'noMore'
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 下拉刷新回调函数
|
||||
*/
|
||||
onPullDownRefresh() {
|
||||
this.formData.status = 'more'
|
||||
this.$refs.udb.loadData({
|
||||
clear: true
|
||||
}, () => {
|
||||
this.tipShow = true
|
||||
clearTimeout(this.timer)
|
||||
this.timer = setTimeout(()=>{
|
||||
this.tipShow = false
|
||||
},1000)
|
||||
uni.stopPullDownRefresh()
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 上拉加载回调函数
|
||||
*/
|
||||
onReachBottom() {
|
||||
this.$refs.udb.loadMore()
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/common/uni-ui.scss';
|
||||
|
||||
page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
background-color: #efeff4;
|
||||
min-height: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #67c23a;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: #f0f9eb;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
transform: translateY(-100%);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.tips-ani {
|
||||
transform: translateY(0);
|
||||
height: 40px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.list-picture {
|
||||
width: 100%;
|
||||
height: 145px;
|
||||
}
|
||||
|
||||
.thumb-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-ellipsis-1 {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.uni-ellipsis-2 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
492
pages/bill/detail.vue
Normal file
492
pages/bill/detail.vue
Normal file
@ -0,0 +1,492 @@
|
||||
<template>
|
||||
<scroll-view scroll-y class="page-scroll">
|
||||
<view class="container">
|
||||
<view class="form-card">
|
||||
<view class="form-header">
|
||||
<text class="form-title">编辑账单</text>
|
||||
</view>
|
||||
|
||||
<view class="form-body">
|
||||
<view class="form-item">
|
||||
<text class="label">账单类型</text>
|
||||
<view class="type-selector-compact">
|
||||
<view
|
||||
class="type-option-compact"
|
||||
:class="{ active: form.type === 1 }"
|
||||
@click="form.type = 1; loadCategories()"
|
||||
>
|
||||
<text class="type-icon-compact">📤</text>
|
||||
<text class="type-text-compact">支出</text>
|
||||
</view>
|
||||
<view
|
||||
class="type-option-compact"
|
||||
:class="{ active: form.type === 2 }"
|
||||
@click="form.type = 2; loadCategories()"
|
||||
>
|
||||
<text class="type-icon-compact">📥</text>
|
||||
<text class="type-text-compact">收入</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">分类</text>
|
||||
<view v-if="categories.length > 0" class="category-grid">
|
||||
<view
|
||||
v-for="category in categories"
|
||||
:key="category.id"
|
||||
class="category-icon-item"
|
||||
:class="{ active: selectedCategory?.id === category.id }"
|
||||
@click="selectCategory(category)"
|
||||
>
|
||||
<view class="category-icon-circle">
|
||||
<text class="category-icon-emoji">{{ category.icon || '📦' }}</text>
|
||||
</view>
|
||||
<text class="category-icon-name">{{ category.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="category-empty">
|
||||
<text>暂无分类</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">金额</text>
|
||||
<input
|
||||
v-model="form.amount"
|
||||
type="text"
|
||||
inputmode="decimal"
|
||||
placeholder="请输入金额"
|
||||
class="input"
|
||||
@input="onAmountInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">日期</text>
|
||||
<picker mode="date" v-model="form.billDate" @change="onDateChange">
|
||||
<view class="picker">
|
||||
<text>{{ form.billDate || '选择日期' }}</text>
|
||||
<text class="arrow">></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">备注</text>
|
||||
<textarea v-model="form.description" placeholder="请输入备注(可选)" class="textarea" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-footer">
|
||||
<button class="delete-btn" @click="handleDelete">删除账单</button>
|
||||
<button class="submit-btn" @click="handleUpdate">保存修改</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { getBill, updateBill as updateBillApi, deleteBill as deleteBillApi } from '../../api/bill'
|
||||
import { getCategories } from '../../api/category'
|
||||
import { formatDate } from '../../utils/date'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const billId = ref(null)
|
||||
const categories = ref([])
|
||||
const selectedCategory = ref(null)
|
||||
|
||||
const form = ref({
|
||||
type: 1,
|
||||
categoryId: null,
|
||||
amount: '',
|
||||
description: '',
|
||||
billDate: formatDate(new Date())
|
||||
})
|
||||
|
||||
const loadCategories = async () => {
|
||||
try {
|
||||
const type = form.value.type || 1
|
||||
const data = await getCategories(type)
|
||||
categories.value = data || []
|
||||
// 如果当前选中的分类不在新类型中,清空选择
|
||||
if (selectedCategory.value && selectedCategory.value.type !== type) {
|
||||
selectedCategory.value = null
|
||||
form.value.categoryId = null
|
||||
} else if (selectedCategory.value) {
|
||||
// 重新查找选中的分类
|
||||
const category = categories.value.find(cat => cat.id === selectedCategory.value.id)
|
||||
if (category) {
|
||||
selectedCategory.value = category
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载分类失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
const loadBill = async (id) => {
|
||||
try {
|
||||
const data = await getBill(id)
|
||||
if (data) {
|
||||
form.value = {
|
||||
type: data.type || 1,
|
||||
categoryId: data.categoryId,
|
||||
amount: Math.abs(data.amount || 0).toString(),
|
||||
description: data.description || '',
|
||||
billDate: formatDate(data.billDate || new Date())
|
||||
}
|
||||
|
||||
// 加载分类后设置选中的分类
|
||||
await loadCategories()
|
||||
const category = categories.value.find(cat => cat.id === data.categoryId)
|
||||
if (category) {
|
||||
selectedCategory.value = category
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载账单失败', error)
|
||||
uni.showToast({
|
||||
title: '加载账单失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const selectCategory = (category) => {
|
||||
selectedCategory.value = category
|
||||
form.value.categoryId = category.id
|
||||
}
|
||||
|
||||
const onDateChange = (e) => {
|
||||
form.value.billDate = e.detail.value
|
||||
}
|
||||
|
||||
const onAmountInput = (e) => {
|
||||
let value = e.detail.value || ''
|
||||
value = value.replace(/[^\d.]/g, '')
|
||||
const parts = value.split('.')
|
||||
if (parts.length > 2) {
|
||||
value = parts[0] + '.' + parts.slice(1).join('')
|
||||
}
|
||||
if (parts.length === 2 && parts[1].length > 2) {
|
||||
value = parts[0] + '.' + parts[1].substring(0, 2)
|
||||
}
|
||||
form.value.amount = value
|
||||
}
|
||||
|
||||
const handleUpdate = async () => {
|
||||
if (!form.value.type) {
|
||||
uni.showToast({
|
||||
title: '请选择账单类型',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!form.value.categoryId) {
|
||||
uni.showToast({
|
||||
title: '请选择分类',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!form.value.amount || parseFloat(form.value.amount) <= 0) {
|
||||
uni.showToast({
|
||||
title: '请输入有效金额',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await updateBillApi(billId.value, {
|
||||
type: form.value.type,
|
||||
categoryId: form.value.categoryId,
|
||||
amount: parseFloat(form.value.amount),
|
||||
description: form.value.description,
|
||||
billDate: form.value.billDate
|
||||
})
|
||||
|
||||
uni.showToast({
|
||||
title: '更新成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 触发首页刷新
|
||||
uni.$emit('refreshBills')
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
} catch (error) {
|
||||
console.error('更新失败', error)
|
||||
uni.showToast({
|
||||
title: error.message || '更新失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = () => {
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这笔账单吗?删除后无法恢复',
|
||||
confirmColor: '#fa3534',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await deleteBillApi(billId.value)
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 触发首页刷新
|
||||
uni.$emit('refreshBills')
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
} catch (error) {
|
||||
console.error('删除失败', error)
|
||||
uni.showToast({
|
||||
title: error.message || '删除失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 监听账单类型变化,重新加载分类
|
||||
watch(() => form.value.type, (newType) => {
|
||||
if (newType && billId.value) {
|
||||
loadCategories()
|
||||
}
|
||||
})
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.id) {
|
||||
billId.value = options.id
|
||||
loadBill(options.id)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-scroll {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
padding-bottom: calc(50px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.container {
|
||||
min-height: calc(100vh - 100rpx);
|
||||
background: #f5f5f5;
|
||||
padding: 20rpx;
|
||||
padding-bottom: calc(170rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.form-header {
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-body {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.type-selector-compact {
|
||||
display: flex;
|
||||
gap: 15rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.type-option-compact {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 15rpx 30rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
border: 2rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
min-width: 120rpx;
|
||||
}
|
||||
|
||||
.type-option-compact.active {
|
||||
background: #f0f7ff;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.type-icon-compact {
|
||||
font-size: 32rpx;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
|
||||
.type-text-compact {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.type-option-compact.active .type-text-compact {
|
||||
color: #667eea;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.category-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.category-icon-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: calc(25% - 15rpx);
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.category-icon-circle {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
background: #f8f8f8;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 8rpx;
|
||||
border: 3rpx solid transparent;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.category-icon-item.active .category-icon-circle {
|
||||
background: #f0f7ff;
|
||||
border-color: #667eea;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.category-icon-emoji {
|
||||
font-size: 48rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.category-icon-name {
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.category-icon-item.active .category-icon-name {
|
||||
color: #667eea;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.category-empty {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
color: #999;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.input, .textarea {
|
||||
width: 100%;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
pointer-events: auto;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
min-height: 200rpx;
|
||||
}
|
||||
|
||||
.picker {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.form-footer {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
background: #fa3534;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
flex: 2;
|
||||
height: 88rpx;
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
337
pages/category/category.vue
Normal file
337
pages/category/category.vue
Normal file
@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">分类管理</text>
|
||||
<button class="add-btn" @click="showAddModal = true">+ 添加</button>
|
||||
</view>
|
||||
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{ active: activeType === 1 }" @click="activeType = 1">
|
||||
支出
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeType === 2 }" @click="activeType = 2">
|
||||
收入
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="category-list">
|
||||
<view v-for="category in filteredCategories" :key="category.id" class="category-item">
|
||||
<text class="category-icon">{{ category.icon }}</text>
|
||||
<text class="category-name">{{ category.name }}</text>
|
||||
<view v-if="!category.userId" class="tag">系统</view>
|
||||
<view v-else class="actions">
|
||||
<text class="action-btn" @click="editCategory(category)">编辑</text>
|
||||
<text class="action-btn delete" @click="deleteCategory(category.id)">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 添加/编辑弹窗 -->
|
||||
<view v-if="showAddModal || editingCategory" class="modal" @click="closeModal">
|
||||
<view class="modal-content" @click.stop>
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">{{ editingCategory ? '编辑分类' : '添加分类' }}</text>
|
||||
<text class="close-btn" @click="closeModal">×</text>
|
||||
</view>
|
||||
<view class="modal-body">
|
||||
<view class="form-item">
|
||||
<text class="label">分类名称</text>
|
||||
<input v-model="form.name" placeholder="请输入分类名称" class="input" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">图标</text>
|
||||
<input v-model="form.icon" placeholder="请输入图标(如:🍔)" class="input" />
|
||||
</view>
|
||||
<button class="submit-btn" @click="submitCategory">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { getCategories, createCategory, updateCategory, deleteCategory as deleteCategoryApi } from '../../api/category'
|
||||
|
||||
const activeType = ref(1)
|
||||
const categories = ref([])
|
||||
const showAddModal = ref(false)
|
||||
const editingCategory = ref(null)
|
||||
|
||||
const form = ref({
|
||||
name: '',
|
||||
icon: '📦',
|
||||
type: 1
|
||||
})
|
||||
|
||||
const filteredCategories = computed(() => {
|
||||
return categories.value.filter(cat => cat.type === activeType.value)
|
||||
})
|
||||
|
||||
const loadCategories = async () => {
|
||||
try {
|
||||
const data = await getCategories()
|
||||
categories.value = data || []
|
||||
} catch (error) {
|
||||
console.error('加载分类失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
const editCategory = (category) => {
|
||||
editingCategory.value = category
|
||||
form.value = {
|
||||
name: category.name,
|
||||
icon: category.icon,
|
||||
type: category.type
|
||||
}
|
||||
}
|
||||
|
||||
const deleteCategory = async (id) => {
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这个分类吗?',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await deleteCategoryApi(id)
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
})
|
||||
loadCategories()
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '删除失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const submitCategory = async () => {
|
||||
if (!form.value.name) {
|
||||
uni.showToast({
|
||||
title: '请输入分类名称',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
form.value.type = activeType.value
|
||||
if (editingCategory.value) {
|
||||
await updateCategory(editingCategory.value.id, form.value)
|
||||
uni.showToast({
|
||||
title: '更新成功',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
await createCategory(form.value)
|
||||
uni.showToast({
|
||||
title: '添加成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
closeModal()
|
||||
loadCategories()
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: editingCategory.value ? '更新失败' : '添加失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
showAddModal.value = false
|
||||
editingCategory.value = null
|
||||
form.value = {
|
||||
name: '',
|
||||
icon: '📦',
|
||||
type: 1
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCategories()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 8rpx;
|
||||
font-size: 26rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
margin-top: 20rpx;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.category-list {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
font-size: 48rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
flex: 1;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.tag {
|
||||
background: #f0f0f0;
|
||||
color: #999;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 4rpx;
|
||||
font-size: 22rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
color: #667eea;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.action-btn.delete {
|
||||
color: #fa3534;
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
width: 80%;
|
||||
max-width: 600rpx;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
font-size: 48rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
297
pages/index/index.vue
Normal file
297
pages/index/index.vue
Normal file
@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">我的账单</text>
|
||||
<view class="summary">
|
||||
<view class="summary-item">
|
||||
<text class="label">本月支出</text>
|
||||
<text class="amount expense">¥{{ monthlyExpense.toFixed(2) }}</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">本月收入</text>
|
||||
<text class="amount income">¥{{ monthlyIncome.toFixed(2) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bill-list">
|
||||
<view v-for="(group, date) in groupedBills" :key="date" class="bill-group">
|
||||
<view class="group-header">
|
||||
<text class="date">{{ date }}</text>
|
||||
<text class="total">¥{{ getGroupTotal(group).toFixed(2) }}</text>
|
||||
</view>
|
||||
<view v-for="bill in group" :key="bill.id" class="bill-item" @click="viewBill(bill)">
|
||||
<view class="bill-icon">{{ bill.categoryIcon || '📦' }}</view>
|
||||
<view class="bill-info">
|
||||
<text class="bill-category">{{ bill.categoryName || '未分类' }}</text>
|
||||
<text class="bill-desc" v-if="bill.description">{{ bill.description }}</text>
|
||||
</view>
|
||||
<text class="bill-amount" :class="bill.amount > 0 ? 'income' : 'expense'">
|
||||
{{ bill.type > 0 ? '-' : '+' }}¥{{ Math.abs(bill.amount).toFixed(2) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="bills.length === 0 && !loading" class="empty">
|
||||
<text>暂无账单记录</text>
|
||||
<text class="empty-tip">点击下方"记账"按钮添加账单</text>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="loading">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { getBills } from '../../api/bill'
|
||||
import { getMonthlyStatistics } from '../../api/statistics'
|
||||
import { formatDate } from '../../utils/date'
|
||||
import { useUserStore } from '../../store/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const bills = ref([])
|
||||
const monthlyIncome = ref(0)
|
||||
const monthlyExpense = ref(0)
|
||||
const loading = ref(false)
|
||||
|
||||
const groupedBills = computed(() => {
|
||||
const groups = {}
|
||||
bills.value.forEach(bill => {
|
||||
const date = formatDate(bill.billDate)
|
||||
if (!groups[date]) {
|
||||
groups[date] = []
|
||||
}
|
||||
groups[date].push(bill)
|
||||
})
|
||||
return groups
|
||||
})
|
||||
|
||||
const getGroupTotal = (group) => {
|
||||
return group.reduce((sum, bill) => sum + parseFloat(bill.amount || 0), 0)
|
||||
}
|
||||
|
||||
const loadBills = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await getBills()
|
||||
bills.value = data || []
|
||||
} catch (error) {
|
||||
console.error('加载账单失败', error)
|
||||
if (error.message && error.message.includes('401')) {
|
||||
// token过期,跳转到登录页
|
||||
userStore.logout()
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const loadMonthlyStatistics = async () => {
|
||||
try {
|
||||
const now = new Date()
|
||||
const data = await getMonthlyStatistics(now.getFullYear(), now.getMonth() + 1)
|
||||
monthlyIncome.value = data.totalIncome || 0
|
||||
monthlyExpense.value = data.totalExpense || 0
|
||||
} catch (error) {
|
||||
console.error('加载统计失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
const viewBill = (bill) => {
|
||||
// 跳转到账单编辑页面
|
||||
uni.navigateTo({
|
||||
url: `/pages/bill/detail?id=${bill.id}`
|
||||
})
|
||||
}
|
||||
|
||||
const onPullDownRefresh = () => {
|
||||
loadBills()
|
||||
loadMonthlyStatistics()
|
||||
setTimeout(() => {
|
||||
uni.stopPullDownRefresh()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 检查登录状态
|
||||
if (!userStore.isLoggedIn) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
loadBills()
|
||||
loadMonthlyStatistics()
|
||||
})
|
||||
|
||||
// 监听刷新事件
|
||||
uni.$on('refreshBills', () => {
|
||||
loadBills()
|
||||
loadMonthlyStatistics()
|
||||
})
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// uni-app 页面生命周期钩子
|
||||
export default {
|
||||
onShow() {
|
||||
// 页面显示时刷新 - 通过事件触发
|
||||
uni.$emit('refreshBills')
|
||||
},
|
||||
onPullDownRefresh() {
|
||||
// 下拉刷新 - 通过事件触发
|
||||
uni.$emit('refreshBills')
|
||||
setTimeout(() => {
|
||||
uni.stopPullDownRefresh()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
min-height: calc(100vh - 100rpx);
|
||||
background: #f5f5f5;
|
||||
padding-bottom: calc(170rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 40rpx 30rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.summary {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.amount {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.bill-list {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.bill-group {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background: #f8f8f8;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.total {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.bill-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.bill-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.bill-icon {
|
||||
font-size: 48rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.bill-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.bill-category {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.bill-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.bill-amount {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.bill-amount.income {
|
||||
color: #19be6b;
|
||||
}
|
||||
|
||||
.bill-amount.expense {
|
||||
color: #fa3534;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 100rpx 0;
|
||||
color: #999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
font-size: 24rpx;
|
||||
margin-top: 20rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
22
pages/login/login-simple.vue
Normal file
22
pages/login/login-simple.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<view style="padding: 100px; text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;">
|
||||
<text style="font-size: 48px; color: #fff; margin-bottom: 40px; display: block;">强宝爱记账</text>
|
||||
<text style="font-size: 32px; color: rgba(255,255,255,0.9); display: block;">登录页面测试</text>
|
||||
<text style="font-size: 24px; color: rgba(255,255,255,0.7); margin-top: 20px; display: block;">如果能看到这个,说明路由正常</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
onLoad() {
|
||||
console.log('登录页面加载成功')
|
||||
},
|
||||
onReady() {
|
||||
console.log('登录页面准备完成')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
205
pages/login/login.vue
Normal file
205
pages/login/login.vue
Normal file
@ -0,0 +1,205 @@
|
||||
<template>
|
||||
<view class="login-container">
|
||||
<view class="login-header">
|
||||
<text class="app-title">强宝爱记账</text>
|
||||
<text class="app-subtitle">智能记账,轻松管理</text>
|
||||
</view>
|
||||
|
||||
<view class="login-form">
|
||||
<view class="form-item">
|
||||
<input
|
||||
v-model="form.username"
|
||||
placeholder="请输入用户名"
|
||||
class="input"
|
||||
maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<input
|
||||
v-model="form.password"
|
||||
placeholder="请输入密码"
|
||||
type="password"
|
||||
class="input"
|
||||
maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view v-if="isRegister" class="form-item">
|
||||
<input
|
||||
v-model="form.nickname"
|
||||
placeholder="请输入昵称(可选)"
|
||||
class="input"
|
||||
maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<button class="login-btn" @click="handleSubmit" :loading="loading">
|
||||
{{ isRegister ? '注册' : '登录' }}
|
||||
</button>
|
||||
|
||||
<view class="switch-mode" @click="switchMode">
|
||||
<text>{{ isRegister ? '已有账号?去登录' : '没有账号?去注册' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { register, login } from '../../api/auth'
|
||||
import { useUserStore } from '../../store/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const isRegister = ref(false)
|
||||
const loading = ref(false)
|
||||
const form = ref({
|
||||
username: '',
|
||||
password: '',
|
||||
nickname: ''
|
||||
})
|
||||
|
||||
const switchMode = () => {
|
||||
isRegister.value = !isRegister.value
|
||||
form.value = {
|
||||
username: '',
|
||||
password: '',
|
||||
nickname: ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!form.value.username || !form.value.password) {
|
||||
uni.showToast({
|
||||
title: '请输入用户名和密码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (isRegister.value && form.value.password.length < 6) {
|
||||
uni.showToast({
|
||||
title: '密码长度至少6位',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
let response
|
||||
if (isRegister.value) {
|
||||
response = await register({
|
||||
username: form.value.username,
|
||||
password: form.value.password,
|
||||
nickname: form.value.nickname || form.value.username
|
||||
})
|
||||
} else {
|
||||
response = await login({
|
||||
username: form.value.username,
|
||||
password: form.value.password
|
||||
})
|
||||
}
|
||||
|
||||
// 保存token和用户信息
|
||||
userStore.login(response.token, {
|
||||
username: response.username,
|
||||
nickname: response.nickname
|
||||
})
|
||||
|
||||
uni.showToast({
|
||||
title: isRegister.value ? '注册成功' : '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 跳转到首页
|
||||
setTimeout(() => {
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}, 1500)
|
||||
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '操作失败',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
.login-header {
|
||||
text-align: center;
|
||||
margin-bottom: 80rpx;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
display: block;
|
||||
font-size: 56rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.app-subtitle {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.login-form {
|
||||
width: 100%;
|
||||
max-width: 600rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #fff;
|
||||
color: #667eea;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-top: 40rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.switch-mode {
|
||||
text-align: center;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.switch-mode text {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 26rpx;
|
||||
}
|
||||
</style>
|
||||
246
pages/statistics/statistics.vue
Normal file
246
pages/statistics/statistics.vue
Normal file
@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{ active: activeTab === 'daily' }" @click="switchTab('daily')">
|
||||
按日
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeTab === 'weekly' }" @click="switchTab('weekly')">
|
||||
按周
|
||||
</view>
|
||||
<view class="tab" :class="{ active: activeTab === 'monthly' }" @click="switchTab('monthly')">
|
||||
按月
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="summary-card">
|
||||
<view class="summary-item">
|
||||
<text class="label">总收入</text>
|
||||
<text class="amount income">¥{{ statistics.totalIncome?.toFixed(2) || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">总支出</text>
|
||||
<text class="amount expense">¥{{ statistics.totalExpense?.toFixed(2) || '0.00' }}</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<text class="label">余额</text>
|
||||
<text class="amount balance">¥{{ getBalance.toFixed(2) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="category-stats">
|
||||
<text class="section-title">分类统计</text>
|
||||
<view v-if="statistics.categoryStatistics && statistics.categoryStatistics.length > 0">
|
||||
<view v-for="item in statistics.categoryStatistics" :key="item.categoryId" class="category-item">
|
||||
<text class="category-icon">{{ item.categoryIcon || '📦' }}</text>
|
||||
<view class="category-info">
|
||||
<text class="category-name">{{ item.categoryName }}</text>
|
||||
<view class="progress-bar">
|
||||
<view class="progress-fill" :style="{ width: getProgress(item) + '%' }"></view>
|
||||
</view>
|
||||
</view>
|
||||
<text class="category-amount">¥{{ item.amount?.toFixed(2) || '0.00' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty">
|
||||
<text>暂无统计数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { getDailyStatistics, getWeeklyStatistics, getMonthlyStatistics } from '../../api/statistics'
|
||||
import { formatDate, getWeekStart } from '../../utils/date'
|
||||
|
||||
const activeTab = ref('monthly')
|
||||
const statistics = ref({
|
||||
totalIncome: 0,
|
||||
totalExpense: 0,
|
||||
balance: 0,
|
||||
categoryStatistics: [],
|
||||
dailyStatistics: []
|
||||
})
|
||||
|
||||
const switchTab = async (tab) => {
|
||||
activeTab.value = tab
|
||||
await loadStatistics()
|
||||
}
|
||||
|
||||
const loadStatistics = async () => {
|
||||
try {
|
||||
const now = new Date()
|
||||
let data
|
||||
|
||||
if (activeTab.value === 'daily') {
|
||||
const startDate = formatDate(now)
|
||||
const endDate = formatDate(now)
|
||||
data = await getDailyStatistics(startDate, endDate)
|
||||
} else if (activeTab.value === 'weekly') {
|
||||
const weekStart = formatDate(getWeekStart(now))
|
||||
data = await getWeeklyStatistics(weekStart)
|
||||
} else {
|
||||
data = await getMonthlyStatistics(now.getFullYear(), now.getMonth() + 1)
|
||||
}
|
||||
|
||||
const income = data?.totalIncome || 0
|
||||
const expense = data?.totalExpense || 0
|
||||
statistics.value = {
|
||||
totalIncome: income,
|
||||
totalExpense: expense,
|
||||
balance: income - expense,
|
||||
categoryStatistics: data?.categoryStatistics || [],
|
||||
dailyStatistics: data?.dailyStatistics || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载统计失败', error)
|
||||
statistics.value = {
|
||||
totalIncome: 0,
|
||||
totalExpense: 0,
|
||||
balance: 0,
|
||||
categoryStatistics: [],
|
||||
dailyStatistics: []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getBalance = computed(() => {
|
||||
return statistics.value.totalIncome - statistics.value.totalExpense
|
||||
})
|
||||
|
||||
const getProgress = (item) => {
|
||||
const total = statistics.value.totalExpense || 1
|
||||
const amount = parseFloat(item.amount || 0)
|
||||
return total > 0 ? (amount / total) * 100 : 0
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadStatistics()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
min-height: calc(100vh - 100rpx);
|
||||
background: #f5f5f5;
|
||||
padding: 20rpx;
|
||||
padding-bottom: calc(170rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
background: #667eea;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12rpx;
|
||||
padding: 40rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.amount {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.category-stats {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.category-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.category-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
font-size: 48rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.category-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 8rpx;
|
||||
background: #f0f0f0;
|
||||
border-radius: 4rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: #667eea;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
|
||||
.category-amount {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding: 60rpx 0;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
80
static/css/common.css
Normal file
80
static/css/common.css
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
111
static/tabbar/README.md
Normal file
111
static/tabbar/README.md
Normal file
@ -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 可能无法正常显示
|
||||
|
||||
BIN
static/tabbar/add-active.png
Normal file
BIN
static/tabbar/add-active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
BIN
static/tabbar/add.png
Normal file
BIN
static/tabbar/add.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
BIN
static/tabbar/home-active.png
Normal file
BIN
static/tabbar/home-active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
static/tabbar/home.png
Normal file
BIN
static/tabbar/home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
static/tabbar/statistic-active.png
Normal file
BIN
static/tabbar/statistic-active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
static/tabbar/statistics.png
Normal file
BIN
static/tabbar/statistics.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
47
store/user.js
Normal file
47
store/user.js
Normal file
@ -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')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
@ -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"]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
75
uni.scss
Normal file
75
uni.scss
Normal file
@ -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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
427
uniCloud-alipay/database/db_init.json
Normal file
427
uniCloud-alipay/database/db_init.json
Normal file
@ -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
|
||||
}]
|
||||
}
|
||||
}
|
||||
122
uniCloud-alipay/database/opendb-news-articles.schema.json
Normal file
122
uniCloud-alipay/database/opendb-news-articles.schema.json
Normal file
@ -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"
|
||||
]
|
||||
}
|
||||
14
uni_modules/uni-badge/changelog.md
Normal file
14
uni_modules/uni-badge/changelog.md
Normal file
@ -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目录规范
|
||||
252
uni_modules/uni-badge/components/uni-badge/uni-badge.vue
Normal file
252
uni_modules/uni-badge/components/uni-badge/uni-badge.vue
Normal file
@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<view class="uni-badge--x">
|
||||
<slot />
|
||||
<text v-if="text" :class="classNames" :style="[badgeWidth, positionStyle, customStyle, dotStyle]"
|
||||
class="uni-badge"
|
||||
@click="onClick()">{{displayValue}}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Badge 数字角标
|
||||
* @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=21
|
||||
* @property {String} text 角标内容
|
||||
* @property {String} type = [default|primary|success|warning|error] 颜色类型
|
||||
* @value default 灰色
|
||||
* @value primary 蓝色
|
||||
* @value success 绿色
|
||||
* @value warning 黄色
|
||||
* @value error 红色
|
||||
* @property {String} size = [normal|small] Badge 大小
|
||||
* @value normal 一般尺寸
|
||||
* @value small 小尺寸
|
||||
* @property {String} inverted = [true|false] 是否无需背景颜色
|
||||
* @event {Function} click 点击 Badge 触发事件
|
||||
* @example <uni-badge text="1"></uni-badge>
|
||||
*/
|
||||
export default {
|
||||
name: 'UniBadge',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
inverted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isDot: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxNum: {
|
||||
type: Number,
|
||||
default: 99
|
||||
},
|
||||
absolute: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
offset: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [0, 0]
|
||||
}
|
||||
},
|
||||
text: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: 'normal'
|
||||
},
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
width() {
|
||||
return String(this.text).length * 8 + 12
|
||||
},
|
||||
classNames() {
|
||||
const {
|
||||
inverted,
|
||||
type,
|
||||
size,
|
||||
absolute
|
||||
} = this
|
||||
return [
|
||||
inverted ? 'uni-badge--' + type + '-inverted' : '',
|
||||
'uni-badge--' + type,
|
||||
'uni-badge--' + size,
|
||||
absolute ? 'uni-badge--absolute' : ''
|
||||
]
|
||||
},
|
||||
positionStyle() {
|
||||
if (!this.absolute) return {}
|
||||
let w = this.width / 2,
|
||||
h = 10
|
||||
if (this.isDot) {
|
||||
w = 5
|
||||
h = 5
|
||||
}
|
||||
const x = `${- w + this.offset[0]}px`
|
||||
const y = `${- h + this.offset[1]}px`
|
||||
|
||||
const whiteList = {
|
||||
rightTop: {
|
||||
right: x,
|
||||
top: y
|
||||
},
|
||||
rightBottom: {
|
||||
right: x,
|
||||
bottom: y
|
||||
},
|
||||
leftBottom: {
|
||||
left: x,
|
||||
bottom: y
|
||||
},
|
||||
leftTop: {
|
||||
left: x,
|
||||
top: y
|
||||
}
|
||||
}
|
||||
const match = whiteList[this.absolute]
|
||||
return match ? match : whiteList['rightTop']
|
||||
},
|
||||
badgeWidth() {
|
||||
return {
|
||||
width: `${this.width}px`
|
||||
}
|
||||
},
|
||||
dotStyle() {
|
||||
if (!this.isDot) return {}
|
||||
return {
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
borderRadius: '10px'
|
||||
}
|
||||
},
|
||||
displayValue() {
|
||||
const { isDot, text, maxNum } = this
|
||||
return isDot ? '' : (Number(text) > maxNum ? `${maxNum}+` : text)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$bage-size: 12px;
|
||||
$bage-small: scale(0.8);
|
||||
$bage-height: 20px;
|
||||
|
||||
.uni-badge--x {
|
||||
/* #ifdef APP-NVUE */
|
||||
align-self: flex-start;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
display: inline-block;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-badge--absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.uni-badge {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
flex-direction: row;
|
||||
height: $bage-height;
|
||||
line-height: $bage-height;
|
||||
color: $uni-text-color;
|
||||
border-radius: 100px;
|
||||
background-color: $uni-bg-color-hover;
|
||||
background-color: transparent;
|
||||
text-align: center;
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
font-size: $bage-size;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-badge--inverted {
|
||||
padding: 0 5px 0 0;
|
||||
color: $uni-bg-color-hover;
|
||||
}
|
||||
|
||||
.uni-badge--default {
|
||||
color: $uni-text-color;
|
||||
background-color: $uni-bg-color-hover;
|
||||
}
|
||||
|
||||
.uni-badge--default-inverted {
|
||||
color: $uni-text-color-grey;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--primary {
|
||||
color: $uni-text-color-inverse;
|
||||
background-color: $uni-color-primary;
|
||||
}
|
||||
|
||||
.uni-badge--primary-inverted {
|
||||
color: $uni-color-primary;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--success {
|
||||
color: $uni-text-color-inverse;
|
||||
background-color: $uni-color-success;
|
||||
}
|
||||
|
||||
.uni-badge--success-inverted {
|
||||
color: $uni-color-success;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--warning {
|
||||
color: $uni-text-color-inverse;
|
||||
background-color: $uni-color-warning;
|
||||
}
|
||||
|
||||
.uni-badge--warning-inverted {
|
||||
color: $uni-color-warning;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--error {
|
||||
color: $uni-text-color-inverse;
|
||||
background-color: $uni-color-error;
|
||||
}
|
||||
|
||||
.uni-badge--error-inverted {
|
||||
color: $uni-color-error;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-badge--small {
|
||||
transform: $bage-small;
|
||||
transform-origin: center center;
|
||||
}
|
||||
</style>
|
||||
84
uni_modules/uni-badge/package.json
Normal file
84
uni_modules/uni-badge/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
uni_modules/uni-badge/readme.md
Normal file
58
uni_modules/uni-badge/readme.md
Normal file
@ -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
|
||||
<uni-badge size="small" :text="100" absolute="rightBottom" type="primary">
|
||||
<button type="default">右上</button>
|
||||
</uni-badge>
|
||||
<uni-badge text="1"></uni-badge>
|
||||
<uni-badge text="2" type="purple" @click="bindClick"></uni-badge>
|
||||
<uni-badge text="3" type="primary" :inverted="true"></uni-badge>
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 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)
|
||||
4
uni_modules/uni-config-center/changelog.md
Normal file
4
uni_modules/uni-config-center/changelog.md
Normal file
@ -0,0 +1,4 @@
|
||||
## 0.0.2(2021-04-16)
|
||||
- 修改插件package信息
|
||||
## 0.0.1(2021-03-15)
|
||||
- 初始化项目
|
||||
80
uni_modules/uni-config-center/package.json
Normal file
80
uni_modules/uni-config-center/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
93
uni_modules/uni-config-center/readme.md
Normal file
93
uni_modules/uni-config-center/readme.md
Normal file
@ -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: 文件不存在
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "uni-config-center",
|
||||
"version": "0.0.2",
|
||||
"description": "配置中心",
|
||||
"main": "index.js",
|
||||
"keywords": [],
|
||||
"author": "DCloud",
|
||||
"license": "Apache-2.0",
|
||||
"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"
|
||||
}
|
||||
4
uni_modules/uni-icons/changelog.md
Normal file
4
uni_modules/uni-icons/changelog.md
Normal file
@ -0,0 +1,4 @@
|
||||
## 1.1.5(2021-05-12)
|
||||
- 新增 组件示例地址
|
||||
## 1.1.4(2021-02-05)
|
||||
- 调整为uni_modules目录规范
|
||||
132
uni_modules/uni-icons/components/uni-icons/icons.js
Normal file
132
uni_modules/uni-icons/components/uni-icons/icons.js
Normal file
@ -0,0 +1,132 @@
|
||||
export default {
|
||||
"pulldown": "\ue588",
|
||||
"refreshempty": "\ue461",
|
||||
"back": "\ue471",
|
||||
"forward": "\ue470",
|
||||
"more": "\ue507",
|
||||
"more-filled": "\ue537",
|
||||
"scan": "\ue612",
|
||||
"qq": "\ue264",
|
||||
"weibo": "\ue260",
|
||||
"weixin": "\ue261",
|
||||
"pengyouquan": "\ue262",
|
||||
"loop": "\ue565",
|
||||
"refresh": "\ue407",
|
||||
"refresh-filled": "\ue437",
|
||||
"arrowthindown": "\ue585",
|
||||
"arrowthinleft": "\ue586",
|
||||
"arrowthinright": "\ue587",
|
||||
"arrowthinup": "\ue584",
|
||||
"undo-filled": "\ue7d6",
|
||||
"undo": "\ue406",
|
||||
"redo": "\ue405",
|
||||
"redo-filled": "\ue7d9",
|
||||
"bars": "\ue563",
|
||||
"chatboxes": "\ue203",
|
||||
"camera": "\ue301",
|
||||
"chatboxes-filled": "\ue233",
|
||||
"camera-filled": "\ue7ef",
|
||||
"cart-filled": "\ue7f4",
|
||||
"cart": "\ue7f5",
|
||||
"checkbox-filled": "\ue442",
|
||||
"checkbox": "\ue7fa",
|
||||
"arrowleft": "\ue582",
|
||||
"arrowdown": "\ue581",
|
||||
"arrowright": "\ue583",
|
||||
"smallcircle-filled": "\ue801",
|
||||
"arrowup": "\ue580",
|
||||
"circle": "\ue411",
|
||||
"eye-filled": "\ue568",
|
||||
"eye-slash-filled": "\ue822",
|
||||
"eye-slash": "\ue823",
|
||||
"eye": "\ue824",
|
||||
"flag-filled": "\ue825",
|
||||
"flag": "\ue508",
|
||||
"gear-filled": "\ue532",
|
||||
"reload": "\ue462",
|
||||
"gear": "\ue502",
|
||||
"hand-thumbsdown-filled": "\ue83b",
|
||||
"hand-thumbsdown": "\ue83c",
|
||||
"hand-thumbsup-filled": "\ue83d",
|
||||
"heart-filled": "\ue83e",
|
||||
"hand-thumbsup": "\ue83f",
|
||||
"heart": "\ue840",
|
||||
"home": "\ue500",
|
||||
"info": "\ue504",
|
||||
"home-filled": "\ue530",
|
||||
"info-filled": "\ue534",
|
||||
"circle-filled": "\ue441",
|
||||
"chat-filled": "\ue847",
|
||||
"chat": "\ue263",
|
||||
"mail-open-filled": "\ue84d",
|
||||
"email-filled": "\ue231",
|
||||
"mail-open": "\ue84e",
|
||||
"email": "\ue201",
|
||||
"checkmarkempty": "\ue472",
|
||||
"list": "\ue562",
|
||||
"locked-filled": "\ue856",
|
||||
"locked": "\ue506",
|
||||
"map-filled": "\ue85c",
|
||||
"map-pin": "\ue85e",
|
||||
"map-pin-ellipse": "\ue864",
|
||||
"map": "\ue364",
|
||||
"minus-filled": "\ue440",
|
||||
"mic-filled": "\ue332",
|
||||
"minus": "\ue410",
|
||||
"micoff": "\ue360",
|
||||
"mic": "\ue302",
|
||||
"clear": "\ue434",
|
||||
"smallcircle": "\ue868",
|
||||
"close": "\ue404",
|
||||
"closeempty": "\ue460",
|
||||
"paperclip": "\ue567",
|
||||
"paperplane": "\ue503",
|
||||
"paperplane-filled": "\ue86e",
|
||||
"person-filled": "\ue131",
|
||||
"contact-filled": "\ue130",
|
||||
"person": "\ue101",
|
||||
"contact": "\ue100",
|
||||
"images-filled": "\ue87a",
|
||||
"phone": "\ue200",
|
||||
"images": "\ue87b",
|
||||
"image": "\ue363",
|
||||
"image-filled": "\ue877",
|
||||
"location-filled": "\ue333",
|
||||
"location": "\ue303",
|
||||
"plus-filled": "\ue439",
|
||||
"plus": "\ue409",
|
||||
"plusempty": "\ue468",
|
||||
"help-filled": "\ue535",
|
||||
"help": "\ue505",
|
||||
"navigate-filled": "\ue884",
|
||||
"navigate": "\ue501",
|
||||
"mic-slash-filled": "\ue892",
|
||||
"search": "\ue466",
|
||||
"settings": "\ue560",
|
||||
"sound": "\ue590",
|
||||
"sound-filled": "\ue8a1",
|
||||
"spinner-cycle": "\ue465",
|
||||
"download-filled": "\ue8a4",
|
||||
"personadd-filled": "\ue132",
|
||||
"videocam-filled": "\ue8af",
|
||||
"personadd": "\ue102",
|
||||
"upload": "\ue402",
|
||||
"upload-filled": "\ue8b1",
|
||||
"starhalf": "\ue463",
|
||||
"star-filled": "\ue438",
|
||||
"star": "\ue408",
|
||||
"trash": "\ue401",
|
||||
"phone-filled": "\ue230",
|
||||
"compose": "\ue400",
|
||||
"videocam": "\ue300",
|
||||
"trash-filled": "\ue8dc",
|
||||
"download": "\ue403",
|
||||
"chatbubble-filled": "\ue232",
|
||||
"chatbubble": "\ue202",
|
||||
"cloud-download": "\ue8e4",
|
||||
"cloud-upload-filled": "\ue8e5",
|
||||
"cloud-upload": "\ue8e6",
|
||||
"cloud-download-filled": "\ue8e9",
|
||||
"headphones":"\ue8bf",
|
||||
"shop":"\ue609"
|
||||
}
|
||||
91
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
Normal file
91
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<text class="uni-icons" :style="styleObj">
|
||||
<slot>{{unicode}}</slot>
|
||||
</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fontData, IconsDataItem } from './uniicons_file'
|
||||
|
||||
/**
|
||||
* Icons 图标
|
||||
* @description 用于展示 icon 图标
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
|
||||
* @property {Number} size 图标大小
|
||||
* @property {String} type 图标图案,参考示例
|
||||
* @property {String} color 图标颜色
|
||||
* @property {String} customPrefix 自定义图标
|
||||
* @event {Function} click 点击 Icon 触发事件
|
||||
*/
|
||||
export default {
|
||||
name: "uni-icons",
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#333333'
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 16
|
||||
},
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
unicode() : string {
|
||||
let codes = fontData.find((item : IconsDataItem) : boolean => { return item.font_class == this.type })
|
||||
if (codes !== null) {
|
||||
return codes.unicode
|
||||
}
|
||||
return ''
|
||||
},
|
||||
iconSize() : string {
|
||||
const size = this.size
|
||||
if (typeof size == 'string') {
|
||||
const reg = /^[0-9]*$/g
|
||||
return reg.test(size as string) ? '' + size + 'px' : '' + size;
|
||||
// return '' + this.size
|
||||
}
|
||||
return this.getFontSize(size as number)
|
||||
},
|
||||
styleObj() : UTSJSONObject {
|
||||
if (this.fontFamily !== '') {
|
||||
return { color: this.color, fontSize: this.iconSize, fontFamily: this.fontFamily }
|
||||
}
|
||||
return { color: this.color, fontSize: this.iconSize }
|
||||
}
|
||||
},
|
||||
created() { },
|
||||
methods: {
|
||||
/**
|
||||
* 字体大小
|
||||
*/
|
||||
getFontSize(size : number) : string {
|
||||
return size + 'px';
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@font-face {
|
||||
font-family: UniIconsFontFamily;
|
||||
src: url('./uniicons.ttf');
|
||||
}
|
||||
|
||||
.uni-icons {
|
||||
font-family: UniIconsFontFamily;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
71
uni_modules/uni-icons/components/uni-icons/uni-icons.vue
Normal file
71
uni_modules/uni-icons/components/uni-icons/uni-icons.vue
Normal file
File diff suppressed because one or more lines are too long
BIN
uni_modules/uni-icons/components/uni-icons/uni.ttf
Normal file
BIN
uni_modules/uni-icons/components/uni-icons/uni.ttf
Normal file
Binary file not shown.
664
uni_modules/uni-icons/components/uni-icons/uniicons.css
Normal file
664
uni_modules/uni-icons/components/uni-icons/uniicons.css
Normal file
@ -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";
|
||||
}
|
||||
BIN
uni_modules/uni-icons/components/uni-icons/uniicons.ttf
Normal file
BIN
uni_modules/uni-icons/components/uni-icons/uniicons.ttf
Normal file
Binary file not shown.
664
uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
Normal file
664
uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
Normal file
@ -0,0 +1,664 @@
|
||||
|
||||
export type IconsData = {
|
||||
id : string
|
||||
name : string
|
||||
font_family : string
|
||||
css_prefix_text : string
|
||||
description : string
|
||||
glyphs : Array<IconsDataItem>
|
||||
}
|
||||
|
||||
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<IconsDataItem>(fontDataJson)
|
||||
649
uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
Normal file
649
uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
Normal file
@ -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<IconsDataItem>(fontDataJson)
|
||||
82
uni_modules/uni-icons/package.json
Normal file
82
uni_modules/uni-icons/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
uni_modules/uni-icons/readme.md
Normal file
46
uni_modules/uni-icons/readme.md
Normal file
@ -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
|
||||
<uni-icons type="contact" size="30"></uni-icons>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 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)
|
||||
24
uni_modules/uni-id/changelog.md
Normal file
24
uni_modules/uni-id/changelog.md
Normal file
@ -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目录规范
|
||||
80
uni_modules/uni-id/package.json
Normal file
80
uni_modules/uni-id/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
uni_modules/uni-id/readme.md
Normal file
33
uni_modules/uni-id/readme.md
Normal file
@ -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'对应的权限
|
||||
}
|
||||
```
|
||||
@ -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.
|
||||
File diff suppressed because one or more lines are too long
11
uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package-lock.json
generated
Normal file
11
uni_modules/uni-id/uniCloud/cloudfunctions/common/uni-id/package-lock.json
generated
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
7
uni_modules/uni-list/changelog.md
Normal file
7
uni_modules/uni-list/changelog.md
Normal file
@ -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 角标显示不正常的问题
|
||||
107
uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue
Normal file
107
uni_modules/uni-list/components/uni-list-ad/uni-list-ad.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<cell>
|
||||
<!-- #endif -->
|
||||
<view class="uni-list-ad">
|
||||
<view v-if="borderShow" :class="{'uni-list--border':border,'uni-list-item--first':isFirstChild}"></view>
|
||||
<ad style="width: 200px;height: 300px;border-width: 1px;border-color: red;border-style: solid;" adpid="1111111111"
|
||||
unit-id="" appid="" apid="" type="feed" @error="aderror" @close="closeAd"></ad>
|
||||
</view>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
</cell>
|
||||
<!-- #endif -->
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifdef APP-NVUE
|
||||
const dom = uni.requireNativePlugin('dom');
|
||||
// #endif
|
||||
export default {
|
||||
name: 'UniListAd',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
}
|
||||
},
|
||||
// inject: ['list'],
|
||||
data() {
|
||||
return {
|
||||
isFirstChild: false,
|
||||
border: false,
|
||||
borderShow: true,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.list = this.getForm()
|
||||
if (this.list) {
|
||||
if (!this.list.firstChildAppend) {
|
||||
this.list.firstChildAppend = true
|
||||
this.isFirstChild = true
|
||||
}
|
||||
this.border = this.list.border
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getForm(name = 'uniList') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
aderror(e) {
|
||||
console.log("aderror: " + JSON.stringify(e.detail));
|
||||
},
|
||||
closeAd(e) {
|
||||
this.borderShow = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uni-list-ad {
|
||||
position: relative;
|
||||
border: 1px red solid;
|
||||
}
|
||||
|
||||
.uni-list--border {
|
||||
position: relative;
|
||||
padding-bottom: 1px;
|
||||
/* #ifdef APP-PLUS */
|
||||
border-top-color: $uni-border-color;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0.5px;
|
||||
/* #endif */
|
||||
margin-left: $uni-spacing-row-lg;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-list--border:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: 1px;
|
||||
content: '';
|
||||
-webkit-transform: scaleY(.5);
|
||||
transform: scaleY(.5);
|
||||
background-color: $uni-border-color;
|
||||
}
|
||||
|
||||
.uni-list-item--first:after {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
@ -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;
|
||||
533
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue
Normal file
533
uni_modules/uni-list/components/uni-list-chat/uni-list-chat.vue
Normal file
@ -0,0 +1,533 @@
|
||||
<template>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<cell>
|
||||
<!-- #endif -->
|
||||
<view :hover-class="!clickable && !link ? '' : 'uni-list-chat--hover'" class="uni-list-chat" @click.stop="onClick">
|
||||
<view :class="{ 'uni-list--border': border, 'uni-list-chat--first': isFirstChild }"></view>
|
||||
<view class="uni-list-chat__container">
|
||||
<view class="uni-list-chat__header-warp">
|
||||
<view v-if="avatarCircle || avatarList.length === 0" class="uni-list-chat__header" :class="{ 'header--circle': avatarCircle }">
|
||||
<image class="uni-list-chat__header-image" :src="avatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<!-- 头像组 -->
|
||||
<view v-else class="uni-list-chat__header">
|
||||
<view v-for="(item, index) in avatarList" :key="index" class="uni-list-chat__header-box" :class="computedAvatar"
|
||||
:style="{ width: imageWidth + 'px', height: imageWidth + 'px' }">
|
||||
<image class="uni-list-chat__header-image" :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }" :src="item.url"
|
||||
mode="aspectFill"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="badgeText && badgePositon === 'left'" class="uni-list-chat__badge uni-list-chat__badge-pos" :class="[isSingle]">
|
||||
<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
|
||||
</view>
|
||||
<view class="uni-list-chat__content">
|
||||
<view class="uni-list-chat__content-main">
|
||||
<text class="uni-list-chat__content-title uni-ellipsis">{{ title }}</text>
|
||||
<text class="uni-list-chat__content-note uni-ellipsis">{{ note }}</text>
|
||||
</view>
|
||||
<view class="uni-list-chat__content-extra">
|
||||
<slot>
|
||||
<text class="uni-list-chat__content-extra-text">{{ time }}</text>
|
||||
<view v-if="badgeText && badgePositon === 'right'" class="uni-list-chat__badge" :class="[isSingle, badgePositon === 'right' ? 'uni-list-chat--right' : '']">
|
||||
<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
</cell>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 头像大小
|
||||
const avatarWidth = 45;
|
||||
|
||||
/**
|
||||
* ListChat 聊天列表
|
||||
* @description 聊天列表,用于创建聊天类列表
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
|
||||
* @property {String} title 标题
|
||||
* @property {String} note 描述
|
||||
* @property {Boolean} clickable = [true|false] 是否开启点击反馈,默认为false
|
||||
* @property {String} badgeText 数字角标内容
|
||||
* @property {String} badgePositon = [left|right] 角标位置,默认为 right
|
||||
* @property {String} link = [false|navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈,默认为false
|
||||
* @value false 不开启
|
||||
* @value navigateTo 同 uni.navigateTo()
|
||||
* @value redirectTo 同 uni.redirectTo()
|
||||
* @value reLaunch 同 uni.reLaunch()
|
||||
* @value switchTab 同 uni.switchTab()
|
||||
* @property {String | PageURIString} to 跳转目标页面
|
||||
* @property {String} time 右侧时间显示
|
||||
* @property {Boolean} avatarCircle = [true|false] 是否显示圆形头像,默认为false
|
||||
* @property {String} avatar 头像地址,avatarCircle 不填时生效
|
||||
* @property {Array} avatarList 头像组,格式为 [{url:''}]
|
||||
* @event {Function} click 点击 uniListChat 触发事件
|
||||
*/
|
||||
export default {
|
||||
name: 'UniListChat',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
note: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
clickable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
link: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
to: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
badgeText: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
badgePositon: {
|
||||
type: String,
|
||||
default: 'right'
|
||||
},
|
||||
time: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
avatarCircle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
avatarList: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
// inject: ['list'],
|
||||
computed: {
|
||||
isSingle() {
|
||||
if (this.badgeText === 'dot') {
|
||||
return 'uni-badge--dot';
|
||||
} else {
|
||||
const badgeText = this.badgeText.toString();
|
||||
if (badgeText.length > 1) {
|
||||
return 'uni-badge--complex';
|
||||
} else {
|
||||
return 'uni-badge--single';
|
||||
}
|
||||
}
|
||||
},
|
||||
computedAvatar() {
|
||||
if (this.avatarList.length > 4) {
|
||||
this.imageWidth = avatarWidth * 0.31;
|
||||
return 'avatarItem--3';
|
||||
} else if (this.avatarList.length > 1) {
|
||||
this.imageWidth = avatarWidth * 0.47;
|
||||
return 'avatarItem--2';
|
||||
} else {
|
||||
this.imageWidth = avatarWidth;
|
||||
return 'avatarItem--1';
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFirstChild: false,
|
||||
border: true,
|
||||
// avatarList: 3,
|
||||
imageWidth: 50
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.list = this.getForm()
|
||||
if (this.list) {
|
||||
if (!this.list.firstChildAppend) {
|
||||
this.list.firstChildAppend = true;
|
||||
this.isFirstChild = true;
|
||||
}
|
||||
this.border = this.list.border;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getForm(name = 'uniList') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
onClick() {
|
||||
if (this.to !== '') {
|
||||
this.openPage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.clickable || this.link) {
|
||||
this.$emit('click', {
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
},
|
||||
openPage() {
|
||||
if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
|
||||
this.pageApi(this.link);
|
||||
} else {
|
||||
this.pageApi('navigateTo');
|
||||
}
|
||||
},
|
||||
pageApi(api) {
|
||||
uni[api]({
|
||||
url: this.to,
|
||||
success: res => {
|
||||
this.$emit('click', {
|
||||
data: res
|
||||
});
|
||||
},
|
||||
fail: err => {
|
||||
this.$emit('click', {
|
||||
data: err
|
||||
});
|
||||
console.error(err.errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$background-color: #fff;
|
||||
$divide-line-color: #e5e5e5;
|
||||
$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;
|
||||
$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;
|
||||
|
||||
.uni-list-chat {
|
||||
font-size: $uni-font-size-lg;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background-color: $background-color;
|
||||
}
|
||||
|
||||
// .uni-list-chat--disabled {
|
||||
// opacity: 0.3;
|
||||
// }
|
||||
|
||||
.uni-list-chat--hover {
|
||||
background-color: $hover;
|
||||
}
|
||||
|
||||
.uni-list--border {
|
||||
position: relative;
|
||||
margin-left: $uni-spacing-row-lg;
|
||||
/* #ifdef APP-PLUS */
|
||||
border-top-color: $divide-line-color;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0.5px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-list--border:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: 1px;
|
||||
content: '';
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
background-color: $divide-line-color;
|
||||
}
|
||||
|
||||
.uni-list-item--first:after {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.uni-list-chat--first {
|
||||
border-top-width: 0px;
|
||||
}
|
||||
|
||||
.uni-ellipsis {
|
||||
/* #ifndef APP-NVUE */
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
lines: 1;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-ellipsis-2 {
|
||||
/* #ifndef APP-NVUE */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef APP-NVUE */
|
||||
lines: 2;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-list-chat__container {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
padding: $uni-spacing-row-base $uni-spacing-row-lg;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-chat__header-warp {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-list-chat__header {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
align-content: center;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap-reverse;
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
width: $avatar-width;
|
||||
height: $avatar-width;
|
||||
/* #endif */
|
||||
|
||||
border-radius: $avatar-border-radius;
|
||||
border-color: $avatar-border-color;
|
||||
border-width: $avatar-border-width;
|
||||
border-style: solid;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-chat__header-box {
|
||||
/* #ifndef APP-PLUS */
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
width: $avatar-width;
|
||||
height: $avatar-width;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
/* #endif */
|
||||
overflow: hidden;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.uni-list-chat__header-image {
|
||||
margin: 1px;
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
width: $avatar-width;
|
||||
height: $avatar-width;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-list-chat__header-image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.avatarItem--1 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.avatarItem--2 {
|
||||
width: 47%;
|
||||
height: 47%;
|
||||
}
|
||||
|
||||
.avatarItem--3 {
|
||||
width: 32%;
|
||||
height: 32%;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.header--circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-list-chat__content {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.uni-list-chat__content-main {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-left: $uni-spacing-row-base;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-chat__content-title {
|
||||
font-size: $title-size;
|
||||
color: $title-color;
|
||||
font-weight: $title-weight;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-chat__content-note {
|
||||
margin-top: 3px;
|
||||
color: $note-color;
|
||||
font-size: $note-size;
|
||||
font-weight: $title-weight;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-chat__content-extra {
|
||||
/* #ifndef APP-NVUE */
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.uni-list-chat__content-extra-text {
|
||||
color: $right-text-color;
|
||||
font-size: $right-text-size;
|
||||
font-weight: $right-text-weight;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-chat__badge-pos {
|
||||
position: absolute;
|
||||
/* #ifdef APP-NVUE */
|
||||
left: 55px;
|
||||
top: 3px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
left: calc(#{$avatar-width} + 10px - #{$badge-space} + #{$badge-left});
|
||||
top: calc(#{$uni-spacing-row-base}/ 2 + 1px + #{$badge-top});
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-list-chat__badge {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 100px;
|
||||
background-color: $badge-background-color;
|
||||
}
|
||||
|
||||
.uni-list-chat__badge-text {
|
||||
color: $badge-color;
|
||||
font-size: $badge-font;
|
||||
}
|
||||
|
||||
.uni-badge--single {
|
||||
/* #ifndef APP-NVUE */
|
||||
// left: calc(#{$avatar-width} + 7px + #{$badge-left});
|
||||
/* #endif */
|
||||
width: $badge-size;
|
||||
height: $badge-size;
|
||||
}
|
||||
|
||||
.uni-badge--complex {
|
||||
/* #ifdef APP-NVUE */
|
||||
left: 50px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
width: auto;
|
||||
/* #endif */
|
||||
height: $badge-size;
|
||||
padding: 0 $badge-space;
|
||||
}
|
||||
|
||||
.uni-badge--dot {
|
||||
/* #ifdef APP-NVUE */
|
||||
left: 60px;
|
||||
top: 6px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
left: calc(#{$avatar-width} + 15px - #{$dot-width}/ 2 + 1px + #{$badge-left});
|
||||
/* #endif */
|
||||
width: $dot-width;
|
||||
height: $dot-height;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.uni-list-chat--right {
|
||||
/* #ifdef APP-NVUE */
|
||||
left: 0;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
438
uni_modules/uni-list/components/uni-list-item/uni-list-item.vue
Normal file
438
uni_modules/uni-list/components/uni-list-item/uni-list-item.vue
Normal file
@ -0,0 +1,438 @@
|
||||
<template>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<cell>
|
||||
<!-- #endif -->
|
||||
|
||||
<view
|
||||
:class="{ 'uni-list-item--disabled': disabled }"
|
||||
:hover-class="(!clickable && !link) || disabled || showSwitch ? '' : 'uni-list-item--hover'"
|
||||
class="uni-list-item"
|
||||
@click.stop="onClick"
|
||||
>
|
||||
<view v-if="!isFirstChild" class="border--left" :class="{ 'uni-list--border': border }"></view>
|
||||
<view class="uni-list-item__container" :class="{ 'container--right': showArrow || link, 'flex--direction': direction === 'column' }">
|
||||
<slot name="header">
|
||||
<view class="uni-list-item__header">
|
||||
<view v-if="thumb" class="uni-list-item__icon"><image :src="thumb" class="uni-list-item__icon-img" :class="['uni-list--' + thumbSize]" /></view>
|
||||
<view v-else-if="showExtraIcon" class="uni-list-item__icon"><uni-icons :color="extraIcon.color" :size="extraIcon.size" :type="extraIcon.type" /></view>
|
||||
</view>
|
||||
</slot>
|
||||
<slot name="body">
|
||||
<view class="uni-list-item__content" :class="{ 'uni-list-item__content--center': thumb || showExtraIcon || showBadge || showSwitch }">
|
||||
<text v-if="title" class="uni-list-item__content-title" :class="[ellipsis !== 0 && ellipsis <= 2 ? 'uni-ellipsis-' + ellipsis : '']">{{ title }}</text>
|
||||
<text v-if="note" class="uni-list-item__content-note">{{ note }}</text>
|
||||
</view>
|
||||
</slot>
|
||||
<slot name="footer">
|
||||
<view v-if="rightText || showBadge || showSwitch" class="uni-list-item__extra" :class="{ 'flex--justify': direction === 'column' }">
|
||||
<text v-if="rightText" class="uni-list-item__extra-text">{{ rightText }}</text>
|
||||
<uni-badge v-if="showBadge" :type="badgeType" :text="badgeText" />
|
||||
<switch v-if="showSwitch" :disabled="disabled" :checked="switchChecked" @change="onSwitchChange" />
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<uni-icons v-if="showArrow || link" :size="16" class="uni-icon-wrapper" color="#bbb" type="arrowright" />
|
||||
</view>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
</cell>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* ListItem 列表子组件
|
||||
* @description 列表子组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
|
||||
* @property {String} title 标题
|
||||
* @property {String} note 描述
|
||||
* @property {String} thumb 左侧缩略图,若thumb有值,则不会显示扩展图标
|
||||
* @property {String} thumbSize = [lg|base|sm] 略缩图大小
|
||||
* @value lg 大图
|
||||
* @value base 一般
|
||||
* @value sm 小图
|
||||
* @property {String} badgeText 数字角标内容
|
||||
* @property {String} badgeType 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21)
|
||||
* @property {String} rightText 右侧文字内容
|
||||
* @property {Boolean} disabled = [true|false] 是否禁用
|
||||
* @property {Boolean} clickable = [true|false] 是否开启点击反馈
|
||||
* @property {String} link = [navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈
|
||||
* @value navigateTo 同 uni.navigateTo()
|
||||
* @value redirectTo 同 uni.redirectTo()
|
||||
* @value reLaunch 同 uni.reLaunch()
|
||||
* @value switchTab 同 uni.switchTab()
|
||||
* @property {String | PageURIString} to 跳转目标页面
|
||||
* @property {Boolean} showBadge = [true|false] 是否显示数字角标
|
||||
* @property {Boolean} showSwitch = [true|false] 是否显示Switch
|
||||
* @property {Boolean} switchChecked = [true|false] Switch是否被选中
|
||||
* @property {Boolean} showExtraIcon = [true|false] 左侧是否显示扩展图标
|
||||
* @property {Object} extraIcon 扩展图标参数,格式为 {color: '#4cd964',size: '22',type: 'spinner'}
|
||||
* @property {String} direction = [row|column] 排版方向
|
||||
* @value row 水平排列
|
||||
* @value column 垂直排列
|
||||
* @event {Function} click 点击 uniListItem 触发事件
|
||||
* @event {Function} switchChange 点击切换 Switch 时触发
|
||||
*/
|
||||
export default {
|
||||
name: 'UniListItem',
|
||||
props: {
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'row'
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
note: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
ellipsis: {
|
||||
type: [Number],
|
||||
default: 0
|
||||
},
|
||||
disabled: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
clickable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showArrow: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
link: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
to: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
showBadge: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
showSwitch: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
switchChecked: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
badgeText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
badgeType: {
|
||||
type: String,
|
||||
default: 'success'
|
||||
},
|
||||
rightText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
thumb: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
thumbSize: {
|
||||
type: String,
|
||||
default: 'base'
|
||||
},
|
||||
showExtraIcon: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
extraIcon: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
type: 'contact',
|
||||
color: '#000000',
|
||||
size: 20
|
||||
};
|
||||
}
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
// inject: ['list'],
|
||||
data() {
|
||||
return {
|
||||
isFirstChild: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.list = this.getForm()
|
||||
// 判断是否存在 uni-list 组件
|
||||
if(this.list){
|
||||
if (!this.list.firstChildAppend) {
|
||||
this.list.firstChildAppend = true;
|
||||
this.isFirstChild = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getForm(name = 'uniList') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
onClick() {
|
||||
if (this.to !== '') {
|
||||
this.openPage();
|
||||
return;
|
||||
}
|
||||
if (this.clickable || this.link) {
|
||||
this.$emit('click', {
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
},
|
||||
onSwitchChange(e) {
|
||||
this.$emit('switchChange', e.detail);
|
||||
},
|
||||
openPage() {
|
||||
if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
|
||||
this.pageApi(this.link);
|
||||
} else {
|
||||
this.pageApi('navigateTo');
|
||||
}
|
||||
},
|
||||
pageApi(api) {
|
||||
uni[api]({
|
||||
url: this.to,
|
||||
success: res => {
|
||||
this.$emit('click', {
|
||||
data: res
|
||||
});
|
||||
},
|
||||
fail: err => {
|
||||
this.$emit('click', {
|
||||
data: err
|
||||
});
|
||||
console.error(err.errMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$list-item-pd: $uni-spacing-col-lg $uni-spacing-row-lg;
|
||||
|
||||
.uni-list-item {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
font-size: $uni-font-size-lg;
|
||||
position: relative;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
flex-direction: row;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-list-item--disabled {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.uni-list-item--hover {
|
||||
background-color: $uni-bg-color-hover;
|
||||
}
|
||||
|
||||
.uni-list-item__container {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
padding: $list-item-pd;
|
||||
padding-left: $uni-spacing-row-lg;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
// align-items: center;
|
||||
}
|
||||
|
||||
.container--right {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
// .border--left {
|
||||
// margin-left: $uni-spacing-row-lg;
|
||||
// }
|
||||
|
||||
.uni-list--border {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
/* #ifdef APP-NVUE */
|
||||
border-top-color: $uni-border-color;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0.5px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-list--border:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: 1px;
|
||||
content: '';
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
background-color: $uni-border-color;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.uni-list-item__content {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
padding-right: 8px;
|
||||
flex: 1;
|
||||
color: #3b4144;
|
||||
// overflow: hidden;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-item__content--center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.uni-list-item__content-title {
|
||||
font-size: $uni-font-size-base;
|
||||
color: #3b4144;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-item__content-note {
|
||||
margin-top: 6rpx;
|
||||
color: $uni-text-color-grey;
|
||||
font-size: $uni-font-size-sm;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.uni-list-item__extra {
|
||||
// width: 25%;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-list-item__header {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-list-item__icon {
|
||||
margin-right: 18rpx;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-list-item__icon-img {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: block;
|
||||
/* #endif */
|
||||
height: $uni-img-size-base;
|
||||
width: $uni-img-size-base;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.uni-icon-wrapper {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.flex--direction {
|
||||
flex-direction: column;
|
||||
/* #ifndef APP-NVUE */
|
||||
align-items: initial;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.flex--justify {
|
||||
/* #ifndef APP-NVUE */
|
||||
justify-content: initial;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-list--lg {
|
||||
height: $uni-img-size-lg;
|
||||
width: $uni-img-size-lg;
|
||||
}
|
||||
|
||||
.uni-list--base {
|
||||
height: $uni-img-size-base;
|
||||
width: $uni-img-size-base;
|
||||
}
|
||||
|
||||
.uni-list--sm {
|
||||
height: $uni-img-size-sm;
|
||||
width: $uni-img-size-sm;
|
||||
}
|
||||
|
||||
.uni-list-item__extra-text {
|
||||
color: $uni-text-color-grey;
|
||||
font-size: $uni-font-size-sm;
|
||||
}
|
||||
.uni-ellipsis-1 {
|
||||
/* #ifndef APP-NVUE */
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
lines: 1;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-ellipsis-2 {
|
||||
/* #ifndef APP-NVUE */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef APP-NVUE */
|
||||
lines: 2;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
106
uni_modules/uni-list/components/uni-list/uni-list.vue
Normal file
106
uni_modules/uni-list/components/uni-list/uni-list.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view class="uni-list uni-border-top-bottom">
|
||||
<view v-if="border" class="uni-list--border-top"></view>
|
||||
<slot />
|
||||
<view v-if="border" class="uni-list--border-bottom"></view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<list class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop" loadmoreoffset="15"><slot /></list>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* List 列表
|
||||
* @description 列表组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
|
||||
* @property {String} border = [true|false] 标题
|
||||
*/
|
||||
export default {
|
||||
name: 'uniList',
|
||||
'mp-weixin': {
|
||||
options: {
|
||||
multipleSlots: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
enableBackToTop: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
scrollY: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
// provide() {
|
||||
// return {
|
||||
// list: this
|
||||
// };
|
||||
// },
|
||||
created() {
|
||||
this.firstChildAppend = false;
|
||||
},
|
||||
methods: {
|
||||
loadMore(e) {
|
||||
this.$emit('scrolltolower');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.uni-list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
background-color: $uni-bg-color;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.uni-list--border {
|
||||
position: relative;
|
||||
/* #ifdef APP-NVUE */
|
||||
border-top-color: $uni-border-color;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0.5px;
|
||||
border-bottom-color: $uni-border-color;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 0.5px;
|
||||
/* #endif */
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
|
||||
.uni-list--border-top {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: 1px;
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
background-color: $uni-border-color;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.uni-list--border-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: 1px;
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
background-color: $uni-border-color;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
65
uni_modules/uni-list/components/uni-list/uni-refresh.vue
Normal file
65
uni_modules/uni-list/components/uni-list/uni-refresh.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<refresh :display="display" @refresh="onrefresh" @pullingdown="onpullingdown">
|
||||
<slot />
|
||||
</refresh>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view ref="uni-refresh" class="uni-refresh" v-show="isShow">
|
||||
<slot />
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'UniRefresh',
|
||||
props: {
|
||||
display: {
|
||||
type: [String],
|
||||
default: "hide"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pulling: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isShow() {
|
||||
if (this.display === "show" || this.pulling === true) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
onchange(value) {
|
||||
this.pulling = value;
|
||||
},
|
||||
onrefresh(e) {
|
||||
this.$emit("refresh", e);
|
||||
},
|
||||
onpullingdown(e) {
|
||||
// #ifdef APP-NVUE
|
||||
this.$emit("pullingdown", e);
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
var detail = {
|
||||
viewHeight: 90,
|
||||
pullingDistance: e.height
|
||||
}
|
||||
this.$emit("pullingdown", detail);
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.uni-refresh {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
87
uni_modules/uni-list/components/uni-list/uni-refresh.wxs
Normal file
87
uni_modules/uni-list/components/uni-list/uni-refresh.wxs
Normal file
@ -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
|
||||
}
|
||||
87
uni_modules/uni-list/package.json
Normal file
87
uni_modules/uni-list/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
347
uni_modules/uni-list/readme.md
Normal file
347
uni_modules/uni-list/readme.md
Normal file
@ -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
|
||||
<uni-list>
|
||||
<uni-list-item title="列表文字" ></uni-list-item>
|
||||
<uni-list-item :disabled="true" title="列表禁用状态" ></uni-list-item>
|
||||
</uni-list>
|
||||
|
||||
```
|
||||
|
||||
### 多行内容显示
|
||||
|
||||
- 设置 `note` 属性 ,可以在第二行显示描述文本信息
|
||||
|
||||
```html
|
||||
<uni-list>
|
||||
<uni-list-item title="列表文字" note="列表描述信息"></uni-list-item>
|
||||
<uni-list-item :disabled="true" title="列表文字" note="列表禁用状态"></uni-list-item>
|
||||
</uni-list>
|
||||
|
||||
```
|
||||
|
||||
### 右侧显示角标、switch
|
||||
|
||||
- 设置 `show-badge` 属性 ,可以显示角标内容
|
||||
- 设置 `show-switch` 属性,可以显示 switch 开关
|
||||
|
||||
```html
|
||||
<uni-list>
|
||||
<uni-list-item title="列表右侧显示角标" :show-badge="true" badge-text="12" ></uni-list-item>
|
||||
<uni-list-item title="列表右侧显示 switch" :show-switch="true" @switchChange="switchChange" ></uni-list-item>
|
||||
</uni-list>
|
||||
|
||||
```
|
||||
|
||||
### 左侧显示略缩图、图标
|
||||
|
||||
- 设置 `thumb` 属性 ,可以在列表左侧显示略缩图
|
||||
- 设置 `show-extra-icon` 属性,并指定 `extra-icon` 可以在左侧显示图标
|
||||
|
||||
```html
|
||||
<uni-list>
|
||||
<uni-list-item title="列表左侧带略缩图" note="列表描述信息" thumb="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png"
|
||||
thumb-size="lg" rightText="右侧文字"></uni-list-item>
|
||||
<uni-list-item :show-extra-icon="true" :extra-icon="extraIcon1" title="列表左侧带扩展图标" ></uni-list-item>
|
||||
</uni-list>
|
||||
```
|
||||
|
||||
### 开启点击反馈和右侧箭头
|
||||
- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
|
||||
- 设置 `link` 属性,会自动开启点击反馈,并给列表右侧添加一个箭头
|
||||
- 设置 `to` 属性,可以跳转页面,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
|
||||
|
||||
```html
|
||||
|
||||
<uni-list>
|
||||
<uni-list-item title="开启点击反馈" clickable @click="onClick" ></uni-list-item>
|
||||
<uni-list-item title="默认 navigateTo 方式跳转页面" link to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
|
||||
<uni-list-item title="reLaunch 方式跳转页面" link="reLaunch" to="/pages/vue/index/index" @click="onClick($event,1)" ></uni-list-item>
|
||||
</uni-list>
|
||||
|
||||
```
|
||||
|
||||
|
||||
### 聊天列表示例
|
||||
- 设置 `clickable` 为 `true` ,则表示这是一个可点击的列表,会默认给一个点击效果,并可以监听 `click` 事件
|
||||
- 设置 `link` 属性,会自动开启点击反馈,`link` 的值表示跳转方式,如果不指定,默认为 `navigateTo`
|
||||
- 设置 `to` 属性,可以跳转页面
|
||||
- `time` 属性,通常会设置成时间显示,但是这个属性不仅仅可以设置时间,你可以传入任何文本,注意文本长度可能会影响显示
|
||||
- `avatar` 和 `avatarList` 属性同时只会有一个生效,同时设置的话,`avatarList` 属性的长度大于1 ,`avatar` 属性将失效
|
||||
- 可以通过默认插槽自定义列表右侧内容
|
||||
|
||||
```html
|
||||
|
||||
<uni-list>
|
||||
<uni-list :border="true">
|
||||
<!-- 显示圆形头像 -->
|
||||
<uni-list-chat :avatar-circle="true" title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" ></uni-list-chat>
|
||||
<!-- 右侧带角标 -->
|
||||
<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-text="12"></uni-list-chat>
|
||||
<!-- 头像显示圆点 -->
|
||||
<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat>
|
||||
<!-- 头像显示角标 -->
|
||||
<uni-list-chat title="uni-app" avatar="https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="99"></uni-list-chat>
|
||||
<!-- 显示多头像 -->
|
||||
<uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot"></uni-list-chat>
|
||||
<!-- 自定义右侧内容 -->
|
||||
<uni-list-chat title="uni-app" :avatar-list="avatarList" note="您收到一条新的消息" time="2020-02-02 20:20" badge-positon="left" badge-text="dot">
|
||||
<view class="chat-custom-right">
|
||||
<text class="chat-custom-text">刚刚</text>
|
||||
<!-- 需要使用 uni-icons 请自行引入 -->
|
||||
<uni-icons type="star-filled" color="#999" size="18"></uni-icons>
|
||||
</view>
|
||||
</uni-list-chat>
|
||||
</uni-list>
|
||||
</uni-list>
|
||||
|
||||
```
|
||||
|
||||
```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
|
||||
<uni-list>
|
||||
<uni-list-item title="自定义右侧插槽" note="列表描述信息" link>
|
||||
<template slot="header">
|
||||
<image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
|
||||
</template>
|
||||
</uni-list-item>
|
||||
<uni-list-item>
|
||||
<!-- 自定义 header -->
|
||||
<view slot="header" class="slot-box"><image class="slot-image" src="/static/logo.png" mode="widthFix"></image></view>
|
||||
<!-- 自定义 body -->
|
||||
<text slot="body" class="slot-box slot-text">自定义插槽</text>
|
||||
<!-- 自定义 footer-->
|
||||
<template slot="footer">
|
||||
<image class="slot-image" src="/static/logo.png" mode="widthFix"></image>
|
||||
</template>
|
||||
</uni-list-item>
|
||||
</uni-list>
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 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)
|
||||
6
uni_modules/uni-load-more/changelog.md
Normal file
6
uni_modules/uni-load-more/changelog.md
Normal file
@ -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目录规范
|
||||
File diff suppressed because one or more lines are too long
82
uni_modules/uni-load-more/package.json
Normal file
82
uni_modules/uni-load-more/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
uni_modules/uni-load-more/readme.md
Normal file
70
uni_modules/uni-load-more/readme.md
Normal file
@ -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
|
||||
<uni-load-more :status="more"></uni-load-more>
|
||||
```
|
||||
|
||||
## 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)
|
||||
8
uni_modules/uni-scss/changelog.md
Normal file
8
uni_modules/uni-scss/changelog.md
Normal file
@ -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
|
||||
1
uni_modules/uni-scss/index.scss
Normal file
1
uni_modules/uni-scss/index.scss
Normal file
@ -0,0 +1 @@
|
||||
@import './styles/index.scss';
|
||||
82
uni_modules/uni-scss/package.json
Normal file
82
uni_modules/uni-scss/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4
uni_modules/uni-scss/readme.md
Normal file
4
uni_modules/uni-scss/readme.md
Normal file
@ -0,0 +1,4 @@
|
||||
`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
|
||||
|
||||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
|
||||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
|
||||
7
uni_modules/uni-scss/styles/index.scss
Normal file
7
uni_modules/uni-scss/styles/index.scss
Normal file
@ -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';
|
||||
3
uni_modules/uni-scss/styles/setting/_border.scss
Normal file
3
uni_modules/uni-scss/styles/setting/_border.scss
Normal file
@ -0,0 +1,3 @@
|
||||
.uni-border {
|
||||
border: 1px $uni-border-1 solid;
|
||||
}
|
||||
66
uni_modules/uni-scss/styles/setting/_color.scss
Normal file
66
uni_modules/uni-scss/styles/setting/_color.scss
Normal file
@ -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;
|
||||
}
|
||||
55
uni_modules/uni-scss/styles/setting/_radius.scss
Normal file
55
uni_modules/uni-scss/styles/setting/_radius.scss
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
uni_modules/uni-scss/styles/setting/_space.scss
Normal file
56
uni_modules/uni-scss/styles/setting/_space.scss
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
167
uni_modules/uni-scss/styles/setting/_styles.scss
Normal file
167
uni_modules/uni-scss/styles/setting/_styles.scss
Normal file
@ -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 */
|
||||
24
uni_modules/uni-scss/styles/setting/_text.scss
Normal file
24
uni_modules/uni-scss/styles/setting/_text.scss
Normal file
@ -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 */
|
||||
}
|
||||
146
uni_modules/uni-scss/styles/setting/_variables.scss
Normal file
146
uni_modules/uni-scss/styles/setting/_variables.scss
Normal file
@ -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;
|
||||
19
uni_modules/uni-scss/styles/tools/functions.scss
Normal file
19
uni_modules/uni-scss/styles/tools/functions.scss
Normal file
@ -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;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user