From 634e0b9456f44788e55d4e917290faeb54f65ef1 Mon Sep 17 00:00:00 2001 From: zhangzhen Date: Tue, 10 Feb 2026 09:51:18 +0800 Subject: [PATCH] beta --- .gitignore | 10 + .hbuilderx/launch.json | 10 + .vscode/extensions.json | 5 + App.vue | 86 ++ PRD.md | 801 ++++++++++++++++ api/index.js | 49 + assets/autorun.png | Bin 0 -> 536 bytes assets/bg.png | Bin 0 -> 11165 bytes assets/clean.png | Bin 0 -> 347 bytes assets/door.png | Bin 0 -> 282 bytes assets/global.css | 43 + assets/layout.css | 125 +++ assets/light.png | Bin 0 -> 551 bytes assets/logo.png | Bin 0 -> 33553 bytes assets/nowifi.png | Bin 0 -> 558 bytes assets/wifi.png | Bin 0 -> 515 bytes assets/xiaodu.png | Bin 0 -> 401 bytes assets/zhenkong.png | Bin 0 -> 590 bytes components/HeadTitle.vue | 56 ++ components/InputModal.vue | 118 +++ components/InputNum.vue | 105 +++ components/InputNumDrawer.vue | 116 +++ components/InputNumPop.vue | 126 +++ components/Notice.vue | 64 ++ components/PageFooter.vue | 109 +++ components/PageHeader.vue | 133 +++ components/SlotNotice.vue | 59 ++ components/global/index.js | 10 + components/xuan-switch/xuan-switch.vue | 195 ++++ db/sqlite.js | 425 +++++++++ index.html | 20 + js_sdk/zw-devicemac/devicemac.js | 114 +++ js_sdk/zw-devicemac/package.json | 27 + main.js | 34 + manifest.json | 121 +++ package.json | 6 + pages.json | 107 +++ pages/database/database.vue | 205 +++++ pages/index.vue | 754 +++++++++++++++ pages/index/index.vue | 58 ++ pages/log.vue | 168 ++++ pages/modbus/modbus.vue | 432 +++++++++ pages/set/base.vue | 184 ++++ pages/set/device.vue | 101 ++ pages/set/endomanage.vue | 311 +++++++ pages/set/net.vue | 159 ++++ pages/set/personmanage.vue | 297 ++++++ pages/set/run.vue | 318 +++++++ pages/setting.vue | 214 +++++ pages/start.vue | 866 ++++++++++++++++++ static/beep_01.mp3 | Bin 0 -> 8777 bytes static/logo.png | Bin 0 -> 4023 bytes store/index.js | 114 +++ uni.promisify.adaptor.js | 13 + uni.scss | 76 ++ uni_modules/android-serialport/changelog.md | 19 + uni_modules/android-serialport/encrypt | Bin 0 -> 144 bytes uni_modules/android-serialport/package.json | 87 ++ uni_modules/android-serialport/readme.md | 173 ++++ .../utssdk/app-android/config.json | 4 + .../utssdk/app-android/index.uts | Bin 0 -> 5536 bytes .../app-android/libs/serialport-release.aar | Bin 0 -> 31692 bytes uni_modules/uni-data-select/changelog.md | 51 ++ .../uni-data-select/uni-data-select.vue | 837 +++++++++++++++++ uni_modules/uni-data-select/package.json | 106 +++ uni_modules/uni-data-select/readme.md | 8 + uni_modules/uni-easyinput/changelog.md | 121 +++ .../components/uni-easyinput/common.js | 54 ++ .../uni-easyinput/uni-easyinput.vue | 662 +++++++++++++ uni_modules/uni-easyinput/package.json | 107 +++ uni_modules/uni-easyinput/readme.md | 11 + uni_modules/uni-grid/changelog.md | 13 + .../uni-grid-item/uni-grid-item.vue | 127 +++ .../uni-grid/components/uni-grid/uni-grid.vue | 142 +++ uni_modules/uni-grid/package.json | 86 ++ uni_modules/uni-grid/readme.md | 11 + uni_modules/uni-icons/changelog.md | 44 + .../components/uni-icons/uni-icons.uvue | 91 ++ .../components/uni-icons/uni-icons.vue | 110 +++ .../components/uni-icons/uniicons.css | 664 ++++++++++++++ .../components/uni-icons/uniicons.ttf | Bin 0 -> 35824 bytes .../components/uni-icons/uniicons_file.ts | 664 ++++++++++++++ .../components/uni-icons/uniicons_file_vue.js | 649 +++++++++++++ uni_modules/uni-icons/package.json | 111 +++ uni_modules/uni-icons/readme.md | 8 + uni_modules/uni-load-more/changelog.md | 23 + .../components/uni-load-more/i18n/en.json | 5 + .../components/uni-load-more/i18n/index.js | 8 + .../uni-load-more/i18n/zh-Hans.json | 5 + .../uni-load-more/i18n/zh-Hant.json | 5 + .../uni-load-more/uni-load-more.vue | 404 ++++++++ uni_modules/uni-load-more/package.json | 105 +++ uni_modules/uni-load-more/readme.md | 14 + uni_modules/uni-popup/changelog.md | 102 +++ .../components/uni-popup-dialog/keypress.js | 45 + .../uni-popup-dialog/uni-popup-dialog.vue | 330 +++++++ .../uni-popup-message/uni-popup-message.vue | 143 +++ .../uni-popup-share/uni-popup-share.vue | 188 ++++ .../components/uni-popup/i18n/en.json | 7 + .../components/uni-popup/i18n/index.js | 8 + .../components/uni-popup/i18n/zh-Hans.json | 7 + .../components/uni-popup/i18n/zh-Hant.json | 7 + .../components/uni-popup/keypress.js | 45 + .../uni-popup/components/uni-popup/popup.js | 26 + .../components/uni-popup/uni-popup.uvue | 90 ++ .../components/uni-popup/uni-popup.vue | 518 +++++++++++ uni_modules/uni-popup/package.json | 107 +++ uni_modules/uni-popup/readme.md | 17 + uni_modules/uni-row/changelog.md | 10 + .../uni-row/components/uni-col/uni-col.vue | 317 +++++++ .../uni-row/components/uni-row/uni-row.vue | 190 ++++ uni_modules/uni-row/package.json | 87 ++ uni_modules/uni-row/readme.md | 10 + uni_modules/uni-scss/changelog.md | 8 + uni_modules/uni-scss/index.scss | 1 + uni_modules/uni-scss/package.json | 82 ++ uni_modules/uni-scss/readme.md | 4 + uni_modules/uni-scss/styles/index.scss | 7 + .../uni-scss/styles/setting/_border.scss | 3 + .../uni-scss/styles/setting/_color.scss | 66 ++ .../uni-scss/styles/setting/_radius.scss | 55 ++ .../uni-scss/styles/setting/_space.scss | 56 ++ .../uni-scss/styles/setting/_styles.scss | 167 ++++ .../uni-scss/styles/setting/_text.scss | 24 + .../uni-scss/styles/setting/_variables.scss | 146 +++ .../uni-scss/styles/tools/functions.scss | 19 + uni_modules/uni-scss/theme.scss | 31 + uni_modules/uni-scss/variables.scss | 62 ++ uni_modules/uni-section/changelog.md | 2 + .../components/uni-section/uni-section.vue | 167 ++++ uni_modules/uni-section/package.json | 87 ++ uni_modules/uni-section/readme.md | 8 + uni_modules/uni-transition/changelog.md | 31 + .../uni-transition/createAnimation.js | 131 +++ .../uni-transition/uni-transition.vue | 292 ++++++ uni_modules/uni-transition/package.json | 112 +++ uni_modules/uni-transition/readme.md | 11 + utils/actions.js | 9 + utils/beeper.js | 56 ++ utils/cmd.js | 231 +++++ utils/common.js | 91 ++ utils/request/core/request.js | 143 +++ utils/request/core/utils.js | 102 +++ utils/request/index.js | 182 ++++ utils/request/request.js | 7 + utils/request/request.md | 471 ++++++++++ utils/request/upload/qiniuUploader.js | 163 ++++ utils/request/upload/upload.js | 203 ++++ utils/request/upload/utils.js | 288 ++++++ utils/storage.js | 85 ++ 150 files changed, 18730 insertions(+) create mode 100644 .gitignore create mode 100644 .hbuilderx/launch.json create mode 100644 .vscode/extensions.json create mode 100644 App.vue create mode 100644 PRD.md create mode 100644 api/index.js create mode 100644 assets/autorun.png create mode 100644 assets/bg.png create mode 100644 assets/clean.png create mode 100644 assets/door.png create mode 100644 assets/global.css create mode 100644 assets/layout.css create mode 100644 assets/light.png create mode 100644 assets/logo.png create mode 100644 assets/nowifi.png create mode 100644 assets/wifi.png create mode 100644 assets/xiaodu.png create mode 100644 assets/zhenkong.png create mode 100644 components/HeadTitle.vue create mode 100644 components/InputModal.vue create mode 100644 components/InputNum.vue create mode 100644 components/InputNumDrawer.vue create mode 100644 components/InputNumPop.vue create mode 100644 components/Notice.vue create mode 100644 components/PageFooter.vue create mode 100644 components/PageHeader.vue create mode 100644 components/SlotNotice.vue create mode 100644 components/global/index.js create mode 100644 components/xuan-switch/xuan-switch.vue create mode 100644 db/sqlite.js create mode 100644 index.html create mode 100644 js_sdk/zw-devicemac/devicemac.js create mode 100644 js_sdk/zw-devicemac/package.json create mode 100644 main.js create mode 100644 manifest.json create mode 100644 package.json create mode 100644 pages.json create mode 100644 pages/database/database.vue create mode 100644 pages/index.vue create mode 100644 pages/index/index.vue create mode 100644 pages/log.vue create mode 100644 pages/modbus/modbus.vue create mode 100644 pages/set/base.vue create mode 100644 pages/set/device.vue create mode 100644 pages/set/endomanage.vue create mode 100644 pages/set/net.vue create mode 100644 pages/set/personmanage.vue create mode 100644 pages/set/run.vue create mode 100644 pages/setting.vue create mode 100644 pages/start.vue create mode 100644 static/beep_01.mp3 create mode 100644 static/logo.png create mode 100644 store/index.js create mode 100644 uni.promisify.adaptor.js create mode 100644 uni.scss create mode 100644 uni_modules/android-serialport/changelog.md create mode 100644 uni_modules/android-serialport/encrypt create mode 100644 uni_modules/android-serialport/package.json create mode 100644 uni_modules/android-serialport/readme.md create mode 100644 uni_modules/android-serialport/utssdk/app-android/config.json create mode 100644 uni_modules/android-serialport/utssdk/app-android/index.uts create mode 100644 uni_modules/android-serialport/utssdk/app-android/libs/serialport-release.aar create mode 100644 uni_modules/uni-data-select/changelog.md create mode 100644 uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue create mode 100644 uni_modules/uni-data-select/package.json create mode 100644 uni_modules/uni-data-select/readme.md create mode 100644 uni_modules/uni-easyinput/changelog.md create mode 100644 uni_modules/uni-easyinput/components/uni-easyinput/common.js create mode 100644 uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue create mode 100644 uni_modules/uni-easyinput/package.json create mode 100644 uni_modules/uni-easyinput/readme.md create mode 100644 uni_modules/uni-grid/changelog.md create mode 100644 uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue create mode 100644 uni_modules/uni-grid/components/uni-grid/uni-grid.vue create mode 100644 uni_modules/uni-grid/package.json create mode 100644 uni_modules/uni-grid/readme.md create mode 100644 uni_modules/uni-icons/changelog.md create mode 100644 uni_modules/uni-icons/components/uni-icons/uni-icons.uvue create mode 100644 uni_modules/uni-icons/components/uni-icons/uni-icons.vue create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons.css create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons.ttf create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons_file.ts create mode 100644 uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js create mode 100644 uni_modules/uni-icons/package.json create mode 100644 uni_modules/uni-icons/readme.md create mode 100644 uni_modules/uni-load-more/changelog.md create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/en.json create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/index.js create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json create mode 100644 uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json create mode 100644 uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue create mode 100644 uni_modules/uni-load-more/package.json create mode 100644 uni_modules/uni-load-more/readme.md create mode 100644 uni_modules/uni-popup/changelog.md create mode 100644 uni_modules/uni-popup/components/uni-popup-dialog/keypress.js create mode 100644 uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue create mode 100644 uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue create mode 100644 uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/en.json create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/index.js create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json create mode 100644 uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json create mode 100644 uni_modules/uni-popup/components/uni-popup/keypress.js create mode 100644 uni_modules/uni-popup/components/uni-popup/popup.js create mode 100644 uni_modules/uni-popup/components/uni-popup/uni-popup.uvue create mode 100644 uni_modules/uni-popup/components/uni-popup/uni-popup.vue create mode 100644 uni_modules/uni-popup/package.json create mode 100644 uni_modules/uni-popup/readme.md create mode 100644 uni_modules/uni-row/changelog.md create mode 100644 uni_modules/uni-row/components/uni-col/uni-col.vue create mode 100644 uni_modules/uni-row/components/uni-row/uni-row.vue create mode 100644 uni_modules/uni-row/package.json create mode 100644 uni_modules/uni-row/readme.md create mode 100644 uni_modules/uni-scss/changelog.md create mode 100644 uni_modules/uni-scss/index.scss create mode 100644 uni_modules/uni-scss/package.json create mode 100644 uni_modules/uni-scss/readme.md create mode 100644 uni_modules/uni-scss/styles/index.scss create mode 100644 uni_modules/uni-scss/styles/setting/_border.scss create mode 100644 uni_modules/uni-scss/styles/setting/_color.scss create mode 100644 uni_modules/uni-scss/styles/setting/_radius.scss create mode 100644 uni_modules/uni-scss/styles/setting/_space.scss create mode 100644 uni_modules/uni-scss/styles/setting/_styles.scss create mode 100644 uni_modules/uni-scss/styles/setting/_text.scss create mode 100644 uni_modules/uni-scss/styles/setting/_variables.scss create mode 100644 uni_modules/uni-scss/styles/tools/functions.scss create mode 100644 uni_modules/uni-scss/theme.scss create mode 100644 uni_modules/uni-scss/variables.scss create mode 100644 uni_modules/uni-section/changelog.md create mode 100644 uni_modules/uni-section/components/uni-section/uni-section.vue create mode 100644 uni_modules/uni-section/package.json create mode 100644 uni_modules/uni-section/readme.md create mode 100644 uni_modules/uni-transition/changelog.md create mode 100644 uni_modules/uni-transition/components/uni-transition/createAnimation.js create mode 100644 uni_modules/uni-transition/components/uni-transition/uni-transition.vue create mode 100644 uni_modules/uni-transition/package.json create mode 100644 uni_modules/uni-transition/readme.md create mode 100644 utils/actions.js create mode 100644 utils/beeper.js create mode 100644 utils/cmd.js create mode 100644 utils/common.js create mode 100644 utils/request/core/request.js create mode 100644 utils/request/core/utils.js create mode 100644 utils/request/index.js create mode 100644 utils/request/request.js create mode 100644 utils/request/request.md create mode 100644 utils/request/upload/qiniuUploader.js create mode 100644 utils/request/upload/upload.js create mode 100644 utils/request/upload/utils.js create mode 100644 utils/storage.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..49910bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +node_modules +out/ +logs/ +run/ +.idea/ +package-lock.json +data/ +.vscode/launch.json +unpackage/ +pnpm-lock.yaml diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json new file mode 100644 index 0000000..29998cf --- /dev/null +++ b/.hbuilderx/launch.json @@ -0,0 +1,10 @@ +{ + "version" : "1.0", + "configurations" : [ + { + "customPlaygroundType" : "local", + "playground" : "custom", + "type" : "uni-app:app-android" + } + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..05b187b --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "tencent-cloud.coding-copilot" + ] +} \ No newline at end of file diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..0bd478f --- /dev/null +++ b/App.vue @@ -0,0 +1,86 @@ + + + diff --git a/PRD.md b/PRD.md new file mode 100644 index 0000000..b1ec5f7 --- /dev/null +++ b/PRD.md @@ -0,0 +1,801 @@ +# 智能内镜储存柜系统 PRD + +## 文档信息 +- **项目名称**: 智能内镜储存柜系统 +- **版本**: v1.0.1 +- **文档日期**: 2026-01-20 +- **应用平台**: Android (UniApp + Vue3) + +--- + +## 1. 产品概述 + +### 1.1 产品定位 +智能内镜储存柜是一款面向医疗场景的专业内镜存储管理设备,通过物联网技术实现内镜的智能存取、环境监控、自动消毒等功能,提升医院内镜管理效率和使用安全性。 + +### 1.2 核心价值 +- **智能管理**: 通过RFID/IC卡技术实现内镜自动识别和存取记录 +- **环境监控**: 实时监控储存柜内的温度、湿度、压差等关键指标 +- **安全存储**: 自动消毒、真空保鲜、门禁管理等多重保障 +- **数据追溯**: 完整的操作日志记录,便于追踪和管理 + +--- + +## 2. 系统架构 + +### 2.1 技术栈 +- **前端框架**: UniApp + Vue3 +- **UI组件**: Ant Design Vue +- **状态管理**: Vuex +- **本地存储**: SQLite +- **硬件通信**: RS485 (传感器 + 门控制) + RS232 (卡片识别 + 设备控制) +- **原生插件**: android-serialport (串口通信) + +### 2.2 硬件组成 +- **RS485串口**: 温湿度传感器、压差传感器、门锁控制器(左右门) +- **RS232串口**: 16个内镜位置IC卡读写器,门口1个IC卡读写器(可读取人员卡和内镜卡) +- **继电器控制**: 风机、照明、真空泵、消毒设备 +- **门系统**: 主门(概念门)、左门、右门(实体门) + +--- + +## 3. 功能模块 + +### 3.1 启动模块 + +#### 功能描述 +应用启动页面,负责系统初始化和硬件自检。 + +#### 核心功能 +- **串口初始化** + - RS485串口: `/dev/ttyUSB2`, 波特率 9600 + - RS232串口: `/dev/ttyUSB1`, 波特率 115200 + - 支持通过配置文件自定义串口参数 + +- **本地存储初始化** + - 加载运行参数配置 + - 加载基础设置 + - 加载服务器配置 + +- **数据库初始化** + - user表: 人员卡信息 + - endo表: 内镜卡片信息 + - scope表: 16个内镜位置状态 + - log表: 操作日志 + +- **时间同步** + - 本地时间初始化 + - 网络时间同步(联网状态下) + +#### 入口控制 +- 点击"进入"按钮跳转主界面 +- 密码保护: 可设置屏幕解锁密码 +- 调试模式: 连续点击标题5次触发,提供Modbus调试、SQLite调试、清除缓存功能 + +--- + +### 3.2 主界面模块 + +#### 功能描述 +系统核心操作界面,实时显示设备状态和内镜存储情况。 + +#### 核心功能 + +##### 3.2.1 环境监控显示 +- **温度显示**: 实时显示当前温度(°C),超出阈值自动启动风机 +- **湿度显示**: 实时显示当前湿度(%RH),超出阈值自动启动风机 +- **压差显示**: 实时显示当前压差(Pa),支持压差补偿值设置 +- **联网状态**: 显示当前网络连接状态 +- **模式切换**: 自动模式/清扫模式 + +##### 3.2.2 内镜存储管理 +- **16个存储位置**: 每个位置支持2个内镜存储位 +- **实时状态显示**: + - 空闲: 显示"已取出" + - 占用: 显示内镜编号和存储时长(如: "已存入:32h 42m") + - 临期提醒: 黄色高亮显示(超过临期阈值) + - 超期提醒: 红色高亮显示(超过超期阈值) +- **自动刷新**: 每60秒自动刷新内镜列表数据 + +##### 3.2.3 设备控制 +| 控制项 | 功能说明 | 手动操作 | 自动逻辑 | +|--------|----------|----------|----------| +| 照明 | 控制柜内照明 | 开启/关闭按钮 | 开门自动开启,关门自动关闭 | +| 开门 | 控制左门/右门 | 手动选择门,通过RS485发送开门指令 | 人员刷卡验证通过后,弹窗选择开左门/右门 | +| 消毒 | 控制消毒设备 | 点击开启(运行指定时长后自动关闭) | 根据时间段自动启动/停止 | +| 真空 | 控制真空泵 | (预留) | 开门关闭,关门开启,定时运行/停止 | + +##### 3.2.4 模式切换 +- **自动模式**: 系统自动运行消毒、真空泵、风机等任务 +- **清扫模式**: 停止自动任务,便于设备维护清洁 + +--- + +### 3.3 串口通信模块 + +#### 3.3.1 RS485通信(传感器数据) + +**支持的传感器:** +- **温湿度传感器**: 站号02 + - 读取指令: `020300000002C438` + - 返回数据格式: `01 03 04 XX XX XX XX XX XX ...` + +- **压差传感器**: 站号01 + - 读取指令: `01030001000295CB` + - 返回数据格式: `01 03 02 XX XX XX XX ...` + +- **门状态监测与控制**: 站号03 + - 协议说明: 采用中盛4路数字IO模块,通过Modbus RTU协议通信 + - 左门控制(通道1,地址0000H): + - 左门开门指令(磁吸通电): `030600000001480A` (发送后,leftDoor状态更新为true) + - 左门关门指令(磁吸断电): `03060000000089CA` (发送后,leftDoor状态更新为false) + - 右门控制(通道2,地址0001H): + - 右门开门指令(磁吸通电): `03060001000109CA` (发送后,rightDoor状态更新为true) + - 右门关门指令(磁吸断电): `03060001000048E8` (发送后,rightDoor状态更新为false) + - 门状态上报(功能码04,读输入寄存器): + - 左门触点开关状态变化时主动上报 + - 右门触点开关状态变化时主动上报 + - 收到上报数据后需更新对应门状态 + - 状态定义: true=开门(磁吸通电), false=关门(磁吸断电,触点触发) + +**门状态计算规则:** +- 门状态(door) = 左门状态(leftDoor) OR 右门状态(rightDoor) +- 任一门打开时,door状态为开 +- 两门都关闭时,door状态为关 + +**数据读取策略:** +- 定时轮询: 每5秒读取一次温湿度数据,间隔1秒读取压差数据 +- 数据校验: 温湿度数据过滤异常值(0-100范围内有效) + +#### 3.3.2 RS232通信(控制与卡片识别) + +**指令协议:** +| 功能 | 指令码 | 格式 | 说明 | +|------|--------|------|------| +| 风机控制 | 02 | `5AA5EE02` + `01`(开)/`00`(关) | 控制风机 | +| 照明控制 | 03 | `5AA5EE03` + `01`(开)/`00`(关) | 控制照明 | +| 真空泵控制 | 04 | `5AA5EE04` + `01`(开)/`00`(关) | 控制真空泵 | +| 消毒控制 | 05 | `5AA5EE05` + `01`(开)/`00`(关) | 控制消毒设备 | + +**门状态逻辑说明:** +- 门开关状态(door)是逻辑状态,由左右门物理状态共同决定 +- 规则: `door = leftDoor OR rightDoor` + - 左门开 或 右门开 → door = true (开) + - 左门关 且 右门关 → door = false (关) + +**门控制流程:** +1. 发送开门指令到RS485站号03 + - 左门开门: `cmd.LeftDoor(true)` → 发送 `030600000001480A` (磁吸通电) + - 右门开门: `cmd.RightDoor(true)` → 发送 `03060001000109CA` (磁吸通电) +2. 指令发送后,立即更新对应门的物理状态 + - 左门打开 → `leftDoor = true` + - 右门打开 → `rightDoor = true` +3. 根据左右门状态自动计算门状态 + - `door = leftDoor OR rightDoor` +4. 发送关门指令到RS485站号03 + - 左门关门: `cmd.LeftDoor(false)` → 发送 `03060000000089CA` (磁吸断电) + - 右门关门: `cmd.RightDoor(false)` → 发送 `03060001000048E8` (磁吸断电) +5. 指令发送后,更新对应门的物理状态 + - 左门关闭 → `leftDoor = false` + - 右门关闭 → `rightDoor = false` +6. 重新计算门状态 `door = leftDoor OR rightDoor` + +**卡片识别协议:** +- **门口IC卡读写器**: 1个,位于门口,可读取人员卡和内镜卡 + - 卡存入: `20 01 00 08 04 00 00 00 [卡号4字节] [校验] 03` (14字节) + - 卡离开: `20 01 00 01 02 [校验] 03` (7字节) + - 卡号位置: 倒数4-8字节为卡号数据 + +- **16个内镜位置IC卡读写器**: 每个内镜位置1个,仅读取内镜卡 + - 卡存入: `20 01 00 08 04 00 00 00 [卡号4字节] [校验] 03` (14字节) + - 卡离开: `20 01 00 01 02 [校验] 03` (7字节) + - 卡号位置: 倒数4-8字节为卡号数据 + +**卡片处理逻辑:** +- **卡片读取**: 接收卡片数据 → 提取卡号 → 在数据库中比对判断卡片类型 + - 在user表中找到 → 人员卡 + - 在endo表中找到 → 内镜卡 + - 都未找到 → 无效卡片 + +- **人员卡存入**: 验证人员卡号是否在user数据库中 → 弹窗选择开左门/开右门 → 用户确认后通过RS485发送开门指令 → 更新门状态 → 记录日志 +- **内镜卡存入**: 验证内镜卡号是否在endo数据库中 → 弹窗选择存入/取出 → 用户选择后更新scope表对应位置 → 记录日志 +- **内镜卡取出**: 弹窗确认取出 → 更新scope表对应位置为空闲 → 记录日志 + +--- + +### 3.4 自动任务模块 + +#### 3.4.1 自动消毒任务 +- **配置**: 支持多时间段配置(如: 08:00-10:00, 14:00-16:00) +- **执行逻辑**: + - 到达开始时间 → 启动消毒和风机 + - 到达结束时间 → 停止消毒 + - 仅在自动模式下生效 +- **运行时长**: 手动启动时运行指定时长后自动关闭 + +#### 3.4.2 真空泵任务 +- **运行时长控制**: 连续运行超过指定时长后自动停止 +- **间隔运行控制**: 停止后间隔指定时长自动启动 +- **执行逻辑**: + - 开门时 → 关闭真空泵 + - 关门时 → 启动真空泵和风机 + - 到达运行时长 → 关闭真空泵 + - 到达间隔时长 → 启动真空泵和风机 + +#### 3.4.3 风机自动控制 +- **启动条件**: + - 温度超过阈值 + - 湿度超过阈值 + - 消毒设备启动 + - 真空泵启动 +- **停止条件**: + - 温度和湿度均低于阈值 + - 照明、真空泵、消毒、门均处于关闭状态 + - 清扫模式下不自动控制 + +#### 3.4.4 门状态监控 +- **开门超时报警**: 开门超过3分钟且非清扫模式 → 触发蜂鸣器报警 → 弹窗提示 +- **门状态记录**: 记录开门/关门时间 +- **门状态同步**: 概念门(door)状态 = 左门(leftDoor) OR 右门(rightDoor) +- **门状态监测**: 通过RS485站号03接收触点开关状态上报(功能码04) + - 收到DI状态变化上报时解析并更新对应门状态 + - 左门触点触发(关门): 更新 `leftDoor = false` + - 右门触点触发(关门): 更新 `rightDoor = false` + +--- + +### 3.5 设置模块 + +#### 功能描述 +系统参数配置界面,需密码验证后访问。 + +#### 3.5.1 设置菜单 + +**设备信息管理** +- 查看设备基本信息 +- 设备SN码管理 + +**基础设置** +- 屏幕解锁密码 +- 设置密码(访问设置界面) + +**服务器设置** +- 服务器IP地址 +- 服务器端口 +- API接口配置 + +**运行参数设置** +- 温度阈值(自动启动风机) +- 湿度阈值(自动启动风机) +- 压差补偿值 +- 内镜临期提醒时长 +- 内镜超期提醒时长 +- 消毒时长(手动启动时的运行时间) +- 真空泵运行时长 +- 真空泵间隔时长 +- 自动消毒时间段配置(支持多时段) + +**内镜信息管理** +- 添加/编辑/删除内镜卡片 +- 内镜RFID编号 +- 内镜型号、品牌、类型 + +**人员信息管理** +- 添加/编辑/删除人员卡片 +- 人员IC卡编号 +- 人员姓名 + +#### 3.5.2 数据同步功能 +- **时间同步**: 同步网络时间 +- **内镜信息同步**: 从服务器同步内镜列表 +- **人员信息同步**: 从服务器同步人员列表 +- **运行参数同步**: 从服务器同步运行参数 + +--- + +### 3.6 日志模块 + +#### 功能描述 +显示系统操作日志,支持分页查询。 + +#### 核心功能 +- **日志类型**: + - 内镜存入记录 + - 内镜取出记录 + - 刷卡开门记录 + - 设备操作记录 + +- **日志字段**: + - 时间 + - 操作对象(人员/内镜编号) + - 操作类型(存入/取出/开门等) + +- **分页显示**: 每页15条,支持上一页/下一页翻页 + +--- + +## 4. 数据库设计 + +### 4.1 user表(人员信息) +| 字段名 | 类型 | 说明 | +|--------|------|------| +| ic | TEXT | 人员卡号 | +| name | TEXT | 人员姓名 | +| create_time | TEXT | 创建时间 | +| _openid | VARCHAR(64) | 用户标识 | + +### 4.2 endo表(内镜信息) +| 字段名 | 类型 | 说明 | +|--------|------|------| +| rfid | TEXT | 内镜RFID编号 | +| ic | TEXT | 内镜IC卡号 | +| model | TEXT | 内镜型号 | +| brand | TEXT | 品牌 | +| type | TEXT | 类型 | +| create_time | TEXT | 创建时间 | +| _openid | VARCHAR(64) | 用户标识 | + +### 4.3 scope表(内镜位置状态) +| 字段名 | 类型 | 说明 | +|--------|------|------| +| key | INTEGER | 位置编号(0-15) | +| name | TEXT | 状态名称(enter/leave) | +| ic | TEXT | 存储的内镜卡号 | +| time | TEXT | 存入时间 | +| _openid | VARCHAR(64) | 用户标识 | + +### 4.4 log表(操作日志) +| 字段名 | 类型 | 说明 | +|--------|------|------| +| name | TEXT | 操作对象 | +| action | TEXT | 操作类型 | +| create_time | TEXT | 操作时间 | +| _openid | VARCHAR(64) | 用户标识 | + +--- + +## 5. 状态管理(Vuex) + +### 5.1 relay(继电器状态) +```javascript +{ + door: false, // 主门状态(概念门) + leftDoor: false, // 左门状态 + rightDoor: false, // 右门状态 + wind: false, // 风机状态 + light: false, // 照明状态 + vacuum: false, // 真空泵状态 + disinfect: false // 消毒状态 +} +``` + +### 5.2 sensor(传感器数据) +```javascript +{ + temp: 0, // 温度(°C) + humi: 0, // 湿度(%RH) + pressure: 0 // 压差 +} +``` + +### 5.3 run(运行参数) +```javascript +{ + temp: 30, // 温度阈值 + humi: 60, // 湿度阈值 + pressureCom: 0, // 压差补偿值 + endoNear: 24, // 临期提醒时长(小时) + endoOver: 48, // 超期提醒时长(小时) + disinfectTime: 30, // 消毒时长(分钟) + vacuumRunTime: 5, // 真空泵运行时长(分钟) + vacuumPerHour: 2, // 真空泵间隔时长(小时) + group: [ // 自动消毒时间段 + { start: {h:8, m:0}, end: {h:10, m:0}, status: true }, + { start: {h:14, m:0}, end: {h:16, m:0}, status: true } + ] +} +``` + +### 5.4 timer(计时器状态) +```javascript +{ + door: '', // 开门时间 + doorAlert: false, // 门报警状态 + disinfect: '', // 消毒开始时间 + wind: '', // 风机开始时间 + vacuumStart: '', // 真空泵开始时间 + vacuumEnd: '' // 真空泵停止时间 +} +``` + +### 5.5 其他状态 +- `clean`: 清扫模式标志 +- `autoDisinfect`: 自动消毒标志 +- `connect`: 网络连接状态 +- `apiUrl`: API服务器地址 +- `time`: 当前系统时间 + +--- + +## 6. 接口设计(API) + +### 6.1 获取网络时间 +- **接口**: `GET /api/time` +- **返回**: 时间字符串(如: "2026-01-20 10:30:00") + +### 6.2 内镜列表同步 +- **接口**: `GET /api/endoscopelist` +- **返回**: +```json +{ + "endoscope_list": [ + { + "endoscope_rfid": "RFID001", + "endoscope_model": "型号1", + "endoscope_brand": "品牌1", + "endoscope_type": "胃镜" + } + ] +} +``` + +### 6.3 人员列表同步 +- **接口**: `GET /api/userlist` +- **返回**: 人员列表数据 + +### 6.4 运行参数同步 +- **接口**: `GET /api/parameterlist` +- **返回**: 运行参数配置数据 + +### 6.5 日志上传 +- **接口**: `POST /api/logsync` +- **参数**: 日志数据数组 + +--- + +## 7. 交互流程 + +### 7.1 完整操作流程 +``` +1. 刷人员卡 + - 系统读取卡号,验证是否在user数据库中 + - 验证通过: 弹窗提示"选择要打开的门",显示"开左门"和"开右门"按钮 + - 验证失败: 提示"无权限" + +2. 选择门并打开 + - 用户点击"开左门"或"开右门" + - 通过RS485发送对应开门指令 + - 系统自动开启照明和风机 + - 提示"左门已打开"或"右门已打开" + +3. 刷内镜卡 + - 系统读取卡号,验证是否在endo数据库中 + - 验证通过: 弹窗提示"选择操作",显示"存入"和"取出"按钮 + - 验证失败: 提示"无效内镜卡" + +4. 选择操作 + - 用户点击"存入": 根据插入位置更新scope表 → 记录日志 → 提示"内镜已存入" + - 用户点击"取出": 更新scope表对应位置为空闲 → 记录日志 → 提示"内镜已取出" + +5. 关门 + - 用户手动关门 + - 触点开关触发,IO控制器上报DI状态变化 + - 系统收到上报数据,更新对应门状态为关闭 + - 自动关闭照明,开启真空泵和风机 +``` + +### 7.2 内镜存取详细流程 +``` +1. 用户将内镜卡插入对应位置 +2. IC卡读写器检测到卡片 +3. 系统解析卡片数据,提取卡号 +4. 在数据库中查询卡号,判断卡片类型 + - 在endo表中找到 → 内镜卡 + - 在user表中找到 → 人员卡 + - 都未找到 → 无效卡片 +5. 验证内镜卡号是否在endo数据库中 + - 验证通过: 弹窗选择"存入"或"取出" + - 用户选择存入: 根据插入位置更新scope表对应位置 → 记录日志 → 弹窗提示"内镜已存入" + - 用户选择取出: 更新scope表对应位置为空闲 → 记录日志 → 弹窗提示"内镜已取出" + - 验证失败: 提示"无效内镜卡" +``` + +### 7.2 内镜取出流程 +``` +1. 用户点击"取镜"按钮 +2. 弹窗显示"取镜",提示"请刷人员卡" +3. 用户刷人员卡 + - 系统读取卡号,验证是否在user数据库中 + - 验证通过: 弹窗显示人员姓名 + - 验证失败: 提示"无权限" +4. 系统提示"请刷内镜卡" +5. 用户刷内镜卡 + - 系统读取卡号,验证是否在endo数据库中 + - 验证通过: 弹窗显示内镜名称、钢印号、类型等信息 + - 验证失败: 提示"无效内镜卡" +6. 弹窗显示"确定"按钮 +7. 用户点击"确定"按钮 + - 系统更新scope表对应位置为空闲 + - 记录操作日志(包括操作人员、内镜信息) + - 弹出Toast提示"取镜成功" + - 关闭弹窗 +``` + +### 7.3 人员刷卡开门流程 +``` +1. 人员在主门处刷人员卡 +2. IC卡读写器检测到卡片 +3. 系统解析卡片数据,提取卡号 +4. 在数据库中查询卡号,判断卡片类型 + - 在user表中找到 → 人员卡 + - 在endo表中找到 → 内镜卡 + - 都未找到 → 无效卡片 +5. 验证人员卡号是否在user数据库中 + - 验证通过: 弹窗选择"开左门"或"开右门" + - 用户选择左门: 通过RS485发送左门开门指令 `030600000001480A` → 更新leftDoor状态 → 记录日志 → 提示"左门已打开" + - 用户选择右门: 通过RS485发送右门开门指令 `03060001000109CA` → 更新rightDoor状态 → 记录日志 → 提示"右门已打开" + - 验证失败: 提示"无权限" +``` + +### 7.4 手动开门流程 +``` +1. 点击主界面"开门"按钮 +2. 弹出门选择对话框(开左门/开右门) +3. 用户选择要打开的门 +4. 通过RS485发送对应开门指令 + - 左门: 发送 `030600000001480A` → 更新leftDoor=true → 记录日志 → 提示"左门已打开" + - 右门: 发送 `03060001000109CA` → 更新rightDoor=true → 记录日志 → 提示"右门已打开" +``` + +### 7.5 开门事件自动处理流程 +``` +1. 检测到门打开(通过RS485站号03监测,发送开门指令后立即更新状态) + - 左门打开: leftDoor = true + - 右门打开: rightDoor = true + - door = leftDoor OR rightDoor +2. 关闭真空泵 +3. 延迟300ms开启照明 +4. 延迟300ms开启风机 +5. 记录开门时间 +6. 启动开门超时监控(3分钟) +``` + +### 7.7 关门事件自动处理流程 +``` +1. 检测到门关闭(通过RS485站号03监测,收到功能码04的DI状态上报) +2. 解析上报数据,识别是左门还是右门的触点触发 + - 左门触点触发: 更新 leftDoor = false + - 右门触点触发: 更新 rightDoor = false +3. 重新计算door状态: door = leftDoor OR rightDoor +4. 关闭照明 +5. 延迟300ms开启真空泵和风机 +6. 清除开门超时监控 +7. 停止报警 +``` + +--- + +## 8. 异常处理 + +### 8.1 串口通信异常 +- 串口初始化失败 → 提示"初始化串口失败" +- 串口打开失败 → 提示错误信息 +- 指令发送失败 → 记录错误日志,不影响系统运行 + +### 8.2 数据验证异常 +- 无效内镜卡 → 弹窗提示"无效内镜卡" +- 无效人员卡 → 弹窗提示"无权限" +- 超期内镜 → 黄色高亮提醒 +- 超期内镜 → 红色高亮提醒 + +### 8.3 网络异常 +- 网络未连接 → 显示"未连接"状态 +- 网络同步失败 → 提示"同步失败,请检查网络" +- 自动重试机制(暂未实现) + +### 8.4 设备操作异常 +- 开门超时(>3分钟) → 蜂鸣器报警 + 弹窗提示"未关门,请及时关闭" +- 温湿度异常 → 自动启动风机 +- 压差数据异常 → 过滤无效数据 + +--- + +## 9. 安全设计 + +### 9.1 访问控制 +- 屏幕解锁密码: 保护主界面访问 +- 设置密码: 保护设置界面访问 + +### 9.2 操作审计 +- 所有关键操作记录到日志表 +- 日志包含时间、操作人、操作内容 + +### 9.3 卡片验证 +- 所有内镜卡和人员卡必须在数据库中注册 +- 未经注册的卡片无法操作 + +### 9.4 调试模式保护 +- 调试入口隐藏(连续点击标题5次触发) +- 调试模式提供数据清除功能(需谨慎操作) + +--- + +## 10. 性能要求 + +### 10.1 响应时间 +- 界面切换: < 300ms +- 串口指令响应: < 100ms +- 数据刷新间隔: 60秒 + +### 10.2 数据处理 +- 串口数据解析: 实时处理 +- 数据库查询: < 200ms +- 日志记录: 异步存储 + +### 10.3 资源占用 +- 内存占用: < 200MB +- CPU占用: < 20%(正常运行时) + +--- + +## 11. 非功能性需求 + +### 11.1 可靠性 +- 7x24小时不间断运行 +- 异常情况下自动恢复 +- 断网情况下本地功能正常运行 + +### 11.2 可维护性 +- 模块化设计,便于功能扩展 +- 完善的日志记录 +- 调试模式支持问题排查 + +### 11.3 可扩展性 +- 支持增加内镜位置(需修改硬件) +- 支持新增传感器类型 +- 支持新增控制设备 + +--- + +## 12. 版本规划 + +### v1.0.1 (当前版本) +- ✅ 基础功能完整 +- ✅ 左右门独立控制 +- ✅ RS485门状态监测集成 +- ✅ 自动任务执行 +- ✅ 日志记录 +- ✅ 环境监控 +- ✅ 卡片识别 + +### v1.1.0 (当前开发中) +- 🔄 取镜流程优化(人员卡+内镜卡双卡片验证) +- 🔄 串口通信错误处理优化 +- 🔄 状态同步逻辑完善 + +### v2.0.0 (未来规划) +- 📋 网络日志上传 +- 📋 远程控制接口 +- 📋 数据统计分析 +- 📋 多设备管理 + +--- + +## 13. 附录 + +### 13.1 术语表 +| 术语 | 说明 | +|------|------| +| 主门(概念门) | 逻辑门状态,由左门和右门状态共同决定(door = leftDoor OR rightDoor) | +| 实体门 | 物理门锁(左门/右门) | +| IC卡 | 接触式智能卡 | +| RFID卡 | 射频识别卡 | +| RS485 | 串行通信标准,用于传感器通信和门控制 | +| RS232 | 串行通信标准,用于卡片识别和设备控制 | + +### 13.2 硬件清单 +| 设备 | 数量 | 说明 | +|------|------|------| +| 温湿度传感器 | 1 | 站号02,RS485通信 | +| 压差传感器 | 1 | 站号01,RS485通信 | +| 门状态监测与门锁控制 | 1 | 站号03,RS485通信,中盛4路数字IO模块,控制左右门磁吸和触点开关 | +| IC卡读写器(门口) | 1 | 位于门口,可读取人员卡和内镜卡,RS232通信 | + +| 继电器模块 | 1 | 控制风机、照明、真空泵、消毒设备 | + +### 13.3 通信协议 + +#### RS485传感器数据格式 +**温湿度数据(站号02)** +``` +帧格式: 01 03 04 [湿度高字节] [湿度低字节] [温度高字节] [温度低字节] [CRC低] [CRC高] +示例: 01 03 04 02 98 00 BC 7B D5 +``` + +**压差数据(站号01)** +``` +帧格式: 01 03 02 [压差高字节] [压差低字节] [CRC低] [CRC高] +示例: 01 03 02 12 34 B5 33 +``` + +**门控制数据(站号03,中盛4路数字IO模块)** +``` +硬件配置: +- 站号: 03 +- 通道1(地址0000H): 左门磁吸控制(DO) + 左门触点开关(DI) +- 通道2(地址0001H): 右门磁吸控制(DO) + 右门触点开关(DI) +- 控制指令: 功能码06(写单个保持寄存器) +- 状态上报: 功能码04(读输入寄存器),DI状态变化主动上报 + +控制指令: +左门开门(磁吸通电): 03 06 00 00 00 01 48 0A (发送后,leftDoor=true) +左门关门(磁吸断电): 03 06 00 00 00 00 89 CA (发送后,leftDoor=false) +右门开门(磁吸通电): 03 06 00 01 00 01 09 CA (发送后,rightDoor=true) +右门关门(磁吸断电): 03 06 00 01 00 00 49 E8 (发送后,rightDoor=false) + +状态上报: +收到功能码04的上报数据,解析DI状态 +- 左门触点触发: 更新 leftDoor=false +- 右门触点触发: 更新 rightDoor=false +``` + +#### RS232控制指令格式 +``` +帧格式: 5AA5EE [指令码] [操作码] [校验和] +指令码: 02=风机, 03=照明, 04=真空泵, 05=消毒 +操作码: 01=开启, 00=关闭 + +示例: +风机开启: 5AA5EE0201 +照明开启: 5AA5EE0301 +真空泵开启: 5AA5EE0401 +消毒开启: 5AA5EE0501 +``` + +#### 门控制说明 +- **开门操作**: 通过RS485站号03发送开门指令(磁吸通电) + - 左门开启: `cmd.LeftDoor(true)` → 发送 `030600000001480A` (发送后,leftDoor状态更新为true) + - 右门开启: `cmd.RightDoor(true)` → 发送 `03060001000109CA` (发送后,rightDoor状态更新为true) + +- **关门操作**: 通过RS485站号03发送关门指令(磁吸断电) + - 左门关闭: `cmd.LeftDoor(false)` → 发送 `03060000000089CA` (发送后,leftDoor状态更新为false) + - 右门关闭: `cmd.RightDoor(false)` → 发送 `03060001000048E8` (发送后,rightDoor状态更新为false) + +- **门状态计算**: + - 门状态(door)根据左右门物理状态实时计算 + - 规则: `door = leftDoor OR rightDoor` + - 任一门打开 → door状态为开 + - 两门全关 → door状态为关 + +- **门状态上报**: + - 接收到功能码04的DI状态上报数据 + - 解析上报数据识别触点开关状态 + - 左门触点触发(关门) → 更新 `leftDoor = false` + - 右门触点触发(关门) → 更新 `rightDoor = false` + +#### RS232卡片数据格式 +**卡片数据通过同一通道读取** +``` +卡存入(14字节): +格式: 20 01 00 08 04 00 00 00 [卡号4字节] [校验] 03 +卡号位置: 倒数4-8字节(字节位置6-9) + +卡离开(7字节): +格式: 20 01 00 01 02 [校验] 03 + +卡片类型判断: +- 从数据库查询卡号 +- 在user表找到 → 人员卡 +- 在endo表找到 → 内镜卡 +- 都未找到 → 无效卡片 +``` + +### 13.4 开发环境 +- **IDE**: HBuilderX / VSCode +- **Node.js**: >= 14.0 +- **Android SDK**: API Level 21+ +- **UniApp**: 3.x + +--- + +**文档结束** diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..572f599 --- /dev/null +++ b/api/index.js @@ -0,0 +1,49 @@ +import request from '@/utils/request' + +// 时间 +export const time = (param) => { + return request.get('/cabinetapi/now', param) +} + +// 内镜列表 +export const endoscopelist = (param) => { + return request.get('/cabinetapi/endoscopelist', param) +} + +// 用户列表 +export const userlist = (param) => { + return request.get('/cabinetapi/userlist', param) +} + +// 提交基础设置 +export const deviceinfo = (param) => { + return request.get('/cabinetapi/deviceinfo', param) +} + +// 获取运行参数 +export const parameterlist = (param) => { + return request.get('/cabinetapi/parameterlist', param) +} + +// 提交本机运行参数 +export const parametersubmit = (param) => { + return request.get('/cabinetapi/parametersubmit', param) +} + +// 内镜存入 +export const endoscopeinware = (param) => { + return request.get('/cabinetapi/endoscopeinware', param) +} + + // 内镜取出 +export const endoscopeoutware = (param) => { + return request.get('/cabinetapi/endoscopeoutware', param) +} + + // 提交日志 +export const logsync = (param) => { + return request.get('/cabinetapi/logsync', param) +} + + + diff --git a/assets/autorun.png b/assets/autorun.png new file mode 100644 index 0000000000000000000000000000000000000000..4a53108903c5a115d1c3aa7b8128420237ea2569 GIT binary patch literal 536 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 O%wAO2RVz}l4*OsCun5%v literal 0 HcmV?d00001 diff --git a/assets/clean.png b/assets/clean.png new file mode 100644 index 0000000000000000000000000000000000000000..2a7db9fe6ec4b2e9615b96afcaebca62da5cbb3a GIT binary patch literal 347 zcmV-h0i^zkP)Px#1am@3R0s$N2z&@+hyVZq1xZ9fR9J=Ol)(*yFbqWllQ0q^v>UJi-Jm1TO*%qH zV1$hDdjY9Ub$y%@Tyl-6 d+IaUJ#;B5>x&IbkkpudN!PC{xWt~$(698r@Y .ant-layout, +.ant-layout.ant-layout-has-sider > .ant-layout-content { + width: 0; +} +.ant-layout-header, +.ant-layout-footer { + flex: 0 0 auto; +} +.ant-layout-header { + height: 64px; + padding: 0 50px; + color: rgba(0, 0, 0, 0.85); + line-height: 64px; + background: #001529; +} +.ant-layout-footer { + padding: 24px 50px; + color: rgba(0, 0, 0, 0.85); + font-size: 14px; + background: #f0f2f5; +} +.ant-layout-content { + flex: auto; + /* fix firefox can't set height smaller than content on flex item */ + min-height: 0; +} +.ant-layout-sider { + position: relative; + /* fix firefox can't set width smaller than content on flex item */ + min-width: 0; + background: #001529; + transition: all 0.2s; +} +.ant-layout-sider-children { + height: 100%; + margin-top: -0.1px; + padding-top: 0.1px; +} +.ant-layout-sider-children .ant-menu.ant-menu-inline-collapsed { + width: auto; +} +.ant-layout-sider-has-trigger { + padding-bottom: 48px; +} +.ant-layout-sider-right { + order: 1; +} +.ant-layout-sider-trigger { + position: fixed; + bottom: 0; + z-index: 1; + height: 48px; + color: #fff; + line-height: 48px; + text-align: center; + background: #002140; + cursor: pointer; + transition: all 0.2s; +} +.ant-layout-sider-zero-width > * { + overflow: hidden; +} +.ant-layout-sider-zero-width-trigger { + position: absolute; + top: 64px; + right: -36px; + z-index: 1; + width: 36px; + height: 42px; + color: #fff; + font-size: 18px; + line-height: 42px; + text-align: center; + background: #001529; + border-radius: 0 2px 2px 0; + cursor: pointer; + transition: background 0.3s ease; +} +.ant-layout-sider-zero-width-trigger::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: transparent; + transition: all 0.3s; + content: ''; +} +.ant-layout-sider-zero-width-trigger:hover::after { + background: rgba(255, 255, 255, 0.1); +} +.ant-layout-sider-zero-width-trigger-right { + left: -36px; + border-radius: 2px 0 0 2px; +} +.ant-layout-sider-light { + background: #fff; +} +.ant-layout-sider-light .ant-layout-sider-trigger { + color: rgba(0, 0, 0, 0.85); + background: #fff; +} +.ant-layout-sider-light .ant-layout-sider-zero-width-trigger { + color: rgba(0, 0, 0, 0.85); + background: #fff; +} +.ant-layout-rtl { + direction: rtl; +} diff --git a/assets/light.png b/assets/light.png new file mode 100644 index 0000000000000000000000000000000000000000..a54695ed26d84ae0106e025e9ba935adc8697c4a GIT binary patch literal 551 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 literal 0 HcmV?d00001 diff --git a/assets/wifi.png b/assets/wifi.png new file mode 100644 index 0000000000000000000000000000000000000000..74dbaee794d02d7d75d5b9f27dc679985ce433ea GIT binary patch literal 515 zcmV+e0{s1nP)Px#1am@3R0s$N2z&@+hyVZqtw}^dR9J=OR>5(DFc4g2@(&$ECD1|WAT3Y=slX+; z1k!<%3RD8P0^9-aVExFE(a4gJgvlp6!ZA~eaK5}NQEj8WKH3KQB4e~dx|cBq zQz9fLH!39_)cekU4rn?@^j-jb0r>VcO}Uar8gMI3IQNWu@Fx-7C}i6}pv=>f*h4lv z%8#rvH?ehUg+v2@QtIOQz5(!V%|&qLpij?rdijcxX#=yYEp9n$Vq9lUMOK+VWoUYd zR7?yNfY*Y3>yRYRMKp=G3euK)8+R;`F{8E0+}j)X5VdLpYu)~Tz_J0ej1jwE(TX77 zPx#1am@3R0s$N2z&@+hyVZqJ4r-AR9J=WR?$&|Kos0{_%|ici76#kAXY%^Kr28y zumkPDbU->ttYH1{y@-SxE)19ZVP}{D-aB^h-rnPYD?m~usl5i*5cx{dLBH6{_0iI= zh}>F#m}eCvwf@DCyh`V2B(0JPu+?b>$Q@sj)=2~eW*x%E&14l}>;W7jb9a*%Vmx3g zaR|)388xugacx)Gi^ZC-?B*Kk*jd)0L9qfXchjwTKc2z^|3LE9d;tJY{dh4anU%`7 z*N&u{>>j`!$?K$PWEb!Q0waP0&20I700000NkvXXu0mjfl5?u- literal 0 HcmV?d00001 diff --git a/assets/zhenkong.png b/assets/zhenkong.png new file mode 100644 index 0000000000000000000000000000000000000000..bf805facaf54520dd3bfd7874e17059aca3e520a GIT binary patch literal 590 zcmV-U0Px#1am@3R0s$N2z&@+hyVZq_(?=TR7i=fSJ8EYFbq8RbpSRfnV@V?Mo2ecgR%kX z1Q~&Lf~FHBogmr3=>$n9xcQ;bOg1S}JBn!DJlAW4!A=xYeEIhz6GPhU2qjO`RT?*is&m6!)GA7A7)7R}z z-ZqnL964qr+=_31m+AW?;~^Imz)8kB7qpP^djV*f3+jW<@ww)Lo@IQP0qO)I8}w7g zIr8TC@RseVsNZJzl&aM7B~g`4Qq6gixy=StfjR};kqi=xQZdLnf9m9kKgY%n6D&1s@9AJ>n9%JYAL@(ezWfiI!_qPDGDJxJrlHJyPyLYq> z(s^j^eJr^WKn>tgy3y`mY$@8PJV~KXu2eN@-#UL{(pkmMUL{3|*{Z4-`bk+h3)ZPB zo6CgcIYDo{=aq_Igo095)Ch6bp5g=rUL_vzkcwWie)pwEiV+yq5)l z7ZGc>74HBJF?N%r+^+OoiD@O?Dxpf!O_9c`PmD@c$Kv`9fffoNbUe%Da{|0mpN&V^ cfdS)x0Y;gV>h_waRR91007*qoM6N<$g3%%YlK=n! literal 0 HcmV?d00001 diff --git a/components/HeadTitle.vue b/components/HeadTitle.vue new file mode 100644 index 0000000..9af3a05 --- /dev/null +++ b/components/HeadTitle.vue @@ -0,0 +1,56 @@ + + + + + \ No newline at end of file diff --git a/components/InputModal.vue b/components/InputModal.vue new file mode 100644 index 0000000..68f0371 --- /dev/null +++ b/components/InputModal.vue @@ -0,0 +1,118 @@ + + + + + \ No newline at end of file diff --git a/components/InputNum.vue b/components/InputNum.vue new file mode 100644 index 0000000..f23075d --- /dev/null +++ b/components/InputNum.vue @@ -0,0 +1,105 @@ + + + + + \ No newline at end of file diff --git a/components/InputNumDrawer.vue b/components/InputNumDrawer.vue new file mode 100644 index 0000000..301b972 --- /dev/null +++ b/components/InputNumDrawer.vue @@ -0,0 +1,116 @@ + + + + + \ No newline at end of file diff --git a/components/InputNumPop.vue b/components/InputNumPop.vue new file mode 100644 index 0000000..e44d659 --- /dev/null +++ b/components/InputNumPop.vue @@ -0,0 +1,126 @@ + + + + + \ No newline at end of file diff --git a/components/Notice.vue b/components/Notice.vue new file mode 100644 index 0000000..2e2c67d --- /dev/null +++ b/components/Notice.vue @@ -0,0 +1,64 @@ + + + + + \ No newline at end of file diff --git a/components/PageFooter.vue b/components/PageFooter.vue new file mode 100644 index 0000000..1b96257 --- /dev/null +++ b/components/PageFooter.vue @@ -0,0 +1,109 @@ + + + + + \ No newline at end of file diff --git a/components/PageHeader.vue b/components/PageHeader.vue new file mode 100644 index 0000000..2cce06b --- /dev/null +++ b/components/PageHeader.vue @@ -0,0 +1,133 @@ + + + + + \ No newline at end of file diff --git a/components/SlotNotice.vue b/components/SlotNotice.vue new file mode 100644 index 0000000..522bd6b --- /dev/null +++ b/components/SlotNotice.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/components/global/index.js b/components/global/index.js new file mode 100644 index 0000000..a5fc33b --- /dev/null +++ b/components/global/index.js @@ -0,0 +1,10 @@ +const modules = import.meta.globEager('./*.vue') +const map = {} +Object.keys(modules).forEach(file => { + const modulesName = file.replace('./', '').replace('.vue', '') + map[modulesName] = modules[file].default +}) +const globalComponents = { + ...map, +} +export default globalComponents diff --git a/components/xuan-switch/xuan-switch.vue b/components/xuan-switch/xuan-switch.vue new file mode 100644 index 0000000..9a873a3 --- /dev/null +++ b/components/xuan-switch/xuan-switch.vue @@ -0,0 +1,195 @@ + + + + + diff --git a/db/sqlite.js b/db/sqlite.js new file mode 100644 index 0000000..be762bf --- /dev/null +++ b/db/sqlite.js @@ -0,0 +1,425 @@ +const dbName = "sqlite" +// "user", "log" + +export const openDb = () => { + //如果数据库存在则打开,不存在则创建。 + return new Promise((resolve, reject) => { + plus.sqlite.openDatabase({ + name: dbName, //数据库名称 + path: `_doc/${dbName}.db`, //数据库地址 + success(e) { + resolve(e); + }, + fail(e) { + reject(e); + } + }) + }) +} +// 查询所有数据表名 +export const getTable = () => { + return new Promise((resolve, reject) => { + plus.sqlite.selectSql({ + name: dbName, + sql: "select * FROM sqlite_master where type='table'", + success(e) { + resolve(e); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) +} +// 查询表数据总条数 +export const getCount = (tabName) => { + return new Promise((resolve, reject) => { + plus.sqlite.selectSql({ + name: dbName, + sql: "select count(*) as num from " + tabName, + success(e) { + resolve(e); + }, + fail(e) { + reject(e); + } + }) + }) +} + +// 查询表是否存在 +export const isTable = (tabName) => { + return new Promise((resolve, reject) => { + plus.sqlite.selectSql({ + name: dbName, + sql: `select count(*) as isTable FROM sqlite_master where type='table' and name='${tabName}'`, + success(e) { + // console.log(e) + resolve(e[0].isTable ? true : false); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) +} +/** + * 修改数据 + * @param {String} tabName 表名 + * @param {Object} setData 修改数据 + * @param {String} setName 查询字段名 + * @param {String} setVal 查询字段值 +*/ +export const updateSQL = (tabName, setData, setName, setVal) => { + if (JSON.stringify(setData) !== '{}') { + let dataKeys = Object.keys(setData) + let setStr = '' + dataKeys.forEach((item, index) => { + // console.log(setData[item]) + setStr += ( + `${item} = ${JSON.stringify(setData[item])}${dataKeys.length - 1 !== index ? "," : ""}`) + }) + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: `update ${tabName} set ${setStr} where ${setName} = "${setVal}"`, + success(e) { + resolve(e); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) + } else { + return new Promise((resolve, reject) => { + reject("错误") + }); + } +} + +//删除数据库数据 +export const deleteInformationType = (tabName,setData) => { + if (JSON.stringify(setData) !== '{}') { + let dataKeys = Object.keys(setData) + let setStr = '' + dataKeys.forEach((item, index) => { + // console.log(setData[item]) + setStr += ( + `${item}=${JSON.stringify(setData[item])}${dataKeys.length - 1 !== index ? " and " : ""}`) + }) + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: `delete from ${tabName} where ${setStr}`, + success(e) { + resolve(e); + }, + fail(e) { + reject(e); + } + }) + }) + } else { + return new Promise((resolve, reject) => { + reject("错误") + }); + } +} + +//关闭数据库 +export const closeSQL = (name) => { + return new Promise((resolve, reject) => { + plus.sqlite.closeDatabase({ + name: 'pop', + success(e) { + resolve(e); + }, + fail(e) { + reject(e); + } + }) + }) +} + +//监听数据库是否开启 +export const isOpen = () => { + let open = plus.sqlite.isOpenDatabase({ + name: dbName, + path: `_doc/${dbName}.db`, + }) + return open; +} + +// 创建用户表 +export const addUserTable = () => { + const tabName = 'user' + // tabName不能用数字作为表格名的开头 + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: `create table if not exists ${tabName}("id" INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(255) NOT NULL, ic VARCHAR(255), ic2 VARCHAR(255), number CHAR(50), type CHAR(50) )`, + success(e) { + resolve(e); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) +} +// 创建日志表 +export const addLogTable = () => { + const tabName = 'log' + // tabName不能用数字作为表格名的开头 + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: `create table if not exists ${tabName}("id" INTEGER PRIMARY KEY AUTOINCREMENT,"name" VARCHAR(255) NOT NULL,action VARCHAR(255) NOT NULL, create_time datetime DEFAULT (datetime('now', 'localtime')))`, + success(e) { + resolve(e); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) +} + +// 创建内镜存储表 +export const addScopeTable = () => { + const tabName = 'scope' + // tabName不能用数字作为表格名的开头 + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: `create table if not exists ${tabName}("key" INTEGER NOT NULL,"ic" CHAR(50) , "rfid" CHAR(50), "name" VARCHAR(255), time datetime DEFAULT (datetime('now', 'localtime')))`, + success(e) { + resolve(e); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) +} + +// 创建内镜存储表 +export const addEndoTable = () => { + const tabName = 'endo' + // tabName不能用数字作为表格名的开头 + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: `create table if not exists ${tabName}("id" INTEGER PRIMARY KEY AUTOINCREMENT,"endoscope_id" CHAR(255), "name" CHAR(50), "brand" CHAR(50),"model" CHAR(50), "type" CHAR(50), "rfid" CHAR(50) ,"ic" VARCHAR(255), "ic2" VARCHAR(255), time datetime DEFAULT (datetime('now', 'localtime')))`, + success(e) { + resolve(e); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) +} + +/** + * 添加数据 + * @param {String} tabName 表名 + * @param {Object} obj 添加数据 +*/ +export const addTabItem = (tabName,obj) => { + if (obj) { + let keys = Object.keys(obj) + let keyStr = keys.toString() + let valStr = '' + keys.forEach((item, index) => { + if (keys.length - 1 == index) { + valStr += ('"' + obj[item] + '"') + } else { + valStr += ('"' + obj[item] + '",') + } + }) + // console.log(valStr) + let sqlStr = `insert into ${tabName} (${keyStr}) values(${valStr})` + // console.log(sqlStr) + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: sqlStr, + success(e) { + resolve(e); + }, + fail(e) { + // console.log(e) + reject(e); + } + }) + }) + } else { + return new Promise((resolve, reject) => { + reject("错误") + }) + } +} + +// 合并数据 +export const mergeSql = (name,tabName,tabs) => { + if (!tabs || tabs.length == 0) { + return new Promise((resolve, reject) => { + reject("错误") + }) + } + let itemValStr = '' + tabs.forEach((item, index) => { + let itemKey = Object.keys(item) + let itemVal = '' + itemKey.forEach((key, i) => { + if (itemKey.length - 1 == i) { + if (typeof item[key] == 'object') { + itemVal += (`'${JSON.stringify(item[key])}'`) + } else { + itemVal += (`'${item[key]}'`) + } + } else { + if (typeof item[key] == 'object') { + itemVal += (`'${JSON.stringify(item[key])}',`) + } else { + itemVal += (`'${item[key]}',`) + } + } + }) + if (tabs.length - 1 == index) { + itemValStr += ('(' + itemVal + ')') + } else { + itemValStr += ('(' + itemVal + '),') + } + }) + let keys = Object.keys(tabs[0]) + let keyStr = keys.toString() + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: name, + sql: `insert or ignore into ${tabName} (${keyStr}) values ${itemValStr}`, + success(e) { + resolve(e); + }, + fail(e) { + // console.log(e) + reject(e); + } + }) + }) +} + +/** + * 获取分页数据库数据 + * @param {String} tabName 表名 + * @param {Number} num 页码 + * @param {Number} size 每页数据条数 + * @param {String} byName 排序字段 + * @param {String} byType 排序方式 +*/ +export const getDataList = async (tabName, num = 1, size = 15, byName, byType) => { + let count = 0 + let sql = '' + let numindex = 0 + let total = 0 + await getCount(tabName).then((resNum) => { + count = Math.ceil(resNum[0].num / size) + total = resNum[0].num + }) + if(((num - 1) * size) == 0) { + numindex = 0 + } else { + numindex = ((num - 1) * size) + 1 + } + sql = `select * from ${tabName}` + if(byName && byType) { + // desc asc + sql += ` order by ${byName} ${byType}` + } + sql += ` limit ${numindex},${size}` + if (count < num - 1) { + return new Promise((resolve, reject) => { + reject("无数据") + }); + } else { + return new Promise((resolve, reject) => { + plus.sqlite.selectSql({ + name: dbName, + // sql: "select * from userInfo limit 3 offset 3", + sql:sql , + success(e) { + let data = { list: e, totalPage: count, total: total } + resolve(data); + }, + fail(e) { + reject(e); + } + }) + }) + } +} +//查询数据库数据 +export const selectDataList = (tabName,setData,byName,byType) => { + let setStr = '' + let sql = '' + if (JSON.stringify(setData) !== '{}') { + let dataKeys = Object.keys(setData) + dataKeys.forEach((item, index) => { + // console.log(setData[item]) + setStr += ( + `${item}=${JSON.stringify(setData[item])}${dataKeys.length - 1 !== index ? " and " : ""}`) + }) + sql = `select * from ${tabName} where ${setStr}` + } else { + sql = `select * from ${tabName}` + } + if(byName && byType) { + // desc asc + sql += ` order by ${byName} ${byType}` + } + // console.log(sql) + if (tabName !== undefined) { + return new Promise((resolve, reject) => { + plus.sqlite.selectSql({ + name: dbName, + sql: sql, + success(e) { + resolve(e); + }, + fail(e) { + console.log(e) + reject(e); + } + }) + }) + } else { + return new Promise((resolve, reject) => { + reject("错误") + }); + } +} + +// 删除数据表 +export const dropTable = (tabName) => { + return new Promise((resolve, reject) => { + plus.sqlite.executeSql({ + name: dbName, + sql: `DROP TABLE ${tabName}`, + success(e) { + resolve(e); + }, + fail(e) { + reject(e); + } + }) + }) +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..c3ff205 --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + diff --git a/js_sdk/zw-devicemac/devicemac.js b/js_sdk/zw-devicemac/devicemac.js new file mode 100644 index 0000000..fbca70f --- /dev/null +++ b/js_sdk/zw-devicemac/devicemac.js @@ -0,0 +1,114 @@ +//获取mac地址 + +// "" +// "" +// "" +// "" +export function getMacAddress() { + try { + var NetworkInterface = plus.android.importClass('java.net.NetworkInterface') + var interfaces = NetworkInterface.getNetworkInterfaces() + + // 直接使用 Enumeration 的方法(而非 Iterator) + while (plus.android.invoke(interfaces, 'hasMoreElements')) { + var intf = plus.android.invoke(interfaces, 'nextElement') + var name = plus.android.invoke(intf, 'getName') + + if (name === 'wlan0' || name === 'eth0' || name === 'wlan1') { + var macBytes = plus.android.invoke(intf, 'getHardwareAddress') + if (macBytes) { + var macStr = Array.from(macBytes) + .map(byte => (byte & 0xff).toString(16).padStart(2, '0')) + .join(':') + .toUpperCase() + console.log('MAC Address:', macStr) + return macStr + } + } + } + + console.error('No valid MAC address found') + return null + } catch (e) { + console.error('Failed to get MAC address:', e) + return null + } +} +// 获取唯一设备ID +export function getDeviceId() { + var settings = plus.android.importClass('android.provider.Settings') + var Secure = settings.Secure + var context = plus.android.runtimeMainActivity() + var androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID) + return androidId +} +// 备用方案 获取UUID +export function generateUUID() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (Math.random() * 16) | 0, + v = c == 'x' ? r : (r & 0x3) | 0x8 + return v.toString(16) + }) +} +// +/** + * 获取蓝牙 MAC 地址(兼容 Android 5.0+) + * @returns {string|null} MAC 地址(格式 "XX:XX:XX:XX:XX:XX"),失败返回 null + */ +function getBluetoothMacLegacy() { + if (plus.os.name !== 'Android') { + console.error('仅支持 Android') + return null + } + + try { + const BluetoothAdapter = plus.android.importClass('android.bluetooth.BluetoothAdapter') + const adapter = BluetoothAdapter.getDefaultAdapter() + if (!adapter) { + console.error('蓝牙未启用') + return null + } + + const mac = plus.android.invoke(adapter, 'getAddress') + if (mac && mac !== '02:00:00:00:00:00') { + return mac + } + return null + } catch (e) { + console.error('获取失败:', e) + return null + } +} +function getBluetoothMacModern() { + try { + const Context = plus.android.importClass('android.content.Context') + const BluetoothManager = plus.android.importClass('android.bluetooth.BluetoothManager') + + const mainActivity = plus.android.runtimeMainActivity() + const bluetoothManager = mainActivity.getSystemService(Context.BLUETOOTH_SERVICE) + const adapter = plus.android.invoke(bluetoothManager, 'getAdapter') + + if (!adapter) return null + + const mac = plus.android.invoke(adapter, 'getAddress') + return mac && mac !== '02:00:00:00:00:00' ? mac : null + } catch (e) { + console.error('BluetoothManager 方式失败:', e) + return null + } +} +export function getBluetoothMacAddress() { + const Build = plus.android.importClass('android.os.Build') + const isModernAndroid = Build.VERSION.SDK_INT >= 23 // Android 6.0+ + + // 先尝试新方法,再回退旧方法 + const mac = isModernAndroid ? getBluetoothMacModern() : getBluetoothMacLegacy() + + if (mac) { + console.log('获取到蓝牙 MAC:', mac) + return mac + } else { + console.error('无法获取真实 MAC') + return null + } +} diff --git a/js_sdk/zw-devicemac/package.json b/js_sdk/zw-devicemac/package.json new file mode 100644 index 0000000..a19c5bd --- /dev/null +++ b/js_sdk/zw-devicemac/package.json @@ -0,0 +1,27 @@ +{ + "id": "zw-devicemac", + "name": "获取安卓设备MAC地址", + "displayName": "获取安卓设备MAC地址", + "version": "0.1.0", + "description": "兼容vue3用于获取安卓设备MAC地址,可支持Wi-Fi/蜂窝网络", + "keywords": [ + "js", + "安卓MAC地址", + "vue3" + ], + "dcloudext": { + "type": "js_sdk", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + } + }, + "uni_modules": { + "dependencies": [], + "encrypt": [] + } +} \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..f9c6e01 --- /dev/null +++ b/main.js @@ -0,0 +1,34 @@ +import App from './App' +import * as antIcons from '@ant-design/icons-vue'; +import Antd from 'ant-design-vue'; + +import 'ant-design-vue/dist/antd.css'; +// import { notification } from 'ant-design-vue'; +// import components from './components/global'; +import './assets/global.css'; + +// #ifndef VUE3 +// import Vue from 'vue' +// import './uni.promisify.adaptor' +// Vue.config.productionTip = false +// App.mpType = 'app' +// const app = new Vue({ +// ...App +// }) +// app.$mount() +// #endif + +// #ifdef VUE3 +import { createSSRApp } from 'vue' +import store from './store' +export function createApp() { + const app = createSSRApp(App) + + + app.use(store).use(Antd); + + return { + app + } +} +// #endif \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..96e87f4 --- /dev/null +++ b/manifest.json @@ -0,0 +1,121 @@ +{ + "name" : "endoscope", + "appid" : "__UNI__5A0A7D6", + "description" : "", + "versionName" : "1.2.3", + "versionCode" : 109, + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : false, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : { + "SQLite" : {} + }, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ], + "minSdkVersion" : 21 + }, + /* ios打包配置 */ + "ios" : { + "idfa" : false, + "dSYMs" : false + }, + /* SDK配置 */ + "sdkConfigs" : {}, + "splashscreen" : { + "androidStyle" : "common", + "android" : { + "hdpi" : "", + "xhdpi" : "", + "xxhdpi" : "" + } + }, + "icons" : { + "android" : { + "hdpi" : "unpackage/res/icons/72x72.png", + "xhdpi" : "unpackage/res/icons/96x96.png", + "xxhdpi" : "unpackage/res/icons/144x144.png", + "xxxhdpi" : "unpackage/res/icons/192x192.png" + }, + "ios" : { + "appstore" : "unpackage/res/icons/1024x1024.png", + "ipad" : { + "app" : "unpackage/res/icons/76x76.png", + "app@2x" : "unpackage/res/icons/152x152.png", + "notification" : "unpackage/res/icons/20x20.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "proapp@2x" : "unpackage/res/icons/167x167.png", + "settings" : "unpackage/res/icons/29x29.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "spotlight" : "unpackage/res/icons/40x40.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png" + }, + "iphone" : { + "app@2x" : "unpackage/res/icons/120x120.png", + "app@3x" : "unpackage/res/icons/180x180.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "notification@3x" : "unpackage/res/icons/60x60.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "settings@3x" : "unpackage/res/icons/87x87.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png", + "spotlight@3x" : "unpackage/res/icons/120x120.png" + } + } + } + }, + "nativePlugins" : {} + }, + /* 快应用特有相关 */ + "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", + "locale" : "zh-Hans" +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7db0c1e --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "@ant-design/icons-vue": "^7.0.1", + "ant-design-vue": "^3.2.20" + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..7c1894a --- /dev/null +++ b/pages.json @@ -0,0 +1,107 @@ +{ + "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages + { + "path": "pages/start", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/index", + "style": { + "navigationStyle": "custom", + "app-plus": { + "animationType": "none" + } + } + }, + { + "path": "pages/log", + "style": { + "navigationStyle": "custom", + "app-plus": { + "animationType": "none" + } + } + }, + { + "path": "pages/setting", + "style": { + "navigationStyle": "custom", + "app-plus": { + "animationType": "none" + } + } + }, + { + "path": "pages/set/net", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/set/base", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/set/device", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/set/endomanage", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/set/personmanage", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/set/run", + "style": { + "navigationStyle": "custom" + } + }, + { + "path" : "pages/modbus/modbus", + "style" : + { + "navigationBarTitleText" : "串口调试" + } + }, + { + "path" : "pages/database/database", + "style" : + { + "navigationBarTitleText" : "存储调试" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "#fff", + "navigationBarTitleText": "", + "navigationBarBackgroundColor": "#000000", + "backgroundColor": "#000000" + }, + "uniIdRouter": {}, + // "condition": { + // "current": 0, + // "list": [{ + // "name": "", + // "path": "pages/index" + // }] + // }, + "easycom": { + "autoscan": true, + "custom": { + "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue" + } + } +} diff --git a/pages/database/database.vue b/pages/database/database.vue new file mode 100644 index 0000000..40eefae --- /dev/null +++ b/pages/database/database.vue @@ -0,0 +1,205 @@ + + + + + diff --git a/pages/index.vue b/pages/index.vue new file mode 100644 index 0000000..a4dce2c --- /dev/null +++ b/pages/index.vue @@ -0,0 +1,754 @@ + + + + + \ No newline at end of file diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..23fac09 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/pages/log.vue b/pages/log.vue new file mode 100644 index 0000000..6ee5b69 --- /dev/null +++ b/pages/log.vue @@ -0,0 +1,168 @@ + + + + + \ No newline at end of file diff --git a/pages/modbus/modbus.vue b/pages/modbus/modbus.vue new file mode 100644 index 0000000..1665454 --- /dev/null +++ b/pages/modbus/modbus.vue @@ -0,0 +1,432 @@ + + + + + diff --git a/pages/set/base.vue b/pages/set/base.vue new file mode 100644 index 0000000..541c6c9 --- /dev/null +++ b/pages/set/base.vue @@ -0,0 +1,184 @@ + + + + + \ No newline at end of file diff --git a/pages/set/device.vue b/pages/set/device.vue new file mode 100644 index 0000000..4c17bbd --- /dev/null +++ b/pages/set/device.vue @@ -0,0 +1,101 @@ + + + + + \ No newline at end of file diff --git a/pages/set/endomanage.vue b/pages/set/endomanage.vue new file mode 100644 index 0000000..56d86a4 --- /dev/null +++ b/pages/set/endomanage.vue @@ -0,0 +1,311 @@ + + + + + \ No newline at end of file diff --git a/pages/set/net.vue b/pages/set/net.vue new file mode 100644 index 0000000..0f9ed71 --- /dev/null +++ b/pages/set/net.vue @@ -0,0 +1,159 @@ + + + + + \ No newline at end of file diff --git a/pages/set/personmanage.vue b/pages/set/personmanage.vue new file mode 100644 index 0000000..ab99b84 --- /dev/null +++ b/pages/set/personmanage.vue @@ -0,0 +1,297 @@ + + + + + \ No newline at end of file diff --git a/pages/set/run.vue b/pages/set/run.vue new file mode 100644 index 0000000..f34b7db --- /dev/null +++ b/pages/set/run.vue @@ -0,0 +1,318 @@ + + + + + \ No newline at end of file diff --git a/pages/setting.vue b/pages/setting.vue new file mode 100644 index 0000000..c6d7f0e --- /dev/null +++ b/pages/setting.vue @@ -0,0 +1,214 @@ + + + + + \ No newline at end of file diff --git a/pages/start.vue b/pages/start.vue new file mode 100644 index 0000000..3369b52 --- /dev/null +++ b/pages/start.vue @@ -0,0 +1,866 @@ + + + + + \ No newline at end of file diff --git a/static/beep_01.mp3 b/static/beep_01.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d08c8ea2c8884fdaf578b987012b60d11da10513 GIT binary patch literal 8777 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 UAGTk0e61sg|Axc=6%QZ&2j5<}x&QzG literal 0 HcmV?d00001 diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b5771e209bb677e2ebd5ff766ad5ee11790f305a GIT binary patch literal 4023 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 SYs}WS&%*SCNx89m_ state.base, + run: state => state.run, + relay: state => state.relay, + status: state => state.status, + sensor: state => state.sensor, + apiUrl: state => state.apiUrl, + }, + mutations: { + SET_BASE(state, base) { + state.base = { ...state.base, ...base } + }, + SET_RUN(state, run) { + state.run = { ...state.run, ...run } + }, + SET_TIME(state, time) { + state.time = time + }, + CLEAR_TIMER(state) { + state.timer = { + 'disinfect': '', // 自动消毒开始时间 + 'wind': '', // 风机开始时间' + 'vacuumStart': '', // 真空泵开始时间 + 'vacuumEnd': '', // 真空泵开始时间 + 'door': '', // 开门开始时间,(6) 3min未关门报警 + 'doorAlert': false // 开门报警声 + } + }, + }, + actions: { + + } +}) +export default store \ No newline at end of file diff --git a/uni.promisify.adaptor.js b/uni.promisify.adaptor.js new file mode 100644 index 0000000..5fec4f3 --- /dev/null +++ b/uni.promisify.adaptor.js @@ -0,0 +1,13 @@ +uni.addInterceptor({ + returnValue (res) { + if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { + return res; + } + return new Promise((resolve, reject) => { + res.then((res) => { + if (!res) return resolve(res) + return res[0] ? reject(res[0]) : resolve(res[1]) + }); + }); + }, +}); \ No newline at end of file diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..b9249e9 --- /dev/null +++ b/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$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:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16px; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; diff --git a/uni_modules/android-serialport/changelog.md b/uni_modules/android-serialport/changelog.md new file mode 100644 index 0000000..bc8ec32 --- /dev/null +++ b/uni_modules/android-serialport/changelog.md @@ -0,0 +1,19 @@ +## 1.0.9(2025-04-19) +优化 + +## 1.0.8(2025-04-08) +去掉安全判断 +## 1.0.7(2025-02-28) +优化 +## 1.0.6(2025-02-11) +优化 +## 1.0.5(2025-01-16) +修复uniapp bug +## 1.0.4(2024-10-28) +修改uniapp @UTSJS.keepAlive 问题 +## 1.0.3(2024-10-08) +已知问题修复 +## 1.0.1(2024-09-04) +修复bug +## 1.0.0(2024-09-03) +初始化,本周内完善文档 diff --git a/uni_modules/android-serialport/encrypt b/uni_modules/android-serialport/encrypt new file mode 100644 index 0000000000000000000000000000000000000000..5176376c5b7854d23c6ffa90a42829ad51f3f3a9 GIT binary patch literal 144 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
  • ?*IYVb;$Q>qsJ9KA*gI|gF> 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 literal 0 HcmV?d00001 diff --git a/uni_modules/uni-data-select/changelog.md b/uni_modules/uni-data-select/changelog.md new file mode 100644 index 0000000..1681eae --- /dev/null +++ b/uni_modules/uni-data-select/changelog.md @@ -0,0 +1,51 @@ +## 1.1.0(2025-08-19) +- 新增 插槽 selected empty option +- 新增 mutiple 属性,支持多选功能 +- 新增 wrap 属性,支持选中的文字超过一行显示 +- 新增 align 属性,支持修改选中的文字显示的位置 +- 新增 hideRight 属性,支持隐藏右侧所有按钮 +- 新增 mode 属性,支持修改边框样式 +- 新增 事件 open close clear +## 1.0.10(2025-04-14) +- 修复 清除按钮不展示问题 +## 1.0.9(2025-03-26) +- 优化 默认背景为白色与整体组件保持风格统一 +## 1.0.8(2024-03-28) +- 修复 在vue2下:style动态绑定导致编译失败的bug +## 1.0.7(2024-01-20) +- 修复 长文本回显超过容器的bug,超过容器部分显示省略号 +## 1.0.6(2023-04-12) +- 修复 微信小程序点击时会改变背景颜色的 bug +## 1.0.5(2023-02-03) +- 修复 禁用时会显示清空按钮 +## 1.0.4(2023-02-02) +- 优化 查询条件短期内多次变更只查询最后一次变更后的结果 +- 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue +## 1.0.3(2023-01-16) +- 修复 不关联服务空间报错的问题 +## 1.0.2(2023-01-14) +- 新增 属性 `format` 可用于格式化显示选项内容 +## 1.0.1(2022-12-06) +- 修复 当where变化时,数据不会自动更新的问题 +## 0.1.9(2022-09-05) +- 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框 +## 0.1.8(2022-08-29) +- 修复 点击的位置不准确 +## 0.1.7(2022-08-12) +- 新增 支持 disabled 属性 +## 0.1.6(2022-07-06) +- 修复 pc端宽度异常的bug +## 0.1.5 +- 修复 pc端宽度异常的bug +## 0.1.4(2022-07-05) +- 优化 显示样式 +## 0.1.3(2022-06-02) +- 修复 localdata 赋值不生效的 bug +- 新增 支持 uni.scss 修改颜色 +- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用) +## 0.1.2(2022-05-08) +- 修复 当 value 为 0 时选择不生效的 bug +## 0.1.1(2022-05-07) +- 新增 记住上次的选项(仅 collection 存在时有效) +## 0.1.0(2022-04-22) +- 初始化 diff --git a/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue b/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue new file mode 100644 index 0000000..85b2d7b --- /dev/null +++ b/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue @@ -0,0 +1,837 @@ + + + + + diff --git a/uni_modules/uni-data-select/package.json b/uni_modules/uni-data-select/package.json new file mode 100644 index 0000000..4033502 --- /dev/null +++ b/uni_modules/uni-data-select/package.json @@ -0,0 +1,106 @@ +{ + "id": "uni-data-select", + "displayName": "uni-data-select 下拉框选择器", + "version": "1.1.0", + "description": "通过数据驱动的下拉框选择器", + "keywords": [ + "uni-ui", + "select", + "uni-data-select", + "下拉框", + "下拉选" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.1", + "uni-app": "^4.45", + "uni-app-x": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [ + "uni-load-more" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "√", + "aliyun": "√", + "alipay": "√" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "-", + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√", + "alipay": "√", + "toutiao": "√", + "baidu": "-", + "kuaishou": "-", + "jd": "-", + "harmony": "-", + "qq": "-", + "lark": "-" + }, + "quickapp": { + "huawei": "-", + "union": "-" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": "-", + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-data-select/readme.md b/uni_modules/uni-data-select/readme.md new file mode 100644 index 0000000..eb58de3 --- /dev/null +++ b/uni_modules/uni-data-select/readme.md @@ -0,0 +1,8 @@ +## DataSelect 下拉框选择器 +> **组件名:uni-data-select** +> 代码块: `uDataSelect` + +当选项过多时,使用下拉菜单展示并选择内容 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-select) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-easyinput/changelog.md b/uni_modules/uni-easyinput/changelog.md new file mode 100644 index 0000000..065a7c4 --- /dev/null +++ b/uni_modules/uni-easyinput/changelog.md @@ -0,0 +1,121 @@ +## 1.1.22(2025-09-19) +- 修复 禁用状态下背景不生效的问题 +## 1.1.21(2025-08-26) +- 修复 在 @input 中修改 v-model 不生效的问题 +## 1.1.20(2025-08-19) +- 修复 微信小程序平台样式警告问题 +## 1.1.19(2024-07-18) +- 修复 初始值传入 null 导致input报错的bug +## 1.1.18(2024-04-11) +- 修复 easyinput组件双向绑定问题 +## 1.1.17(2024-03-28) +- 修复 在头条小程序下丢失事件绑定的问题 +## 1.1.16(2024-03-20) +- 修复 在密码输入情况下 清除和小眼睛覆盖bug 在edge浏览器下显示双眼睛bug +## 1.1.15(2024-02-21) +- 新增 左侧插槽:left +## 1.1.14(2024-02-19) +- 修复 onBlur的emit传值错误 +## 1.1.12(2024-01-29) +- 补充 adjust-position文档属性补充 +## 1.1.11(2024-01-29) +- 补充 adjust-position属性传递值:(Boolean)当键盘弹起时,是否自动上推页面 +## 1.1.10(2024-01-22) +- 去除 移除无用的log输出 +## 1.1.9(2023-04-11) +- 修复 vue3 下 keyboardheightchange 事件报错的bug +## 1.1.8(2023-03-29) +- 优化 trim 属性默认值 +## 1.1.7(2023-03-29) +- 新增 cursor-spacing 属性 +## 1.1.6(2023-01-28) +- 新增 keyboardheightchange 事件,可监听键盘高度变化 +## 1.1.5(2022-11-29) +- 优化 主题样式 +## 1.1.4(2022-10-27) +- 修复 props 中背景颜色无默认值的bug +## 1.1.0(2022-06-30) + +- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容 +- 新增 clear 事件,点击右侧叉号图标触发 +- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发 +- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等 + +## 1.0.5(2022-06-07) + +- 优化 clearable 显示策略 + +## 1.0.4(2022-06-07) + +- 优化 clearable 显示策略 + +## 1.0.3(2022-05-20) + +- 修复 关闭图标某些情况下无法取消的 bug + +## 1.0.2(2022-04-12) + +- 修复 默认值不生效的 bug + +## 1.0.1(2022-04-02) + +- 修复 value 不能为 0 的 bug + +## 1.0.0(2021-11-19) + +- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput) + +## 0.1.4(2021-08-20) + +- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug + +## 0.1.3(2021-08-11) + +- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 + +## 0.1.2(2021-07-30) + +- 优化 vue3 下事件警告的问题 + +## 0.1.1 + +- 优化 errorMessage 属性支持 Boolean 类型 + +## 0.1.0(2021-07-13) + +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) + +## 0.0.16(2021-06-29) + +- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug + +## 0.0.15(2021-06-21) + +- 修复 passwordIcon 属性拼写错误的 bug + +## 0.0.14(2021-06-18) + +- 新增 passwordIcon 属性,当 type=password 时是否显示小眼睛图标 +- 修复 confirmType 属性不生效的问题 + +## 0.0.13(2021-06-04) + +- 修复 disabled 状态可清出内容的 bug + +## 0.0.12(2021-05-12) + +- 新增 组件示例地址 + +## 0.0.11(2021-05-07) + +- 修复 input-border 属性不生效的问题 + +## 0.0.10(2021-04-30) + +- 修复 ios 遮挡文字、显示一半的问题 + +## 0.0.9(2021-02-05) + +- 调整为 uni_modules 目录规范 +- 优化 兼容 nvue 页面 diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/common.js b/uni_modules/uni-easyinput/components/uni-easyinput/common.js new file mode 100644 index 0000000..fde8d3c --- /dev/null +++ b/uni_modules/uni-easyinput/components/uni-easyinput/common.js @@ -0,0 +1,54 @@ +/** + * @desc 函数防抖 + * @param func 目标函数 + * @param wait 延迟执行毫秒数 + * @param immediate true - 立即执行, false - 延迟执行 + */ +export const debounce = function(func, wait = 1000, immediate = true) { + let timer; + return function() { + let context = this, + args = arguments; + if (timer) clearTimeout(timer); + if (immediate) { + let callNow = !timer; + timer = setTimeout(() => { + timer = null; + }, wait); + if (callNow) func.apply(context, args); + } else { + timer = setTimeout(() => { + func.apply(context, args); + }, wait) + } + } +} +/** + * @desc 函数节流 + * @param func 函数 + * @param wait 延迟执行毫秒数 + * @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发 + */ +export const throttle = (func, wait = 1000, type = 1) => { + let previous = 0; + let timeout; + return function() { + let context = this; + let args = arguments; + if (type === 1) { + let now = Date.now(); + + if (now - previous > wait) { + func.apply(context, args); + previous = now; + } + } else if (type === 2) { + if (!timeout) { + timeout = setTimeout(() => { + timeout = null; + func.apply(context, args) + }, wait) + } + } + } +} diff --git a/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue new file mode 100644 index 0000000..a328da7 --- /dev/null +++ b/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue @@ -0,0 +1,662 @@ + + + + + diff --git a/uni_modules/uni-easyinput/package.json b/uni_modules/uni-easyinput/package.json new file mode 100644 index 0000000..00de64a --- /dev/null +++ b/uni_modules/uni-easyinput/package.json @@ -0,0 +1,107 @@ +{ + "id": "uni-easyinput", + "displayName": "uni-easyinput 增强输入框", + "version": "1.1.22", + "description": "Easyinput 组件是对原生input组件的增强", + "keywords": [ + "uni-ui", + "uniui", + "input", + "uni-easyinput", + "输入框" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "", + "uni-app": "^4.07", + "uni-app-x": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "x", + "aliyun": "x", + "alipay": "x" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "-", + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√", + "alipay": "√", + "toutiao": "√", + "baidu": "√", + "kuaishou": "√", + "jd": "√", + "harmony": "√", + "qq": "√", + "lark": "-" + }, + "quickapp": { + "huawei": "-", + "union": "-" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": "-", + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-easyinput/readme.md b/uni_modules/uni-easyinput/readme.md new file mode 100644 index 0000000..f1faf8f --- /dev/null +++ b/uni_modules/uni-easyinput/readme.md @@ -0,0 +1,11 @@ + + +### Easyinput 增强输入框 +> **组件名:uni-easyinput** +> 代码块: `uEasyinput` + + +easyinput 组件是对原生input组件的增强 ,是专门为配合表单组件[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)而设计的,easyinput 内置了边框,图标等,同时包含 input 所有功能 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-easyinput) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-grid/changelog.md b/uni_modules/uni-grid/changelog.md new file mode 100644 index 0000000..d301166 --- /dev/null +++ b/uni_modules/uni-grid/changelog.md @@ -0,0 +1,13 @@ +## 1.4.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-grid](https://uniapp.dcloud.io/component/uniui/uni-grid) +## 1.3.2(2021-11-09) +- 新增 提供组件设计资源,组件样式调整 +## 1.3.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.3.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.2.4(2021-05-12) +- 新增 组件示例地址 +## 1.2.3(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue b/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue new file mode 100644 index 0000000..19c08d7 --- /dev/null +++ b/uni_modules/uni-grid/components/uni-grid-item/uni-grid-item.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/uni_modules/uni-grid/components/uni-grid/uni-grid.vue b/uni_modules/uni-grid/components/uni-grid/uni-grid.vue new file mode 100644 index 0000000..0edc7ff --- /dev/null +++ b/uni_modules/uni-grid/components/uni-grid/uni-grid.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/uni_modules/uni-grid/package.json b/uni_modules/uni-grid/package.json new file mode 100644 index 0000000..ccb2c91 --- /dev/null +++ b/uni_modules/uni-grid/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-grid", + "displayName": "uni-grid 宫格", + "version": "1.4.0", + "description": "Grid 宫格组件,提供移动端常见的宫格布局,如九宫格。", + "keywords": [ + "uni-ui", + "uniui", + "九宫格", + "表格" +], + "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-scss","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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-grid/readme.md b/uni_modules/uni-grid/readme.md new file mode 100644 index 0000000..0aa44cc --- /dev/null +++ b/uni_modules/uni-grid/readme.md @@ -0,0 +1,11 @@ + + +## Grid 宫格 +> **组件名:uni-grid** +> 代码块: `uGrid` + + +宫格组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-grid) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-icons/changelog.md b/uni_modules/uni-icons/changelog.md new file mode 100644 index 0000000..62e7682 --- /dev/null +++ b/uni_modules/uni-icons/changelog.md @@ -0,0 +1,44 @@ +## 2.0.12(2025-08-26) +- 优化 uni-app x 下 size 类型问题 +## 2.0.11(2025-08-18) +- 修复 图标点击事件返回 +## 2.0.9(2024-01-12) +fix: 修复图标大小默认值错误的问题 +## 2.0.8(2023-12-14) +- 修复 项目未使用 ts 情况下,打包报错的bug +## 2.0.7(2023-12-14) +- 修复 size 属性为 string 时,不加单位导致尺寸异常的bug +## 2.0.6(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.5(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.4(2023-12-06) +- 优化 uni-app x 下示例项目图标排序 +## 2.0.3(2023-12-06) +- 修复 nvue下引入组件报错的bug +## 2.0.2(2023-12-05) +-优化 size 属性支持单位 +## 2.0.1(2023-12-05) +- 新增 uni-app x 支持定义图标 +## 1.3.5(2022-01-24) +- 优化 size 属性可以传入不带单位的字符串数值 +## 1.3.4(2022-01-24) +- 优化 size 支持其他单位 +## 1.3.3(2022-01-17) +- 修复 nvue 有些图标不显示的bug,兼容老版本图标 +## 1.3.2(2021-12-01) +- 优化 示例可复制图标名称 +## 1.3.1(2021-11-23) +- 优化 兼容旧组件 type 值 +## 1.3.0(2021-11-19) +- 新增 更多图标 +- 优化 自定义图标使用方式 +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons) +## 1.1.7(2021-11-08) +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.5(2021-05-12) +- 新增 组件示例地址 +## 1.1.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue new file mode 100644 index 0000000..53eb2ea --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue @@ -0,0 +1,91 @@ + + + + + diff --git a/uni_modules/uni-icons/components/uni-icons/uni-icons.vue b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue new file mode 100644 index 0000000..1bd3d5e --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uni-icons.vue @@ -0,0 +1,110 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.css b/uni_modules/uni-icons/components/uni-icons/uniicons.css new file mode 100644 index 0000000..0a6b6fe --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons.css @@ -0,0 +1,664 @@ + +.uniui-cart-filled:before { + content: "\e6d0"; +} + +.uniui-gift-filled:before { + content: "\e6c4"; +} + +.uniui-color:before { + content: "\e6cf"; +} + +.uniui-wallet:before { + content: "\e6b1"; +} + +.uniui-settings-filled:before { + content: "\e6ce"; +} + +.uniui-auth-filled:before { + content: "\e6cc"; +} + +.uniui-shop-filled:before { + content: "\e6cd"; +} + +.uniui-staff-filled:before { + content: "\e6cb"; +} + +.uniui-vip-filled:before { + content: "\e6c6"; +} + +.uniui-plus-filled:before { + content: "\e6c7"; +} + +.uniui-folder-add-filled:before { + content: "\e6c8"; +} + +.uniui-color-filled:before { + content: "\e6c9"; +} + +.uniui-tune-filled:before { + content: "\e6ca"; +} + +.uniui-calendar-filled:before { + content: "\e6c0"; +} + +.uniui-notification-filled:before { + content: "\e6c1"; +} + +.uniui-wallet-filled:before { + content: "\e6c2"; +} + +.uniui-medal-filled:before { + content: "\e6c3"; +} + +.uniui-fire-filled:before { + content: "\e6c5"; +} + +.uniui-refreshempty:before { + content: "\e6bf"; +} + +.uniui-location-filled:before { + content: "\e6af"; +} + +.uniui-person-filled:before { + content: "\e69d"; +} + +.uniui-personadd-filled:before { + content: "\e698"; +} + +.uniui-arrowthinleft:before { + content: "\e6d2"; +} + +.uniui-arrowthinup:before { + content: "\e6d3"; +} + +.uniui-arrowthindown:before { + content: "\e6d4"; +} + +.uniui-back:before { + content: "\e6b9"; +} + +.uniui-forward:before { + content: "\e6ba"; +} + +.uniui-arrow-right:before { + content: "\e6bb"; +} + +.uniui-arrow-left:before { + content: "\e6bc"; +} + +.uniui-arrow-up:before { + content: "\e6bd"; +} + +.uniui-arrow-down:before { + content: "\e6be"; +} + +.uniui-arrowthinright:before { + content: "\e6d1"; +} + +.uniui-down:before { + content: "\e6b8"; +} + +.uniui-bottom:before { + content: "\e6b8"; +} + +.uniui-arrowright:before { + content: "\e6d5"; +} + +.uniui-right:before { + content: "\e6b5"; +} + +.uniui-up:before { + content: "\e6b6"; +} + +.uniui-top:before { + content: "\e6b6"; +} + +.uniui-left:before { + content: "\e6b7"; +} + +.uniui-arrowup:before { + content: "\e6d6"; +} + +.uniui-eye:before { + content: "\e651"; +} + +.uniui-eye-filled:before { + content: "\e66a"; +} + +.uniui-eye-slash:before { + content: "\e6b3"; +} + +.uniui-eye-slash-filled:before { + content: "\e6b4"; +} + +.uniui-info-filled:before { + content: "\e649"; +} + +.uniui-reload:before { + content: "\e6b2"; +} + +.uniui-micoff-filled:before { + content: "\e6b0"; +} + +.uniui-map-pin-ellipse:before { + content: "\e6ac"; +} + +.uniui-map-pin:before { + content: "\e6ad"; +} + +.uniui-location:before { + content: "\e6ae"; +} + +.uniui-starhalf:before { + content: "\e683"; +} + +.uniui-star:before { + content: "\e688"; +} + +.uniui-star-filled:before { + content: "\e68f"; +} + +.uniui-calendar:before { + content: "\e6a0"; +} + +.uniui-fire:before { + content: "\e6a1"; +} + +.uniui-medal:before { + content: "\e6a2"; +} + +.uniui-font:before { + content: "\e6a3"; +} + +.uniui-gift:before { + content: "\e6a4"; +} + +.uniui-link:before { + content: "\e6a5"; +} + +.uniui-notification:before { + content: "\e6a6"; +} + +.uniui-staff:before { + content: "\e6a7"; +} + +.uniui-vip:before { + content: "\e6a8"; +} + +.uniui-folder-add:before { + content: "\e6a9"; +} + +.uniui-tune:before { + content: "\e6aa"; +} + +.uniui-auth:before { + content: "\e6ab"; +} + +.uniui-person:before { + content: "\e699"; +} + +.uniui-email-filled:before { + content: "\e69a"; +} + +.uniui-phone-filled:before { + content: "\e69b"; +} + +.uniui-phone:before { + content: "\e69c"; +} + +.uniui-email:before { + content: "\e69e"; +} + +.uniui-personadd:before { + content: "\e69f"; +} + +.uniui-chatboxes-filled:before { + content: "\e692"; +} + +.uniui-contact:before { + content: "\e693"; +} + +.uniui-chatbubble-filled:before { + content: "\e694"; +} + +.uniui-contact-filled:before { + content: "\e695"; +} + +.uniui-chatboxes:before { + content: "\e696"; +} + +.uniui-chatbubble:before { + content: "\e697"; +} + +.uniui-upload-filled:before { + content: "\e68e"; +} + +.uniui-upload:before { + content: "\e690"; +} + +.uniui-weixin:before { + content: "\e691"; +} + +.uniui-compose:before { + content: "\e67f"; +} + +.uniui-qq:before { + content: "\e680"; +} + +.uniui-download-filled:before { + content: "\e681"; +} + +.uniui-pyq:before { + content: "\e682"; +} + +.uniui-sound:before { + content: "\e684"; +} + +.uniui-trash-filled:before { + content: "\e685"; +} + +.uniui-sound-filled:before { + content: "\e686"; +} + +.uniui-trash:before { + content: "\e687"; +} + +.uniui-videocam-filled:before { + content: "\e689"; +} + +.uniui-spinner-cycle:before { + content: "\e68a"; +} + +.uniui-weibo:before { + content: "\e68b"; +} + +.uniui-videocam:before { + content: "\e68c"; +} + +.uniui-download:before { + content: "\e68d"; +} + +.uniui-help:before { + content: "\e679"; +} + +.uniui-navigate-filled:before { + content: "\e67a"; +} + +.uniui-plusempty:before { + content: "\e67b"; +} + +.uniui-smallcircle:before { + content: "\e67c"; +} + +.uniui-minus-filled:before { + content: "\e67d"; +} + +.uniui-micoff:before { + content: "\e67e"; +} + +.uniui-closeempty:before { + content: "\e66c"; +} + +.uniui-clear:before { + content: "\e66d"; +} + +.uniui-navigate:before { + content: "\e66e"; +} + +.uniui-minus:before { + content: "\e66f"; +} + +.uniui-image:before { + content: "\e670"; +} + +.uniui-mic:before { + content: "\e671"; +} + +.uniui-paperplane:before { + content: "\e672"; +} + +.uniui-close:before { + content: "\e673"; +} + +.uniui-help-filled:before { + content: "\e674"; +} + +.uniui-paperplane-filled:before { + content: "\e675"; +} + +.uniui-plus:before { + content: "\e676"; +} + +.uniui-mic-filled:before { + content: "\e677"; +} + +.uniui-image-filled:before { + content: "\e678"; +} + +.uniui-locked-filled:before { + content: "\e668"; +} + +.uniui-info:before { + content: "\e669"; +} + +.uniui-locked:before { + content: "\e66b"; +} + +.uniui-camera-filled:before { + content: "\e658"; +} + +.uniui-chat-filled:before { + content: "\e659"; +} + +.uniui-camera:before { + content: "\e65a"; +} + +.uniui-circle:before { + content: "\e65b"; +} + +.uniui-checkmarkempty:before { + content: "\e65c"; +} + +.uniui-chat:before { + content: "\e65d"; +} + +.uniui-circle-filled:before { + content: "\e65e"; +} + +.uniui-flag:before { + content: "\e65f"; +} + +.uniui-flag-filled:before { + content: "\e660"; +} + +.uniui-gear-filled:before { + content: "\e661"; +} + +.uniui-home:before { + content: "\e662"; +} + +.uniui-home-filled:before { + content: "\e663"; +} + +.uniui-gear:before { + content: "\e664"; +} + +.uniui-smallcircle-filled:before { + content: "\e665"; +} + +.uniui-map-filled:before { + content: "\e666"; +} + +.uniui-map:before { + content: "\e667"; +} + +.uniui-refresh-filled:before { + content: "\e656"; +} + +.uniui-refresh:before { + content: "\e657"; +} + +.uniui-cloud-upload:before { + content: "\e645"; +} + +.uniui-cloud-download-filled:before { + content: "\e646"; +} + +.uniui-cloud-download:before { + content: "\e647"; +} + +.uniui-cloud-upload-filled:before { + content: "\e648"; +} + +.uniui-redo:before { + content: "\e64a"; +} + +.uniui-images-filled:before { + content: "\e64b"; +} + +.uniui-undo-filled:before { + content: "\e64c"; +} + +.uniui-more:before { + content: "\e64d"; +} + +.uniui-more-filled:before { + content: "\e64e"; +} + +.uniui-undo:before { + content: "\e64f"; +} + +.uniui-images:before { + content: "\e650"; +} + +.uniui-paperclip:before { + content: "\e652"; +} + +.uniui-settings:before { + content: "\e653"; +} + +.uniui-search:before { + content: "\e654"; +} + +.uniui-redo-filled:before { + content: "\e655"; +} + +.uniui-list:before { + content: "\e644"; +} + +.uniui-mail-open-filled:before { + content: "\e63a"; +} + +.uniui-hand-down-filled:before { + content: "\e63c"; +} + +.uniui-hand-down:before { + content: "\e63d"; +} + +.uniui-hand-up-filled:before { + content: "\e63e"; +} + +.uniui-hand-up:before { + content: "\e63f"; +} + +.uniui-heart-filled:before { + content: "\e641"; +} + +.uniui-mail-open:before { + content: "\e643"; +} + +.uniui-heart:before { + content: "\e639"; +} + +.uniui-loop:before { + content: "\e633"; +} + +.uniui-pulldown:before { + content: "\e632"; +} + +.uniui-scan:before { + content: "\e62a"; +} + +.uniui-bars:before { + content: "\e627"; +} + +.uniui-checkbox:before { + content: "\e62b"; +} + +.uniui-checkbox-filled:before { + content: "\e62c"; +} + +.uniui-shop:before { + content: "\e62f"; +} + +.uniui-headphones:before { + content: "\e630"; +} + +.uniui-cart:before { + content: "\e631"; +} diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons.ttf b/uni_modules/uni-icons/components/uni-icons/uniicons.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14696d038d828073edac09ea4e5ba1dec2f58115 GIT binary patch literal 35824 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 F{2S@rCxHL} literal 0 HcmV?d00001 diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts new file mode 100644 index 0000000..98e93aa --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts @@ -0,0 +1,664 @@ + +export type IconsData = { + id : string + name : string + font_family : string + css_prefix_text : string + description : string + glyphs : Array +} + +export type IconsDataItem = { + font_class : string + unicode : string +} + + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] as IconsDataItem[] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js new file mode 100644 index 0000000..1cd11e1 --- /dev/null +++ b/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js @@ -0,0 +1,649 @@ + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/uni_modules/uni-icons/package.json b/uni_modules/uni-icons/package.json new file mode 100644 index 0000000..60e45f0 --- /dev/null +++ b/uni_modules/uni-icons/package.json @@ -0,0 +1,111 @@ +{ + "id": "uni-icons", + "displayName": "uni-icons 图标", + "version": "2.0.12", + "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。", + "keywords": [ + "uni-ui", + "uniui", + "icon", + "图标" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.2.14", + "uni-app": "^4.08", + "uni-app-x": "^4.61" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [ + "uni-scss" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "x", + "aliyun": "x", + "alipay": "x" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "-", + "android": { + "extVersion": "", + "minVersion": "29" + }, + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√", + "alipay": "√", + "toutiao": "√", + "baidu": "√", + "kuaishou": "-", + "jd": "-", + "harmony": "-", + "qq": "√", + "lark": "-" + }, + "quickapp": { + "huawei": "√", + "union": "√" + } + }, + "uni-app-x": { + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "android": { + "extVersion": "", + "minVersion": "29" + }, + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-icons/readme.md b/uni_modules/uni-icons/readme.md new file mode 100644 index 0000000..86234ba --- /dev/null +++ b/uni_modules/uni-icons/readme.md @@ -0,0 +1,8 @@ +## Icons 图标 +> **组件名:uni-icons** +> 代码块: `uIcons` + +用于展示 icons 图标 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-load-more/changelog.md b/uni_modules/uni-load-more/changelog.md new file mode 100644 index 0000000..c5750ac --- /dev/null +++ b/uni_modules/uni-load-more/changelog.md @@ -0,0 +1,23 @@ +## 1.3.7(2025-08-20) +- 修复 微信小程序css警告问题 +## 1.3.6(2024-10-15) +- 修复 微信小程序中的getSystemInfo警告 +## 1.3.3(2022-01-20) +- 新增 showText属性 ,是否显示文本 +## 1.3.2(2022-01-19) +- 修复 nvue 平台下不显示文本的bug +## 1.3.1(2022-01-19) +- 修复 微信小程序平台样式选择器报警告的问题 +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more) +## 1.2.1(2021-08-24) +- 新增 支持国际化 +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.8(2021-05-12) +- 新增 组件示例地址 +## 1.1.7(2021-03-30) +- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug +## 1.1.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json new file mode 100644 index 0000000..a4f14a5 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "Pull up to show more", + "uni-load-more.contentrefresh": "loading...", + "uni-load-more.contentnomore": "No more data" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js b/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json new file mode 100644 index 0000000..f15d510 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉显示更多", + "uni-load-more.contentrefresh": "正在加载...", + "uni-load-more.contentnomore": "没有更多数据了" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json new file mode 100644 index 0000000..a255c6d --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉顯示更多", + "uni-load-more.contentrefresh": "正在加載...", + "uni-load-more.contentnomore": "沒有更多數據了" +} diff --git a/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue new file mode 100644 index 0000000..0fa17e8 --- /dev/null +++ b/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue @@ -0,0 +1,404 @@ + + + + + diff --git a/uni_modules/uni-load-more/package.json b/uni_modules/uni-load-more/package.json new file mode 100644 index 0000000..3397e8a --- /dev/null +++ b/uni_modules/uni-load-more/package.json @@ -0,0 +1,105 @@ +{ + "id": "uni-load-more", + "displayName": "uni-load-more 加载更多", + "version": "1.3.7", + "description": "LoadMore 组件,常用在列表里面,做滚动加载使用。", + "keywords": [ + "uni-ui", + "uniui", + "加载更多", + "load-more" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "", + "uni-app": "^4.07", + "uni-app-x": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [ + "uni-scss" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "x", + "aliyun": "x", + "alipay": "x" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "-", + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√", + "alipay": "√", + "toutiao": "√", + "baidu": "√", + "kuaishou": "-", + "jd": "-", + "harmony": "-", + "qq": "√", + "lark": "-" + }, + "quickapp": { + "huawei": "√", + "union": "√" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": "-", + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-load-more/readme.md b/uni_modules/uni-load-more/readme.md new file mode 100644 index 0000000..54dc1fa --- /dev/null +++ b/uni_modules/uni-load-more/readme.md @@ -0,0 +1,14 @@ + + +### LoadMore 加载更多 +> **组件名:uni-load-more** +> 代码块: `uLoadMore` + + +用于列表中,做滚动加载使用,展示 loading 的各种状态。 + + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/uni_modules/uni-popup/changelog.md b/uni_modules/uni-popup/changelog.md new file mode 100644 index 0000000..c72474a --- /dev/null +++ b/uni_modules/uni-popup/changelog.md @@ -0,0 +1,102 @@ +## 1.9.11(2025-08-20) +- 修复 uni-popup-dialog组件设置 borderRadius 不生效的 Bug +## 1.9.10(2025-07-18) +- 修复 nvue 下弹窗样式错乱的问题 ,更新依赖 uni-transition 组件 +- 更新 示例取消 borderRadius 属性 ,如需内容圆角,用户应该直接在内容插槽中实现 +## 1.9.9(2025-06-11) +- 修复 uni-popup-dialog 中 setVal 方法报错的问题 +- 修复 uni-popup-dialog 数据双向绑定问题。 +## 1.9.8(2025-04-16) +- 修复 更新组件示例 ,解决更新数据或保存项目导致弹窗消失的问题 +## 1.9.7(2025-04-14) +- 修复 uni-popup-dialog 弹出框在vue3中双向绑定问题 +## 1.9.6(2025-01-08) +- 修复 示例中过期图片地址 +## 1.9.5(2024-10-15) +- 修复 微信小程序中的getSystemInfo警告 +## 1.9.2(2024-09-21) +- 修复 uni-popup在android上的重复点击弹出位置不正确的bug +## 1.9.1(2024-04-02) +- 修复 uni-popup-dialog vue3下使用value无法进行绑定的bug(双向绑定兼容旧写法) +## 1.9.0(2024-03-28) +- 修复 uni-popup-dialog 双向绑定时初始化逻辑修正 +## 1.8.9(2024-03-20) +- 修复 uni-popup-dialog 数据输入时修正为双向绑定 +## 1.8.8(2024-02-20) +- 修复 uni-popup 在微信小程序下出现文字向上闪动的bug +## 1.8.7(2024-02-02) +- 新增 uni-popup-dialog 新增属性focus:input模式下,是否自动自动聚焦 +## 1.8.6(2024-01-30) +- 新增 uni-popup-dialog 新增属性maxLength:限制输入框字数 +## 1.8.5(2024-01-26) +- 新增 uni-popup-dialog 新增属性showClose:控制关闭按钮的显示 +## 1.8.4(2023-11-15) +- 新增 uni-popup 支持uni-app-x 注意暂时仅支持 `maskClick` `@open` `@close` +## 1.8.3(2023-04-17) +- 修复 uni-popup 重复打开时的 bug +## 1.8.2(2023-02-02) +- uni-popup-dialog 组件新增 inputType 属性 +## 1.8.1(2022-12-01) +- 修复 nvue 下 v-show 报错 +## 1.8.0(2022-11-29) +- 优化 主题样式 +## 1.7.9(2022-04-02) +- 修复 弹出层内部无法滚动的bug +## 1.7.8(2022-03-28) +- 修复 小程序中高度错误的bug +## 1.7.7(2022-03-17) +- 修复 快速调用open出现问题的Bug +## 1.7.6(2022-02-14) +- 修复 safeArea 属性不能设置为false的bug +## 1.7.5(2022-01-19) +- 修复 isMaskClick 失效的bug +## 1.7.4(2022-01-19) +- 新增 cancelText \ confirmText 属性 ,可自定义文本 +- 新增 maskBackgroundColor 属性 ,可以修改蒙版颜色 +- 优化 maskClick属性 更新为 isMaskClick ,解决微信小程序警告的问题 +## 1.7.3(2022-01-13) +- 修复 设置 safeArea 属性不生效的bug +## 1.7.2(2021-11-26) +- 优化 组件示例 +## 1.7.1(2021-11-26) +- 修复 vuedoc 文字错误 +## 1.7.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-popup](https://uniapp.dcloud.io/component/uniui/uni-popup) +## 1.6.2(2021-08-24) +- 新增 支持国际化 +## 1.6.1(2021-07-30) +- 优化 vue3下事件警告的问题 +## 1.6.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.5.0(2021-06-23) +- 新增 mask-click 遮罩层点击事件 +## 1.4.5(2021-06-22) +- 修复 nvue 平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.4(2021-06-18) +- 修复 H5平台中间弹出后,点击内容,再点击遮罩无法关闭的Bug +## 1.4.3(2021-06-08) +- 修复 错误的 watch 字段 +- 修复 safeArea 属性不生效的问题 +- 修复 点击内容,再点击遮罩无法关闭的Bug +## 1.4.2(2021-05-12) +- 新增 组件示例地址 +## 1.4.1(2021-04-29) +- 修复 组件内放置 input 、textarea 组件,无法聚焦的问题 +## 1.4.0 (2021-04-29) +- 新增 type 属性的 left\right 值,支持左右弹出 +- 新增 open(String:type) 方法参数 ,可以省略 type 属性 ,直接传入类型打开指定弹窗 +- 新增 backgroundColor 属性,可定义主窗口背景色,默认不显示背景色 +- 新增 safeArea 属性,是否适配底部安全区 +- 修复 App\h5\微信小程序底部安全区占位不对的Bug +- 修复 App 端弹出等待的Bug +- 优化 提升低配设备性能,优化动画卡顿问题 +- 优化 更简单的组件自定义方式 +## 1.2.9(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 1.2.8(2021-02-05) +- 调整为uni_modules目录规范 +## 1.2.7(2021-02-05) +- 调整为uni_modules目录规范 +- 新增 支持 PC 端 +- 新增 uni-popup-message 、uni-popup-dialog扩展组件支持 PC 端 diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js new file mode 100644 index 0000000..6ef26a2 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-dialog/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + this.$once('hook:beforeDestroy', () => { + document.removeEventListener('keyup', listener) + }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue new file mode 100644 index 0000000..ea93ea5 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-dialog/uni-popup-dialog.vue @@ -0,0 +1,330 @@ + + + + + diff --git a/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue new file mode 100644 index 0000000..91370a8 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-message/uni-popup-message.vue @@ -0,0 +1,143 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue new file mode 100644 index 0000000..c8945d5 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup-share/uni-popup-share.vue @@ -0,0 +1,188 @@ + + + + diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/en.json b/uni_modules/uni-popup/components/uni-popup/i18n/en.json new file mode 100644 index 0000000..7f1bd06 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/en.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "cancel", + "uni-popup.ok": "ok", + "uni-popup.placeholder": "pleace enter", + "uni-popup.title": "Hint", + "uni-popup.shareTitle": "Share to" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/index.js b/uni_modules/uni-popup/components/uni-popup/i18n/index.js new file mode 100644 index 0000000..de7509c --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json new file mode 100644 index 0000000..5e3003c --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "确定", + "uni-popup.placeholder": "请输入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json new file mode 100644 index 0000000..13e39eb --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/i18n/zh-Hant.json @@ -0,0 +1,7 @@ +{ + "uni-popup.cancel": "取消", + "uni-popup.ok": "確定", + "uni-popup.placeholder": "請輸入", + "uni-popup.title": "提示", + "uni-popup.shareTitle": "分享到" +} diff --git a/uni_modules/uni-popup/components/uni-popup/keypress.js b/uni_modules/uni-popup/components/uni-popup/keypress.js new file mode 100644 index 0000000..62dda46 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + // this.$once('hook:beforeDestroy', () => { + // document.removeEventListener('keyup', listener) + // }) + }, + render: () => {} +} +// #endif diff --git a/uni_modules/uni-popup/components/uni-popup/popup.js b/uni_modules/uni-popup/components/uni-popup/popup.js new file mode 100644 index 0000000..c4e5781 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/popup.js @@ -0,0 +1,26 @@ + +export default { + data() { + return { + + } + }, + created(){ + this.popup = this.getParent() + }, + methods:{ + /** + * 获取父元素实例 + */ + getParent(name = 'uniPopup') { + 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; + }, + } +} diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue b/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue new file mode 100644 index 0000000..5eb8d5b --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.uvue @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-popup/components/uni-popup/uni-popup.vue b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue new file mode 100644 index 0000000..5af55e0 --- /dev/null +++ b/uni_modules/uni-popup/components/uni-popup/uni-popup.vue @@ -0,0 +1,518 @@ + + + + diff --git a/uni_modules/uni-popup/package.json b/uni_modules/uni-popup/package.json new file mode 100644 index 0000000..eb2bb05 --- /dev/null +++ b/uni_modules/uni-popup/package.json @@ -0,0 +1,107 @@ +{ + "id": "uni-popup", + "displayName": "uni-popup 弹出层", + "version": "1.9.11", + "description": " Popup 组件,提供常用的弹层", + "keywords": [ + "uni-ui", + "弹出层", + "弹窗", + "popup", + "弹框" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "", + "uni-app": "^4.07", + "uni-app-x": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-transition" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "x", + "aliyun": "x", + "alipay": "x" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "√", + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√", + "alipay": "√", + "toutiao": "√", + "baidu": "√", + "kuaishou": "-", + "jd": "-", + "harmony": "-", + "qq": "√", + "lark": "-" + }, + "quickapp": { + "huawei": "-", + "union": "-" + } + }, + "uni-app-x": { + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-popup/readme.md b/uni_modules/uni-popup/readme.md new file mode 100644 index 0000000..fdad4b3 --- /dev/null +++ b/uni_modules/uni-popup/readme.md @@ -0,0 +1,17 @@ + + +## Popup 弹出层 +> **组件名:uni-popup** +> 代码块: `uPopup` +> 关联组件:`uni-transition` + + +弹出层组件,在应用中弹出一个消息提示窗口、提示框等 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-popup) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + + + + diff --git a/uni_modules/uni-row/changelog.md b/uni_modules/uni-row/changelog.md new file mode 100644 index 0000000..5b465bc --- /dev/null +++ b/uni_modules/uni-row/changelog.md @@ -0,0 +1,10 @@ +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-row](https://uniapp.dcloud.io/component/uniui/uni-row) +## 0.1.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.0.4(2021-05-12) +- 新增 组件示例地址 +## 0.0.3(2021-02-05) +- 调整为uni_modules目录规范 +- 新增uni-row组件 diff --git a/uni_modules/uni-row/components/uni-col/uni-col.vue b/uni_modules/uni-row/components/uni-col/uni-col.vue new file mode 100644 index 0000000..84e2deb --- /dev/null +++ b/uni_modules/uni-row/components/uni-col/uni-col.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/uni_modules/uni-row/components/uni-row/uni-row.vue b/uni_modules/uni-row/components/uni-row/uni-row.vue new file mode 100644 index 0000000..f8e8542 --- /dev/null +++ b/uni_modules/uni-row/components/uni-row/uni-row.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/uni_modules/uni-row/package.json b/uni_modules/uni-row/package.json new file mode 100644 index 0000000..3f52fa6 --- /dev/null +++ b/uni_modules/uni-row/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-row", + "displayName": "uni-row 布局-行", + "version": "1.0.0", + "description": "流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。", + "keywords": [ + "uni-ui", + "uniui", + "栅格", + "布局", + "layout" +], + "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-scss"], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-row/readme.md b/uni_modules/uni-row/readme.md new file mode 100644 index 0000000..3c9c8b9 --- /dev/null +++ b/uni_modules/uni-row/readme.md @@ -0,0 +1,10 @@ +## Layout 布局 + +> **组件名 uni-row、uni-col** +> 代码块: `uRow`、`uCol` + + +流式栅格系统,随着屏幕或视口分为 24 份,可以迅速简便地创建布局。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-row) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/changelog.md b/uni_modules/uni-scss/changelog.md new file mode 100644 index 0000000..b863bb0 --- /dev/null +++ b/uni_modules/uni-scss/changelog.md @@ -0,0 +1,8 @@ +## 1.0.3(2022-01-21) +- 优化 组件示例 +## 1.0.2(2021-11-22) +- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题 +## 1.0.1(2021-11-22) +- 修复 vue3中scss语法兼容问题 +## 1.0.0(2021-11-18) +- init diff --git a/uni_modules/uni-scss/index.scss b/uni_modules/uni-scss/index.scss new file mode 100644 index 0000000..1744a5f --- /dev/null +++ b/uni_modules/uni-scss/index.scss @@ -0,0 +1 @@ +@import './styles/index.scss'; diff --git a/uni_modules/uni-scss/package.json b/uni_modules/uni-scss/package.json new file mode 100644 index 0000000..7cc0ccb --- /dev/null +++ b/uni_modules/uni-scss/package.json @@ -0,0 +1,82 @@ +{ + "id": "uni-scss", + "displayName": "uni-scss 辅助样式", + "version": "1.0.3", + "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。", + "keywords": [ + "uni-scss", + "uni-ui", + "辅助样式" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-scss/readme.md b/uni_modules/uni-scss/readme.md new file mode 100644 index 0000000..b7d1c25 --- /dev/null +++ b/uni_modules/uni-scss/readme.md @@ -0,0 +1,4 @@ +`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/index.scss b/uni_modules/uni-scss/styles/index.scss new file mode 100644 index 0000000..ffac4fe --- /dev/null +++ b/uni_modules/uni-scss/styles/index.scss @@ -0,0 +1,7 @@ +@import './setting/_variables.scss'; +@import './setting/_border.scss'; +@import './setting/_color.scss'; +@import './setting/_space.scss'; +@import './setting/_radius.scss'; +@import './setting/_text.scss'; +@import './setting/_styles.scss'; diff --git a/uni_modules/uni-scss/styles/setting/_border.scss b/uni_modules/uni-scss/styles/setting/_border.scss new file mode 100644 index 0000000..12a11c3 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_border.scss @@ -0,0 +1,3 @@ +.uni-border { + border: 1px $uni-border-1 solid; +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_color.scss b/uni_modules/uni-scss/styles/setting/_color.scss new file mode 100644 index 0000000..1ededd9 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_color.scss @@ -0,0 +1,66 @@ + +// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐 +// @mixin get-styles($k,$c) { +// @if $k == size or $k == weight{ +// font-#{$k}:#{$c} +// }@else{ +// #{$k}:#{$c} +// } +// } +$uni-ui-color:( + // 主色 + primary: $uni-primary, + primary-disable: $uni-primary-disable, + primary-light: $uni-primary-light, + // 辅助色 + success: $uni-success, + success-disable: $uni-success-disable, + success-light: $uni-success-light, + warning: $uni-warning, + warning-disable: $uni-warning-disable, + warning-light: $uni-warning-light, + error: $uni-error, + error-disable: $uni-error-disable, + error-light: $uni-error-light, + info: $uni-info, + info-disable: $uni-info-disable, + info-light: $uni-info-light, + // 中性色 + main-color: $uni-main-color, + base-color: $uni-base-color, + secondary-color: $uni-secondary-color, + extra-color: $uni-extra-color, + // 背景色 + bg-color: $uni-bg-color, + // 边框颜色 + border-1: $uni-border-1, + border-2: $uni-border-2, + border-3: $uni-border-3, + border-4: $uni-border-4, + // 黑色 + black:$uni-black, + // 白色 + white:$uni-white, + // 透明 + transparent:$uni-transparent +) !default; +@each $key, $child in $uni-ui-color { + .uni-#{"" + $key} { + color: $child; + } + .uni-#{"" + $key}-bg { + background-color: $child; + } +} +.uni-shadow-sm { + box-shadow: $uni-shadow-sm; +} +.uni-shadow-base { + box-shadow: $uni-shadow-base; +} +.uni-shadow-lg { + box-shadow: $uni-shadow-lg; +} +.uni-mask { + background-color:$uni-mask; +} diff --git a/uni_modules/uni-scss/styles/setting/_radius.scss b/uni_modules/uni-scss/styles/setting/_radius.scss new file mode 100644 index 0000000..9a0428b --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_radius.scss @@ -0,0 +1,55 @@ +@mixin radius($r,$d:null ,$important: false){ + $radius-value:map-get($uni-radius, $r) if($important, !important, null); + // Key exists within the $uni-radius variable + @if (map-has-key($uni-radius, $r) and $d){ + @if $d == t { + border-top-left-radius:$radius-value; + border-top-right-radius:$radius-value; + }@else if $d == r { + border-top-right-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == b { + border-bottom-left-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == l { + border-top-left-radius:$radius-value; + border-bottom-left-radius:$radius-value; + }@else if $d == tl { + border-top-left-radius:$radius-value; + }@else if $d == tr { + border-top-right-radius:$radius-value; + }@else if $d == br { + border-bottom-right-radius:$radius-value; + }@else if $d == bl { + border-bottom-left-radius:$radius-value; + } + }@else{ + border-radius:$radius-value; + } +} + +@each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $key} { + @include radius($key) + } + }@else{ + .uni-radius { + @include radius($key) + } + } +} + +@each $direction in t, r, b, l,tl, tr, br, bl { + @each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $direction}-#{"" + $key} { + @include radius($key,$direction,false) + } + }@else{ + .uni-radius-#{$direction} { + @include radius($key,$direction,false) + } + } + } +} diff --git a/uni_modules/uni-scss/styles/setting/_space.scss b/uni_modules/uni-scss/styles/setting/_space.scss new file mode 100644 index 0000000..3c89528 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_space.scss @@ -0,0 +1,56 @@ + +@mixin fn($space,$direction,$size,$n) { + @if $n { + #{$space}-#{$direction}: #{$size*$uni-space-root}px + } @else { + #{$space}-#{$direction}: #{-$size*$uni-space-root}px + } +} +@mixin get-styles($direction,$i,$space,$n){ + @if $direction == t { + @include fn($space, top,$i,$n); + } + @if $direction == r { + @include fn($space, right,$i,$n); + } + @if $direction == b { + @include fn($space, bottom,$i,$n); + } + @if $direction == l { + @include fn($space, left,$i,$n); + } + @if $direction == x { + @include fn($space, left,$i,$n); + @include fn($space, right,$i,$n); + } + @if $direction == y { + @include fn($space, top,$i,$n); + @include fn($space, bottom,$i,$n); + } + @if $direction == a { + @if $n { + #{$space}:#{$i*$uni-space-root}px; + } @else { + #{$space}:#{-$i*$uni-space-root}px; + } + } +} + +@each $orientation in m,p { + $space: margin; + @if $orientation == m { + $space: margin; + } @else { + $space: padding; + } + @for $i from 0 through 16 { + @each $direction in t, r, b, l, x, y, a { + .uni-#{$orientation}#{$direction}-#{$i} { + @include get-styles($direction,$i,$space,true); + } + .uni-#{$orientation}#{$direction}-n#{$i} { + @include get-styles($direction,$i,$space,false); + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_styles.scss b/uni_modules/uni-scss/styles/setting/_styles.scss new file mode 100644 index 0000000..689afec --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_styles.scss @@ -0,0 +1,167 @@ +/* #ifndef APP-NVUE */ + +$-color-white:#fff; +$-color-black:#000; +@mixin base-style($color) { + color: #fff; + background-color: $color; + border-color: mix($-color-black, $color, 8%); + &:not([hover-class]):active { + background: mix($-color-black, $color, 10%); + border-color: mix($-color-black, $color, 20%); + color: $-color-white; + outline: none; + } +} +@mixin is-color($color) { + @include base-style($color); + &[loading] { + @include base-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &[loading], + &:not([hover-class]):active { + color: $-color-white; + border-color: mix(darken($color,10%), $-color-white); + background-color: mix($color, $-color-white); + } + } + +} +@mixin base-plain-style($color) { + color:$color; + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 70%); + &:not([hover-class]):active { + background: mix($-color-white, $color, 80%); + color: $color; + outline: none; + border-color: mix($-color-white, $color, 50%); + } +} +@mixin is-plain($color){ + &[plain] { + @include base-plain-style($color); + &[loading] { + @include base-plain-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &:active { + color: mix($-color-white, $color, 40%); + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 80%); + } + } + } +} + + +.uni-btn { + margin: 5px; + color: #393939; + border:1px solid #ccc; + font-size: 16px; + font-weight: 200; + background-color: #F9F9F9; + // TODO 暂时处理边框隐藏一边的问题 + overflow: visible; + &::after{ + border: none; + } + + &:not([type]),&[type=default] { + color: #999; + &[loading] { + background: none; + &::before { + margin-right:5px; + } + } + + + + &[disabled]{ + color: mix($-color-white, #999, 60%); + &, + &[loading], + &:active { + color: mix($-color-white, #999, 60%); + background-color: mix($-color-white,$-color-black , 98%); + border-color: mix($-color-white, #999, 85%); + } + } + + &[plain] { + color: #999; + background: none; + border-color: $uni-border-1; + &:not([hover-class]):active { + background: none; + color: mix($-color-white, $-color-black, 80%); + border-color: mix($-color-white, $-color-black, 90%); + outline: none; + } + &[disabled]{ + &, + &[loading], + &:active { + background: none; + color: mix($-color-white, #999, 60%); + border-color: mix($-color-white, #999, 85%); + } + } + } + } + + &:not([hover-class]):active { + color: mix($-color-white, $-color-black, 50%); + } + + &[size=mini] { + font-size: 16px; + font-weight: 200; + border-radius: 8px; + } + + + + &.uni-btn-small { + font-size: 14px; + } + &.uni-btn-mini { + font-size: 12px; + } + + &.uni-btn-radius { + border-radius: 999px; + } + &[type=primary] { + @include is-color($uni-primary); + @include is-plain($uni-primary) + } + &[type=success] { + @include is-color($uni-success); + @include is-plain($uni-success) + } + &[type=error] { + @include is-color($uni-error); + @include is-plain($uni-error) + } + &[type=warning] { + @include is-color($uni-warning); + @include is-plain($uni-warning) + } + &[type=info] { + @include is-color($uni-info); + @include is-plain($uni-info) + } +} +/* #endif */ diff --git a/uni_modules/uni-scss/styles/setting/_text.scss b/uni_modules/uni-scss/styles/setting/_text.scss new file mode 100644 index 0000000..a34d08f --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_text.scss @@ -0,0 +1,24 @@ +@mixin get-styles($k,$c) { + @if $k == size or $k == weight{ + font-#{$k}:#{$c} + }@else{ + #{$k}:#{$c} + } +} + +@each $key, $child in $uni-headings { + /* #ifndef APP-NVUE */ + .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ + /* #ifdef APP-NVUE */ + .container .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ +} diff --git a/uni_modules/uni-scss/styles/setting/_variables.scss b/uni_modules/uni-scss/styles/setting/_variables.scss new file mode 100644 index 0000000..557d3d7 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_variables.scss @@ -0,0 +1,146 @@ +// @use "sass:math"; +@import '../tools/functions.scss'; +// 间距基础倍数 +$uni-space-root: 2 !default; +// 边框半径默认值 +$uni-radius-root:5px !default; +$uni-radius: () !default; +// 边框半径断点 +$uni-radius: map-deep-merge( + ( + 0: 0, + // TODO 当前版本暂时不支持 sm 属性 + // 'sm': math.div($uni-radius-root, 2), + null: $uni-radius-root, + 'lg': $uni-radius-root * 2, + 'xl': $uni-radius-root * 6, + 'pill': 9999px, + 'circle': 50% + ), + $uni-radius +); +// 字体家族 +$body-font-family: 'Roboto', sans-serif !default; +// 文本 +$heading-font-family: $body-font-family !default; +$uni-headings: () !default; +$letterSpacing: -0.01562em; +$uni-headings: map-deep-merge( + ( + 'h1': ( + size: 32px, + weight: 300, + line-height: 50px, + // letter-spacing:-0.01562em + ), + 'h2': ( + size: 28px, + weight: 300, + line-height: 40px, + // letter-spacing: -0.00833em + ), + 'h3': ( + size: 24px, + weight: 400, + line-height: 32px, + // letter-spacing: normal + ), + 'h4': ( + size: 20px, + weight: 400, + line-height: 30px, + // letter-spacing: 0.00735em + ), + 'h5': ( + size: 16px, + weight: 400, + line-height: 24px, + // letter-spacing: normal + ), + 'h6': ( + size: 14px, + weight: 500, + line-height: 18px, + // letter-spacing: 0.0125em + ), + 'subtitle': ( + size: 12px, + weight: 400, + line-height: 20px, + // letter-spacing: 0.00937em + ), + 'body': ( + font-size: 14px, + font-weight: 400, + line-height: 22px, + // letter-spacing: 0.03125em + ), + 'caption': ( + 'size': 12px, + 'weight': 400, + 'line-height': 20px, + // 'letter-spacing': 0.03333em, + // 'text-transform': false + ) + ), + $uni-headings +); + + + +// 主色 +$uni-primary: #2979ff !default; +$uni-primary-disable:lighten($uni-primary,20%) !default; +$uni-primary-light: lighten($uni-primary,25%) !default; + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37 !default; +$uni-success-disable:lighten($uni-success,20%) !default; +$uni-success-light: lighten($uni-success,25%) !default; + +$uni-warning: #f3a73f !default; +$uni-warning-disable:lighten($uni-warning,20%) !default; +$uni-warning-light: lighten($uni-warning,25%) !default; + +$uni-error: #e43d33 !default; +$uni-error-disable:lighten($uni-error,20%) !default; +$uni-error-light: lighten($uni-error,25%) !default; + +$uni-info: #8f939c !default; +$uni-info-disable:lighten($uni-info,20%) !default; +$uni-info-light: lighten($uni-info,25%) !default; + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a !default; // 主要文字 +$uni-base-color: #6a6a6a !default; // 常规文字 +$uni-secondary-color: #909399 !default; // 次要文字 +$uni-extra-color: #c7c7c7 !default; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0 !default; +$uni-border-2: #EDEDED !default; +$uni-border-3: #DCDCDC !default; +$uni-border-4: #B9B9B9 !default; + +// 常规色 +$uni-black: #000000 !default; +$uni-white: #ffffff !default; +$uni-transparent: rgba($color: #000000, $alpha: 0) !default; + +// 背景色 +$uni-bg-color: #f7f7f7 !default; + +/* 水平间距 */ +$uni-spacing-sm: 8px !default; +$uni-spacing-base: 15px !default; +$uni-spacing-lg: 30px !default; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default; +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default; +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default; + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4) !default; diff --git a/uni_modules/uni-scss/styles/tools/functions.scss b/uni_modules/uni-scss/styles/tools/functions.scss new file mode 100644 index 0000000..ac6f63e --- /dev/null +++ b/uni_modules/uni-scss/styles/tools/functions.scss @@ -0,0 +1,19 @@ +// 合并 map +@function map-deep-merge($parent-map, $child-map){ + $result: $parent-map; + @each $key, $child in $child-map { + $parent-has-key: map-has-key($result, $key); + $parent-value: map-get($result, $key); + $parent-type: type-of($parent-value); + $child-type: type-of($child); + $parent-is-map: $parent-type == map; + $child-is-map: $child-type == map; + + @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){ + $result: map-merge($result, ( $key: $child )); + }@else { + $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) )); + } + } + @return $result; +}; diff --git a/uni_modules/uni-scss/theme.scss b/uni_modules/uni-scss/theme.scss new file mode 100644 index 0000000..80ee62f --- /dev/null +++ b/uni_modules/uni-scss/theme.scss @@ -0,0 +1,31 @@ +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; +// 主色 +$uni-primary: #2979ff; +// 辅助色 +$uni-success: #4cd964; +// 警告色 +$uni-warning: #f0ad4e; +// 错误色 +$uni-error: #dd524d; +// 描述色 +$uni-info: #909399; +// 中性色 +$uni-main-color: #303133; +$uni-base-color: #606266; +$uni-secondary-color: #909399; +$uni-extra-color: #C0C4CC; +// 背景色 +$uni-bg-color: #f5f5f5; +// 边框颜色 +$uni-border-1: #DCDFE6; +$uni-border-2: #E4E7ED; +$uni-border-3: #EBEEF5; +$uni-border-4: #F2F6FC; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); diff --git a/uni_modules/uni-scss/variables.scss b/uni_modules/uni-scss/variables.scss new file mode 100644 index 0000000..1c062d4 --- /dev/null +++ b/uni_modules/uni-scss/variables.scss @@ -0,0 +1,62 @@ +@import './styles/setting/_variables.scss'; +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; + +// 主色 +$uni-primary: #2979ff; +$uni-primary-disable:mix(#fff,$uni-primary,50%); +$uni-primary-light: mix(#fff,$uni-primary,80%); + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37; +$uni-success-disable:mix(#fff,$uni-success,50%); +$uni-success-light: mix(#fff,$uni-success,80%); + +$uni-warning: #f3a73f; +$uni-warning-disable:mix(#fff,$uni-warning,50%); +$uni-warning-light: mix(#fff,$uni-warning,80%); + +$uni-error: #e43d33; +$uni-error-disable:mix(#fff,$uni-error,50%); +$uni-error-light: mix(#fff,$uni-error,80%); + +$uni-info: #8f939c; +$uni-info-disable:mix(#fff,$uni-info,50%); +$uni-info-light: mix(#fff,$uni-info,80%); + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a; // 主要文字 +$uni-base-color: #6a6a6a; // 常规文字 +$uni-secondary-color: #909399; // 次要文字 +$uni-extra-color: #c7c7c7; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0; +$uni-border-2: #EDEDED; +$uni-border-3: #DCDCDC; +$uni-border-4: #B9B9B9; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); + +// 背景色 +$uni-bg-color: #f7f7f7; + +/* 水平间距 */ +$uni-spacing-sm: 8px; +$uni-spacing-base: 15px; +$uni-spacing-lg: 30px; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5); +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2); +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5); + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4); diff --git a/uni_modules/uni-section/changelog.md b/uni_modules/uni-section/changelog.md new file mode 100644 index 0000000..738f2b3 --- /dev/null +++ b/uni_modules/uni-section/changelog.md @@ -0,0 +1,2 @@ +## 0.0.1(2022-07-22) +- 初始化 diff --git a/uni_modules/uni-section/components/uni-section/uni-section.vue b/uni_modules/uni-section/components/uni-section/uni-section.vue new file mode 100644 index 0000000..9a52e0b --- /dev/null +++ b/uni_modules/uni-section/components/uni-section/uni-section.vue @@ -0,0 +1,167 @@ + + + + diff --git a/uni_modules/uni-section/package.json b/uni_modules/uni-section/package.json new file mode 100644 index 0000000..0a31fb5 --- /dev/null +++ b/uni_modules/uni-section/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-section", + "displayName": "uni-section 标题栏", + "version": "0.0.1", + "description": "标题栏组件", + "keywords": [ + "uni-ui", + "uniui", + "标题栏" +], + "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-scss" + ], + "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" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-section/readme.md b/uni_modules/uni-section/readme.md new file mode 100644 index 0000000..d47faab --- /dev/null +++ b/uni_modules/uni-section/readme.md @@ -0,0 +1,8 @@ +## Section 标题栏 +> **组件名:uni-section** +> 代码块: `uSection` + +uni-section 组件主要用于文章、列表详情等标题展示 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-section) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/uni_modules/uni-transition/changelog.md b/uni_modules/uni-transition/changelog.md new file mode 100644 index 0000000..01bfb58 --- /dev/null +++ b/uni_modules/uni-transition/changelog.md @@ -0,0 +1,31 @@ +## 1.3.6(2025-07-18) +- 修复 nvue 页面,样式错误问题 +## 1.3.5(2025-06-11) +- 修复 第一次执行不显示动画的问题 +## 1.3.4(2025-04-16) +- 修复 页面数据更新到底动画复原的问题 +- 修复 示例页面打开报错的问题 +## 1.3.3(2024-04-23) +- 修复 当元素会受变量影响自动隐藏的bug +## 1.3.2(2023-05-04) +- 修复 NVUE 平台报错的问题 +## 1.3.1(2021-11-23) +- 修复 init 方法初始化问题 +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-transition](https://uniapp.dcloud.io/component/uniui/uni-transition) +## 1.2.1(2021-09-27) +- 修复 init 方法不生效的 Bug +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.1(2021-05-12) +- 新增 示例地址 +- 修复 示例项目缺少组件的 Bug +## 1.1.0(2021-04-22) +- 新增 通过方法自定义动画 +- 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式 +- 优化 动画触发逻辑,使动画更流畅 +- 优化 支持单独的动画类型 +- 优化 文档示例 +## 1.0.2(2021-02-05) +- 调整为 uni_modules 目录规范 diff --git a/uni_modules/uni-transition/components/uni-transition/createAnimation.js b/uni_modules/uni-transition/components/uni-transition/createAnimation.js new file mode 100644 index 0000000..8f89b18 --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/createAnimation.js @@ -0,0 +1,131 @@ +// const defaultOption = { +// duration: 300, +// timingFunction: 'linear', +// delay: 0, +// transformOrigin: '50% 50% 0' +// } +// #ifdef APP-NVUE +const nvueAnimation = uni.requireNativePlugin('animation') +// #endif +class MPAnimation { + constructor(options, _this) { + this.options = options + // 在iOS10+QQ小程序平台下,传给原生的对象一定是个普通对象而不是Proxy对象,否则会报parameter should be Object instead of ProxyObject的错误 + this.animation = uni.createAnimation({ + ...options + }) + this.currentStepAnimates = {} + this.next = 0 + this.$ = _this + + } + + _nvuePushAnimates(type, args) { + let aniObj = this.currentStepAnimates[this.next] + let styles = {} + if (!aniObj) { + styles = { + styles: {}, + config: {} + } + } else { + styles = aniObj + } + if (animateTypes1.includes(type)) { + if (!styles.styles.transform) { + styles.styles.transform = '' + } + let unit = '' + if(type === 'rotate'){ + unit = 'deg' + } + styles.styles.transform += `${type}(${args+unit}) ` + } else { + styles.styles[type] = `${args}` + } + this.currentStepAnimates[this.next] = styles + } + _animateRun(styles = {}, config = {}) { + let ref = this.$.$refs['ani'].ref + if (!ref) return + return new Promise((resolve, reject) => { + nvueAnimation.transition(ref, { + styles, + ...config + }, res => { + resolve() + }) + }) + } + + _nvueNextAnimate(animates, step = 0, fn) { + let obj = animates[step] + if (obj) { + let { + styles, + config + } = obj + this._animateRun(styles, config).then(() => { + step += 1 + this._nvueNextAnimate(animates, step, fn) + }) + } else { + this.currentStepAnimates = {} + typeof fn === 'function' && fn() + this.isEnd = true + } + } + + step(config = {}) { + // #ifndef APP-NVUE + this.animation.step(config) + // #endif + // #ifdef APP-NVUE + this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config) + this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin + this.next++ + // #endif + return this + } + + run(fn) { + // #ifndef APP-NVUE + this.$.animationData = this.animation.export() + this.$.timer = setTimeout(() => { + typeof fn === 'function' && fn() + }, this.$.durationTime) + // #endif + // #ifdef APP-NVUE + this.isEnd = false + let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref + if(!ref) return + this._nvueNextAnimate(this.currentStepAnimates, 0, fn) + this.next = 0 + // #endif + } +} + + +const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d', + 'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY', + 'translateZ' +] +const animateTypes2 = ['opacity', 'backgroundColor'] +const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom'] +animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => { + MPAnimation.prototype[type] = function(...args) { + // #ifndef APP-NVUE + this.animation[type](...args) + // #endif + // #ifdef APP-NVUE + this._nvuePushAnimates(type, args) + // #endif + return this + } +}) + +export function createAnimation(option, _this) { + if(!_this) return + clearTimeout(_this.timer) + return new MPAnimation(option, _this) +} diff --git a/uni_modules/uni-transition/components/uni-transition/uni-transition.vue b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue new file mode 100644 index 0000000..7677553 --- /dev/null +++ b/uni_modules/uni-transition/components/uni-transition/uni-transition.vue @@ -0,0 +1,292 @@ + + + + + diff --git a/uni_modules/uni-transition/package.json b/uni_modules/uni-transition/package.json new file mode 100644 index 0000000..0542c52 --- /dev/null +++ b/uni_modules/uni-transition/package.json @@ -0,0 +1,112 @@ +{ + "id": "uni-transition", + "displayName": "uni-transition 过渡动画", + "version": "1.3.6", + "description": "元素的简单过渡动画", + "keywords": [ + "uni-ui", + "uniui", + "动画", + "过渡", + "过渡动画" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "", + "uni-app": "^4.12", + "uni-app-x": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [ + "uni-scss" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "x", + "aliyun": "x", + "alipay": "x" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "√", + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": { + }, + "alipay": { + }, + "toutiao": { + }, + "baidu": { + }, + "kuaishou": { + }, + "jd": { + }, + "harmony": "-", + "qq": "√", + "lark": "-" + }, + "quickapp": { + "huawei": "√", + "union": "√" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": "-", + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-transition/readme.md b/uni_modules/uni-transition/readme.md new file mode 100644 index 0000000..2f8a77e --- /dev/null +++ b/uni_modules/uni-transition/readme.md @@ -0,0 +1,11 @@ + + +## Transition 过渡动画 +> **组件名:uni-transition** +> 代码块: `uTransition` + + +元素过渡动画 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-transition) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/utils/actions.js b/utils/actions.js new file mode 100644 index 0000000..e96bbca --- /dev/null +++ b/utils/actions.js @@ -0,0 +1,9 @@ +const actions = [ + { key: 1, 'name': '刷卡开门' }, + { key: 2, 'name': '内镜存入' }, + { key: 3, 'name': '内镜取出' }, +] + +export default { + actions, +} \ No newline at end of file diff --git a/utils/beeper.js b/utils/beeper.js new file mode 100644 index 0000000..699d896 --- /dev/null +++ b/utils/beeper.js @@ -0,0 +1,56 @@ +// 蜂鸣音效管理器 +class Beeper { + + audioContext = null; + // 初始化音频上下文 + initAudioContext() { + if (!this.audioContext) { + this.audioContext = uni.createInnerAudioContext(); + this.audioContext.autoplay = false; + this.audioContext.loop = true; + this.audioContext.src = '/static/beep_01.mp3'; + } + return this.audioContext; + } + + // 播放蜂鸣声 + play() { + if (this.audioContext) { + try { + this.audioContext.pause(); + this.audioContext.play(); + } catch (e) { + // 忽略播放失败的错误 + console.log('播放失败:', e); + } + } else{ + // 创建AudioContext实例 + let audioContext = this.initAudioContext(); + audioContext.play(); + } + } + + // 停止蜂鸣声 + stop() { + if (this.audioContext) { + console.log('停止播放'); + this.audioContext.pause(); + } + } +} + +// 创建全局实例 +const beeper = new Beeper(); + +// 导出函数 +export default { + + play() { + return beeper.play(); + }, + // 停止播放 + stop() { + return beeper.stop(); + }, + +}; \ No newline at end of file diff --git a/utils/cmd.js b/utils/cmd.js new file mode 100644 index 0000000..3d62b46 --- /dev/null +++ b/utils/cmd.js @@ -0,0 +1,231 @@ + +// 接收数据 +// 压差站号:01,温湿度站号:02,门控制站号:03 +// 压差 01 03 02 12 34 B5 33 +// 温湿度 01 03 04 02 98 00 BC 7B D5 +// IC卡 20 01 00 08 04 00 00 00 0e 26 fe ab 8f 03 +// ID卡 20 01 00 05 49 00 b5 6a b5 d8 03 +// 卡离开 20 01 00 01 02 fd 03 +// 门控制指令(中盛4路数字IO模块,功能码06): +// 左门开门: 03 06 00 00 00 01 49 E8 +// 左门关门: 03 06 00 00 00 00 88 28 +// 右门开门: 03 06 00 01 00 01 18 28 +// 右门关门: 03 06 00 01 00 00 D9 E8 + +// 卡片放入和离开 起始位20, 所有卡片通过同一通道读取,通过数据库比对判断类型 +// let RS232 = getApp().globalData.RS232 +import store from '@/store/index.js' + +export default { + // 开左门指令 (通过RS485站号03) + // 中盛4路数字IO模块,功能码06(写单个保持寄存器) + LeftDoor: async (status) => { + // 左门开门: 03 06 00 00 00 01 49 E8 + // 左门关门: 03 06 00 00 00 00 88 28 + let cmd = status ? '03060000000149E8' : '0306000000008828' + store.state.relay.leftDoor = status + // door状态 = leftDoor OR rightDoor (任一门打开则door为true) + store.state.relay.door = store.state.relay.leftDoor || store.state.relay.rightDoor + let RS485 = getApp().globalData.RS485 + await RS485.sendDataString(cmd) + + }, + + // 开右门指令 (通过RS485站号03) + // 中盛4路数字IO模块,功能码06(写单个保持寄存器) + RightDoor: async (status) => { + // 右门开门: 03 06 00 01 00 01 18 28 + // 右门关门: 03 06 00 01 00 00 D9 E8 + let cmd = status ? '0306000100011828' : '030600010000D9E8' + store.state.relay.rightDoor = status + // door状态 = leftDoor OR rightDoor (任一门打开则door为true) + store.state.relay.door = store.state.relay.leftDoor || store.state.relay.rightDoor + let RS485 = getApp().globalData.RS485 + await RS485.sendDataString(cmd) + }, + + // 开门关门控制 01 + // Door: async (status) => { + // let op = status ? '01' : '00' + // let cmd = '5AA5EE01' + op + // store.state.relay.door = status + // let RS232 = getApp().globalData.RS232 + // await RS232.sendDataString(cmd); + // }, + // 开风机指令 02 + Wind: async (status) => { + let op = status ? '01' : '00' + let cmd = '5AA5EE02' + op + store.state.relay.wind = status + let RS232 = getApp().globalData.RS232 + await RS232.sendDataString(cmd); + }, + // 开灯指令 03 + Light: async (status) => { + let op = status ? '01' : '00' + let cmd = '5AA5EE03' + op + store.state.relay.light = status + let RS232 = getApp().globalData.RS232 + await RS232.sendDataString(cmd); + }, + // 开真空指令 04 + Vacuum: async (status) => { + let op = status ? '01' : '00' + let cmd = '5AA5EE04' + op + store.state.relay.vacuum = status + let RS232 = getApp().globalData.RS232 + await RS232.sendDataString(cmd); + }, + // 开关消毒指令 05 + Disinfect: async (status) => { + let op = status ? '01' : '00' + let cmd = '5AA5EE05' + op + store.state.relay.disinfect = status + let RS232 = getApp().globalData.RS232 + await RS232.sendDataString(cmd); + }, + // 获取温湿度 + getTemp: () => { + let RS485 = getApp().globalData.RS485 + let cmd = '020300000002C438'; + RS485.sendDataString(cmd); + }, + + // 获取压差指令 + getPressure: () => { + let RS485 = getApp().globalData.RS485 + let cmd = '01030001000295CB' + RS485.sendDataString(cmd); + }, + + // 解析门卡数据,返回卡号 + parse232dData: (hexString) => { + // IC卡 20 01 00 08 04 00 00 00 0e 26 fe ab 8f 03 + // ID卡 20 01 00 05 49 00 b5 6a b5 d8 03 + // 卡离开 20 01 00 01 02 fd 03 + // 01 地址, 04 00 卡类型,0e 26 fe ab 卡号,8f 校验 03固定值 + // 人员卡地址号0,卡号4个字节,倒数4个字节,倒数一位03固定值,倒数二位校验 + // 内镜卡地址号1-16,卡号4个字节,倒数4个字节,倒数一位03固定值,倒数二位校验 + // 卡离开8位,卡进入11位和14位 + + // 移除空格和换行符 + const hexStr = hexString.replace(/\s+/g, ''); + + // 验证输入 + if (hexStr.length === 0) { + throw new Error('请输入Modbus十六进制数据'); + } + + if (hexStr.length % 2 !== 0) { + throw new Error('请输入有效的Modbus十六进制数据'); + } + + // 解析后的数据对象 + let data = {}; + // 刷卡数据 起始字节20,第二字节站号,结束字节03 + if (hexStr.substr(0, 2) == '20' && hexStr.substr(hexStr.length - 2, 2) == '03') { + // 卡数据 + let hexNum = hexStr.substr(hexStr.length - 12, 8) + // 第二位是地址 + let addHex = hexStr.substr(2, 2) + // 转换成10进制地址号 + let address = parseInt(addHex, 16) + + // 解析后的数据 { address: 0, number: 12345678, cardType: 'ic', action: 'enter', type: 'person' } + data.address = address + if (hexStr.length == 28) { + // 14字节是IC卡号 + let icNo = parseInt(hexNum, 16) + data.number = icNo + data.cardType = 'ic' + data.action = 'enter' + } + if (hexStr.length == 22) { + // 11字节是ID卡号 + let idNo = parseInt(hexNum, 16) + data.number = idNo + data.cardType = 'id' + data.action = 'enter' + } + if (hexStr.length == 14) { + // 7字节是卡离开 + data.action = 'leave' + } + if (address == 0) { + // 人员卡 + data.type = 'person' + } + if (address >= 1 && address <= 16) { + // 内镜卡 + data.type = 'internal' + } + } + // 关门上报指令 + // if (hexStr.toUpperCase() == '5AA50000000000FF') { + // // 开门数据 8个字节 + // data.action = 'door' + // } + return data + }, + parse485Data: (hexString) => { + // 移除空格和换行符 + const hexStr = hexString.replace(/\s+/g, ''); + // 压差站号:01,温湿度站号:02 + let addHex = hexStr.substr(0, 2) + let data = {} + if (hexStr.length == 14 || hexStr.length == 18) { + if (addHex == '01') { + let pressure = parseInt(hexStr.substr(6, 4), 16); + data.pressure = pressure / 10 + } + if (addHex == '02') { + let humi = parseInt(hexStr.substr(6, 4), 16); + let temp = parseInt(hexStr.substr(10, 4), 16); + // 温湿度上报数据异常处理,取正常温湿度范围内数据 + temp = (temp / 10).toFixed(1) + if (temp >= 0 && temp < 100) { + data.temp = temp + } + humi = (humi / 10).toFixed(1) + if (humi >= 0 && humi < 100) { + data.humi = humi + } + } + + if (addHex == '03') { + // 中盛4路数字IO控制器, 站号:03 + // 左门开门: 03 06 00 01 00 01 18 28 + // 左门关门: 03 06 00 01 00 00 D9 E8 + // 03040200010130 + // 右门开门: 03 06 00 00 00 01 49 E8 + // 右门关门: 03 06 00 00 00 00 88 28 + // 03040200024131 + + // 关门状态上报(功能码04,读输入寄存器): + + // DI状态变化上报,解析左右门触点触发 + + let funcHex = hexStr.substr(8, 2); + if (funcHex == '01') { + // 左门关 + data.action = 'LeftDoor' + data.status = 'closed' + } + if (funcHex == '02') { + // 右门关 + data.action = 'RightDoor' + data.status = 'closed' + } + if (funcHex == '03') { + // 2个门关 + data.action = 'door' + data.status = 'closed' + } + + // console.log('parse485Data:',hexStr, data) + } + } + + return data + }, +} \ No newline at end of file diff --git a/utils/common.js b/utils/common.js new file mode 100644 index 0000000..0a1577a --- /dev/null +++ b/utils/common.js @@ -0,0 +1,91 @@ + +export const formatDateTime = (date = new Date()) => { + // 确保传入的是 Date 对象 + if (!(date instanceof Date)) { + date = new Date(date); + } + + // 提取日期时间各部分 + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + const milliseconds = String(date.getMilliseconds()).padStart(3, '0'); + const timezoneOffset = -date.getTimezoneOffset(); + const timezoneHours = String(Math.floor(Math.abs(timezoneOffset) / 60)).padStart(2, '0'); + const timezoneMinutes = String(Math.abs(timezoneOffset) % 60).padStart(2, '0'); + const timezoneSign = timezoneOffset >= 0 ? '+' : '-'; + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +} + +export const getTimeDifference = (time1, time2) => { + // 将时间字符串转换为 Date 对象 + const date1 = new Date(time1); + const date2 = new Date(time2); + + // 计算时间差(毫秒) + const diffMs = Math.abs(date2 - date1); + + // 转换为分钟 + const diffMinutes = Math.floor(diffMs / (1000 * 60)); + + // 计算小时和分钟 + const hours = Math.floor(diffMinutes / 60); + const minutes = diffMinutes % 60; + + // 确定时间差的方向 + const direction = date2 > date1 ? "之后" : "之前"; + + return { + hours, + minutes, + totalMinutes: diffMinutes, + direction + }; +} + +/** + * 比较两个时间字符串(格式:HH:MM) + * @param {string} time1 - 第一个时间字符串,如 "14:00" + * @param {string} time2 - 第二个时间字符串,如 "15:00" + * @returns {number} + * -1: time1 在 time2 之前 + * 0: time1 等于 time2 + * 1: time1 在 time2 之后 + * @throws {Error} 如果时间格式无效 + */ +export function compareTimes(time1, time2) { + // 验证时间格式 + const timeRegex = /^([01]?[0-9]|2[0-3]):([0-5][0-9])$/; + + if (!timeRegex.test(time1) || !timeRegex.test(time2)) { + throw new Error('时间格式无效,请使用 HH:MM 格式(24小时制)'); + } + + // 将时间字符串转换为分钟数进行比较 + const timeToMinutes = (time) => { + const [hours, minutes] = time.split(':').map(Number); + return hours * 60 + minutes; + }; + + const minutes1 = timeToMinutes(time1); + const minutes2 = timeToMinutes(time2); + + if (minutes1 < minutes2) return 1; + if (minutes1 > minutes2) return -1; + return 0; +} + + +// 数字转16进制字符串 +export const numberToHex = (number) => { + return (number & 0xFF).toString(16).padStart(2, '0') +} + +// 延迟执行 +export const delay = (ms) =>{ + return new Promise(resolve => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/utils/request/core/request.js b/utils/request/core/request.js new file mode 100644 index 0000000..ed81b7f --- /dev/null +++ b/utils/request/core/request.js @@ -0,0 +1,143 @@ +import { + mergeConfig, + dispatchRequest, + jsonpRequest +} from "./utils" + +export default class request { + + constructor(options) { + // 请求公共地址 + this.baseUrl = options.baseUrl || ""; + // 公共文件上传请求地址 + this.fileUrl = options.fileUrl || ""; + // 超时时间 + this.timeout = options.timeout || 6000; + // 服务器上传图片默认url + this.defaultUploadUrl = options.defaultUploadUrl || ""; + // 默认请求头 + this.header = options.header || {}; + // 默认配置 + this.config = options.config || { + isPrompt: true, + load: true, + isFactory: true, + resend: 0 + }; + } + + // post请求 + post(url = '', data = {}, options = {}) { + return this.request({ + method: "POST", + data: data, + url: url, + ...options + }); + } + + // get请求 + get(url = '', data = {}, options = {}) { + return this.request({ + method: "GET", + data: data, + url: url, + ...options + }); + } + + // put请求 + put(url = '', data = {}, options = {}) { + return this.request({ + method: "PUT", + data: data, + url: url, + ...options + }); + } + + // delete请求 + delete(url = '', data = {}, options = {}) { + return this.request({ + method: "DELETE", + data: data, + url: url, + ...options + }); + } + + // jsonp请求(只限于H5使用) + jsonp(url = '', data = {}, options = {}) { + return this.request({ + method: "JSONP", + data: data, + url: url, + ...options + }); + } + + // 接口请求方法 + async request(data) { + // 请求数据 + let requestInfo, + // 是否运行过请求开始钩子 + runRequestStart = false; + try { + if (!data.url) { + throw { + errMsg: "【request】缺失数据url", + statusCode: 0 + } + } + // 数据合并 + requestInfo = mergeConfig(this, data); + // 代表之前运行到这里 + runRequestStart = true; + // 请求前回调 + if (this.requestStart) { + let requestStart = this.requestStart(requestInfo); + if (typeof requestStart == "object") { + let changekeys = ["data", "header", "isPrompt", "load", "isFactory"]; + changekeys.forEach(key => { + requestInfo[key] = requestStart[key]; + }); + } else { + throw { + errMsg: "【request】请求开始拦截器未通过", + statusCode: 0, + data: requestInfo.data, + method: requestInfo.method, + header: requestInfo.header, + url: requestInfo.url, + } + } + } + let requestResult = {}; + if (requestInfo.method == "JSONP") { + requestResult = await jsonpRequest(requestInfo); + } else { + requestResult = await dispatchRequest(requestInfo); + } + // 是否用外部的数据处理方法 + if (requestInfo.isFactory && this.dataFactory) { + // 数据处理 + let result = await this.dataFactory({ + ...requestInfo, + response: requestResult + }); + return Promise.resolve(result); + } else { + return Promise.resolve(requestResult); + } + } catch (err) { + this.requestError && this.requestError(err); + return Promise.reject(err); + } finally { + // 如果请求开始未运行到,请求结束也不运行 + if (runRequestStart) { + this.requestEnd && this.requestEnd(requestInfo); + } + } + } + +} diff --git a/utils/request/core/utils.js b/utils/request/core/utils.js new file mode 100644 index 0000000..ee412c5 --- /dev/null +++ b/utils/request/core/utils.js @@ -0,0 +1,102 @@ +// 获取合并的数据 +export const mergeConfig = (_this, options) => { + //判断url是不是链接 + let urlType = /^(http|https):\/\//.test(options.url); + let config = Object.assign({ + timeout: _this.timeout + }, _this.config, options); + if (options.method == "FILE") { + config.url = urlType ? options.url : _this.fileUrl + options.url; + } else { + config.url = urlType ? options.url : _this.baseUrl + options.url; + } + //请求头 + if (options.header) { + config.header = Object.assign({}, _this.header, options.header); + } else { + config.header = Object.assign({}, _this.header); + } + return config; +} + +// 请求 +export const dispatchRequest = (requestInfo) => { + return new Promise((resolve, reject) => { + let requestAbort = true; + let requestData = { + url: requestInfo.url, + header: requestInfo.header, //加入请求头 + success: (res) => { + requestAbort = false; + resolve(res); + }, + fail: (err) => { + requestAbort = false; + if (err.errMsg == "request:fail abort") { + reject({ + errMsg: "请求超时,请重新尝试", + statusCode: 0, + }); + } else { + reject(err); + } + } + }; + //请求类型 + if (requestInfo.method) { + requestData.method = requestInfo.method; + } + if (requestInfo.data) { + requestData.data = requestInfo.data; + } + // #ifdef MP-WEIXIN || MP-ALIPAY + if (requestInfo.timeout) { + requestData.timeout = requestInfo.timeout; + } + // #endif + if (requestInfo.dataType) { + requestData.dataType = requestInfo.dataType; + } + // #ifndef APP-PLUS || MP-ALIPAY + if (requestInfo.responseType) { + requestData.responseType = requestInfo.responseType; + } + // #endif + // #ifdef H5 + if (requestInfo.withCredentials) { + requestData.withCredentials = requestInfo.withCredentials; + } + // #endif + let requestTask = uni.request(requestData); + setTimeout(() => { + if (requestAbort) { + requestTask.abort(); + } + }, requestInfo.timeout) + }) +} +// jsonp请求 +export const jsonpRequest = (requestInfo) => { + return new Promise((resolve, reject) => { + let dataStr = ''; + Object.keys(requestInfo.data).forEach(key => { + dataStr += key + '=' + requestInfo.data[key] + '&'; + }); + //匹配最后一个&并去除 + if (dataStr !== '') { + dataStr = dataStr.substr(0, dataStr.lastIndexOf('&')); + } + requestInfo.url = requestInfo.url + '?' + dataStr; + let callbackName = "callback" + Math.ceil(Math.random() * 1000000); + // #ifdef H5 + window[callbackName] = (data) => { + resolve(data); + } + let script = document.createElement("script"); + script.src = requestInfo.url + "&callback=" + callbackName; + document.head.appendChild(script); + // 及时删除,防止加载过多的JS + document.head.removeChild(script); + // #endif + }); +} diff --git a/utils/request/index.js b/utils/request/index.js new file mode 100644 index 0000000..6d50778 --- /dev/null +++ b/utils/request/index.js @@ -0,0 +1,182 @@ +/** + * request插件地址:https://ext.dcloud.net.cn/plugin?id=822 + */ +import store from '@/store' +import request from './request' + +// 后端api地址 +// const apiUrl = 'http://' + store.getters.apiUrl +const apiUrl = 'http://ectms.dev.opmonitor.com' + +// 可以new多个request来支持多个域名请求 +const $http = new request({ + // 接口请求地址 + baseUrl: apiUrl, + // 服务器本地上传文件地址 + fileUrl: apiUrl, + // 服务器上传图片默认url + defaultUploadUrl: 'upload/image', + // 设置请求头(如果使用报错跨域问题,可能是content-type请求类型和后台那边设置的不一致) + header: { + 'content-type': 'application/json;charset=utf-8' + }, + // 请求超时时间, 单位ms(默认15000) + timeout: 15000, + // 默认配置(可不写) + config: { + // 是否自动提示错误 + isPrompt: true, + // 是否显示加载动画 + load: true, + // 是否使用数据工厂 + isFactory: true + } +}) + +// 当前接口请求数 +let requestNum = 0 +// 请求开始拦截器 +$http.requestStart = options => { + if (options.load) { + if (requestNum <= 0) { + // 打开加载动画 + uni.showLoading({ + title: '加载中', + mask: true + }) + } + requestNum += 1 + } + // 图片上传大小限制 + if (options.method == "FILE" && options.maxSize) { + // 文件最大字节: options.maxSize 可以在调用方法的时候加入参数 + const maxSize = options.maxSize + for (let item of options.files) { + if (item.size > maxSize) { + setTimeout(() => { + uni.showToast({ + title: "图片过大,请重新上传", + icon: "none" + }) + }, 10) + return false + } + } + } + // 请求前加入当前终端 + // options.header['platform'] = store.getters.platform + // 请求前加入Token + // options.header['Access-Token'] = store.getters.token + // return false 表示请求拦截,不会继续请求 + return options +} + +// 请求结束 +$http.requestEnd = options => { + // 判断当前接口是否需要加载动画 + if (options.load) { + requestNum = requestNum - 1 + if (requestNum <= 0) { + uni.hideLoading() + } + } +} + +// 当前是否显示modal +let loginModal = false + +// 所有接口数据处理(可在接口里设置不调用此方法) +// 此方法需要开发者根据各自的接口返回类型修改,以下只是模板 +$http.dataFactory = async res => { + console.log("接口请求数据", { + url: res.url, + resolve: res.response, + header: res.header, + data: res.data, + method: res.method, + }) + + if (!res.response.statusCode || res.response.statusCode != 200) { + // 返回错误的结果(catch接受数据) + return Promise.reject({ + statusCode: res.response.statusCode, + errMsg: 'http状态码错误' + }) + } + + let httpData = res.response.data + return Promise.resolve(httpData) + // if (typeof httpData == "string") { + // try { + // httpData = JSON.parse(httpData) + // } catch (error) { + // // httpData = false + // } + // } + // if (httpData === false || typeof httpData !== 'object') { + // // 返回错误的结果(catch接受数据) + // return Promise.reject({ + // statusCode: res.response.statusCode, + // errMsg: "请检查api地址能否访问正常" + // }) + // } + + /*********以下只是模板(及共参考),需要开发者根据各自的接口返回类型修改*********/ + + // 判断数据是否请求成功 + // result.status [ 200正常 500有错误 401未登录 403没有权限访问 ] + // if (httpData.status == 200) { + // // 返回正确的结果(then接受数据) + // return Promise.resolve(httpData) + // } + + // 其他错误提示 + if (httpData.status == 500) { + if (res.isPrompt) { + setTimeout(() => { + uni.showToast({ + title: httpData.message, + icon: "none", + duration: 2500 + }) + }, 10) + } + // 返回错误的结果(catch接受数据) + return Promise.reject({ + statusCode: 0, + errMsg: httpData.message, + result: httpData + }) + } + + /*********以上只是模板(及共参考),需要开发者根据各自的接口返回类型修改*********/ +} + +// 错误回调 +$http.requestError = e => { + if (e.statusCode === 0) { + throw e + } else { + setTimeout(() => showRequestError(e), 10) + } +} + +// 显示请求错误信息 +const showRequestError = (e) => { + let errMsg = `网络请求出错:${e.errMsg}` + // #ifdef MP-WEIXIN + if (e.errMsg === 'request:fail url not in domain list') { + errMsg = '当前API域名未添加到微信小程序授权名单 ' + e.errMsg + } + // #endif + if (e.errMsg === 'request:fail') { + errMsg = '网络请求错误:请检查api地址能否访问正常' + } + uni.showToast({ + title: errMsg, + icon: "none", + duration: 3500 + }) +} + +export default $http \ No newline at end of file diff --git a/utils/request/request.js b/utils/request/request.js new file mode 100644 index 0000000..16d79d4 --- /dev/null +++ b/utils/request/request.js @@ -0,0 +1,7 @@ +/***************纯粹的数据请求(如果使用这种可以删除掉fileUpload.js)******************/ +// import request from "./core/request.js"; +// export default request; + +/********数据请求同时继承了文件上传(包括七牛云上传)************/ +import upload from "./upload/upload" +export default upload diff --git a/utils/request/request.md b/utils/request/request.md new file mode 100644 index 0000000..14cd8e1 --- /dev/null +++ b/utils/request/request.md @@ -0,0 +1,471 @@ +# request请求、配置简单、批量上传图片、视频、超强适应性(支持多域名请求) +1. 配置简单、源码清晰注释多、适用于一项目多域名请求、第三方请求、七牛云图片上传、本地服务器图片上传等等 +2. 支持请求`get`、`post`、`put`、`delete` +3. 自动显示请求加载动画(可单个接口关闭) +4. 全局`api`数据处理函数,只回调请求正确的数据(可单个接口关闭) +5. 未登录或登录失效自动拦截并调用登录方法(可单个接口关闭) +6. 全局自动提示接口抛出的错误信息(可单个接口关闭) +7. 支持 Promise +8. 支持拦截器 +9. 支持七牛云文件(图片、视频)批量上传 +10. 支持本地服务器文件(图片、视频)批量上传 +11. 支持上传文件拦截过滤 +12. 支持上传文件进度监听 +13. 支持上传文件单张成功回调 + +| `QQ交流群(607391225)` | `微信交流群(加我好友备注"进群")` | +| ----------------------------|--------------------------- | +|![QQ交流群](http://qn.kemean.cn//upload/202004/14/15868301778472k7oubi6.png)|![微信交流群](https://qn.kemean.cn/upload/202010/13/weiXin_group_code.jpg)| +| QQ群号:607391225 |微信号:zhou0612wei| + +### [点击跳转-插件示例](https://ext.dcloud.net.cn/plugin?id=2009) +### [点击跳转-5年的web前端开源的uni-app快速开发模板-下载看文档](https://ext.dcloud.net.cn/plugin?id=2009) + +### 常见问题 +1.接口请求成功了,没有返回数据或者数据是走的catch回调 + +答:`requestConfig.js` 请求配置文件里面,有一个`$http.dataFactory`方法,里面写的只是参考示例,`此方法需要开发者根据各自的接口返回类型修改` + +2.官方的方法有数据,本插件方法请求报错跨域问题 + +答:`requestConfig.js` 请求配置文件里面,`header`请求头设置的`content-type`请求类型需求和后台保持一致 + +3.登录后用户`token`怎么设置? + +答:`requestConfig.js` 请求配置文件里面,`$http.requestStart`请求开始拦截器里面设置 + +4.怎么判断上传的文件(图片)太大?怎么过滤掉太大的文件(图片)? + +答:`requestConfig.js` 请求配置文件里面,`$http.requestStart`请求开始拦截器里面设置 + +5.接口请求成功了,一直提示“网络错误,请检查一下网络”? + +答:`requestConfig.js` 请求配置文件里面,有一个`$http.dataFactory`方法,里面写的只是参考示例,`此方法需要开发者根据各自的接口返回类型修改` + +### 本次更新注意事项 +1. 所有的headers都改成了header(和官方统一) +2. 七牛云的获取token等信息提取到了`requestConfig.js`文件,参考如下 + +``` +// 添加获取七牛云token的方法 +$http.getQnToken = function(callback){ + //该地址需要开发者自行配置(每个后台的接口风格都不一样) + $http.get("api/kemean/aid/qn_upload").then(data => { + /* + *接口返回参数: + *visitPrefix:访问文件的域名 + *token:七牛云上传token + *folderPath:上传的文件夹 + *region: 地区 默认为:SCN + */ + callback({ + visitPrefix: data.visitPrefix, + token: data.token, + folderPath: data.folderPath, + region: "SCN" + }); + }); +} +``` + +### 文件说明 +1. `request => core` 请求方法的目录 +2. `request => core => request.js` 请求方法的class文件 +3. `request => core => utils.js` 请求方法的源码文件 +4. `request => upload` 上传方法的目录 +5. `request => upload => upload.js` 上传方法的class文件 +6. `request => upload => utils.js` 上传方法源码文件 +7. `request => upload => qiniuUploader.js` 七牛云官方上传文件 +8. `request => index.js` 输出方法的文件 +9. `requestConfig.js` 请求配置文件(具体看代码) + +### 在main.js引入并挂在Vue上 +``` +import $http from '@/zhouWei-request/requestConfig'; +Vue.prototype.$http = $http; +``` + +### `requestConfig.js`配置说明(requestConfig.js有配置示例) +``` +import request from "@/plugins/request"; +//可以new多个request来支持多个域名请求 +let $http = new request({ + //接口请求地址 + baseUrl: "https://twin-ui.com/", //示例域名,请自行设计 + //服务器本地上传文件地址 + fileUrl: "https://twin-ui.com/", //示例域名,请自行设计 + // 服务器上传图片默认url + defaultUploadUrl: "api/common/v1/upload_image", + //设置请求头(如果使用报错跨域问题,可能是content-type请求类型和后台那边设置的不一致) + header: { + 'Content-Type': 'application/json;charset=UTF-8' + }, + // 请求超时时间(默认6000) + timeout: 6000, + // 默认配置(可不写) + config: { + // 是否自动提示错误 + isPrompt: true, + // 是否显示加载动画 + load: true, + // 是否使用数据工厂 + isFactory: true, + // ... 可写更多配置 + } +}); + +// 添加获取七牛云token的方法 +$http.getQnToken = function(callback){ + //该地址需要开发者自行配置(每个后台的接口风格都不一样) + $http.get("api/common/v1/qn_upload").then(data => { + /* + *接口返回参数: + *visitPrefix:访问文件的域名 + *token:七牛云上传token + *folderPath:上传的文件夹 + *region: 地区 默认为:SCN + */ + callback({ + visitPrefix: data.visitPrefix, + token: data.token, + folderPath: data.folderPath + }); + }); +} +//当前接口请求数 +let requestNum = 0; +//请求开始拦截器 +$http.requestStart = function(options) { + if (options.load) { + if (requestNum <= 0) { + //打开加载动画 + uni.showLoading({ + title: '加载中', + mask: true + }); + } + requestNum += 1; + } + // 图片上传大小限制 + if (options.method == "FILE" && options.maxSize) { + // 文件最大字节: options.maxSize 可以在调用方法的时候加入参数 + let maxSize = options.maxSize; + for (let item of options.files) { + if (item.size > maxSize) { + setTimeout(() => { + uni.showToast({ + title: "图片过大,请重新上传", + icon: "none" + }); + }, 500); + return false; + } + } + } + //请求前加入token + options.header['token'] = "你的项目登录token"; + return options; // return false 表示请求拦截,不会继续请求 +} +//请求结束 +$http.requestEnd = function(options) { + //判断当前接口是否需要加载动画 + if (options.load) { + requestNum = requestNum - 1; + if (requestNum <= 0) { + uni.hideLoading(); + } + } +} +//所有接口数据处理(可在接口里设置不调用此方法) +//此方法需要开发者根据各自的接口返回类型修改,以下只是模板 +$http.dataFactory = async function(res) { + console.log("接口请求数据", { + url: res.url, + resolve: res.response, + header: res.header, + data: res.data, + method: res.method, + }); + if (res.response.statusCode && res.response.statusCode == 200) { + let httpData = res.response.data; + if (typeof (httpData) == "string") { + httpData = JSON.parse(httpData); + } + //判断数据是否请求成功 + if (httpData.success || httpData.code == 200) { + // ---------重点----------返回正确的结果(then接受数据)------------重点------------ + return Promise.resolve(httpData.data); + } else { + //其他错误提示 + if (res.isPrompt) { // 是否提示 + uni.showToast({ + title: httpData.info || httpData.msg, + icon: "none", + duration: 3000 + }); + } + // --------重点---------返回错误的结果(catch接受数据)------------重点------------ + return Promise.reject({ + statusCode: 0, + errMsg: "【request】" + (httpData.info || httpData.msg) + }); + } + } else { + // 返回错误的结果(catch接受数据) + return Promise.reject({ + statusCode: res.response.statusCode, + errMsg: "【request】数据工厂验证不通过" + }); + } +}; +// 错误回调 +$http.requestError = function (e) { + if (e.statusCode === 0) { + throw e; + } else { + uni.showToast({ + title: "网络错误,请检查一下网络", + icon: "none" + }); + } +} +``` + +### 通用请求方法 +``` +this.$http.request({ + url: 'aid/region', + method: "GET", // POST、GET、PUT、DELETE、JSONP,具体说明查看官方文档 + data: {pid:0}, + timeout: 30000, // 默认 30000 说明:超时时间,单位 ms,具体说明查看官方文档 + dataType: "json", // 默认 json 说明:如果设为 json,会尝试对返回的数据做一次 JSON.parse,具体说明查看官方文档 + responseType: "text", // 默认 text 说明:设置响应的数据类型。合法值:text、arraybuffer,具体说明查看官方文档 + withCredentials: false, // 默认 false 说明:跨域请求时是否携带凭证(cookies),具体说明查看官方文档 + isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示) + load: true,//(默认 true 说明:本接口是否提示加载动画) + header: { //默认 无 说明:请求头 + 'Content-Type': 'application/json' + }, + isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数将失去作用) +}).then(function (response) { + //这里只会在接口是成功状态返回 +}).catch(function (error) { + //这里只会在接口是失败状态返回,不需要去处理错误提示 + console.log(error); +}); +``` + +### get请求 正常写法 +``` +this.$http.get('aid/region',{pid:0}). +then(function (response) { + //这里只会在接口是成功状态返回 +}).catch(function (error) { + //这里只会在接口是失败状态返回,不需要去处理错误提示 + console.log(error); +}); +``` + +### post请求 async写法 +``` +async request(){ + let data = await this.$http.post('aid/region',{pid:0}); + console.log(data); +} +``` + +### 其他功能配置项 +``` +let data = await this.$http.post( + 'http://www.aaa.com/aid/region', //可以直接放链接(将不启用全局定义域名) + { + pid:0 + }, + { + isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示) + load: true,//(默认 true 说明:本接口是否提示加载动画) + header: { //默认 无 说明:请求头 + 'Content-Type': 'application/json' + }, + isFactory: true //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数将失去作用) + } +); +``` + +### `requestConfig.js`可以设置服务器上传图片默认url +``` +//可以new多个request来支持多个域名请求 +let $http = new request({ + //服务器本地上传文件地址 + fileUrl: base.baseUrl, + // 服务器上传图片默认url + defaultUploadUrl: "api/common/v1/upload_image", +}); +``` +``` +// 上传可以不用传递url(使用全局的上传图片url) +this.$http.urlImgUpload({ + name:"后台接受文件key名称", //默认 file + count:"最大选择数",//默认 9 + sizeType:"选择压缩图原图,默认两个都选",//默认 ['original', 'compressed'] + sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera'] + data:"而外参数" //可不填, +}); +// 上传可以不用传递url(使用全局的上传图片url) +this.$http.urlVideoUpload({ + sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera'] + compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false + maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60 + camera: '前置还是后置摄像头', //'front'、'back',默认'back' + name:"后台接受文件key名称", //默认 file + data:"而外参数" //可不填, +}); +// 上传可以不用传递url(使用全局的上传图片url) +this.$http.urlFileUpload({ + files: [], // 必填 临时文件路径 格式: [{path: "图片地址"}] + data:"向服务器传递的参数", //可不填 + name:"后台接受文件key名称", //默认 file +}); +``` + +### 本地服务器图片上传(支持多张上传) +``` +this.$http.urlImgUpload('flie/upload',{ + name:"后台接受文件key名称", //默认 file + count:"最大选择数",//默认 9 + sizeType:"选择压缩图原图,默认两个都选",//默认 ['original', 'compressed'] + sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera'] + data:"而外参数" //可不填, + isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示) + load: true,//(默认 true 说明:本接口是否提示加载动画) + header: { //默认 无 说明:请求头 + 'Content-Type': 'application/json' + }, + isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用) + maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制) + onSelectComplete: res => { + console.log("选择完成返回:",res); + }, + onEachUpdate: res => { + console.log("单张上传成功返回:",res); + }, + onProgressUpdate: res => { + console.log("上传进度返回:",res); + } +}).then(res => { + console.log("全部上传完返回结果:",res); +}); +``` +### 本地服务器视频上传 +``` +this.$http.urlVideoUpload('flie/upload',{ + sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera'] + compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false + maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60 + camera: '前置还是后置摄像头', //'front'、'back',默认'back' + name:"后台接受文件key名称", //默认 file + data:"而外参数" //可不填, + isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示) + load: true,//(默认 true 说明:本接口是否提示加载动画) + header: { //默认 无 说明:请求头 + 'Content-Type': 'application/json' + }, + isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用) + maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制) + onProgressUpdate: res => { + console.log("上传进度返回:",res); + }, + onSelectComplete: res => { + console.log("选择完成返回:",res); + }, +}).then(res => { + console.log("全部上传完返回结果:",res); +}); +``` +### 本地服务器文件上传(支持多张上传) +``` +this.$http.urlFileUpload("flie/upload",{ + files: [], // 必填 临时文件路径 格式: [{path: "图片地址"}] + data:"向服务器传递的参数", //可不填 + name:"后台接受文件key名称", //默认 file + isPrompt: true,//(默认 true 说明:本接口抛出的错误是否提示) + load: true,//(默认 true 说明:本接口是否提示加载动画) + header: { //默认 无 说明:请求头 + 'Content-Type': 'application/json' + }, + isFactory: true, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用) + maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制) + onEachUpdate: res => { + console.log("单张上传成功返回:",res); + }, + onProgressUpdate: res => { + console.log("上传进度返回:",res); + } +}).then(res => { + console.log("全部上传完返回结果:",res); +}); +``` + +### 七牛云图片上传(支持多张上传) +``` +this.$http.qnImgUpload({ + count:"最大选择数", // 默认 9 + sizeType:"选择压缩图原图,默认两个都选", // 默认 ['original', 'compressed'] + sourceType:"选择相机拍照或相册上传 默认两个都选", // 默认 ['album','camera'] + load: true, //(默认 true 说明:本接口是否提示加载动画) + maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制) + onSelectComplete: res => { + console.log("选择完成返回:",res); + }, + onEachUpdate: res => { + console.log("单张上传成功返回:",res); + }, + onProgressUpdate: res => { + console.log("上传进度返回:",res); + } +}).then(res => { + console.log("全部上传完返回结果:",res); +}); +``` +### 七牛云视频上传 +``` +this.$http.qnVideoUpload({ + sourceType:"选择相机拍照或相册上传 默认两个都选",//默认 ['album','camera'] + compressed:"是否压缩所选的视频源文件,默认值为 true,需要压缩",//默认 false + maxDuration: "拍摄视频最长拍摄时间,单位秒。最长支持 60 秒", //默认 60 + camera: '前置还是后置摄像头', //'front'、'back',默认'back' + load: true,//(默认 true 说明:本接口是否提示加载动画) + maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制) + onSelectComplete: res => { + console.log("选择完成返回:",res); + }, + onProgressUpdate: res => { + console.log("上传进度返回:",res); + } +}).then(res => { + console.log("全部上传完返回结果:",res); +}); +``` +### 七牛云文件上传(支持多张上传) +``` +this.$http.qnFileUpload( +{ + files:[], // 必填 临时文件路径 格式: [{path: "图片地址"}] + load: true, //(默认 true 说明:本接口是否提示加载动画) + maxSize: 300000, //(默认 无 说明:上传的文件最大字节数限制,默认不限制) + onEachUpdate: res => { + console.log("单张上传成功返回:",res); + }, + onProgressUpdate: res => { + console.log("上传进度返回:",res); + } +}).then(res => { + console.log("全部上传完返回结果:",res); +}); +``` +### jsonp 跨域请求(只支持H5) +``` +let data = await this.$http.jsonp('http://www.aaa.com/aid/region',{pid:0}, { + isFactory: false, //(默认 true 说明:本接口是否调用公共的数据处理方法,设置false后isPrompt参数奖失去作用) +}); +``` diff --git a/utils/request/upload/qiniuUploader.js b/utils/request/upload/qiniuUploader.js new file mode 100644 index 0000000..9542eb6 --- /dev/null +++ b/utils/request/upload/qiniuUploader.js @@ -0,0 +1,163 @@ + + + var config = { + qiniuRegion: '', + qiniuImageURLPrefix: '', + qiniuUploadToken: '', + qiniuUploadTokenURL: '', + qiniuUploadTokenFunction: null, + qiniuShouldUseQiniuFileName: false + } + + // 在整个程序生命周期中,只需要 init 一次即可 + // 如果需要变更参数,再调用 init 即可 + function init(options) { + config = { + qiniuRegion: '', + qiniuImageURLPrefix: '', + qiniuUploadToken: '', + qiniuUploadTokenURL: '', + qiniuUploadTokenFunction: null, + qiniuShouldUseQiniuFileName: false + }; + updateConfigWithOptions(options); + } + + function updateConfigWithOptions(options) { + if (options.region) { + config.qiniuRegion = options.region; + } else { + console.error('qiniu uploader need your bucket region'); + } + if (options.uptoken) { + config.qiniuUploadToken = options.uptoken; + } else if (options.uptokenURL) { + config.qiniuUploadTokenURL = options.uptokenURL; + } else if (options.uptokenFunc) { + config.qiniuUploadTokenFunction = options.uptokenFunc; + } + if (options.domain) { + config.qiniuImageURLPrefix = options.domain; + } + config.qiniuShouldUseQiniuFileName = options.shouldUseQiniuFileName + } + + function upload(filePath, success, fail, options, progress, cancelTask) { + if (null == filePath) { + console.error('qiniu uploader need filePath to upload'); + return; + } + if (options) { + updateConfigWithOptions(options); + } + if (config.qiniuUploadToken) { + doUpload(filePath, success, fail, options, progress, cancelTask); + } else if (config.qiniuUploadTokenURL) { + getQiniuToken(function () { + doUpload(filePath, success, fail, options, progress, cancelTask); + }); + } else if (config.qiniuUploadTokenFunction) { + config.qiniuUploadToken = config.qiniuUploadTokenFunction(); + if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) { + console.error('qiniu UploadTokenFunction result is null, please check the return value'); + return + } + doUpload(filePath, success, fail, options, progress, cancelTask); + } else { + console.error('qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]'); + return; + } + } + + function doUpload(filePath, success, fail, options, progress, cancelTask) { + if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) { + console.error('qiniu UploadToken is null, please check the init config or networking'); + return + } + var url = uploadURLFromRegionCode(config.qiniuRegion); + var fileName = filePath.split('//')[1]; + if (options && options.key) { + fileName = options.key; + } + var formData = { + 'token': config.qiniuUploadToken + }; + if (!config.qiniuShouldUseQiniuFileName) { + formData['key'] = fileName + } + var uploadTask = wx.uploadFile({ + url: url, + filePath: filePath, + name: 'file', + formData: formData, + success: function (res) { + var dataString = res.data + if (res.data.hasOwnProperty('type') && res.data.type === 'Buffer') { + dataString = String.fromCharCode.apply(null, res.data.data) + } + try { + var dataObject = JSON.parse(dataString); + //do something + var imageUrl = config.qiniuImageURLPrefix + '/' + dataObject.key; + dataObject.imageURL = imageUrl; + if (success) { + success(dataObject); + } + } catch (e) { + console.log('parse JSON failed, origin String is: ' + dataString) + if (fail) { + fail(e); + } + } + }, + fail: function (error) { + console.error(error); + if (fail) { + fail(error); + } + } + }) + + uploadTask.onProgressUpdate((res) => { + progress && progress(res) + }) + + cancelTask && cancelTask(() => { + uploadTask.abort() + }) + } + + function getQiniuToken(callback) { + wx.request({ + url: config.qiniuUploadTokenURL, + success: function (res) { + var token = res.data.uptoken; + if (token && token.length > 0) { + config.qiniuUploadToken = token; + if (callback) { + callback(); + } + } else { + console.error('qiniuUploader cannot get your token, please check the uptokenURL or server') + } + }, + fail: function (error) { + console.error('qiniu UploadToken is null, please check the init config or networking: ' + error); + } + }) + } + + function uploadURLFromRegionCode(code) { + var uploadURL = null; + switch (code) { + case 'ECN': uploadURL = 'https://up.qbox.me'; break; + case 'NCN': uploadURL = 'https://up-z1.qbox.me'; break; + case 'SCN': uploadURL = 'https://up-z2.qbox.me'; break; + case 'NA': uploadURL = 'https://up-na0.qbox.me'; break; + case 'ASG': uploadURL = 'https://up-as0.qbox.me'; break; + default: console.error('please make the region is with one of [ECN, SCN, NCN, NA, ASG]'); + } + return uploadURL; + } + + export { init, upload } diff --git a/utils/request/upload/upload.js b/utils/request/upload/upload.js new file mode 100644 index 0000000..ea3d35d --- /dev/null +++ b/utils/request/upload/upload.js @@ -0,0 +1,203 @@ +import request from "./../core/request.js"; +import { chooseImage, chooseVideo, qiniuUpload, urlUpload } from './utils' +import { + mergeConfig +} from "./../core/utils.js"; +export default class fileUpload extends request { + constructor(props) { + // 调用实现父类的构造函数 + super(props); + } + //七牛云上传图片 + async qnImgUpload(options = {}) { + let files; + try { + files = await chooseImage(options); + // 选择完成回调 + options.onSelectComplete && options.onSelectComplete(files); + } catch (err) { + this.requestError && this.requestError(err); + return Promise.reject(err); + } + if (files) { + return this.qnFileUpload({ + ...options, + files: files + }); + } + } + //七牛云上传视频 + async qnVideoUpload(options = {}) { + let files; + try { + files = await chooseVideo(options); + // 选择完成回调 + options.onSelectComplete && options.onSelectComplete(files); + } catch (err) { + this.requestError && this.requestError(err); + return Promise.reject(err); + } + if (files) { + return this.qnFileUpload({ + ...options, + files: files + }); + } + } + + //七牛云文件上传(支持多张上传) + async qnFileUpload(options = {}) { + let requestInfo; + try { + // 数据合并 + requestInfo = { + ...this.config, + ...options, + header: {}, + method: "FILE" + }; + //请求前回调 + if (this.requestStart) { + let requestStart = this.requestStart(requestInfo); + if (typeof requestStart == "object") { + let changekeys = ["load", "files"]; + changekeys.forEach(key => { + requestInfo[key] = requestStart[key]; + }); + } else { + throw { + errMsg: "【request】请求开始拦截器未通过", + statusCode: 0, + data: requestInfo.data, + method: requestInfo.method, + header: requestInfo.header, + url: requestInfo.url, + } + } + } + let requestResult = await qiniuUpload(requestInfo, this.getQnToken); + return Promise.resolve(requestResult); + } catch (err) { + this.requestError && this.requestError(err); + return Promise.reject(err); + } finally { + this.requestEnd && this.requestEnd(requestInfo); + } + } + //本地服务器图片上传 + async urlImgUpload() { + let options = {}; + if (arguments[0]) { + if (typeof(arguments[0]) == "string") { + options.url = arguments[0]; + } else if (typeof(arguments[0]) == "object") { + options = Object.assign(options, arguments[0]); + } + } + if (arguments[1] && typeof(arguments[1]) == "object") { + options = Object.assign(options, arguments[1]); + } + try { + options.files = await chooseImage(options); + // 选择完成回调 + options.onSelectComplete && options.onSelectComplete(options.files); + } catch (err) { + this.requestError && this.requestError(err); + return Promise.reject(err); + } + if (options.files) { + return this.urlFileUpload(options); + } + } + //本地服务器上传视频 + async urlVideoUpload() { + let options = {}; + if (arguments[0]) { + if (typeof(arguments[0]) == "string") { + options.url = arguments[0]; + } else if (typeof(arguments[0]) == "object") { + options = Object.assign(options, arguments[0]); + } + } + if (arguments[1] && typeof(arguments[1]) == "object") { + options = Object.assign(options, arguments[1]); + } + try { + options.files = await chooseVideo(options); + // 选择完成回调 + options.onSelectComplete && options.onSelectComplete(options.files); + } catch (err) { + this.requestError && this.requestError(err); + return Promise.reject(err); + } + if (options.files) { + return this.urlFileUpload(options); + } + } + //本地服务器文件上传方法 + async urlFileUpload() { + let requestInfo = { + method: "FILE" + }; + if (arguments[0]) { + if (typeof(arguments[0]) == "string") { + requestInfo.url = arguments[0]; + } else if (typeof(arguments[0]) == "object") { + requestInfo = Object.assign(requestInfo, arguments[0]); + } + } + if (arguments[1] && typeof(arguments[1]) == "object") { + requestInfo = Object.assign(requestInfo, arguments[1]); + } + if (!requestInfo.url && this.defaultUploadUrl) { + requestInfo.url = this.defaultUploadUrl; + } + // 请求数据 + // 是否运行过请求开始钩子 + let runRequestStart = false; + try { + if (!requestInfo.url) { + throw { + errMsg: "【request】文件上传缺失数据url", + statusCode: 0, + data: requestInfo.data, + method: requestInfo.method, + header: requestInfo.header, + url: requestInfo.url, + } + } + // 数据合并 + requestInfo = mergeConfig(this, requestInfo); + // 代表之前运行到这里 + runRequestStart = true; + //请求前回调 + if (this.requestStart) { + let requestStart = this.requestStart(requestInfo); + if (typeof requestStart == "object") { + let changekeys = ["data", "header", "isPrompt", "load", "isFactory", "files"]; + changekeys.forEach(key => { + requestInfo[key] = requestStart[key]; + }); + } else { + throw { + errMsg: "【request】请求开始拦截器未通过", + statusCode: 0, + data: requestInfo.data, + method: requestInfo.method, + header: requestInfo.header, + url: requestInfo.url, + } + } + } + let requestResult = await urlUpload(requestInfo, this.dataFactory); + return Promise.resolve(requestResult); + } catch (err) { + this.requestError && this.requestError(err); + return Promise.reject(err); + } finally { + if (runRequestStart) { + this.requestEnd && this.requestEnd(requestInfo); + } + } + } +} diff --git a/utils/request/upload/utils.js b/utils/request/upload/utils.js new file mode 100644 index 0000000..ce5004e --- /dev/null +++ b/utils/request/upload/utils.js @@ -0,0 +1,288 @@ +import * as qiniuUploader from './qiniuUploader' +//七牛云上传文件命名 +export const randomChar = function(l, url = "") { + const x = "0123456789qwertyuioplkjhgfdsazxcvbnm"; + let tmp = ""; + let time = new Date(); + for (let i = 0; i < l; i++) { + tmp += x.charAt(Math.ceil(Math.random() * 100000000) % x.length); + } + return ( + "file/" + + url + + time.getTime() + + tmp + ); +} +//图片选择 +export const chooseImage = function(data) { + return new Promise((resolve, reject) => { + uni.chooseImage({ + count: data.count || 9, //默认9 + sizeType: data.sizeType || ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 + sourceType: data.sourceType || ['album', 'camera'], //从相册选择 + success: function(res) { + resolve(res.tempFiles); + }, + fail: err => { + reject({ + errMsg: err.errMsg, + errCode: err.errCode, + statusCode: 0, + }); + } + }); + }); +} +//视频选择 +export const chooseVideo = function(data) { + return new Promise((resolve, reject) => { + uni.chooseVideo({ + sourceType: data.sourceType || ['album', 'camera'], //从相册选择 + compressed: data.compressed || false, //是否压缩所选的视频源文件,默认值为 true,需要压缩。 + maxDuration: data.maxDuration || 60, //拍摄视频最长拍摄时间,单位秒。最长支持 60 秒。 + camera: data.camera || 'back', //'front'、'back',默认'back' + success: function(res) { + let files = [{ + path: res.tempFilePath + }]; + // #ifdef APP-PLUS || H5 || MP-WEIXIN + files[0].duration = res.duration; + files[0].size = res.size; + files[0].height = res.height; + files[0].width = res.width; + // #endif + // #ifdef H5 + files[0].name = res.name; + // #endif + resolve(files); + }, + fail: err => { + reject({ + errMsg: err.errMsg, + errCode: err.errCode, + statusCode: 0, + }); + } + }); + }); +} +// 七牛云上传 +export const qiniuUpload = function(requestInfo, getQnToken) { + return new Promise((resolve, reject) => { + if (Array.isArray(requestInfo.files)) { + let len = requestInfo.files.length; + let fileList = new Array; + if (getQnToken) { + getQnToken(qnRes => { + /* + *接口返回参数: + *visitPrefix:访问文件的域名 + *token:七牛云上传token + *folderPath:上传的文件夹 + *region: 地区 默认为:SCN + */ + let prefixLen = qnRes.visitPrefix.length; + if(qnRes.visitPrefix.charAt(prefixLen - 1) == '/'){ + qnRes.visitPrefix = qnRes.visitPrefix.substring(0, prefixLen - 1) + } + uploadFile(0); + + function uploadFile(i) { + let item = requestInfo.files[i]; + let updateUrl = randomChar(10, qnRes.folderPath); + let fileData = { + fileIndex: i, + files: requestInfo.files, + ...item + }; + if (item.name) { + fileData.name = item.name; + let nameArr = item.name.split("."); + updateUrl += "." + nameArr[nameArr.length - 1]; + } + // 交给七牛上传 + qiniuUploader.upload(item.path || item, (res) => { + fileData.url = res.imageURL; + requestInfo.onEachUpdate && requestInfo.onEachUpdate({ + url: res.imageURL, + ...fileData + }); + fileList.push(res.imageURL); + if (len - 1 > i) { + uploadFile(i + 1); + } else { + resolve(fileList); + } + }, (error) => { + reject(error); + }, { + region: qnRes.region || 'SCN', //地区 + domain: qnRes.visitPrefix, // bucket 域名,下载资源时用到。 + key: updateUrl, + uptoken: qnRes.token, // 由其他程序生成七牛 uptoken + uptokenURL: 'UpTokenURL.com/uptoken' // 上传地址 + }, (res) => { + console.log(requestInfo); + requestInfo.onProgressUpdate && requestInfo.onProgressUpdate(Object.assign({}, fileData, res)); + // console.log('上传进度', res.progress) + // console.log('已经上传的数据长度', res.totalBytesSent) + // console.log('预期需要上传的数据总长度', res.totalBytesExpectedToSend) + }); + } + }); + } else { + reject({ + errMsg: "请添加七牛云回调方法:getQnToken", + statusCode: 0 + }); + } + } else { + reject({ + errMsg: "files 必须是数组类型", + statusCode: 0 + }); + }; + }); +} +// 服务器URL上传 +export const urlUpload = function(requestInfo, dataFactory) { + return new Promise((resolve, reject) => { + // 本地文件上传去掉默认Content-Type + if (requestInfo.header['Content-Type']) { + delete requestInfo.header['Content-Type']; + } + // 本地文件上传去掉默认Content-Type + if (requestInfo.header['content-type']) { + delete requestInfo.header['content-type']; + } + if (Array.isArray(requestInfo.files)) { + // // #ifdef APP-PLUS || H5 + // let files = []; + // let fileData = { + // files: requestInfo.files, + // name: requestInfo.name || "file" + // }; + // requestInfo.files.forEach(item => { + // let fileInfo = { + // name: requestInfo.name || "file", + // }; + // if(item.path){ + // fileInfo.uri = item.path; + // } else { + // fileInfo.file = item; + // } + // files.push(fileInfo); + // }); + // let config = { + // url: requestInfo.url, + // files: files, + // header: requestInfo.header, //加入请求头 + // success: (response) => { + // //是否用外部的数据处理方法 + // if (requestInfo.isFactory && dataFactory) { + // //数据处理 + // dataFactory({ + // ...requestInfo, + // response: response, + // }).then(data => { + // requestInfo.onEachUpdate && requestInfo.onEachUpdate({ + // data: data, + // ...fileData + // }); + // resolve(data); + // },err => { + // reject(err); + // }); + // } else { + // requestInfo.onEachUpdate && requestInfo.onEachUpdate({ + // data: response, + // ...fileData + // }); + // resolve(response); + // } + // }, + // fail: (err) => { + // reject(err); + // } + // }; + // if (requestInfo.data) { + // config.formData = requestInfo.data; + // } + // const uploadTask = uni.uploadFile(config); + // uploadTask.onProgressUpdate(res => { + // requestInfo.onProgressUpdate && requestInfo.onProgressUpdate(Object.assign({}, fileData, res)); + // }); + // // #endif + // #-ifdef MP + const len = requestInfo.files.length - 1; + let fileList = new Array; + fileUpload(0); + + function fileUpload(i) { + let item = requestInfo.files[i]; + let fileData = { + fileIndex: i, + files: requestInfo.files, + ...item + }; + let config = { + url: requestInfo.url, + filePath: item.path, + header: requestInfo.header, //加入请求头 + name: requestInfo.name || "file", + success: (response) => { + //是否用外部的数据处理方法 + if (requestInfo.isFactory && dataFactory) { + //数据处理 + dataFactory({ + ...requestInfo, + response: response, + }).then(data => { + fileList.push(data); + requestInfo.onEachUpdate && requestInfo.onEachUpdate({ + data: data, + ...fileData + }); + if (len <= i) { + resolve(fileList); + } else { + fileUpload(i + 1); + } + },err => { + reject(err); + }); + } else { + requestInfo.onEachUpdate && requestInfo.onEachUpdate({ + data: response, + ...fileData + }); + fileList.push(response); + if (len <= i) { + resolve(fileList); + } else { + fileUpload(i + 1); + } + } + }, + fail: (err) => { + reject(err); + } + }; + if (requestInfo.data) { + config.formData = requestInfo.data; + } + const uploadTask = uni.uploadFile(config); + uploadTask.onProgressUpdate(res => { + requestInfo.onProgressUpdate && requestInfo.onProgressUpdate(Object.assign({}, fileData, res)); + }); + } + // #-endif + } else { + reject({ + errMsg: "files 必须是数组类型", + statusCode: 0 + }); + } + }); +} diff --git a/utils/storage.js b/utils/storage.js new file mode 100644 index 0000000..7b2ac32 --- /dev/null +++ b/utils/storage.js @@ -0,0 +1,85 @@ +/** + * 缓存数据优化 + * import storage from '@/utils/storage' + * 使用方法 【 + * 一、设置缓存 + * string storage.set('k', 'string你好啊'); + * json storage.set('k', { "b": "3" }, 2); + * array storage.set('k', [1, 2, 3]); + * boolean storage.set('k', true); + * 二、读取缓存 + * 默认值 storage.get('k') + * string storage.get('k', '你好') + * json storage.get('k', { "a": "1" }) + * 三、移除/清理 + * 移除: storage.remove('k'); + * 清理:storage.clear(); + * 】 + * @type {String} + */ + +const postfix = '_expiry' // 缓存有效期后缀 + +export default { + + /** + * 设置缓存 + * @param {[type]} k [键名] + * @param {[type]} v [键值] + * @param {[type]} t [时间、单位秒] + */ + set(k, v, t) { + uni.setStorageSync(k, v) + const seconds = parseInt(t) + if (seconds > 0) { + let timestamp = Date.parse(new Date()) + timestamp = timestamp / 1000 + seconds + uni.setStorageSync(k + postfix, timestamp + '') + } else { + uni.removeStorageSync(k + postfix) + } + }, + + /** + * 获取缓存 + * @param {[type]} k [键名] + * @param {[type]} def [获取为空时默认] + */ + get(k, def) { + const deadtime = parseInt(uni.getStorageSync(k + postfix)) + if (deadtime) { + if (parseInt(deadtime) < Date.parse(new Date()) / 1000) { + if (def) { + return def + } else { + return false + } + } + } + const res = uni.getStorageSync(k) + if (res) { + return res + } + if (def == undefined || def == "") { + def = false + } + return def + }, + + /** + * 删除指定缓存 + * @param {Object} k + */ + remove(k) { + uni.removeStorageSync(k) + uni.removeStorageSync(k + postfix) + }, + + /** + * 清理所有缓存 + * @return {[type]} [description] + */ + clear() { + uni.clearStorageSync() + } +} \ No newline at end of file