From 42eba945e8ff90d0e3270fbe723c506597fcde88 Mon Sep 17 00:00:00 2001 From: bobobobo <1055026847@qq.com> Date: Sun, 4 Jan 2026 23:35:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E7=8E=B0=E5=8A=9F=E8=83=BD=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E6=B7=BB=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.vue | 19 +- TUIKit/components/TUIChat/index.vue | 458 +++++----- TUIKit/components/TUIChat/style/index.scss | 9 + .../contact-list/components/FriendList.vue | 116 ++- .../TUIContact/contact-list/index.vue | 576 +++++++----- TUIKit/components/TUIContact/index.vue | 336 ++++--- TUIKit/components/TUIConversation/index.vue | 333 +++---- api/index.js | 10 + api/my-index.js | 91 ++ components/cb-file-picker/cb-file-picker.vue | 32 +- package-lock.json | 63 +- package.json | 8 +- pages.json | 58 +- pages/address/index.vue | 31 +- pages/login/login.vue | 2 +- pages/my-index/components/card-input.vue | 7 + pages/my-index/components/popup-box.vue | 81 ++ pages/my-index/my-index.vue | 6 +- pages/my-index/personal-center/index.vue | 90 +- pages/my-index/styles/index.scss | 2 +- .../wallet/bank-card/card-details.vue | 183 +++- pages/my-index/wallet/bank-card/index.vue | 113 ++- pages/my-index/wallet/edit-password.vue | 109 ++- pages/my-index/wallet/index.vue | 52 +- pages/my-index/wallet/real-id.vue | 101 ++- pages/news-list/news-list.vue | 6 +- stores/user.js | 13 +- styles/global.scss | 22 + uni_modules/TencentCloud-Push/changelog.md | 29 + uni_modules/TencentCloud-Push/index.js | 0 uni_modules/TencentCloud-Push/package.json | 90 ++ uni_modules/TencentCloud-Push/readme-npm.md | 299 ++++++ uni_modules/TencentCloud-Push/readme.md | 285 ++++++ .../utssdk/app-android/config.json | 27 + .../utssdk/app-android/index.uts | 152 ++++ .../app-android/push-callback-options.uts | 5 + .../utssdk/app-android/push-callback.uts | 28 + .../app-android/push-listener-options.uts | 3 + .../utssdk/app-android/push-listener.uts | 25 + .../utssdk/app-ios/UTS.entitlements | 8 + .../utssdk/app-ios/config.json | 11 + .../utssdk/app-ios/index.uts | 125 +++ .../utssdk/app-ios/push-listener-options.uts | 3 + .../utssdk/app-ios/push-listener.uts | 24 + .../TencentCloud-Push/utssdk/interface.uts | 11 + uni_modules/uni-combox/changelog.md | 17 + .../components/uni-combox/uni-combox.vue | 284 ++++++ uni_modules/uni-combox/package.json | 88 ++ uni_modules/uni-combox/readme.md | 11 + uni_modules/uni-data-checkbox/changelog.md | 51 ++ .../components/uni-data-checkbox/clientdb.js | 316 +++++++ .../uni-data-checkbox/uni-data-checkbox.vue | 853 ++++++++++++++++++ uni_modules/uni-data-checkbox/package.json | 87 ++ uni_modules/uni-data-checkbox/readme.md | 18 + utils/media.js | 45 + utils/uploadFile.js | 1 + utils/use-ui.js | 2 +- vue.config.js | 15 + 58 files changed, 4825 insertions(+), 1015 deletions(-) create mode 100644 pages/my-index/components/popup-box.vue create mode 100644 uni_modules/TencentCloud-Push/changelog.md create mode 100644 uni_modules/TencentCloud-Push/index.js create mode 100644 uni_modules/TencentCloud-Push/package.json create mode 100644 uni_modules/TencentCloud-Push/readme-npm.md create mode 100644 uni_modules/TencentCloud-Push/readme.md create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/config.json create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/index.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/config.json create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts create mode 100644 uni_modules/TencentCloud-Push/utssdk/interface.uts create mode 100644 uni_modules/uni-combox/changelog.md create mode 100644 uni_modules/uni-combox/components/uni-combox/uni-combox.vue create mode 100644 uni_modules/uni-combox/package.json create mode 100644 uni_modules/uni-combox/readme.md create mode 100644 uni_modules/uni-data-checkbox/changelog.md create mode 100644 uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js create mode 100644 uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue create mode 100644 uni_modules/uni-data-checkbox/package.json create mode 100644 uni_modules/uni-data-checkbox/readme.md create mode 100644 utils/media.js create mode 100644 vue.config.js diff --git a/App.vue b/App.vue index de1333d..2bc4f75 100644 --- a/App.vue +++ b/App.vue @@ -1,15 +1,20 @@ - + diff --git a/TUIKit/components/TUIChat/style/index.scss b/TUIKit/components/TUIChat/style/index.scss index 65e8096..0811e20 100644 --- a/TUIKit/components/TUIChat/style/index.scss +++ b/TUIKit/components/TUIChat/style/index.scss @@ -1,3 +1,12 @@ +uni-page-body, +html, +body, +page { + width: 100% !important; + height: 100% !important; + overflow: hidden; +} + @import '../../../assets/styles/common'; @import './web'; @import './h5'; diff --git a/TUIKit/components/TUIContact/contact-list/components/FriendList.vue b/TUIKit/components/TUIContact/contact-list/components/FriendList.vue index e4815b9..ef338e6 100644 --- a/TUIKit/components/TUIContact/contact-list/components/FriendList.vue +++ b/TUIKit/components/TUIContact/contact-list/components/FriendList.vue @@ -26,64 +26,84 @@ diff --git a/TUIKit/components/TUIContact/contact-list/index.vue b/TUIKit/components/TUIContact/contact-list/index.vue index 5993b40..2d3ba9e 100644 --- a/TUIKit/components/TUIContact/contact-list/index.vue +++ b/TUIKit/components/TUIContact/contact-list/index.vue @@ -28,7 +28,13 @@
-
{{ TUITranslateService.t(`TUIContact.${contactListObj.title}`) }}
+
+ {{ + TUITranslateService.t( + `TUIContact.${contactListObj.title}` + ) + }} +
diff --git a/TUIKit/components/TUIContact/index.vue b/TUIKit/components/TUIContact/index.vue index 8c994df..eb23282 100644 --- a/TUIKit/components/TUIContact/index.vue +++ b/TUIKit/components/TUIContact/index.vue @@ -4,19 +4,24 @@ v-else-if="isShowContactList" :class="['tui-contact', !isPC && 'tui-contact-h5']" > - + @@ -28,173 +33,204 @@
- + + -
diff --git a/TUIKit/components/TUIConversation/index.vue b/TUIKit/components/TUIConversation/index.vue index e86ebc9..ad101fa 100644 --- a/TUIKit/components/TUIConversation/index.vue +++ b/TUIKit/components/TUIConversation/index.vue @@ -18,174 +18,195 @@ - + diff --git a/api/index.js b/api/index.js index 018efa1..3fd9fb3 100644 --- a/api/index.js +++ b/api/index.js @@ -34,6 +34,15 @@ export const getUserData = () => { }) } +/** 修改用户信息 */ +export const updateUserData = data => { + return http({ + url: '/api/user/edit', + method: 'put', + data + }) +} + /** 获取用户地址列表 */ export const getUserAddress = (data, loading = true) => { return http({ @@ -128,3 +137,4 @@ export const getTencentUserSig = () => { method: 'get' }) } + diff --git a/api/my-index.js b/api/my-index.js index 585c4cd..4bbfce9 100644 --- a/api/my-index.js +++ b/api/my-index.js @@ -50,3 +50,94 @@ export const getUserPayPwd = () => { method: 'get' }) } + +/** + * 添加/修改支付密码 + * @param {*} data + * @param {*} method post 添加 put 修改 + * @returns + */ +export const updateUserPayPwd = (data, method = 'post') => { + return http({ + url: '/api/service/userPassword', + method, + data + }) +} + +/** + * 添加/修改银行卡 + * @param {*} data + * @param {*} method post 添加 put 修改 + * @returns + */ +export const addUserPayPwd = (data, method = 'post') => { + return http({ + url: '/api/service/userCard', + method, + data + }) +} + +/** 删除银行卡 */ +export const deleteUserPayPwd = id => { + return http({ + url: `/api/service/userCard/${id}`, + method: 'delete' + }) +} + +/** 获取银行卡列表 */ +export const getUserBankList = () => { + return http({ + url: '/api/service/userCard/list', + method: 'get' + }) +} + +/** 获取银行卡详情 */ +export const getUserBankDetail = id => { + return http({ + url: `/api/service/userCard/details/${id}`, + method: 'get' + }) +} + +/** + * 添加/修改用户第三方支付账户 + * @param {*} data 提交数据 + * @param {*} method post 添加 put 修改 + * @returns + */ +export const addUserThirdPay = (data, method = 'post') => { + return http({ + url: '/api/service/userPayment', + method, + data + }) +} + +/** 获取用户第三方支付详情 */ +export const getUserThirdPay = id => { + return http({ + url: `/api/service/userPayment/${id}`, + method: 'get' + }) +} + +/** 获取身份证信息 */ +export const getUserIdCard = () => { + return http({ + url: '/api/service/userVerification/details', + method: 'get' + }) +} + +/** 添加身份证 */ +export const addUserIdCard = data => { + return http({ + url: '/api/service/userVerification', + method: 'post', + data + }) +} diff --git a/components/cb-file-picker/cb-file-picker.vue b/components/cb-file-picker/cb-file-picker.vue index f6869e8..450cb20 100644 --- a/components/cb-file-picker/cb-file-picker.vue +++ b/components/cb-file-picker/cb-file-picker.vue @@ -28,6 +28,12 @@ default: () => [] }) + /** 图片回显列表 */ + const fileLists = defineModel('list', { + type: Array, + default: () => [] + }) + /** 是否为身份证状态 */ const isIdCard = computed(() => props.isFront || props.isBack) @@ -61,25 +67,31 @@ } const onSelect = async e => { - e.tempFiles.forEach(v => { - uploadFile(v.path) - }) - - return - const upData = e.tempFiles.map(v => v.path)[0] - imageValue.value = await uploadSingleFile(upData, { - url: '/api/common/admin/upload/up/single' - }) + if (props.limit === '1') { + const upData = e.tempFiles.map(v => v.path)[0] + imageValue.value = await uploadSingleFile(upData, { + url: '/api/common/admin/upload/up/single' + }) + } else { + e.tempFiles.forEach(v => { + uploadFile(v.path) + }) + } } const onDelete = e => { - imageValue.value.splice(e.index, 1) + if (props.limit === '1') { + imageValue.value = '' + } else { + imageValue.value.splice(e.index, 1) + } } diff --git a/stores/user.js b/stores/user.js index 020e18a..8b509f6 100644 --- a/stores/user.js +++ b/stores/user.js @@ -9,7 +9,7 @@ import { removeSig } from '@/utils/storage' import { useTokenStore } from './token' -import { getUserData, userLogout } from '@/api' +import { getUserData, userLogout, updateUserData } from '@/api' import { ref } from 'vue' import { useUI } from '@/utils/use-ui' import { reLaunch } from '@/utils/router' @@ -62,6 +62,7 @@ export const useUserStore = defineStore('user', () => { * 登录腾讯 IM */ const loginTencentIM = async () => { + console.log(11111111111111111111111) await TUILogin.login({ SDKAppID: tencentUserSig.value.sdkappID, userID: tencentUserSig.value.userId, @@ -90,16 +91,17 @@ export const useUserStore = defineStore('user', () => { /** 刷新用户信息(如用户信息被修改) */ const refreshUserInfo = async () => { const res = await getUserData() - await setUserInfo(res.data) + await setUserInfoData(res.data) + userInfo.value = res.data } /** * 更新部分用户信息(例如昵称、头像) */ - const updateUserInfo = partialData => { + const updateUserInfo = async partialData => { if (!userInfo.value) return - userInfo.value = { ...userInfo.value, ...partialData } - setUserInfoData(userInfo.value) + await updateUserData(partialData) + await refreshUserInfo() } return { @@ -107,6 +109,7 @@ export const useUserStore = defineStore('user', () => { tencentUserSig, refreshUserInfo, fetchUserInfo, + loginTencentIM, setUserInfo, clearUserInfo, updateUserInfo diff --git a/styles/global.scss b/styles/global.scss index 58e0484..f99a2c7 100644 --- a/styles/global.scss +++ b/styles/global.scss @@ -15,3 +15,25 @@ page { padding: 12rpx 36rpx; border-radius: 8rpx; } + +/** uni-swipe-action 滑动右边样式 */ +.public-uni-swipe-action-right { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: rgb(47, 194, 17); + width: 130rpx; + .iocn-name { + font-family: PingFang SC, PingFang SC; + font-weight: 500; + font-size: 28rpx; + color: #fff; + text-align: left; + font-style: normal; + text-transform: none; + } + &:last-child { + background: rgb(206, 59, 22); + } +} diff --git a/uni_modules/TencentCloud-Push/changelog.md b/uni_modules/TencentCloud-Push/changelog.md new file mode 100644 index 0000000..c5e53f6 --- /dev/null +++ b/uni_modules/TencentCloud-Push/changelog.md @@ -0,0 +1,29 @@ +## 1.2.0(2025-03-31) +- 适配出海手机支持 FCM 推送。 +## 1.1.0(2024-12-11) +- 大幅减小插件包体积,优化产品体验。 +- 兼容 HBuilderX 4.36 的 Breaking changes。如果您需要 vivo/荣耀 的厂商推送,请参考 [文档](https://cloud.tencent.com/document/product/269/103522),正确配置 `manifestPlaceholders.json` 和 `mcn-services.json`。 + +## 1.0.0(2024-11-29) +- 优化和 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合时的产品体验。 +- 新增点击通知栏事件 NOTIFICATION_CLICKED,支持获取推送扩展信息。 +- 在线通道支持自定义铃音功能。 + +## 0.5.1(2024-11-07) +- 优化和 [@tencentcloud/chat-uikit-uniapp](https://cloud.tencent.com/document/product/269/64507) 融合时的产品体验。 +- 优化和 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合时的产品体验。 +- 新增接口 disablePostNotificationInForeground,此接口可实现应用在前台时,开/关通知栏通知(默认开)。 +- 新增接口 createNotificationChannel,支持 FCM/OPPO 自定义铃音。 + +## 0.4.0(2024-10-17) +- 支持与 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合打包。 + +## 0.3.0(2024-10-12) +- 新增接口 addPushListener/removePushListener,支持获取在线推送消息,支持推送消息撤回通知。 + +## 0.2.0(2024-09-18) +- 支持 FCM +- 支持 hihonor + +## 0.1.0(2024-09-10) + - 使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。 \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/index.js b/uni_modules/TencentCloud-Push/index.js new file mode 100644 index 0000000..e69de29 diff --git a/uni_modules/TencentCloud-Push/package.json b/uni_modules/TencentCloud-Push/package.json new file mode 100644 index 0000000..11c4355 --- /dev/null +++ b/uni_modules/TencentCloud-Push/package.json @@ -0,0 +1,90 @@ +{ + "name": "@tencentcloud/uni-app-push", + "id": "TencentCloud-Push", + "main": "index.js", + "displayName": "【官方】uni-app 腾讯云推送服务(Push)", + "version": "1.2.0", + "description": "使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。", + "license": "ISC", + "keywords": [ + "腾讯云", + "Push", + "推送", + "Android/iOS", + "谷歌FCM" +], + "repository": "", + "engines": { + "HBuilderX": "^3.6.8" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "腾讯云即时通信IM隐私保护指引: https://web.sdk.qcloud.com/document/Tencent-IM-Privacy-Protection-Guidelines.html\n移动推送隐私保护指引: https://privacy.qq.com/document/preview/8565a4a2d26e480187ed86b0cc81d727", + "permissions": "本地存储空间" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-android": "y", + "app-ios": "y", + "app-harmony": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/readme-npm.md b/uni_modules/TencentCloud-Push/readme-npm.md new file mode 100644 index 0000000..e3cba80 --- /dev/null +++ b/uni_modules/TencentCloud-Push/readme-npm.md @@ -0,0 +1,299 @@ +# TencentCloud-Push + +## 简介 + +使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。 + +腾讯云推送服务(Push)提供一站式 App 推送解决方案,助您轻松提升用户留存和互动活跃度,支持与腾讯云即时通信 IM SDK、实时音视频 TRTC SDK、音视频通话 SDK、直播 SDK等音视频终端产品协同集成,在不同场景联合使用,提升业务整体功能体验。 + + + + + +#### 数据可视化,辅助运营策略 + + + +#### 支持推送消息全链路问题排查 + + + +#### 六地服务部署,严守数据安全 + +提供了中国、东南亚(新加坡、印尼雅加达)、东北亚(韩国首尔)、欧洲(德国法兰克福)以及北美(美国硅谷)数据存储中心供选择,每个数据中心均支持全球接入。如果您的应用在境外上线且用户主要在境外,您可以根据消息传输需求及合规要求,选择适合您业务的境外数据中心,保障您的数据安全。 + + +## 快速跑通 + +### 步骤1:创建应用 + +进入 [控制台](https://console.cloud.tencent.com/im) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/e2761226f7d2bbdfb0a301192316c7d3.png) + +### 步骤2:开通推送服务 Push + +进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天) + +![](https://qcloudimg.tencent-cloud.cn/image/document/a7e1f3847c91a807ec9be3a586f1290f.png) + +### 步骤3:下载腾讯云推送服务(Push)并复制 Push SDK 到您的项目中 + +1. 下载腾讯云推送服务(Push)。 +``` +npm install @tencentcloud/uni-app-push +``` + +2. 复制 Push SDK 到您的项目中。 + +【macOS 端】 + +``` bash +mkdir -p ./uni_modules/TencentCloud-Push && rsync -av ./node_modules/@tencentcloud/uni-app-push/ ./uni_modules/TencentCloud-Push +``` +【Window 端】 + +``` bash +xcopy .\node_modules\@tencentcloud\uni-app-push .\uni_modules\TencentCloud-Push /i /e +``` + +### 步骤4:在 App.vue 中引入并注册腾讯云推送服务(Push) + +将 SDKAppID 和 appKey 替换为您在IM 控制台 - 推送服务 Push - 接入设置页面 获取的应用的信息。如图所示: + +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/push.png) + +```ts +// 集成 TencentCloud-Push +import * as Push from '@/uni_modules/TencentCloud-Push'; +const SDKAppID = 0; // 您的 SDKAppID +const appKey = ''; // 客户端密钥 +Push.registerPush(SDKAppID, appKey, (data) => { + console.log('registerPush ok', data); + Push.getRegistrationID((registrationID) => { + console.log('getRegistrationID ok', registrationID); + }); + }, (errCode, errMsg) => { + console.error('registerPush failed', errCode, errMsg); + } +); + +// 监听通知栏点击事件,获取推送扩展信息 +Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => { + // res 为推送扩展信息 + console.log('notification clicked', res); +}); + +// 监听在线推送 +Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => { + // res 为消息内容 + console.log('message received', res); +}); + +// 监听在线推送被撤回 +Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => { + // res 为被撤回的消息 ID + console.log('message revoked', res); +}); +``` + +### 步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。) + +单击 HBuilderX 的 【运行 > 运行到手机或模拟器 > 制作自定义调试基座】,使用云端证书制作 Android 或 iOS 自定义调试基座。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/742b7c05364e8ff9a16d5d5601aa038b.png) + +自定义调试基座打好后,安装到手机运行。 + +[登录](https://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。 +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/test-online-push.png) + +## 厂商推送配置 +> - 请注意!HBuilderX 4.36 发布了不向下兼容的更新,如果您使用的是 HBuilderX 4.36 或者更高版本,且需要 vivo/荣耀 的厂商推送, +请升级推送版本到 1.1.0 或更高版本,并参考文档正确配置 `manifestPlaceholders.json` 和 `mcs-services.json`。 +> - 请在 `nativeResources` 目录下进行推送配置。若项目根目录尚未创建该文件夹,请新建一个名为 `nativeResources` 的文件夹。 +> - 离线推送厂商配置完成后,需要打包自定义基座。参考:[[快速跑通]>[步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)]](#user-content-step5) + +### 【Android】 + +1. 新建 nativeResources/android/assets 目录。 + +2. 在 [推送服务 Push > 接入设置 > 一键式快速配置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 下载 `timpush-configs.json` 文件,配置到 nativeResources/android/assets 目录下。 + +3. For 华为: + + 配置 `agconnect-services.json` (此文件获取详见 [厂商配置 > uniapp > 华为 > 步骤4:获取应用信息](https://cloud.tencent.com/document/product/269/103769))到 nativeResources/android 目录下。 + +4. For Google FCM: + + 4.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `project.plugins`,添加 `"com.google.gms.google-services"`,如下: + ``` + { + ... + "project": { + "plugins": [ + ... + "com.google.gms.google-services" + ] + } + } + ``` + + 4.2. 配置 `google-services.json` 文件到 nativeResources/android/ 目录。 + +5. For 荣耀: + + 5.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:honor:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:honor:8.3.6498" + ] + } + ``` + + 5.2. 配置 `mcs-services.json` 文件到 nativeResources/android 目录下。 + + 5.3. 配置 `appID` 到 nativeResources/android/manifestPlaceholders.json 中的 `"HONOR_APPID"`,如下: + ``` + { + "HONOR_APPID": "" + } + ``` + +6. For vivo: + + 6.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:vivo:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:vivo:8.3.6498" + ] + } + ``` + + 6.2. 配置 `appID` 和 `appKey` 到 nativeResources/android/manifestPlaceholders.json 中的 `VIVO_APPKEY` 和 `VIVO_APPID`,如下: + ``` + { + "VIVO_APPKEY": "", + "VIVO_APPID": "", + } + ``` + +### 【iOS】 + +1. 新建 nativeResources/ios/Resources 目录。 + +2. 在 nativeResources/ios/Resources 中**新建 timpush-configs.json 文件**。 + +3. 并将在 [IM控制台 > 推送服务 Push > 接入设置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 获取的证书ID,补充到 timpush-configs.json 文件中。 + + ``` + { + "businessID":"xxx" + } + ``` + +## 接口 + +| API | 描述| +|----|---| +| registerPush | 注册推送服务 (必须在 App 用户同意了隐私政策,并且允许为 App 用户提供推送服务后,再调用该接口使用推送服务)。
首次注册成功后,TencentCloud-Push SDK 生成该设备的标识 - RegistrationID。
业务侧可以把这个 RegistrationID 保存到业务服务器。业务侧根据 RegistrationID 向设备推送消息或者通知。| +| unRegisterPush | 反注册关闭推送服务。| +| setRegistrationID | 设置注册推送服务使用的推送 ID 标识,即 RegistrationID。
如果业务侧期望业务账号 ID 和推送 ID 一致,方便使用,可使用此接口,此时需注意,此接口需在 registerPush(注册推送服务)之前调用。| +| getRegistrationID | 注册推送服务成功后,获取推送 ID 标识,即 RegistrationID。| +| getNotificationExtInfo | 获取推送扩展信息。| +| getNotificationExtInfo | 收到离线推送时,点击通知栏拉起 app,调用此接口可获取推送扩展信息。| +| addPushListener | 添加 Push 监听器。| +| removePushListener | 移除 Push 监听器。| +| disablePostNotificationInForeground | 应用在前台时,开/关通知栏通知。| +| createNotificationChannel | 创建客户端通知 channel。| + + +```ts +registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|SDKAppID|number|是|推送(Push)应用 ID| +|appKey|string|是|推送(Push)应用客户端密钥| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +setRegistrationID(registrationID: string, onSuccess: () => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|registrationID|string|是|设备的推送标识 ID,卸载重装会改变。| +|onSuccess|function|是|接口调用成功的回调函数| + + +```ts +getRegistrationID(onSuccess: (registrationID: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +getNotificationExtInfo(onSuccess: (extInfo: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +addPushListener(eventName: string, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|是|推送事件处理方法| + +```ts +removePushListener(eventName: string, listener?: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|否|推送事件处理方法| + +```ts +disablePostNotificationInForeground(disable: boolean); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|disable|boolean|是|应用在前台时,开/关通知栏通知,默认开
- true: 应用在前台时,关闭通知栏通知。
- false: 应用在前台时,开启通知栏通知。| + +```ts +createNotificationChannel(options: any, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|options.channelID|string|是|自定义 channel 的 ID| +|options.channelName|string|是|自定义 channel 的名称| +|options.channelDesc|string|否|自定义 channel 的描述| +|options.channelSound|string|否|自定义 channel 的铃音,音频文件名,不带后缀,音频文件需要放到 xxx/nativeResources/android/res/raw 中。
例如:
`options.channelSound = private_ring`,即设置 `xxx/nativeResources/android/res/raw/private_ring.mp3` 为自定义铃音| +|listener|function|是|接口调用成功的回调函数| diff --git a/uni_modules/TencentCloud-Push/readme.md b/uni_modules/TencentCloud-Push/readme.md new file mode 100644 index 0000000..f49324e --- /dev/null +++ b/uni_modules/TencentCloud-Push/readme.md @@ -0,0 +1,285 @@ +# TencentCloud-Push + +## 简介 + +使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。 + +腾讯云推送服务(Push)提供一站式 App 推送解决方案,助您轻松提升用户留存和互动活跃度,支持与腾讯云即时通信 IM SDK、实时音视频 TRTC SDK、音视频通话 SDK、直播 SDK等音视频终端产品协同集成,在不同场景联合使用,提升业务整体功能体验。 + + + + + +#### 数据可视化,辅助运营策略 + + + +#### 支持推送消息全链路问题排查 + + + +#### 六地服务部署,严守数据安全 + +提供了中国、东南亚(新加坡、印尼雅加达)、东北亚(韩国首尔)、欧洲(德国法兰克福)以及北美(美国硅谷)数据存储中心供选择,每个数据中心均支持全球接入。如果您的应用在境外上线且用户主要在境外,您可以根据消息传输需求及合规要求,选择适合您业务的境外数据中心,保障您的数据安全。 + + +## 快速跑通 + +### 步骤1:创建应用 + +进入 [控制台](https://console.cloud.tencent.com/im) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/e2761226f7d2bbdfb0a301192316c7d3.png) + +### 步骤2:开通推送服务 Push + +进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天) + +![](https://qcloudimg.tencent-cloud.cn/image/document/a7e1f3847c91a807ec9be3a586f1290f.png) + +### 步骤3:将 [uni-app 腾讯云推送服务(Push)](https://ext.dcloud.net.cn/plugin?id=20169)插件导入 HbuilderX 中的工程。如图所示: + +![](https://qcloudimg.tencent-cloud.cn/image/document/ab8061fea2bf6659f571c2c11aa0d8f4.png) +![](https://qcloudimg.tencent-cloud.cn/image/document/13a3e33564e6ab79d3e609b36e8ba0d5.png) +![](https://qcloudimg.tencent-cloud.cn/image/document/3c7060f9db637c826009926c5f34a1b8.png) + +### 步骤4:在 App.vue 中引入并注册腾讯云推送服务(Push) + +将 SDKAppID 和 appKey 替换为您在IM 控制台 - 推送服务 Push - 接入设置页面 获取的应用的信息。如图所示: + +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/push.png) + +```ts +// 集成 TencentCloud-Push +import * as Push from '@/uni_modules/TencentCloud-Push'; +const SDKAppID = 0; // 您的 SDKAppID +const appKey = ''; // 客户端密钥 +Push.registerPush(SDKAppID, appKey, (data) => { + console.log('registerPush ok', data); + Push.getRegistrationID((registrationID) => { + console.log('getRegistrationID ok', registrationID); + }); + }, (errCode, errMsg) => { + console.error('registerPush failed', errCode, errMsg); + } +); + +// 监听通知栏点击事件,获取推送扩展信息 +Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => { + // res 为推送扩展信息 + console.log('notification clicked', res); +}); + +// 监听在线推送 +Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => { + // res 为消息内容 + console.log('message received', res); +}); + +// 监听在线推送被撤回 +Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => { + // res 为被撤回的消息 ID + console.log('message revoked', res); +}); +``` + +### 步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。) + +单击 HBuilderX 的 【运行 > 运行到手机或模拟器 > 制作自定义调试基座】,使用云端证书制作 Android 或 iOS 自定义调试基座。 + +![](https://qcloudimg.tencent-cloud.cn/image/document/742b7c05364e8ff9a16d5d5601aa038b.png) + +自定义调试基座打好后,安装到手机运行。 + +[登录](https://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。 +![](https://sdk-web-1252463788.cos.ap-hongkong.myqcloud.com/im/assets/push/test-online-push.png) + + +## 厂商推送配置 + +> - 请注意!HBuilderX 4.36 发布了不向下兼容的更新,如果您使用的是 HBuilderX 4.36 或者更高版本,且需要 vivo/荣耀 的厂商推送, +请升级推送版本到 1.1.0 或更高版本,并参考文档正确配置 `manifestPlaceholders.json` 和 `mcs-services.json`。 +> - 请在 `nativeResources` 目录下进行推送配置。若项目根目录尚未创建该文件夹,请新建一个名为 `nativeResources` 的文件夹。 +> - 厂商推送配置完成后,需要打包自定义基座。参考:[[快速跑通]>[步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)]](#step5) + +#### 【Android】 + +1. 新建 nativeResources/android/assets 目录。 + +2. 在 [推送服务 Push > 接入设置 > 一键式快速配置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 下载 `timpush-configs.json` 文件,配置到 nativeResources/android/assets 目录下。 + +3. For 华为: + + 配置 `agconnect-services.json` (此文件获取详见 [厂商配置 > uniapp > 华为 > 步骤4:获取应用信息](https://cloud.tencent.com/document/product/269/103769))到 nativeResources/android 目录下。 + +4. For Google FCM: + + 4.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `project.plugins`,添加 `"com.google.gms.google-services"`,如下: + ``` + { + ... + "project": { + "plugins": [ + ... + "com.google.gms.google-services" + ] + } + } + ``` + + 4.2. 配置 `google-services.json` 文件到 nativeResources/android/ 目录。 + +5. For 荣耀: + + 5.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:honor:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:honor:8.3.6498" + ] + } + ``` + + 5.2. 配置 `mcs-services.json` 文件到 nativeResources/android 目录下。 + + 5.3. 配置 `appID` 到 nativeResources/android/manifestPlaceholders.json 中的 `"HONOR_APPID"`,如下: + ``` + { + "HONOR_APPID": "" + } + ``` + +6. For vivo: + + 6.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:vivo:8.3.6498"`,如下: + ``` + { + ... + "dependencies": [ + ... + "com.tencent.timpush:vivo:8.3.6498" + ] + } + ``` + + 6.2. 配置 `appID` 和 `appKey` 到 nativeResources/android/manifestPlaceholders.json 中的 `VIVO_APPKEY` 和 `VIVO_APPID`,如下: + ``` + { + "VIVO_APPKEY": "", + "VIVO_APPID": "", + } + ``` + +#### 【iOS】 + +1. 新建 nativeResources/ios/Resources 目录。 + +2. 在 nativeResources/ios/Resources 目录下新建 `timpush-configs.json` 文件。 + +3. 将在 [IM控制台 > 推送服务 Push > 接入设置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 获取的证书ID,补充到 `timpush-configs.json` 文件中。 + + ``` + { + "businessID":"xxx" + } + ``` + +## 接口 + +| API | 描述| +|----|---| +| registerPush | 注册推送服务 (必须在 App 用户同意了隐私政策,并且允许为 App 用户提供推送服务后,再调用该接口使用推送服务)。
首次注册成功后,TencentCloud-Push SDK 生成该设备的标识 - RegistrationID。
业务侧可以把这个 RegistrationID 保存到业务服务器。业务侧根据 RegistrationID 向设备推送消息或者通知。| +| unRegisterPush | 反注册关闭推送服务。| +| setRegistrationID | 设置注册推送服务使用的推送 ID 标识,即 RegistrationID。
如果业务侧期望业务账号 ID 和推送 ID 一致,方便使用,可使用此接口,此时需注意,此接口需在 registerPush(注册推送服务)之前调用。| +| getRegistrationID | 注册推送服务成功后,获取推送 ID 标识,即 RegistrationID。| +| getNotificationExtInfo | 收到离线推送时,点击通知栏拉起 app,调用此接口可获取推送扩展信息。| +| addPushListener | 添加 Push 监听器。| +| removePushListener | 移除 Push 监听器。| +| disablePostNotificationInForeground | 应用在前台时,开/关通知栏通知(默认开)。| +| createNotificationChannel | 创建客户端通知 channel。| + +```ts +registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|SDKAppID|number|是|推送(Push)应用 ID| +|appKey|string|是|推送(Push)应用客户端密钥| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| +|onError|function|否|接口调用失败的回调函数| + +```ts +setRegistrationID(registrationID: string, onSuccess: () => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|registrationID|string|是|设备的推送标识 ID,卸载重装会改变。| +|onSuccess|function|是|接口调用成功的回调函数| + + +```ts +getRegistrationID(onSuccess: (registrationID: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +getNotificationExtInfo(onSuccess: (extInfo: string) => void): void; +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|onSuccess|function|是|接口调用成功的回调函数| + +```ts +addPushListener(eventName: string, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|是|推送事件处理方法| + +```ts +removePushListener(eventName: string, listener?: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|eventName|string|是|推送事件类型| +|listener|function|否|推送事件处理方法| + +```ts +disablePostNotificationInForeground(disable: boolean); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|disable|boolean|是|应用在前台时,开/关通知栏通知,默认开
- true: 应用在前台时,关闭通知栏通知。
- false: 应用在前台时,开启通知栏通知。| + +```ts +createNotificationChannel(options: any, listener: (data: any) => void); +``` + +|属性|类型|必填|说明| +|----|---|----|----| +|options.channelID|string|是|自定义 channel 的 ID| +|options.channelName|string|是|自定义 channel 的名称| +|options.channelDesc|string|否|自定义 channel 的描述| +|options.channelSound|string|否|自定义 channel 的铃音,音频文件名,不带后缀,音频文件需要放到 xxx/nativeResources/android/res/raw 中。
例如:
`options.channelSound = private_ring`,即设置 `xxx/nativeResources/android/res/raw/private_ring.mp3` 为自定义铃音| +|listener|function|是|接口调用成功的回调函数| diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/config.json b/uni_modules/TencentCloud-Push/utssdk/app-android/config.json new file mode 100644 index 0000000..a2340f5 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/config.json @@ -0,0 +1,27 @@ +{ + "minSdkVersion": "21", + "dependencies": [ + "com.google.android.material:material:1.3.0", + "com.google.code.gson:gson:2.9.1", + "commons-codec:commons-codec:1.15", + "com.github.bumptech.glide:glide:4.12.0", + "com.tencent.timpush:timpush:8.5.6864", + "com.tencent.liteav.tuikit:tuicore:8.5.6864", + "com.tencent.timpush:huawei:8.5.6864", + "com.tencent.timpush:xiaomi:8.5.6864", + "com.tencent.timpush:oppo:8.5.6864", + "com.tencent.timpush:meizu:8.5.6864", + "com.tencent.timpush:fcm:8.5.6864" + ], + "project": { + "plugins": [ + "com.huawei.agconnect", + "com.hihonor.mcs.asplugin" + ], + "dependencies": [ + "com.huawei.agconnect:agcp:1.9.1.301", + "com.google.gms:google-services:4.3.15", + "com.hihonor.mcs:asplugin:2.0.1.300" + ] + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/index.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/index.uts new file mode 100644 index 0000000..ebba851 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/index.uts @@ -0,0 +1,152 @@ +import { UTSAndroid } from 'io.dcloud.uts'; +import Context from 'android.content.Context'; +import TIMPushManager from 'com.tencent.qcloud.tim.push.TIMPushManager'; +import TIMPushConfig from 'com.tencent.qcloud.tim.push.config.TIMPushConfig'; +import { PushCallbackOptions } from './push-callback-options.uts'; +import { PushListenerOptions } from './push-listener-options.uts'; +import PushCallback from './push-callback.uts'; +import PushListener from './push-listener.uts'; + +const context: Context | null = UTSAndroid.getAppContext(); +console.warn('Push | package.name:', context?.getPackageName()); +TIMPushConfig.getInstance().setRunningPlatform(2); +const Push = TIMPushManager.getInstance(); + +export class EVENT { + static MESSAGE_RECEIVED: string = 'message_received' + static MESSAGE_REVOKED: string = 'message_revoked' + static NOTIFICATION_CLICKED: string = 'notification_clicked' +} + +let disableNotification = false; +export function disablePostNotificationInForeground(disable: boolean): void { + console.log('Push | disablePostNotificationInForeground', disable); + disableNotification = disable; + Push.disablePostNotificationInForeground(disableNotification); +} + +export function registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void { + if (SDKAppID == 0) { + onError?.(9010001, 'Invalid SDKAppID'); + } else if (appKey == '') { + onError?.(9010002, 'Invalid appKey'); + } + const pushCbOptions: PushCallbackOptions = { + apiName: 'registerPush', + success: (res?: any) => { + Push.disablePostNotificationInForeground(disableNotification); + // 强转下类型,避免类型推断错误 + let token: string = res as string; + onSuccess(token); + }, + fail: (errCode: number, errMsg: string) => { + onError?.(errCode, errMsg); + } + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.registerPush(context, SDKAppID.toInt(), appKey, new PushCallback(pushCbOptions)); +} + +export function setRegistrationID(registrationID: string, onSuccess: () => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'setRegistrationID', + success: (res?: any) => { + onSuccess(); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + } + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.setRegistrationID(registrationID, new PushCallback(pushCbOptions)); +} + +export function getRegistrationID(onSuccess: (registrationID: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'getRegistrationID', + success: (res?: any) => { + // 强转下类型,避免类型推断错误 + let registrationID: string = res as string; + onSuccess(registrationID); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + } + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.getRegistrationID(new PushCallback(pushCbOptions)); +} + +export function unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'unRegisterPush', + success: (res?: any) => { + onSuccess(); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + }, + }; + // 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误 + Push.unRegisterPush(new PushCallback(pushCbOptions)); +} + +export function createNotificationChannel(options: any, onSuccess: (extInfo: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'createNotificationChannel', + success: (res?: any) => { + let ret: string = res as string; + onSuccess(ret); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + }, + }; + Push.callExperimentalAPI('createNotificationChannel', JSON.stringify(options), new PushCallback(pushCbOptions)); +} + +export function getNotificationExtInfo(onSuccess: (extInfo: string) => void): void { + const pushCbOptions: PushCallbackOptions = { + apiName: 'getNotificationExtInfo', + success: (res?: any) => { + let ret: string = res as string; + onSuccess(ret); + }, + fail: (errCode: number, errMsg: string) => { + // 空实现 + }, + }; + Push.callExperimentalAPI('getNotificationExtInfo', null, new PushCallback(pushCbOptions)); +} + +const listenerMap = new Map void>>(); + +const pushListenerOptions: PushListenerOptions = { + listener: (eventName: string, data: any) => { + listenerMap.get(eventName)?.forEach(item => { + item(data); + }); + }, +}; + +const pushListener = new PushListener(pushListenerOptions); + +@UTSJS.keepAlive +export function addPushListener(eventName: string, listener: (res: any) => void): void { + if(listenerMap.size === 0) { + Push.addPushListener(pushListener); + } + const listeners:Array<(res: any) => void> = [listener]; + listenerMap.get(eventName)?.forEach(item => { + listeners.push(item); + }) + listenerMap.set(eventName, listeners); +} + + +export function removePushListener(eventName: string, listener?: (res: any) => void): void { + listenerMap.delete(eventName); + if(listenerMap.size === 0) { + Push.removePushListener(pushListener); + } +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts new file mode 100644 index 0000000..ab6f7bf --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback-options.uts @@ -0,0 +1,5 @@ +export type PushCallbackOptions = { + apiName: string + success: (res?: any) => void + fail: (errCode: number, errMsg: string) => void +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts new file mode 100644 index 0000000..32c9f57 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-callback.uts @@ -0,0 +1,28 @@ +import TIMPushCallback from 'com.tencent.qcloud.tim.push.TIMPushCallback'; +import { PushCallbackOptions } from './push-callback-options.uts'; + +const LOG_PREFIX: string = 'Push |'; +export default class PushCallback implements TIMPushCallback { + private apiName: string; + private success: (data?: any) => void; + private fail: (errCode: number, errMsg: string) => void; + + constructor(options: PushCallbackOptions) { + this.apiName = options.apiName; + this.success = options.success; + this.fail = options.fail; + } + + override onSuccess(data?: any) { + console.log(`${LOG_PREFIX} ${this.apiName} ok, data:`, data); + if (data == null) { + this.success?.(''); + } else { + this.success?.(data); + } + } + + override onError(errCode: Int, errMsg: string, data?: any) { + this.fail?.(errCode as number, errMsg); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts new file mode 100644 index 0000000..a155ba2 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener-options.uts @@ -0,0 +1,3 @@ +export type PushListenerOptions = { + listener: (eventType: string, data: any) => void +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts new file mode 100644 index 0000000..5c39c24 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-android/push-listener.uts @@ -0,0 +1,25 @@ +import TIMPushListener from 'com.tencent.qcloud.tim.push.TIMPushListener'; +import TIMPushMessage from 'com.tencent.qcloud.tim.push.TIMPushMessage'; +import { PushListenerOptions } from './push-listener-options.uts'; + +const LOG_PREFIX: string = 'Push | PushListener'; +export default class PushListener implements TIMPushListener { + private listener: (eventType: string, data: any) => void; + + constructor(options: PushListenerOptions) { + this.listener = options.listener; + console.log(`${LOG_PREFIX} ok`); + } + + override onRecvPushMessage(message: TIMPushMessage) { + this.listener('message_received', { data: message }); + } + + override onRevokePushMessage(messageID: string) { + this.listener('message_revoked', { data: messageID }); + } + + override onNotificationClicked(ext: string) { + this.listener('notification_clicked', { data: ext }); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements b/uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements new file mode 100644 index 0000000..903def2 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/UTS.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/config.json b/uni_modules/TencentCloud-Push/utssdk/app-ios/config.json new file mode 100644 index 0000000..f4b471d --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/config.json @@ -0,0 +1,11 @@ +{ + "deploymentTarget": "9.0", + "dependencies-pods": [ + { + "name": "TXIMSDK_Plus_iOS_XCFramework", + "version": "8.5.6864" + }, { + "name": "TIMPush", + "version": "8.5.6864" + }] +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts b/uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts new file mode 100644 index 0000000..0d58ad2 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts @@ -0,0 +1,125 @@ +import { TIMPushManager } from "TIMPush" +import { NSObject } from "DCloudUTSFoundation" +import PushListener from './push-listener.uts' +import { PushListenerOptions } from './push-listener-options.uts' + +const LOG_PREFIX = 'Push |'; + +export class EVENT { + static MESSAGE_RECEIVED: string = 'message_received' + static MESSAGE_REVOKED: string = 'message_revoked' + static NOTIFICATION_CLICKED: string = 'notification_clicked' +} + +function setRunningPlatform(): void { + console.log(LOG_PREFIX, 'setRunningPlatform'); + const param = new NSString("{\"runningPlatform\":2}"); + TIMPushManager.callExperimentalAPI('setPushConfig', param = param, succ = (ext?: NSObject): void => { + let platform: string = ext as string; + console.log(LOG_PREFIX, 'setRunningPlatform ok. platform:', platform); + }, fail = (code?: Int32 ,desc?:String): void => { + console.log(LOG_PREFIX, `setRunningPlatform fail. code: ${code}, desc: ${desc}`); + } + ); +} + +let disableNotification = false; + +export function disablePostNotificationInForeground(_disable: boolean): void { + console.log(LOG_PREFIX, 'disablePostNotificationInForeground', _disable); + disableNotification = _disable; + TIMPushManager.disablePostNotificationInForeground(disable = disableNotification); +} + +export function registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void { + if (SDKAppID == 0) { + onError?.(9010001, 'Invalid SDKAppID'); + } else if (appKey == '') { + onError?.(9010002, 'Invalid appKey'); + } + setRunningPlatform(); + TIMPushManager.registerPush(SDKAppID.toInt32(), appKey = appKey, succ = (deviceToken?: Data): void => { + TIMPushManager.disablePostNotificationInForeground(disable = disableNotification); + console.log('devicetoken ->', deviceToken, deviceToken?.count); + onSuccess(''); + }, fail = (code?: Int32 ,desc?:String): void => { + onError?.(code as number, desc as string); + } + ); +} + +export function unRegisterPush(onSuccess: () => void, onError: (errCode: number, errMsg: string) => void): void { + TIMPushManager.unRegisterPush((): void => { + onSuccess(); + }, fail = (code?: Int32 ,desc?:String): void => { + onError(code as number, desc as string); + } + ); +} + +export function setRegistrationID(registrationID: string, onSuccess: () => void): void { + console.log(LOG_PREFIX, 'setRegistrationID', `registrationID:${registrationID}`); + TIMPushManager.setRegistrationID(registrationID, callback = (): void => { + console.log(LOG_PREFIX, 'setRegistrationID ok'); + onSuccess(); + }); +} + +export function getRegistrationID(onSuccess: (registrationID: string) => void): void { + TIMPushManager.getRegistrationID((value ?: string): void => { + // 这里需要转一下,否则会有问题 + let ret: string = value as string; + onSuccess(ret); + }); +} + +export function createNotificationChannel(options: any, onSuccess: (data: string) => void): void { + // 空实现 +} + +// 注意!!!这里的 extInfo 不能写成 ext,否则会跟内部的 ext?:NSObject 有冲突;也不能写成 extension,否则会导致编译错误 +export function getNotificationExtInfo(onSuccess: (extInfo: string) => void): void { + console.log(LOG_PREFIX, 'getNotificationExtInfo'); + TIMPushManager.callExperimentalAPI('getNotificationExtInfo', param = {}, succ = (ext?: NSObject): void => { + let str: string = ext as string; + console.log(LOG_PREFIX, 'getNotificationExtInfo ok. ext:', str); + onSuccess(str); + }, fail = (code?: Int32 ,desc?:String): void => { + // 空实现 + } + ); +} + + +const listenerMap = new Map void>>(); + +const pushListenerOptions: PushListenerOptions = { + listener: (eventName: string, data: any) => { + listenerMap.get(eventName)?.forEach(item => { + item(data); + }); + }, +}; + +const pushListener = new PushListener(pushListenerOptions); + +@UTSJS.keepAlive +export function addPushListener(eventName: string, _listener: (res: any) => void): void { + console.log(LOG_PREFIX, 'addPushListener', eventName); + if(listenerMap.size === 0) { + TIMPushManager.addPushListener(listener = pushListener); + } + const listeners:Array<(res: any) => void> = [_listener]; + listenerMap.get(eventName)?.forEach(item => { + listeners.push(item); + }) + listenerMap.set(eventName, listeners); +} + +export function removePushListener(eventName: string, _listener?: (res: any) => void): void { + console.log(LOG_PREFIX, 'removePushListener', eventName); + listenerMap.delete(eventName); + if(listenerMap.size === 0) { + TIMPushManager.removePushListener(listener = pushListener); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts new file mode 100644 index 0000000..db8c8ff --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener-options.uts @@ -0,0 +1,3 @@ +export type PushListenerOptions = { + listener: (eventType: string, data: any) => void +} diff --git a/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts new file mode 100644 index 0000000..5e87c34 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/app-ios/push-listener.uts @@ -0,0 +1,24 @@ +import { TIMPushListener, TIMPushMessage} from "TIMPush" +import { PushListenerOptions } from './push-listener-options.uts'; + +const LOG_PREFIX: string = 'Push | PushListener'; +export default class PushListener implements TIMPushListener { + private listener: (eventType: string, data: any) => void; + + constructor(options: PushListenerOptions) { + this.listener = options.listener; + console.log(`${LOG_PREFIX} ok`); + } + + onRecvPushMessage(message: TIMPushMessage) { + this.listener('message_received', { data: message }); + } + + onRevokePushMessage(messageID: string) { + this.listener('message_revoked', { data: messageID }); + } + + onNotificationClicked(ext: string) { + this.listener('notification_clicked', { data: ext }); + } +} \ No newline at end of file diff --git a/uni_modules/TencentCloud-Push/utssdk/interface.uts b/uni_modules/TencentCloud-Push/utssdk/interface.uts new file mode 100644 index 0000000..ecf8da4 --- /dev/null +++ b/uni_modules/TencentCloud-Push/utssdk/interface.uts @@ -0,0 +1,11 @@ +interface Push { + setRegistrationID(registrationID: string, onSuccess: () => void): void, + registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void, + getRegistrationID(onSuccess: (registrationID: string) => void): void, + unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void, + getNotificationExtInfo(onSuccess: (extInfo: string) => void): void + addPushListener(eventName: string, listener: (res: any) => void): void + removePushListener(eventName: string, listener?: (res: any) => void): void + disablePostNotificationInForeground(disable: boolean): void + createNotificationChannel(options: any, onSuccess: (data: string) => void): void +} diff --git a/uni_modules/uni-combox/changelog.md b/uni_modules/uni-combox/changelog.md new file mode 100644 index 0000000..a9c0f2c --- /dev/null +++ b/uni_modules/uni-combox/changelog.md @@ -0,0 +1,17 @@ +## 1.0.2(2024-09-21) +- 新增 clearAble属性 +## 1.0.1(2021-11-23) +- 优化 label、label-width 属性 +## 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-combox](https://uniapp.dcloud.io/component/uniui/uni-combox) +## 0.1.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.0.6(2021-05-12) +- 新增 组件示例地址 +## 0.0.5(2021-04-21) +- 优化 添加依赖 uni-icons, 导入后自动下载依赖 +## 0.0.4(2021-02-05) +- 优化 组件引用关系,通过uni_modules引用组件 +## 0.0.3(2021-02-04) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-combox/components/uni-combox/uni-combox.vue b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue new file mode 100644 index 0000000..cc702c2 --- /dev/null +++ b/uni_modules/uni-combox/components/uni-combox/uni-combox.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/uni_modules/uni-combox/package.json b/uni_modules/uni-combox/package.json new file mode 100644 index 0000000..7af24fc --- /dev/null +++ b/uni_modules/uni-combox/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-combox", + "displayName": "uni-combox 组合框", + "version": "1.0.2", + "description": "可以选择也可以输入的表单项 ", + "keywords": [ + "uni-ui", + "uniui", + "combox", + "组合框", + "select" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "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" + }, + "uni_modules": { + "dependencies": [ + "uni-scss", + "uni-icons" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "n" + }, + "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-combox/readme.md b/uni_modules/uni-combox/readme.md new file mode 100644 index 0000000..ffa2cc8 --- /dev/null +++ b/uni_modules/uni-combox/readme.md @@ -0,0 +1,11 @@ + + +## Combox 组合框 +> **组件名:uni-combox** +> 代码块: `uCombox` + + +组合框组件。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-data-checkbox/changelog.md b/uni_modules/uni-data-checkbox/changelog.md new file mode 100644 index 0000000..7c99f6c --- /dev/null +++ b/uni_modules/uni-data-checkbox/changelog.md @@ -0,0 +1,51 @@ +## 1.0.6(2024-10-22) +- 新增 当 multiple 为 false 且传递的 value 为 数组时,使用数组第一项用作反显 +## 1.0.5(2024-03-20) +- 修复 单选模式下选中样式不生效的bug +## 1.0.4(2024-01-27) +- 修复 修复错别字chagne为change +## 1.0.3(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 1.0.2(2022-06-30) +- 优化 在 uni-forms 中的依赖注入方式 +## 1.0.1(2022-02-07) +- 修复 multiple 为 true 时,v-model 的值为 null 报错的 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-data-checkbox](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox) +## 0.2.5(2021-08-23) +- 修复 在uni-forms中 modelValue 中不存在当前字段,当前字段必填写也不参与校验的问题 +## 0.2.4(2021-08-17) +- 修复 单选 list 模式下 ,icon 为 left 时,选中图标不显示的问题 +## 0.2.3(2021-08-11) +- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题 +## 0.2.2(2021-07-30) +- 优化 在uni-forms组件,与label不对齐的问题 +## 0.2.1(2021-07-27) +- 修复 单选默认值为0不能选中的Bug +## 0.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.1.11(2021-07-06) +- 优化 删除无用日志 +## 0.1.10(2021-07-05) +- 修复 由 0.1.9 引起的非 nvue 端图标不显示的问题 +## 0.1.9(2021-07-05) +- 修复 nvue 黑框样式问题 +## 0.1.8(2021-06-28) +- 修复 selectedTextColor 属性不生效的Bug +## 0.1.7(2021-06-02) +- 新增 map 属性,可以方便映射text/value属性 +## 0.1.6(2021-05-26) +- 修复 不关联服务空间的情况下组件报错的Bug +## 0.1.5(2021-05-12) +- 新增 组件示例地址 +## 0.1.4(2021-04-09) +- 修复 nvue 下无法选中的问题 +## 0.1.3(2021-03-22) +- 新增 disabled属性 +## 0.1.2(2021-02-24) +- 优化 默认颜色显示 +## 0.1.1(2021-02-24) +- 新增 支持nvue +## 0.1.0(2021-02-18) +- “暂无数据”显示居中 diff --git a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js new file mode 100644 index 0000000..9a44a9e --- /dev/null +++ b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/clientdb.js @@ -0,0 +1,316 @@ + +const events = { + load: 'load', + error: 'error' +} +const pageMode = { + add: 'add', + replace: 'replace' +} + +const attrs = [ + 'pageCurrent', + 'pageSize', + 'collection', + 'action', + 'field', + 'getcount', + 'orderby', + 'where' +] + +export default { + data() { + return { + loading: false, + listData: this.getone ? {} : [], + paginationInternal: { + current: this.pageCurrent, + size: this.pageSize, + count: 0 + }, + errorMessage: '' + } + }, + created() { + let db = null; + let dbCmd = null; + + if(this.collection){ + this.db = uniCloud.database(); + this.dbCmd = this.db.command; + } + + this._isEnded = false + + this.$watch(() => { + let al = [] + attrs.forEach(key => { + al.push(this[key]) + }) + return al + }, (newValue, oldValue) => { + this.paginationInternal.pageSize = this.pageSize + + let needReset = false + for (let i = 2; i < newValue.length; i++) { + if (newValue[i] != oldValue[i]) { + needReset = true + break + } + } + if (needReset) { + this.clear() + this.reset() + } + if (newValue[0] != oldValue[0]) { + this.paginationInternal.current = this.pageCurrent + } + + this._execLoadData() + }) + + // #ifdef H5 + if (process.env.NODE_ENV === 'development') { + this._debugDataList = [] + if (!window.unidev) { + window.unidev = { + clientDB: { + data: [] + } + } + } + unidev.clientDB.data.push(this._debugDataList) + } + // #endif + + // #ifdef MP-TOUTIAO + let changeName + let events = this.$scope.dataset.eventOpts + for (let i = 0; i < events.length; i++) { + let event = events[i] + if (event[0].includes('^load')) { + changeName = event[1][0][0] + } + } + if (changeName) { + let parent = this.$parent + let maxDepth = 16 + this._changeDataFunction = null + while (parent && maxDepth > 0) { + let fun = parent[changeName] + if (fun && typeof fun === 'function') { + this._changeDataFunction = fun + maxDepth = 0 + break + } + parent = parent.$parent + maxDepth--; + } + } + // #endif + + // if (!this.manual) { + // this.loadData() + // } + }, + // #ifdef H5 + beforeDestroy() { + if (process.env.NODE_ENV === 'development' && window.unidev) { + let cd = this._debugDataList + let dl = unidev.clientDB.data + for (let i = dl.length - 1; i >= 0; i--) { + if (dl[i] === cd) { + dl.splice(i, 1) + break + } + } + } + }, + // #endif + methods: { + loadData(args1, args2) { + let callback = null + if (typeof args1 === 'object') { + if (args1.clear) { + this.clear() + this.reset() + } + if (args1.current !== undefined) { + this.paginationInternal.current = args1.current + } + if (typeof args2 === 'function') { + callback = args2 + } + } else if (typeof args1 === 'function') { + callback = args1 + } + + this._execLoadData(callback) + }, + loadMore() { + if (this._isEnded) { + return + } + this._execLoadData() + }, + refresh() { + this.clear() + this._execLoadData() + }, + clear() { + this._isEnded = false + this.listData = [] + }, + reset() { + this.paginationInternal.current = 1 + }, + remove(id, { + action, + callback, + confirmTitle, + confirmContent + } = {}) { + if (!id || !id.length) { + return + } + uni.showModal({ + title: confirmTitle || '提示', + content: confirmContent || '是否删除该数据', + showCancel: true, + success: (res) => { + if (!res.confirm) { + return + } + this._execRemove(id, action, callback) + } + }) + }, + _execLoadData(callback) { + if (this.loading) { + return + } + this.loading = true + this.errorMessage = '' + + this._getExec().then((res) => { + this.loading = false + const { + data, + count + } = res.result + this._isEnded = data.length < this.pageSize + + callback && callback(data, this._isEnded) + this._dispatchEvent(events.load, data) + + if (this.getone) { + this.listData = data.length ? data[0] : undefined + } else if (this.pageData === pageMode.add) { + this.listData.push(...data) + if (this.listData.length) { + this.paginationInternal.current++ + } + } else if (this.pageData === pageMode.replace) { + this.listData = data + this.paginationInternal.count = count + } + + // #ifdef H5 + if (process.env.NODE_ENV === 'development') { + this._debugDataList.length = 0 + this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData))) + } + // #endif + }).catch((err) => { + this.loading = false + this.errorMessage = err + callback && callback() + this.$emit(events.error, err) + }) + }, + _getExec() { + let exec = this.db + if (this.action) { + exec = exec.action(this.action) + } + + exec = exec.collection(this.collection) + + if (!(!this.where || !Object.keys(this.where).length)) { + exec = exec.where(this.where) + } + if (this.field) { + exec = exec.field(this.field) + } + if (this.orderby) { + exec = exec.orderBy(this.orderby) + } + + const { + current, + size + } = this.paginationInternal + exec = exec.skip(size * (current - 1)).limit(size).get({ + getCount: this.getcount + }) + + return exec + }, + _execRemove(id, action, callback) { + if (!this.collection || !id) { + return + } + + const ids = Array.isArray(id) ? id : [id] + if (!ids.length) { + return + } + + uni.showLoading({ + mask: true + }) + + let exec = this.db + if (action) { + exec = exec.action(action) + } + + exec.collection(this.collection).where({ + _id: dbCmd.in(ids) + }).remove().then((res) => { + callback && callback(res.result) + if (this.pageData === pageMode.replace) { + this.refresh() + } else { + this.removeData(ids) + } + }).catch((err) => { + uni.showModal({ + content: err.message, + showCancel: false + }) + }).finally(() => { + uni.hideLoading() + }) + }, + removeData(ids) { + let il = ids.slice(0) + let dl = this.listData + for (let i = dl.length - 1; i >= 0; i--) { + let index = il.indexOf(dl[i]._id) + if (index >= 0) { + dl.splice(i, 1) + il.splice(index, 1) + } + } + }, + _dispatchEvent(type, data) { + if (this._changeDataFunction) { + this._changeDataFunction(data, this._isEnded) + } else { + this.$emit(type, data, this._isEnded) + } + } + } +} diff --git a/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue new file mode 100644 index 0000000..4da7bbe --- /dev/null +++ b/uni_modules/uni-data-checkbox/components/uni-data-checkbox/uni-data-checkbox.vue @@ -0,0 +1,853 @@ + + + + + diff --git a/uni_modules/uni-data-checkbox/package.json b/uni_modules/uni-data-checkbox/package.json new file mode 100644 index 0000000..f823e8b --- /dev/null +++ b/uni_modules/uni-data-checkbox/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-data-checkbox", + "displayName": "uni-data-checkbox 数据选择器", + "version": "1.0.6", + "description": "通过数据驱动的单选框和复选框", + "keywords": [ + "uni-ui", + "checkbox", + "单选", + "多选", + "单选多选" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.1" + }, + "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" + }, + "uni_modules": { + "dependencies": ["uni-load-more","uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "n" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-harmony": "u", + "app-uvue": "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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-data-checkbox/readme.md b/uni_modules/uni-data-checkbox/readme.md new file mode 100644 index 0000000..6eb253d --- /dev/null +++ b/uni_modules/uni-data-checkbox/readme.md @@ -0,0 +1,18 @@ + + +## DataCheckbox 数据驱动的单选复选框 +> **组件名:uni-data-checkbox** +> 代码块: `uDataCheckbox` + + +本组件是基于uni-app基础组件checkbox的封装。本组件要解决问题包括: + +1. 数据绑定型组件:给本组件绑定一个data,会自动渲染一组候选内容。再以往,开发者需要编写不少代码实现类似功能 +2. 自动的表单校验:组件绑定了data,且符合[uni-forms](https://ext.dcloud.net.cn/plugin?id=2773)组件的表单校验规范,搭配使用会自动实现表单校验 +3. 本组件合并了单选多选 +4. 本组件有若干风格选择,如普通的单选多选框、并列button风格、tag风格。开发者可以快速选择需要的风格。但作为一个封装组件,样式代码虽然不用自己写了,却会牺牲一定的样式自定义性 + +在uniCloud开发中,`DB Schema`中配置了enum枚举等类型后,在web控制台的[自动生成表单](https://uniapp.dcloud.io/uniCloud/schema?id=autocode)功能中,会自动生成``uni-data-checkbox``组件并绑定好data + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-checkbox) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/utils/media.js b/utils/media.js new file mode 100644 index 0000000..60ed82d --- /dev/null +++ b/utils/media.js @@ -0,0 +1,45 @@ +/** + * 封装 uni.chooseImage,返回 Promise,便于 async/await 使用 + * @param {Object} options - 透传给 uni.chooseImage 的配置 + * @returns {Promise>} 返回选中的临时图片路径数组 + */ +export function chooseImage(options = {}) { + // 默认配置 + const defaultOptions = { + count: 1, + sourceType: ['album', 'camera'], + ...options + } + + return new Promise((resolve, reject) => { + uni.chooseImage({ + ...defaultOptions, + success(res) { + if (res.tempFilePaths && res.tempFilePaths.length > 0) { + resolve(res.tempFilePaths) + } else { + reject(new Error('未选择任何图片')) + } + }, + fail(err) { + // 统一错误处理(如权限被拒、用户取消等) + let msg = '选择图片失败' + if (err.errMsg.includes('cancel')) { + msg = '用户取消选择' + } else if ( + err.errMsg.includes('auth deny') || + err.errMsg.includes('permission') + ) { + msg = '请在设置中开启相册或相机权限' + } + // 可选:自动弹出 toast 提示 + uni.showToast({ + title: msg, + icon: 'none', + duration: 2000 + }) + reject(new Error(msg)) + } + }) + }) +} diff --git a/utils/uploadFile.js b/utils/uploadFile.js index 6cd0d2d..a07bd5f 100644 --- a/utils/uploadFile.js +++ b/utils/uploadFile.js @@ -132,3 +132,4 @@ export const uploadMultipleFiles = (filePaths, config = {}) => { ) return Promise.all(uploadPromises) } + diff --git a/utils/use-ui.js b/utils/use-ui.js index 691494d..baa543c 100644 --- a/utils/use-ui.js +++ b/utils/use-ui.js @@ -31,7 +31,7 @@ const hideLoading = () => { * @param {string} type - 'success' | 'error' | 'warning' | 'none' * @param {number} duration - 持续时间(毫秒) */ -const showToast = (message, type = 'none', duration = 2000) => { +const showToast = (message, type = 'none', duration = 1800) => { let icon = 'none' if (type === 'success') icon = 'success' if (type === 'error') icon = 'error' diff --git a/vue.config.js b/vue.config.js new file mode 100644 index 0000000..6ceaea9 --- /dev/null +++ b/vue.config.js @@ -0,0 +1,15 @@ +const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default; +module.exports = { + parallel: false, + configureWebpack: { + plugins: [ + ScriptSetup({ + /* options */ + }), + ], + }, + chainWebpack(config) { + // disable type check and let `vue-tsc` handles it + config.plugins.delete('fork-ts-checker'); + }, +};