初始化项目

This commit is contained in:
考拉
2025-09-12 21:32:12 +08:00
commit bdfa64c482
651 changed files with 110673 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
/.hbuilderx/
/node_modules/
/unpackage/dist/
/package-lock.json
/unpackage/release/
/unpackage/cache/
/json/
/unpackage/debug/

191
App.vue Normal file
View File

@@ -0,0 +1,191 @@
<script>
import {
version,
name
} from './package.json'
import {
versionName
} from '@/manifest.json'
import consoleImgs from '@/common/consoleImgs.js'
// #ifdef APP-PLUS
import appUpgrade from '@/common/appUpgrade.js';
const TUICalling = uni.requireNativePlugin("TUICallingUniPlugin-TUICallingModule");
// #endif
export default {
onLaunch: function() {
// #ifdef H5
console.log(
`%c 考拉Team ${name} %c v${version} `,
'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
'background:#007aff ;padding: 1px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;'
)
console.log(consoleImgs.fz)
// todo 下列两行
uni.setStorageSync('device', 'H5');
uni.setStorageSync('version', versionName);
this.$http.request({
url: '/common/getVersion',
success: (res) => {
if(res.data.data.upgrade=='Y'){
console.log(
`%c 有新版本 `+res.data.data.version,
'background:#007aff ;padding: 1px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;'
)
}
}
});
// #endif
console.log('App Launch')
let token= uni.getStorageSync('Authorization');
if (!token) {
//不存在则跳转至登录页
// #ifdef APP-PLUS
plus.navigator.closeSplashscreen();
// #endif
} else {
this.$store.dispatch('get_UserInfo').then(res=>{
// #ifdef APP-PLUS
var nickName=res.nickName
var portrait=res.portrait
this.$http.request({
url: '/trtc/getSign',
success: (res) => {
var sdkAppID=res.data.data.appId
var userID=res.data.data.userId
var userSig=res.data.data.sign
TUICalling.login({//登录音视频
sdkAppID: sdkAppID,
userID: userID,
userSig: userSig
},(res) => {
console.log('音视频登录成功')
TUICalling.setUserNickname({
nickName: nickName
})
TUICalling.setUserAvatar({
avatar: portrait
})
plus.io.requestFileSystem(plus.io.PRIVATE_WWW, function(fs) {
fs.root.getFile('/static/longcall.mp3', {
create: false
}, function(fileEntry) {
fileEntry.file(function(file) {
TUICalling.setCallingBell({
ringtone: file.fullPath
},(res) => {
console.log(JSON.stringify(res))
})
});
});
});
})
}
});
this.$http.request({
url: '/my/refresh',
success: (res) => {}
});
// #endif
this.$socketTask.connectSocket()
})
uni.reLaunch({
url: "wx/tabbar1/index",
}).then(res=>{
// #ifdef APP-PLUS
plus.navigator.closeSplashscreen();
// #endif
})
}
// #ifdef APP-PLUS
//升级检测
uni.getSystemInfo({
success: (res)=> {
uni.setStorageSync('device', res.platform);
plus.runtime.getProperty(plus.runtime.appid, (widgetInfo)=> {
uni.setStorageSync('version', widgetInfo.version);
this.$http.request({
url: '/common/getVersion',
success: (res) => {
if(res.data.data.upgrade=='Y'){
appUpgrade.init({
titleText: '版本更新'+res.data.data.version,
packageUrl:res.data.data.url,
content: res.data.data.content,
forceUpgrade:res.data.data.forceUpgrade=='Y' ? true : false
});
appUpgrade.show();
}
}
});
});
}
});
uni.onNetworkStatusChange( (res)=> {
if(res.isConnected){
this.$store.dispatch('get_UserInfo')
}
});
// #endif
},
onShow: function() {
console.log('App Show')
uni.getStorage({
key: 'call',
success: (res) => {
var callx=res.data
if(callx){
var call=JSON.parse(callx)
function getInervalHour(startDate) {//获取两个时间之间的小时
if (!startDate) {
return '0秒'
}
var ms = new Date().getTime() - startDate;
if (ms < 0) return '0秒';
if((ms/1000)<60){
return Math.floor(ms / 1000)+'';
}else{
return Math.floor(ms / 1000 /60)+'';
}
}
var msgType=''
if(call.type=='audio'){
msgType='TRTC_VOICE_END'
}
if(call.type=='video'){
msgType='TRTC_VIDEO_END'
}
this.$fc.pushOutMsg({
msgContent:getInervalHour(call.startTime),
msgType:msgType,
windowType:'SINGLE',
userId:call.userId,
})
uni.removeStorageSync('call')
}
}
});
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
/*每个页面公共css */
@import '@/uni_modules/uni-scss/index.scss';
@import "@/static/styles/animation.css";
/* #ifndef APP-NVUE */
@import '@/static/customicons.css';
// 设置整个项目的背景色
page {
box-sizing: border-box;
}
/* #endif */
// 以下内容最好转移到单页
</style>

373
LICENSE Normal file
View File

@@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

43
README.md Normal file
View File

@@ -0,0 +1,43 @@
# chat-uniapp微聊
```
基于uniapp的即时通讯app客户端支持iOS与Android双系统打包运行
```
## 项目说明
+ 一直以来都有一个社交梦想做一款IM应用看了很多优秀的开源项目但是没有合适自己的。于是利用休息时间自己写了这么一套系统。
+ 项目第一个版本历时2个月前端使用`uniapp`,后端使用`SpringBoot`
+ 手机端使用`uniapp`实现,目前仅支持`安卓端``iOS端``H5端`
## 技术使用
+ 推送uniPush + websocket
+ 资源阿里OSS图片、声音、视频、文件等
+ 音视频TRTC
+ 地图:高德地图
+ 后端Hutool、MyBatis-Plus、shiro、sharding-jdbc等
+ 前端uniapp(Vue3)
## 演示效果
<img src="https://img.alicdn.com/imgextra/i3/87413133/O1CN01bZSz2q1Z0xco96F1t_!!87413133.jpg" width="200">
<img src="https://img.alicdn.com/imgextra/i3/87413133/O1CN01Pe8G6S1Z0xcmQluDI_!!87413133.jpg" width="200">
<img src="https://img.alicdn.com/imgextra/i1/87413133/O1CN012JP8VW1Z0xccuWKzM_!!87413133.jpg" width="200">
<img src="https://img.alicdn.com/imgextra/i4/87413133/O1CN01fMUNJA1Z0xck1w0kt_!!87413133.jpg" width="200">
<img src="https://img.alicdn.com/imgextra/i3/87413133/O1CN01n8MZhZ1Z0xctYZEbM_!!87413133.jpg" width="200">
## 传送门
+ 您的支持,就是我们`【生发的动力】`,请手动点个`star`吧。
+ chat-flutter
[https://github.com/lakaola/chat-flutter](https://github.com/lakaola/chat-flutter)
[https://gitee.com/lakaola/chat-flutter](https://gitee.com/lakaola/chat-flutter)
+ chat-uniapp
[https://github.com/lakaola/chat-uniapp](https://github.com/lakaola/chat-uniapp)
[https://gitee.com/lakaola/chat-uniapp](https://gitee.com/lakaola/chat-uniapp)
+ chat-api
[https://github.com/lakaola/chat-api](https://github.com/lakaola/chat-api)
[https://gitee.com/lakaola/chat-api](https://gitee.com/lakaola/chat-api)
+ 加入QQ群[![加入QQ群](https://img.shields.io/badge/加入QQ群-535099683-blue.svg)](https://jq.qq.com/?_wv=1027&k=PQMnFugm) 详细文档进群获取535099683

13
androidPrivacy.json Normal file
View File

@@ -0,0 +1,13 @@
{
"version" : "1.0.0",
"prompt" : "template",
"title" : "隐私政策及服务协议",
"message" : "请你务必审慎阅读、充分理解“服务协议”和“隐私政策”各条款,为了更好的向你提供服务,我们需要收集你的设备标识、等信息用于登录及消息推送。<br/>  你可阅读<a href=\"http://im.q3z3.com/public/am.html\">《隐私及服务协议》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
"buttonAccept" : "同意并接受",
"buttonRefuse" : "暂不同意",
"hrefLoader" : "system|default",
"disagreeMode" : {
"support" : false,
"loadNativePlugins" : true
}
}

213
common/appUpgrade.js Normal file
View File

@@ -0,0 +1,213 @@
var _maskView, _contentView, _downloadTask, _loadingProgress, _screenHeight, _screenWidth, _config = {
forceUpgrade: false,
titleText: "版本更新",
content: "",
contentAlign: "left",
loadingColor: "#329EEE",
cancelText: "暂不升级",
cancelColor: "#666",
confirmText: "立即升级",
confirmColor: "#329EEE",
windowHeight: 380,
packageUrl: "",
browser: false,
maskColor: "rgba(0,0,0,0.3)"
},
_calculatePosition = function() {
return {
top: (_screenHeight - _config.windowHeight) / 2,
left: _screenWidth * .05,
width: _screenWidth * .9,
right: _screenWidth * .05,
height: _config.windowHeight
}
},
_createMask = function() {
_maskView = new plus.nativeObj.View("maskView", {
top: "0px",
left: "0px",
width: "100%",
height: "100%",
backgroundColor: _config.maskColor
})
},
_createContentView = function() {
var calculatePosition = _calculatePosition();
_contentView = new plus.nativeObj.View("contentView", {
top: calculatePosition.top + "px",
left: calculatePosition.left + "px",
height: _config.windowHeight + "px",
width: calculatePosition.width + "px",
overflow: "auto"
});
_contentView.drawRect({
color: "#ffffff",
radius: "20px"
}, {
width: "100%",
height: "100%"
}, "roundedRect");
_contentView.drawText(_config.titleText, {
top: "20px",
height: "20px",
}, {
size: "16px",
color: "#333",
align: "center",
}, "titleText");
_contentView.drawText(_config.content, {
top: "60px",
left: "20px",
right: "20px",
height: _config.windowHeight - 120 + "px",
}, {
size: "16px",
color: "#666",
align: _config.contentAlign,
verticalAlign: "top",
whiteSpace: "normal",
overflow: "ellipsis"
}, "UpdaterContent");
_createLoading(-2);
var top = _config.windowHeight - 60 + 15;
var fontSize = '16px';
if (!_config.forceUpgrade) {
_contentView.drawRichText("<font style=\"font-size:" + fontSize + ";\" color=\"" + _config.cancelColor +
"\">" + _config
.cancelText + "</font>", {
width: "50%",
top: top + "px",
left: "0px"
}, {
align: "center",
onClick: function() {
close()
}
}, "cancel");
_contentView.drawRichText("<font color=\"" + _config.confirmColor +
"\" style=\"font-size:" + fontSize + ";\">" +
_config.confirmText + "</font>", {
width: "50%",
right: "0px",
top: top + "px"
}, {
align: "center",
onClick: function() {
_config.packageUrl ? "android" === plus.os.name.toLowerCase() ? _config.browser ? (plus
.runtime.openURL(_config.packageUrl)) : _createTask() : plus.runtime.openURL(
_config.packageUrl) : uni.showToast({
title: "安装包地址为空",
icon: "none"
})
}
}, "submit")
} else {
_contentView.drawRichText("<font color=\"" + _config.confirmColor + "\" style=\"font-size:" + fontSize +
";\">" +
_config.confirmText + "</font>", {
width: "100%",
right: "0px",
top: top + "px"
}, {
align: "center",
onClick: function() {
_config.packageUrl ? "android" === plus.os.name.toLowerCase() ? _config.browser ? (plus
.runtime.openURL(_config.packageUrl)) : _createTask() : plus.runtime.openURL(
_config.packageUrl) : uni.showToast({
title: "安装包地址为空",
icon: "none"
})
}
}, "submit")
}
},
_createLoading = function(progress) {
var calculatePosition = _calculatePosition();
var top = _config.windowHeight - 65;
var width = 0 <= progress ? (calculatePosition.width - 100) / 100 * progress : 0;
width = parseInt(width);
var text = 100 <= progress ? "下载完成" : "下载中...";
var loadingText = "";
loadingText = -1 == progress ? "资源加载中..." : 0 <= progress ? text + "(" + progress + "%)" : "";
_contentView.drawRect({
color: _config.loadingColor
}, {
width: width + "px",
height: "3px",
left: "20px",
top: top + "px"
}, "loading");
_contentView.drawRichText("<font color=\"" + _config.loadingColor + "\">" + loadingText + "</font>", {
width: "100px",
top: top + "px",
left: width + "px"
}, {
align: "center"
}, "loadingText")
},
_createTask = function() {
return _downloadTask ? void console.log("正在下载中") : void(_createLoading(-1),
_downloadTask =
uni.downloadFile({
url: _config.packageUrl,
success: function(res) {
if (200 === res.statusCode) {
var tempFilePath = res.tempFilePath;
uni.saveFile({
tempFilePath: tempFilePath,
success: function(res) {
plus.runtime.install(res.savedFilePath, {
force: true
}, function(res) {
console.log('安装包信息' + JSON.stringify(res))
}, function(res) {
uni.showToast({
title: '安装失败,请检查下载链接',
icon: 'none',
duration: 3000
});
});
close();
}
})
}
}
}), _downloadTask.onProgressUpdate(function(res) {
_loadingProgress != res.progress && (_loadingProgress = res.progress, _createLoading(res
.progress));
}))
},
init = function(option) {
_screenHeight = plus.screen.resolutionHeight;
_screenWidth = plus.screen.resolutionWidth;
_downloadTask = null;
option.titleText && (_config.titleText = option.titleText);
option.windowHeight && (_config.windowHeight = option.windowHeight);
option.forceUpgrade && (_config.forceUpgrade = option.forceUpgrade);
option.content && (_config.content = option.content);
option.contentAlign && (_config.contentAlign = option.contentAlign);
option.loadingColor && (_config.loadingColor = option.loadingColor);
option.cancelText && (_config.cancelText = option.cancelText);
option.cancelColor && (_config.cancelColor = option.cancelColor);
option.confirmText && (_config.confirmText = option.confirmText);
option.confirmColor && (_config.confirmColor = option.confirmColor);
option.packageUrl && (_config.packageUrl = option.packageUrl);
option.browser && (_config.browser = option.browser);
option.maskColor && (_config.maskColor = option.maskColor);
_createMask();
_createContentView();
},
show = function() {
_maskView && _maskView.show();
_contentView && _contentView.show();
},
close = function() {
_downloadTask && (_downloadTask.abort(), _downloadTask = null, _createLoading(-2));
_maskView && _maskView.hide();
_contentView && _contentView.hide();
};
export default {
init: init,
show: show,
close: close
}

210
common/browser.js Normal file
View File

@@ -0,0 +1,210 @@
export default {
init: function(options) {
this.initWebview(options)
this.handleEvent()
return this
},
initWebview: function(options) {
var hh=plus.screen.height-44
var _self = this
_self.webview = plus.webview.create('', 'browser', {
scalable:true,
height:hh+'px',
bottom:'44px',
background:'#ff5500',
titleNView: {
backgroundColor: '#FFFFFF',
progress: { //进度条
color: '#4678e7',
height: '3px'
},
splitLine: { //底部分割线
color: '#cccccc',
height: '1px'
},
buttons: [{ //关闭按钮
'float': 'left',
fontSrc: '/static/uni.ttf',
text: '\ue460',
onclick: _self.close.bind(_self)
}, { //更多按钮
'float': 'right',
fontSrc: '/static/uni.ttf',
text: '\ue507',
onclick: _self.more.bind(_self)
}]
},
additionalHttpHeaders: options.headers || {}
})
// 配置下拉刷新
_self.webview.setPullToRefresh({
support: true
}, function() {
_self.reload()
var titleUpdate = function() {
setTimeout(function() {
_self.webview.endPullToRefresh()
_self.webview.removeEventListener('titleUpdate', titleUpdate)
}, 300)
};
_self.webview.addEventListener('titleUpdate', titleUpdate)
})
//绘制返回前进按钮
this.navBottom = new plus.nativeObj.View("navBottom", {
bottom: '0px',
left: '0px',
height: '44px',
width: '100%',
backgroundColor: 'rgb(255,255,255)'
})
var screenWidth = plus.screen.resolutionWidth
var left = screenWidth / 4
this.navBottom.draw([{
tag: 'font',
id: 'back',
text: '\ue471',
textStyles: {
fontSrc: '/static/uni.ttf',
size: '24px',
color: '#000000'
},
position: {
right: left+48,
height: '100%',
}
},
{
tag: 'font',
id: 'forward',
text: '\ue470',
textStyles: {
fontSrc: '/static/uni.ttf',
size: '24px',
color: '#000000'
},
position: {
left: left,
height: '100%',
}
}
])
//点击前进或后退
this.navBottom.addEventListener("click", (e) => {
if (e.clientX > left && e.clientX < (left + 24)) {
_self.back()
}
if (e.clientX > (screenWidth - left - 12) && e.clientX < (screenWidth - left + 12)) {
_self.forward()
}
})
//监听页面变化
_self.webview.addEventListener('loaded', function() {
_self.webview.canBack(function(event) {
var canBack = false
if (event.canBack) {
canBack = true
_self.navBottom.show()
} else {
canBack = false
}
_self.webview.canForward(function(event) {
if (event.canForward) {
_self.navBottom.drawText('\ue470', {
left: left,
height: '100%'
}, {
color: '#000000',
fontSrc: '/static/uni.ttf',
size: '24px'
}, 'forward')
} else {
_self.navBottom.drawText('\ue470', {
left: left,
height: '100%'
}, {
color: '#EEEEEE',
fontSrc: '/static/uni.ttf',
size: '24px'
}, 'forward')
}
if (!canBack && !event.canForward) {
// _self.navBottom.hide()
}
})
})
_self.navBottom.show()
}, false)
},
handleEvent: function(url) {
var _self = this
plus.key.addEventListener('backbutton', function() {
_self.close()
return
var topWebview = plus.webview.getTopWebview()
// 不等于浏览器窗口
if (topWebview.id !== 'browser') {
// 这里除了浏览器窗口就是首页了,直接退出了;
plus.runtime.quit()
} else {
_self.back()
}
})
},
show: function(url) {
url = url || 'https://www.baidu.com'
this.webview.loadURL(url)
this.webview.show('slide-in-right')
},
more: function() {
var _self = this
uni.showActionSheet({
itemList: ['刷新', '浏览器打开'],
success: function(res) {
if (res.tapIndex == 0) {
_self.reload()
} else if (res.tapIndex == 1) {
plus.runtime.openURL(_self.webview.getURL())
}
}
})
},
reload: function() {
// 刷新
this.webview.reload(true)
},
back: function() {
//后退
var _self = this
_self.webview.canBack(function(event) {
if (event.canBack) {
_self.webview.back()
} else {
_self.close()
}
})
},
forward: function() {
//前进
var _self = this
_self.webview.canForward(function(event) {
if (event.canForward) {
_self.webview.forward();
} else {
plus.nativeUI.toast('没有可前进的地址')
}
})
},
close: function() {
//关闭
// this.navBottom.hide()
this.navBottom.close()
this.navBottom=null;
this.webview.close('browser', 'slide-out-right')
this.webview.clear()
plus.key.removeEventListener("backbutton", function() {
});
}
}

30165
common/city.js Normal file

File diff suppressed because it is too large Load Diff

3
common/consoleImgs.js Normal file
View File

@@ -0,0 +1,3 @@
export default {
fz:' ......................阿弥陀佛......................\n' + ' _oo0oo_ \n' + ' o8888888o \n' + ' 88" . "88 \n' + ' (| -_- |) \n' + ' 0\\ = /0 \n' + ' ___/---\\___ \n' + " .' \\| |/ '. \n" + ' / \\\\||| : |||// \\ \n' + ' / _||||| -卍-|||||_ \\ \n' + ' | | \\\\\\ - /// | | \n' + " | \\_| ''\\---/'' |_/ | \n" + " \\ .-\\__ '-' ___/-. / \n" + " ___'. .' /--.--\\ '. .'___ \n" + ' ."" < .___\\_<|>_/___.> "". \n' + ' | | : - \\.;\\ _ /;./ - : | | \n' + ' \\ \\ _. \\_ __\\ /__ _/ .- / / \n' + ' =====-.____.___ \\_____/___.-___.-===== \n' + ' =---= \n' + ' \n' + '....................佛祖保佑 ,永无BUG...................'
}

259
common/md5.js Normal file
View File

@@ -0,0 +1,259 @@
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*/
/*
* Configurable variables. You may need to tweak these to be compatible with
* the server-side, but the defaults work in most cases.
*/
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
/*
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
/*
* Perform a simple self-test to see if the VM is working
*/
function md5_vm_test()
{
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length
*/
function core_md5(x, len)
{
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5_cmn(q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
/*
* Calculate the HMAC-MD5, of a key and some data
*/
function core_hmac_md5(key, data)
{
var bkey = str2binl(key);
if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
return core_md5(opad.concat(hash), 512 + 128);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Convert a string to an array of little-endian words
* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*/
function str2binl(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
return bin;
}
/*
* Convert an array of little-endian words to a string
*/
function binl2str(bin)
{
var str = "";
var mask = (1 << chrsz) - 1;
for(var i = 0; i < bin.length * 32; i += chrsz)
str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
return str;
}
/*
* Convert an array of little-endian words to a hex string.
*/
function binl2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
}
/*
* Convert an array of little-endian words to a base-64 string
*/
function binl2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
export default {
hex_md5
}

245
common/permission.js Normal file
View File

@@ -0,0 +1,245 @@
/// null = 未请求1 = 已允许0 = 拒绝|受限, 2 = 系统未开启
var isIOS
function album() {
var result = 0;
var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
var authStatus = PHPhotoLibrary.authorizationStatus();
if (authStatus === 0) {
result = null;
} else if (authStatus == 3) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(PHPhotoLibrary);
return result;
}
function camera() {
var result = 0;
var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
if (authStatus === 0) {
result = null;
} else if (authStatus == 3) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(AVCaptureDevice);
return result;
}
function location() {
var result = 0;
var cllocationManger = plus.ios.import("CLLocationManager");
var enable = cllocationManger.locationServicesEnabled();
var status = cllocationManger.authorizationStatus();
if (!enable) {
result = 2;
} else if (status === 0) {
result = null;
} else if (status === 3 || status === 4) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(cllocationManger);
return result;
}
function push() {
var result = 0;
var UIApplication = plus.ios.import("UIApplication");
var app = UIApplication.sharedApplication();
var enabledTypes = 0;
if (app.currentUserNotificationSettings) {
var settings = app.currentUserNotificationSettings();
enabledTypes = settings.plusGetAttribute("types");
if (enabledTypes == 0) {
result = 0;
console.log("推送权限没有开启");
} else {
result = 1;
console.log("已经开启推送功能!")
}
plus.ios.deleteObject(settings);
} else {
enabledTypes = app.enabledRemoteNotificationTypes();
if (enabledTypes == 0) {
result = 3;
console.log("推送权限没有开启!");
} else {
result = 4;
console.log("已经开启推送功能!")
}
}
plus.ios.deleteObject(app);
plus.ios.deleteObject(UIApplication);
return result;
}
function contact() {
var result = 0;
var CNContactStore = plus.ios.import("CNContactStore");
var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
if (cnAuthStatus === 0) {
result = null;
} else if (cnAuthStatus == 3) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(CNContactStore);
return result;
}
function record() {
var result = null;
var avaudiosession = plus.ios.import("AVAudioSession");
var avaudio = avaudiosession.sharedInstance();
var status = avaudio.recordPermission();
console.log("permissionStatus:" + status);
if (status === 1970168948) {
result = null;
} else if (status === 1735552628) {
result = 1;
} else {
result = 0;
}
plus.ios.deleteObject(avaudiosession);
return result;
}
function calendar() {
var result = null;
var EKEventStore = plus.ios.import("EKEventStore");
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
if (ekAuthStatus == 3) {
result = 1;
console.log("日历权限已经开启");
} else {
console.log("日历权限没有开启");
}
plus.ios.deleteObject(EKEventStore);
return result;
}
function memo() {
var result = null;
var EKEventStore = plus.ios.import("EKEventStore");
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
if (ekAuthStatus == 3) {
result = 1;
console.log("备忘录权限已经开启");
} else {
console.log("备忘录权限没有开启");
}
plus.ios.deleteObject(EKEventStore);
return result;
}
function requestIOS(permissionID) {
return new Promise((resolve, reject) => {
switch (permissionID) {
case "push":
resolve(push());
break;
case "location":
resolve(location());
break;
case "record":
resolve(record());
break;
case "camera":
resolve(camera());
break;
case "album":
resolve(album());
break;
case "contact":
resolve(contact());
break;
case "calendar":
resolve(calendar());
break;
case "memo":
resolve(memo());
break;
default:
resolve(0);
break;
}
});
}
function requestAndroid(permissionID) {
return new Promise((resolve, reject) => {
plus.android.requestPermissions(
[permissionID],
function(resultObj) {
var result = 0;
for (var i = 0; i < resultObj.granted.length; i++) {
var grantedPermission = resultObj.granted[i];
console.log('已获取的权限:' + grantedPermission);
result = 1
}
for (var i = 0; i < resultObj.deniedPresent.length; i++) {
var deniedPresentPermission = resultObj.deniedPresent[i];
console.log('拒绝本次申请的权限:' + deniedPresentPermission);
result = 0
}
for (var i = 0; i < resultObj.deniedAlways.length; i++) {
var deniedAlwaysPermission = resultObj.deniedAlways[i];
console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
result = -1
}
resolve(result);
},
function(error) {
console.log('result error: ' + error.message)
resolve({
code: error.code,
message: error.message
});
}
);
});
}
function gotoAppPermissionSetting() {
if (permission.isIOS) {
var UIApplication = plus.ios.import("UIApplication");
var application2 = UIApplication.sharedApplication();
var NSURL2 = plus.ios.import("NSURL");
var setting2 = NSURL2.URLWithString("app-settings:");
application2.openURL(setting2);
plus.ios.deleteObject(setting2);
plus.ios.deleteObject(NSURL2);
plus.ios.deleteObject(application2);
} else {
var Intent = plus.android.importClass("android.content.Intent");
var Settings = plus.android.importClass("android.provider.Settings");
var Uri = plus.android.importClass("android.net.Uri");
var mainActivity = plus.android.runtimeMainActivity();
var intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
intent.setData(uri);
mainActivity.startActivity(intent);
}
}
const permission = {
get isIOS(){
return typeof isIOS === 'boolean' ? isIOS : (isIOS = uni.getSystemInfoSync().platform === 'ios')
},
requestIOS: requestIOS,
requestAndroid: requestAndroid,
gotoAppSetting: gotoAppPermissionSetting
}
export default permission

142
common/pinyin.js Normal file

File diff suppressed because one or more lines are too long

982
common/publicFc.js Normal file
View File

@@ -0,0 +1,982 @@
import http from '@/common/request'
import browser from '@/common/browser'
import store from '../store'
import pinyin from '@/common/pinyin.js';
export default {
// 获取字典
getdict(dict) {
return new Promise((resolve, reject) => {
http.request({
url: '/system/dict/data/type/' + dict,
success: (res) => {
if (res.data.code == 200) {
var data = res.data.data
var arr = []
for (var i = 0; i < data.length; i++) {
arr.push({
label: data[i].dictLabel,
value: data[i].dictValue
})
}
// return arr
resolve(arr);
} else {
reject(res);
}
},
fail: (res) => {
reject(new Error(res.errMsg));
}
});
});
},
//文本转json
returnParse(txt) {
return JSON.parse(txt);
},
//字典翻译
findLabel(arr, text) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].value == text) {
return arr[i].label
break;
}
}
},
//判断按钮权限
permissions(permissions) {
var data = store.state.permissions
var have = data.indexOf(permissions)
if (have !== -1) {
return true
}
},
//判断单个角色权限
hasRole(Role) {
var data = store.state.userRole
var have = data.indexOf(Role)
if (have !== -1) {
return true
}
},
//判断多个角色权限
hasRoles(Roles) {
var data = store.state.userRole
function fidrole(Roles) {
for (var i = 0; i < Roles.length; i++) {
var have = data.indexOf(Roles[i])
if (have !== -1) {
return true
}
}
return false
}
return fidrole(Roles)
},
//预览单张图片
previewImagesolo(File) {
uni.previewImage({
urls: [File],
});
},
//预览一组图片(图片组,图片索引)
previewImages(FilePaths, current) {
uni.previewImage({
urls: FilePaths,
current: current
});
},
//根据后缀判断文件类型
getFileType(fileName) {
// 后缀获取
let suffix = '';
// 获取类型结果
let result = '';
try {
const flieArr = fileName.split('.');
suffix = flieArr[flieArr.length - 1];
} catch (err) {
suffix = '';
}
// fileName无后缀返回 false
if (!suffix) {
return false;
}
suffix = suffix.toLocaleLowerCase();
// 图片格式
const imglist = ['png', 'jpg', 'jpeg', 'bmp', 'gif'];
// 进行图片匹配
result = imglist.find(item => item === suffix);
if (result) {
return 'image';
}
// 匹配txt
const txtlist = ['txt'];
result = txtlist.find(item => item === suffix);
if (result) {
return 'txt';
}
// 匹配 excel
const excelist = ['xls', 'xlsx'];
result = excelist.find(item => item === suffix);
if (result) {
return 'excel';
}
// 匹配 word
const wordlist = ['doc', 'docx'];
result = wordlist.find(item => item === suffix);
if (result) {
return 'word';
}
// 匹配 pdf
const pdflist = ['pdf'];
result = pdflist.find(item => item === suffix);
if (result) {
return 'pdf';
}
// 匹配 ppt
const pptlist = ['ppt', 'pptx'];
result = pptlist.find(item => item === suffix);
if (result) {
return 'ppt';
}
// 匹配 视频
const videolist = ['mp4', 'm2v', 'mkv', 'rmvb', 'wmv', 'avi', 'flv', 'mov', 'm4v'];
result = videolist.find(item => item === suffix);
if (result) {
return 'video';
}
// 匹配 音频
const radiolist = ['mp3', 'wav', 'wmv'];
result = radiolist.find(item => item === suffix);
if (result) {
return 'radio';
}
// 其他 文件类型
return 'other';
},
//新开页面打开文档支持格式doc, xls, ppt, pdf, docx, xlsx, pptx
onOpenDoc(e) {
uni.downloadFile({
url: e,
success: function(res) {
var filePath = res.tempFilePath;
uni.openDocument({
filePath: filePath,
success: function(res) {
console.log('打开文档成功');
}
});
}
});
},
//模拟浏览器打开第三方链接
openWebView(url) {
// #ifndef APP-PLUS
uni.showToast({
title: '仅手机端可打开',
icon: 'none'
})
return
// #endif
var options = { // 自定义头部参数
}
browser.init(options)
browser.show(url)
},
//获取时间format
getNewDate(format, add0,datetime) {
//获取当前时间
function addZero(val) {
//补零
if (add0) {
return val <= 9 ? '0' + val : val;
} else {
return val
}
}
var date = new Date()
if(datetime){
date=new Date(datetime)
}
var year = date.getFullYear(),
month = addZero(date.getMonth() + 1),
strDate = addZero(date.getDate()),
hours = addZero(date.getHours()),
minutes = addZero(date.getMinutes()),
seconds = addZero(date.getSeconds());
switch (format) {
case 'y':
return year;
break;
case 'm':
return month;
break;
case 'd':
return strDate;
break;
case 'h':
return hours;
break;
case 'mm':
return minutes;
break;
case 'ss':
return seconds;
break;
case 'ymd':
return year + '/' + month + '/' + strDate;
break;
case 'hmmss':
return hours + ':' + minutes + ':' + seconds;
break;
default:
return year + '/' + month + '/' + strDate + ' ' + hours + ':' + minutes + ':' + seconds;
break;
}
},
//获取本地存储object/初始化
getKeyObjectStorage(keyname) {
try {
var chatData = uni.getStorageSync(keyname);
if (chatData) {
chatData = JSON.parse(chatData)
return chatData
} else {
chatData = new Object()
return chatData
uni.setStorageSync(keyname, JSON.stringify(chatData));
}
} catch (e) {
return new Object()
}
},
loadMore({
url='xxx/list/',
queryParams={
refreshing:false,
pageNum:1,
status: 'more',//more loading前 loading loading中 noMore 没有更多了
pageSize:10
},
status='0'//0无更多数据 1持续加载 2重新加载 3无数据+清空数据
}){
return new Promise((resolve, reject) => {
http.request({
url:url+'&pageNum='+(queryParams.refreshing ? 1 : queryParams.pageNum) +'&pageSize=' +queryParams.pageSize,
success: res => {
if (res.data.code == 200) {
let list = [];
let data = res.data.rows;
if (queryParams.refreshing&&res.data.rows == ''||queryParams.refreshing&&res.data.rows.length==0) {
queryParams.status='noMore'
resolve({
queryParams:queryParams,
list:list,
status:'3'
})
return
}
if (res.data.rows == ''||res.data.rows.length==0) {
queryParams.status='noMore'
resolve({
queryParams:queryParams,
list:list,
status:'0'
})
return
}
for (let i = 0, length = data.length; i < length; i++) {
var item = data[i];
list.push(item);
}
if (queryParams.refreshing) {
queryParams.refreshing = false;
queryParams.pageNum = 2;
queryParams.status='more'
resolve({
queryParams:queryParams,
list:list,
status:'2'
})
} else {
queryParams.pageNum += 1;
queryParams.status='more'
resolve({
queryParams:queryParams,
list:list,
status:'1'
})
}
} else {
reject(res);
}
},
fail: (res) => {
reject(res);
}
});
});
},
//接收推送消息
getPush(resbody) {
console.log(resbody)
var pushType = resbody.pushType //推送类型
if (pushType == 'MSG') {
if(resbody.msgContent.msgType=='TRTC_VOICE_START'||resbody.msgContent.msgType=='TRTC_VIDEO_START'){
//音视频开始拦截
return
}
var userId=resbody.fromInfo.userId
var windowType='SINGLE'
if(resbody.groupInfo.userId){
userId=resbody.groupInfo.userId
windowType='GROUP'
}
this.pushInMsg({
type: resbody.msgContent.msgType == 'ALERT' ? 3 : 1, //显示类型 1左侧 2右侧 3中间
msgContent: resbody.msgContent.content, //msg内容
msgType: resbody.msgContent.msgType, //msgType信息类型
windowType: windowType, //聊天室类型 SINGLE GROUP
time: resbody.createTime, //时间
fromInfo:resbody.fromInfo,//来源信息
groupInfo:resbody.groupInfo,//群信息
userId: userId,//talktoId
personId:resbody.fromInfo.userId,
msgId:resbody.msgId,//消息Id
disturb:resbody.msgContent.disturb,//是否静默消息
top:resbody.msgContent.top//是否置顶
})
return
}
if (pushType == 'NOTICE') {//红点通知等
if(resbody.msgContent.topicReply.count){
store.commit('update_topicReply',resbody.msgContent.topicReply)
}
if(resbody.msgContent.topicRed.portrait){
store.commit('update_topicRed',resbody.msgContent.topicRed)
}
if(resbody.msgContent.friendApply.count){
store.commit('update_friendApply',resbody.msgContent.friendApply)
}
}
},
// 接收到的聊天推送
pushInMsg({
msgId,//消息Id
msgContent,//内容
msgType,//消息类型
windowType,//聊天室类型 SINGLE GROUP
userId,//聊天对象ID
personId,//发送人ID
time,//时间
type,//显示类型 1左侧 2右侧 3中间
fromInfo,//来源
groupInfo,//群信息
disturb,//是否静默消息
top//是否置顶
}) {
var msgTypeLabel = ''; //消息类型
if (msgType == 'TEXT') {
msgTypeLabel = msgContent;
}
if (msgType == 'ALERT') {
msgTypeLabel = msgContent;
}
if (msgType == 'IMAGE') {
msgTypeLabel = '[图片]';
}
if (msgType == 'VOICE') {
msgTypeLabel = '[语音]';
}
if (msgType == 'VIDEO') {
msgTypeLabel = '[视频]';
}
if (msgType == 'LOCATION') {
msgTypeLabel = '[位置]';
}
if (msgType == 'COLLECTION') {
msgTypeLabel = '[收藏]';
}
if (msgType == 'CARD') {
msgTypeLabel = '[名片]';
}
if (msgType == 'FILE') {
msgTypeLabel = '[文件]';
}
if (msgType == 'TRTC_VOICE_END') {
msgTypeLabel = '[语音通话]'
}
if (msgType == 'TRTC_VIDEO_END') {
msgTypeLabel = '[视频通话]'
}
store.dispatch('createChatObj',{
userId:userId,
windowType:windowType,
}).then(res=>{
var localData=res.data
store.dispatch('getchatDatalist');
store.dispatch('getChatList');
var chatWindowData = store.state.chatDatalist[userId].list
var chatListInfo = store.state.chatlist[userId]
// 找到数组中对象属性值一样的对象并返回
function arrfindobject({arr,object,key}){
var result=arr.find(item =>{
return item[key] == object[key]
});
return result
}
var same=arrfindobject({arr:chatWindowData,object:{
msgId:msgId
},key:'msgId'})
if(same){
return
}
//离线消息体
var msgOffline = {
userId: userId,
personId: personId,
nickName: fromInfo.nickName,
portrait: fromInfo.portrait,
msgType: msgType,
content: msgContent,
time: time,
type: type,
msgId:msgId,
windowType: windowType
}
// 聊天记录体
var msgList = {}
if(windowType=='SINGLE'){
msgList = {
userId: userId,
personId: personId,
nickName: fromInfo.nickName,
portrait: fromInfo.portrait,
content: msgTypeLabel,
time: time,
num: disturb=='Y' ? 'dot' : (chatListInfo.num ? chatListInfo.num + 1 : 1),
windowType: windowType,
disturb:disturb,//是否静默消息
top:top,//是否置顶
userType:fromInfo.userType
}
// #ifdef APP-PLUS
plus.push.createMessage(msgTypeLabel, "payload", {
cover: true,
sound: 'system',
title: fromInfo.nickName
});
// #endif
}
if(windowType=='GROUP'){
msgList = {
userId: userId,
personId: personId,
nickName: groupInfo.nickName,
portrait: groupInfo.portrait,
content: msgTypeLabel,
time: time,
num: disturb=='Y' ? 'dot' : (chatListInfo.num ? chatListInfo.num + 1 : 1),
windowType: windowType,
disturb:disturb,//是否静默消息
top:top,//是否置顶
userType:'GROUP'
}
// #ifdef APP-PLUS
plus.push.createMessage(msgTypeLabel, "payload", {
cover: true,
sound: 'system',
title: groupInfo.nickName
});
// #endif
}
chatWindowData.push(msgOffline)
store.dispatch('updateChatById', {
userId: userId,
data: chatWindowData
})
store.dispatch('updateChatListInfoById', {
userId: userId,
data: msgList
})
store.dispatch('tabBarpull')
store.dispatch('updateChatDataState',userId);
});
},
//发送消息
pushOutMsg({
msgContent, //内容
msgType, //消息类型
windowType, //聊天室类型SINGLE GROUP
userId
}) {
let portrait=store.state.talkToData.portrait
var msgTypeLabel = ''; //消息类型
if (msgType == 'TEXT') {
msgTypeLabel = msgContent;
}
if (msgType == 'ALERT') {
msgTypeLabel = msgContent;
}
if (msgType == 'IMAGE') {
msgTypeLabel = '[图片]';
}
if (msgType == 'VOICE') {
msgTypeLabel = '[语音]';
}
if (msgType == 'VIDEO') {
msgTypeLabel = '[视频]';
}
if (msgType == 'LOCATION') {
msgTypeLabel = '[位置]';
}
if (msgType == 'COLLECTION') {
msgTypeLabel = '[收藏]';
}
if (msgType == 'CARD') {
msgTypeLabel = '[名片]';
}
if (msgType == 'FILE') {
msgTypeLabel = '[文件]';
}
if (msgType == 'TRTC_VOICE_END') {
msgTypeLabel = '[语音通话]'
}
if (msgType == 'TRTC_VIDEO_END') {
msgTypeLabel = '[视频通话]'
}
var userInfo = store.state.userInfo;
store.dispatch('createChatObj',{
userId:userId,
windowType:windowType,
}).then(res=>{
var localData=res.data
store.dispatch('getchatDatalist');
store.dispatch('getChatList');
var chatWindowData = store.state.chatDatalist[userId].list
var chatListInfo = store.state.chatlist[userId]
var time = this.getNewDate('format',true)
//在线消息体
var msgOnlie={}
//聊天记录
var msgList={}
var url=''
if(windowType=='SINGLE'){
msgOnlie = {
userId: userId,
msgType: msgType,
content: msgContent
}
url='/chat/sendMsg'
msgList = {
userId: userId,
personId: userInfo.userId,
nickName: localData.fromInfo.nickName,
portrait: portrait,
content: msgTypeLabel,
time: time,
num: chatListInfo.disturb=='Y' ? 'dot' : (chatListInfo.num ? chatListInfo.num : 0),
windowType: windowType,
disturb:chatListInfo.disturb ? chatListInfo.disturb : 'N',//是否静默消息
top:chatListInfo.top ? chatListInfo.top : 'N',//是否置顶
userType:localData.fromInfo.userType
}
}
if(windowType=='GROUP'){
msgOnlie = {
groupId: userId,
msgType: msgType,
content: msgContent
}
url='/group/sendMsg'
msgList = {
userId: userId,
personId: userInfo.userId,
nickName: localData.groupInfo.nickName,
portrait: portrait,
content: msgTypeLabel,
time: time,
num: chatListInfo.disturb=='Y' ? 'dot' : (chatListInfo.num ? chatListInfo.num : 0),
windowType: windowType,
disturb:chatListInfo.disturb ? chatListInfo.disturb : 'N',//是否静默消息
top:chatListInfo.top ? chatListInfo.top : 'N',//是否置顶
userType:'GROUP'
}
}
//离线消息体 自己的消息
var msgOffline = {
userId: userInfo.userId,
personId: userInfo.userId,
nickName: userInfo.nickName,
portrait: userInfo.portrait,
msgType: msgType,
content: msgContent,
time: time,
type: 2,
msgId:'local',
windowType: windowType
};
//离线/发送失败错误消息体
var msgNotSend = {
userId: userInfo.userId,
portrait: userInfo.portrait,
msgType: msgType,
content: msgContent,
type: 3
};
var msgSendType = 'wating';
http.request({
url: url,
method: 'POST',
data: JSON.stringify(msgOnlie),
success: res => {
if (res.data.code == 200) {
if (res.data.data.status !== '0') {
msgSendType = 'error';
msgOffline.sendtype = msgSendType;
msgOffline.msgId=res.data.data.msgId
msgNotSend.content = res.data.data.statusLabel;
msgList.content = res.data.data.statusLabel;
} else {
msgSendType = 'success';
}
} else {
msgSendType = 'error';
msgOffline.sendtype = msgSendType;
msgNotSend.content = res.data.msg;
}
chatWindowData.push(msgOffline);
if (msgSendType == 'error') {
chatWindowData.push(msgNotSend);
}
store.dispatch('updateChatById', {
userId: userId,
data: chatWindowData
});
store.dispatch('updateChatListInfoById', {
userId: userId,
data: msgList
});
store.dispatch('tabBarpull');
store.dispatch('updateChatDataState',userId);
},
fail: res => {
msgSendType = 'error';
msgOffline.sendtype = msgSendType;
msgNotSend.content = '发送失败,请检查网络';
chatWindowData.push(msgOffline);
chatWindowData.push(msgNotSend);
store.dispatch('updateChatById', {
userId: userId,
data: chatWindowData
});
store.dispatch('updateChatListInfoById', {
userId: userId,
data: msgList
});
store.dispatch('tabBarpull');
store.dispatch('updateChatDataState',userId);
}
});
});
},
//H5保存base64图片
h5SaveBase64Img({
base64
}) {
var arr = base64.split(',');
var bytes = atob(arr[1]);
let ab = new ArrayBuffer(bytes.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
var blob = new Blob([ab], {
type: 'application/octet-stream'
});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = new Date().getTime() + ".png";
var e = document.createEvent('MouseEvents');
e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(e);
URL.revokeObjectURL(url);
},
//APP保存base64图片
plusSaveBase64Img({
base64
}) {
const bitmap = new plus.nativeObj.Bitmap("test");
bitmap.loadBase64Data(base64, function() {
const url = new Date().getTime() + ".png"; // url为时间戳命名方式
bitmap.save(url, {
overwrite: true, // 是否覆盖
}, (i) => {
uni.saveImageToPhotosAlbum({
filePath: url,
success: function() {
uni.showToast({
title: '图片保存成功',
icon: 'none'
})
bitmap.clear()
}
});
}, (e) => {
uni.showToast({
title: '图片保存失败',
icon: 'none'
})
bitmap.clear()
});
}, (e) => {
uni.showToast({
title: '图片保存失败',
icon: 'none'
})
bitmap.clear()
});
},
// 寻找数组中的对象中的key对应值的对象
arrFindkey({
arr, //数组[{id:'1'}]
key, //key键值'id'
val //值 '1'
}) {
var item = arr.find(function(obj, i, arr) {
return obj[key] === val
})
var index = arr.findIndex(function(obj, i, arr) {
return obj[key] === val
})
return {
item: item,
index: index
}
},
//APP下载文件
plusDownload({
onlinePath,
savePath = 'file://storage/emulated/0/Documents/weiliao/'
}) {
return new Promise((resolve, reject) => {
// #ifdef H5
reject('下载失败H5不支持plus')
return
// #endif
var fname = onlinePath.split("/").pop()
var localPath = savePath + fname
plus.io.resolveLocalFileSystemURL( //检测本地是否存在
localPath,
(entry) => {
console.log('文件已存在' + entry.name)
resolve(entry.fullPath)
},
(e) => {
console.log('文件不存在:' + e.message);
uni.showLoading({
title: '加载中'
})
createDownload(onlinePath)
}
);
function createDownload(e) {
let downloadOptions = {
method: "GET",
timeout: 120,
retryInterval: 10,
filename: savePath
};
// https://www.html5plus.org/doc/zh_cn/downloader.html#plus.downloader.Download
var dtask = plus.downloader.createDownload(e, downloadOptions, function(download, status) {
uni.hideLoading()
// 下载完成
if (status == 200) {
resolve(download.filename)
} else {
reject({
status: status,
msg: '下载失败'
})
}
});
dtask.start();
}
})
},
//APP打开文件
plusOpenFile({
filePath
}) {
let system = uni.getSystemInfoSync().platform;
if (system == 'ios') {
filePath = encodeURI(filePath);
}
uni.openDocument({
filePath,
success: res => {
// console.log('打开文件成功');
},
fail: res => {
console.log(res);
}
});
},
// 汉字拼音A-Z排序
sortList({
list,
key
}) {
var sortKey = [] //字母
list.forEach(item => {
let firstChar = ''
item[key] = item[key] ? item[key].trim() : ""
if (item[key]) { // 如传入空字符串getCamelFistChar错误地返回Y
firstChar = pinyin.getCamelFistChar(item[key]).toUpperCase() // 如字母开头,将返回字母且保留原大小写;一律改为大写
var reg = /^\d+$/;
if (reg.test(firstChar)) {
firstChar = 'Z#'
}
item.sort = firstChar
sortKey.push(firstChar)
}
})
sortKey = [...new Set(sortKey)]
list.sort((a, b) => a.sort.localeCompare(b.sort, 'zh')) //排序
sortKey.sort((a, b) => a.localeCompare(b, 'zh')) //排序
var sortlist = []
for (var i = 0; i < sortKey.length; i++) {
var sort = sortKey[i]
if (sort == 'Z#') {
sort = '#'
}
sortlist.push({
letter: sort,
data: []
})
for (var j = 0; j < list.length; j++) {
var item = list[j]
if (item.sort == 'Z#') {
item.sort = '#'
}
if (item.sort == sort) {
sortlist[i].data.push(item)
}
}
}
return sortlist
},
saoyisao(){//扫一扫
// #ifdef APP-PLUS
uni.scanCode({
success: (res)=> {
var result=res.result
var data=res.result.split(':')
var type=data[0]
var value=data[1]
switch (type){
case 'group':
uni.navigateTo({
url:'../../wx/groupInfo/scanCodeDetail?param='+result
})
break;
case 'user':
uni.navigateTo({
url:'../../wx/personInfo/detail?param='+value+'&source=1'
})
break;
default:
break;
}
}
});
// #endif
// #ifndef APP-PLUS
uni.showToast({
title:'扫一扫',
icon:'none'
})
// #endif
},
// 设置原生titleNView导航文字
setTitleNViewBtns(index,text){
let pages = getCurrentPages();
let page = pages[pages.length - 1];
// #ifdef APP-PLUS
let currentWebview = page.$getAppWebview();
let titleObj = currentWebview.getStyle().titleNView;
if (!titleObj.buttons) {
return;
}
titleObj.buttons[index].text = text;
currentWebview.setStyle({
titleNView: titleObj
});
// #endif
},
debounce(func, wait = 1000, immediate = true){
/**
* @desc 函数防抖
* @param func 目标函数
* @param wait 延迟执行毫秒数
* @param immediate true - 立即执行, false - 延迟执行
*/
let timer;
return function() {
let args = arguments;
if (timer) {
clearTimeout(timer);
}
if (immediate) {
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait);
if (callNow){
func.apply(this, args);
}
} else {
timer = setTimeout(() => {
func.apply(this, args);
}, wait)
}
}
},
throttle (func, wait = 1000, type = 1) {
/**
* @desc 函数节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 使用表时间戳,在时间段开始的时候触发 2 使用表定时器,在时间段结束的时候触发
*/
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)
}
}
}
}
}

302
common/request.js Normal file
View File

@@ -0,0 +1,302 @@
// #ifdef APP-PLUS
import appUpgrade from '@/common/appUpgrade.js';
// #endif
import {clearSocketTask} from "@/common/socketTask.js";
let http = {
'setBaseUrl': (url) => {
if (url.charAt(url.length - 1) === "/") {
url = url.substr(0, url.length - 1)
}
http.baseUrl = url;
},
'header': {},
'beforeRequestFilter': (config) => {
return config
},
'beforeResponseFilter': (res) => {
return res
},
'afterResponseFilter': (successResult) => {},
'get': get,
'delete': deletE,
'post': post,
'put': put,
'request': request,
'uploadFile': uploadFile,
'downloadFile': downloadFile
}
function init(con) {
//url
let url = http.baseUrl;
if (url && con.url && !con.url.match(/^(http|https):\/\/([\w.]+\/?)\S*$/)) {
if (con.url.charAt(0) !== "/") {
con.url = "/" + con.url;
}
con.url = url.concat(con.url);
}
//header
if (http.header != undefined && http.header != null) {
if (!con.header) {
con.header = http.header;
} else {
Object.keys(http.header).forEach(function(key) {
con.header[key] = http.header[key]
});
}
}
}
function request(con) {
init(con);
let config = { //判断是否有以下属性没有就赋予默认值
url: con.url ? con.url : http.baseUrl,
data: con.data,
header: con.header,
method: con.method ? con.method : 'GET',
dataType: con.dataType ? con.dataType : 'json',
responseType: con.responseType ? con.responseType : 'text',
success: con.success ? (res) => {
http.afterResponseFilter(con.success(http.beforeResponseFilter(res)));
} : null,
fail: con.fail ? (res) => {
con.fail(res);
} : () => {
uni.showToast({
title: '请检查网络',
icon: 'none'
});
uni.hideLoading();
},
complete: con.complete ? (res) => {
con.complete(res);
} : (res) => {
// console.log(con)
// console.log(res)
if (!res.statusCode) {
uni.showToast({
title: '请求失败',
icon: 'none'
});
uni.hideLoading();
}
if (res.statusCode !== 200) {
uni.showToast({
title: '请求失败',
icon: 'none'
});
uni.hideLoading();
}
if (res.statusCode == 200) {
if (res.data.code == 401) { //登录过期
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none'
});
clearSocketTask()
uni.hideLoading();
uni.clearStorage()
// setTimeout(()=>{
uni.reLaunch({
url:'/pages/wxindex/index'
})
// },1000)
}
// #ifdef APP-PLUS
if (res.data.code == 601) { //强制拉起升级
request({
url: '/common/getVersion',
success: (res) => {
appUpgrade.init({
titleText: '版本更新'+res.data.data.version,
packageUrl:res.data.data.url,
content: res.data.data.content,
forceUpgrade:true
});
appUpgrade.show();
}
});
}
// #endif
else if (res.data.code && res.data.code !== 200) { //这里code是自己的服务器正确标识
uni.showToast({
title: res.data.msg,
icon: 'none',
position:'top'
});
}
uni.hideLoading();
}
uni.stopPullDownRefresh();
}
}
const AUTH_TOKEN = ["Authorization","device","version"];
for (var i = 0; i < AUTH_TOKEN.length; i++) {
if (uni.getStorageSync(AUTH_TOKEN[i])) {
http.header[AUTH_TOKEN[i]] = uni.getStorageSync(AUTH_TOKEN[i]);
}
}
return uni.request(http.beforeRequestFilter(config));
}
function get(url, con, success) {
let conf = {};
if (con && typeof con == 'function') {
if (success && typeof success == 'object') {
conf = success;
}
conf.success = con
} else {
if (con && typeof con == 'object') {
conf = con;
}
conf.success = success;
}
if (url) {
conf.url = url
}
conf.method = "GET";
return request(conf);
}
function deletE(url, con, success) {
let conf = {};
if (con && typeof con == 'function') {
if (success && typeof success == 'object') {
conf = success;
}
conf.success = con
} else {
if (con && typeof con == 'object') {
conf = con;
}
conf.success = success;
}
if (url) {
conf.url = url
}
conf.method = "DELETE";
return request(conf);
}
function post(url, data, con, success) {
let conf = {};
if (con && typeof con == 'function') {
if (success && typeof success == 'object') {
conf = success
}
conf.success = con;
} else {
if (con && typeof con == 'object') {
conf = con;
}
conf.success = success;
}
if (url) {
conf.url = url
}
if (data) {
conf.data = data
}
conf.method = "POST";
return request(conf);
}
function put(url, data, con, success) {
let conf = {};
if (con && typeof con == 'function') {
if (success && typeof success == 'object') {
conf = success
}
conf.success = con;
} else {
if (con && typeof con == 'object') {
conf = con;
}
conf.success = success;
}
if (url) {
conf.url = url
}
if (data) {
conf.data = data
}
conf.method = "PUT";
return request(conf);
}
function uploadFile(con) {
init(con);
let config = {
url: con.url ? con.url : http.baseUrl,
files: con.files,
filesType: con.filesType,
filePath: con.filePath,
name: con.name,
header: con.header,
formData: con.formData,
success: con.success ? (res) => {
http.afterResponseFilter(con.success(http.beforeResponseFilter(res)));
} : null,
fail: con.fail ? (res) => {
con.fail(res);
} : null,
complete: con.complete ? (res) => {
con.complete(res);
} : null
}
const AUTH_TOKEN = ["Authorization","device","version"];
for (var i = 0; i < AUTH_TOKEN.length; i++) {
if (uni.getStorageSync(AUTH_TOKEN[i])) {
http.header[AUTH_TOKEN[i]] = uni.getStorageSync(AUTH_TOKEN[i]);
}
}
return uni.uploadFile(http.beforeRequestFilter(config));
}
function downloadFile(con) {
init(con);
let config = {
url: con.url ? con.url : http.baseUrl,
header: con.header,
success: con.success ? (res) => {
http.afterResponseFilter(con.success(http.beforeResponseFilter(res)));
} : null,
fail: con.fail ? (res) => {
con.fail(res);
} : null,
complete: con.complete ? (res) => {
con.complete(res);
} : null
}
return uni.downloadFile(http.beforeRequestFilter(config));
}
// 使用
//POST
// this.$http.request({
// url: '/xxx',
// method: 'POST',
// data:JSON.stringify({id:111}),
// success: (res) => {
// if (res.data.code == 200) {
//
// }
// }
// });
//GET
// this.$http.request({
// url: '/xxx?id=111',
// success: (res) => {
// if (res.data.code == 200) {
//
// }
// }
// });
// 地址及配置
http.setBaseUrl("https://im-api.q3z3.com"); //在线服务器
// http.setBaseUrl("http://192.168.0.200:8080"); //离线服务器
export default http

114
common/socketTask.js Normal file
View File

@@ -0,0 +1,114 @@
import fc from '@/common/publicFc.js'
let timer = null; //心跳计时器
let debug = false; //debug输出log
let retimer = null; //重连计时器
let pingCount = 0; //心跳次数
let pingCountMax = 5; //最大心跳次数超过重连
let pingTimeout = 5000; //心跳间隔时间(毫秒)
let connectTimeout = 2000; //重连时间(毫秒)
let socketTask = null; //ws
// 连接WebSocket
export function connectSocket() {
debug && console.log(socketTask);
var token = uni.getStorageSync('Authorization');
if (!token || socketTask) {
console.log('开启socketTask失败')
return
}
socketTask = uni.connectSocket({
url: 'wss://im-api.q3z3.com/ws?Authorization=' + uni.getStorageSync('Authorization'),//WebSocket地址
// url: 'ws://192.168.0.200:8080/ws?Authorization=' + uni.getStorageSync('Authorization'),//WebSocket地址
complete: () => {}
});
socketTask.onOpen(res => {
console.log('WebSocket连接已打开');
debug && console.log(socketTask);
// 发送心跳
socketTask.send({
data: 'isConnact',
success: res => {
if (res.errMsg == 'sendSocketMessage:ok') {
debug && console.log('WebSocket心跳ping');
}
}
})
// 定时心跳
timer = setInterval(() => {
// ping超过5次未响应则重连
pingCount++
debug && console.log('ping次数'+pingCount+'/'+pingCountMax);
if (pingCount >= pingCountMax) {
clearSocketTask()
reConnectSocket()
return
}
socketTask.send({
data: 'isConnact',
success: res => {
if (res.errMsg == 'sendSocketMessage:ok') {
debug && console.log('WebSocket心跳ping');
}
}
})
}, pingTimeout)
})
// 监听接收
socketTask.onMessage(res => {
if (socketTask && token) {
if(res.data=='ok'){
pingCount = 0;
return
}
var data = JSON.parse(res.data);
fc.getPush(data);
console.log('WebSocket接收消息');
}
})
// 监听关闭
socketTask.onClose((res) => {
debug && console.log(socketTask);
console.log('WebSocket连接已关闭');
if (!socketTask) {
console.log('无需操作')
return
}
if (socketTask.readyState !== 1) {
console.log('需要重新连接')
clearSocketTask()
reConnectSocket()
}
})
// 监听异常
socketTask.onError(res => {
debug && console.log(socketTask);
console.log('WebSocket连接异常');
if (!socketTask) {
console.log('无需操作')
return
}
if (socketTask.readyState !== 1) {
console.log('需要重新连接')
clearSocketTask()
reConnectSocket()
}
});
}
// 清理WebSocket
export function clearSocketTask() {
clearInterval(timer)
clearTimeout(retimer)
pingCount = 0;
if (socketTask) {
socketTask.close()
socketTask = null
console.log('主动关闭WebSocket');
}
}
// 重新连接WebSocket
export function reConnectSocket() {
retimer = setTimeout(() => {
connectSocket()
}, connectTimeout)
}

75
common/zmmFormCheck.js Normal file
View File

@@ -0,0 +1,75 @@
// 表单验证
// zmm2113@qq.com
/**
* @property {Object} formData 表单
* @property {Object} rules 验证规则
**/
export default {
error: '',
check: function(formData, rules) {
var formDataKeys = Object.keys(formData)
for (var i = 0; i < formDataKeys.length; i++) {
var key = formDataKeys[i]
if (rules[key]) {
var itemRules = rules[key].rules
var itemValue = formData[key]
for (var j = 0; j < itemRules.length; j++) {
var rule = itemRules[j]
switch (rule.checkType){
case 'required'://必填项
if(!itemValue) {this.error = rule.errorMsg; return false;}
break;
case 'phone'://手机号码验证
var reg = /^1[0-9]{10,10}$/;
if (!reg.test(itemValue)) { this.error = rule.errorMsg; return false; }
break;
case 'email'://邮箱验证
var reg = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
if (!reg.test(itemValue)) { this.error = rule.errorMsg; return false; }
break;
case 'idcard'://15-18位身份证验证
var reg = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/;
if (!reg.test(itemValue)) { this.error = rule.errorMsg; return false; }
break;
case 'url'://网址验证
var reg = /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?$/;
if (!reg.test(itemValue)) { this.error = rule.errorMsg; return false; }
break;
case 'reg'://正则验证 checkRule必填
if(!rule.checkRule){
this.error=key+' 校验失败'
console.warn(key+' checkRule规则未填写')
return false;
}
var reg = rule.checkRule;
if (!reg.test(itemValue)) { this.error = rule.errorMsg; return false; }
break;
case 'number'://数字
var reg = /^\d+$/;
if (!reg.test(itemValue)) { this.error = rule.errorMsg; return false; }
break;
case 'same'://是否相同 checkRule必填
if(!rule.checkRule){
this.error=key+' 校验失败'
console.warn(key+' checkRule规则未填写')
return false;
}
if (itemValue!==formData[rule.checkRule]) { this.error = rule.errorMsg; return false; }
break;
case 'string'://字符串 checkRule必填
if(!rule.checkRule){
this.error=key+' 校验失败'
console.warn(key+' checkRule规则未填写')
return false;
}
var reg = new RegExp('^.{' + rule.checkRule + '}$');
if (!reg.test(itemValue)) { this.error = rule.errorMsg; return false; }
break;
}
}
}
}
return true;
}
}

View File

@@ -0,0 +1,620 @@
<template>
<view class="friendsCircle-content-item">
<image class="friendsCircle-content-avatar" :src="content.avatar" mode="aspectFill"></image>
<view class="friendsCircle-content-right">
<view class="friendsCircle-content-nikeName">{{ content.nikeName }}</view>
<view class="friendsCircle-content-text">{{ content.text }}</view>
<view class="friendsCircle-content-imgs" v-if="content.topicType=='IMAGE'&&content.files.length>0">
<image v-for="(item, ii) in content.files" :key="ii" class="friendsCircle-content-img" :class="'fci' + content.files.length" :src="item.url" mode="aspectFill" @click="pimgs(content.files,ii)"></image>
</view>
<view class="friendsCircle-content-video" @click="openVideo(content.files[0].videoUrl)" v-if="content.topicType=='VIDEO'&&content.files.length>0">
<image class="friendsCircle-content-video-icon" src="../../static/img/bf.png" mode="aspectFill"></image>
<image class="friendsCircle-content-video-img" :src="content.files[0].url" mode="aspectFill"></image>
</view>
<view v-if="content.location" class="friendsCircle-content-location" @click="goMap(content.location)">{{ content.location.name }}</view>
<view class="friendsCircle-content-tools">
<view class="friendsCircle-content-time">{{ content.time }}</view>
<view class="friendsCircle-content-tool" :class="{ 'tabon': tabToolIndex }">
<view class="wxfont caidan" @click="tabTool(i)"></view>
<view class="friendsCircle-content-tool-absolute">
<view class="friendsCircle-popup">
<view class="friendsCircle-popup-item" @click="zan(content)">
<view class="friendsCircle-popup-icon wxfont zan"></view>
<view class="friendsCircle-popup-text" v-if="content.like=='Y'">取消</view>
<view class="friendsCircle-popup-text" v-else></view>
</view>
<view class="friendsCircle-popup-item" @click="comment(content)">
<view class="friendsCircle-popup-icon wxfont pinglun"></view>
<view class="friendsCircle-popup-text">评论</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="friendsCircle-content-item-detail">
<view class="friendsCircle-content-item-detail-item" v-if="content.likeList&&content.likeList.length>0">
<view class="friendsCircle-like-icon wxfont zan"></view>
<view class="friendsCircle-like">
<image class="friendsCircle-like-img" mode="aspectFill" v-for="(z,zindex) in content.likeList" :src="z.portrait"></image>
</view>
</view>
<view class="friendsCircle-content-item-detail-item" v-if="content.replyList&&content.replyList.length>0">
<view class="friendsCircle-comment-icon wxfont pinglun"></view>
<view class="friendsCircle-comment">
<view class="friendsCircle-comment-item" v-for="(c,ci) in content.replyList" :key="ci">
<image class="friendsCircle-comment-img" :src="c.portrait" mode="aspectFill"></image>
<view class="friendsCircle-comment-item-text">
<view class="friendsCircle-comment-item-name">
<text class="friendsCircle-comment-text">{{c.nickName}}</text>
<text class="friendsCircle-comment-item-time">{{c.createTime}}</text>
</view>
<view style="width: 100%;" @click="replyclick(c,ci)">
<view class="friendsCircle-comment-feedback" v-if="c.replyType=='2'">
<text>回复</text>
<text class="friendsCircle-comment-text">{{c.toNickName}}</text>
</view>
<text class="friendsCircle-comment-textx">{{c.content}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
<view style="height: 120rpx;"></view>
<view class="zfb-tk-send-tool" :style="{bottom:keyboardHeight+'px'}">
<form @submit="sendMsg(msg)">
<view class="zfb-tk-send-tool-c">
<view class="zfb-tk-send-tool-input-box" @click="msgFocus=true">
<textarea class="zfb-tk-send-tool-input" :adjust-position="false" :focus="msgFocus" v-model="msg" :placeholder="placeholder" confirm-type="send" @confirm="sendMsg(msg)" hold-keyboard :maxlength="-1" auto-height />
</view>
<view class="zfb-tk-send-tool-text" @click="sendMsg(msg)" :style="{ background: msg !== '' ? '#1BC418' : '#F7F7F7', color: msg !== '' ? '#fff' : '#ddd', 'border-color': msg !== '' ? '#1BC418' : '#ddd' }">发送</view>
</view>
</form>
</view>
</template>
<script>
export default {
// 朋友圈列表内容区
data() {
return {
timer:null,
placeholder:'评论',
keyboardHeight:0,
msg: '',
type:'msg',
replydata:'',
msgFocus:false,
tabToolIndex: false,
content:this.detail
};
},
props:{
detail:{
type:Object
}
},
watch:{
detail(v){
this.content=v
}
},
computed:{
userInfo(){
return this.$store.state.userInfo
}
},
mounted() {
// #ifdef APP-PLUS
uni.onKeyboardHeightChange(res => {
this.keyboardHeight=res.height
})
// #endif
},
methods: {
scrolltoBottom() {
this.$nextTick(()=>{
this.timer = setTimeout(() => {
uni.pageScrollTo({
scrollTop: 9999999,
duration: 10
});
this.$forceUpdate()
}, 100);
})
},
replyclick(e,ci){
if(e.canDeleted=='Y'){
this.hidenTool()
uni.showActionSheet({
itemList: ['复制','删除'],
success: (res) => {
switch (res.tapIndex){
case 0:
uni.setClipboardData({
data: e.content,
success: function() {
uni.showToast({
title: '复制成功',
icon: 'none',
position: 'bottom'
})
}
});
break;
case 1:
this.$http.request({
url: '/topic/removeReply/'+e.replyId,
success: (res) => {
if (res.data.code == 200) {
uni.showToast({
title:'删除成功',
icon:'none'
})
this.content.replyList.splice(ci,1)
}
}
});
break;
default:
break;
}
}
});
}else{
this.replydata=e
this.type='reply'
this.placeholder='回复'+e.nickName
this.$nextTick(()=>{
this.msgFocus=true
})
}
},
gofriend(e){
uni.navigateTo({
url:'../../wx/personInfo/detail?param='+e.userId
})
},
pimgs(arr,ii){
var imgs=[]
for (var i = 0; i < arr.length; i++) {
imgs.push(arr[i].url)
}
this.$fc.previewImages(imgs, ii)
},
goMap(e) {
uni.openLocation({
latitude: e.latitude,
longitude: e.longitude,
success: function() {}
});
},
openVideo(e){
this.$fc.plusDownload({onlinePath:e}).then(res=>{
this.$fc.plusOpenFile({filePath:res})
})
},
tabTool(e) {
this.tabToolIndex=!this.tabToolIndex
},
comment(e) {
this.hidenTool()
//评论
this.type='msg'
this.placeholder='评论'
this.$nextTick(()=>{
this.msgFocus=true
})
},
zan(e,i){//点赞
switch (e.like){
case 'N':
this.$http.request({
url: '/topic/like/'+e.topicId,
success: (res) => {
if (res.data.code == 200) {
var like=e.like=='N' ? e.like='Y' : e.like='N'
this.content.like=like
this.content.likeList.push({
userId: this.userInfo.userId,
nickName: this.userInfo.nickName,
portrait: this.userInfo.portrait
})
}
}
});
break;
case 'Y':
this.$http.request({
url: '/topic/cancelLike/'+e.topicId,
success: (res) => {
if (res.data.code == 200) {
var like=e.like=='N' ? e.like='Y' : e.like='N'
this.content.like=like
var thisObj=this.$fc.arrFindkey({arr:this.content.likeList,key:'userId',val:this.userInfo.userId})
this.content.likeList.splice(thisObj.index,1)
}
}
});
break;
default:
break;
}
},
sendMsg(e) {
if (!e) {
return;
}
var replyId=''
var replyType=''
if(this.type=='msg'){
replyId=this.content.topicId
replyType='1'
}
if(this.type=='reply'){
replyId=this.replydata.replyId
replyType='2'
}
this.$http.request({
url: '/topic/reply',
method: 'POST',
data:JSON.stringify({
replyId: replyId,
replyType: replyType,
content: e
}),
success: (res) => {
if (res.data.code == 200) {
this.content.replyList.push(res.data.data)
this.$nextTick(()=>{
this.scrolltoBottom()
})
}
}
});
this.msg=''
},
hidenTool() {//隐藏选项和输入框
this.tabToolIndex = false;
}
}
};
</script>
<style scoped lang="scss">
.zfb-tk-send-tool {
background: #f7f7f7;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
.zfb-tk-send-tool-c {
padding: 16rpx 12rpx;
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
border: 1px #ddd solid;
border-left: none;
border-right: none;
}
.zfb-tk-send-tool-c .zfb-tk-send-tool-btn {
transition: color 0.5s;
}
.zfb-tk-send-tool .zfb-tk-send-tool-input {
padding:0 24rpx;
box-sizing: border-box !important;
width: 100%;
background: #fff;
}
.zfb-tk-send-tool-text {
white-space: nowrap;
padding: 10rpx 24rpx;
border-radius: 12rpx;
border: 1px #ddd solid;
background: #f7f7f7;
color: #ddd;
}
.friendsCircle-content-item{
display: flex;
flex-direction: row;
padding:24rpx;
}
.friendsCircle-content-item-detail{
margin:0 24rpx;
border-radius: 8rpx;
margin-top: 24rpx;
padding-bottom: 0;
margin-bottom: 1px;
}
.friendsCircle-content-avatar{
border-radius: 10rpx;
width: 90rpx;
height: 90rpx;
min-width: 90rpx;
}
.friendsCircle-content-right{
display: flex;flex-direction: column;
padding-left: 18rpx;
flex: 1;
box-sizing: border-box;
}
.friendsCircle-content-nikeName{
font-size: 32rpx;
color: #5F698C;
margin-bottom: 10rpx;
}
.friendsCircle-content-text{
font-size: 32rpx;
color: #333;
}
.friendsCircle-content-imgs{
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex: 1;
margin-top: 24rpx;
}
.friendsCircle-content-img{
max-width: 100%;
}
.friendsCircle-content-img.fci1{
height: 550rpx;
max-width: 500rpx;
margin-right: 5px;
}
.friendsCircle-content-img.fci2{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci2:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci3{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci3:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci4{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci4:nth-child(2n){
margin-right: 185rpx;
}
.friendsCircle-content-img.fci5{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci5:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci6{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci6:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci7{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci7:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci8{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci8:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci9{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci9:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-location{
font-size: 24rpx;
color: #5F698C;
margin-top: 12rpx;
}
.friendsCircle-content-time{
font-size: 24rpx;
color: #666666;
margin-right: auto;
}
.friendsCircle-content-tools{
margin-top: 24rpx;
display: flex;flex-direction: row;align-items: center;
}
.friendsCircle-content-tool{
padding:4rpx 16rpx;
border-radius: 10rpx;
background-color: #F8F8FA;
color: #63678C;
display: flex;flex-direction: row;
position: relative;
}
.tabon .friendsCircle-content-tool-absolute{
display: block;
}
.friendsCircle-content-tool-absolute{
position: absolute;
right: 100%;
top: 50%;
transform: translateY(-50%);
display: none;
}
.friendsCircle-popup{
margin-right: 24rpx;
border-radius: 12rpx;
background-color: rgba(0,0,0,0.7);
height: 75rpx;
display: flex;flex-direction: row;align-items: center;
padding:0 24rpx;
}
.friendsCircle-popup-item{
color: #fff;
padding:0 25rpx;
height: 100%;
display: flex;flex-direction: row;align-items: center;
}
.friendsCircle-popup-item:nth-child(1):active .friendsCircle-popup-icon{
font-size: 56rpx;
}
.friendsCircle-popup-icon{
font-size: 46rpx;
}
.friendsCircle-popup-text{
white-space: nowrap;
}
.friendsCircle-like{
display: flex;flex-direction: row;align-items: center;flex-wrap: wrap;
}
.friendsCircle-like-icon,.friendsCircle-like-text,.friendsCircle-comment-text{
color: #5F698C !important;
font-size: 24rpx;
}
.friendsCircle-comment-feedback .friendsCircle-comment-text{
margin:0 6rpx;
}
.friendsCircle-comment-feedback .friendsCircle-comment-text::after{
content: ":";
color: #333;
}
.friendsCircle-comment-item-name{
display: flex;flex-direction: row;
width: 100%;
}
.friendsCircle-comment-item-time{
margin-left: auto;
font-size: 24rpx;
color: #999;
}
.friendsCircle-like-icon,.friendsCircle-comment-icon{
width: 40rpx;
min-width: 40rpx;
height: 60rpx;
display: flex;flex-direction: row;align-items: center;justify-content: center;
font-size: 32rpx;
}
.friendsCircle-like-text{
margin-left: 4rpx;
}
.friendsCircle-like-text::after{
content: ",";
}
.friendsCircle-like-text:nth-last-child(1)::after{
content: "";
}
.friendsCircle-comment{
background-color: #F7F7F7;
border-radius: 8rpx;
flex: 1;
}
.friendsCircle-comment-item{
font-size: 28rpx;
padding: 12rpx;
white-space: pre-wrap;
display: flex;flex-direction: row;
}
.friendsCircle-comment-feedback{
display: inline-block;
}
.friendsCircle-comment-feedback text{
font-size: 28rpx;
color: #333;
}
.friendsCircle-comment-textx{
word-break: break-all;
}
.friendsCircle-like-img,.friendsCircle-comment-img{
width: 60rpx;
height: 60rpx;
border-radius: 12rpx;
margin-left: 10rpx;
margin-bottom: 12rpx;
}
.friendsCircle-comment-img{
margin-right: 12rpx;
margin-left: 0px;
}
.friendsCircle-content-item-detail-item{
display: flex;flex-direction: row;
padding: 12rpx;
padding-bottom: 0;
margin-bottom: 4rpx;
border-radius: 8rpx;
background-color: #F7F7F7;
}
.friendsCircle-comment-item-text{
flex: 1;
display: flex;flex-direction: column;
align-items:flex-start;
}
.friendsCircle-content-video{
height: 550rpx;
max-width: 400rpx;
position: relative;
margin-right: 14rpx;
margin-top: 24rpx;
}
.friendsCircle-content-video-img{
width: 100%;
height: 100%;
}
.friendsCircle-content-video-icon{
z-index: 1;
position: absolute;
left: 50%;
top: 50%;
width: 60rpx !important;
height: 60rpx !important;
transform: translate(-50%,-50%);
}
.zfb-tk-send-tool-input-box{
overflow: auto;
width: 100%;
margin: 0 12rpx;
min-height: 75rpx;
background-color: #fff;
border-radius: 24rpx;
padding-top: 18rpx;
max-height: 225rpx;
box-sizing: border-box;
}
</style>

View File

@@ -0,0 +1,558 @@
<template>
<view class="friendsCircle-content-item" v-for="(v, i) in content" :key="i">
<image class="friendsCircle-content-avatar" :src="v.avatar" mode="aspectFill" @click="gofriend(v)"></image>
<view class="friendsCircle-content-right">
<view class="friendsCircle-content-nickName" @click="gofriend(v)">{{ v.nickName }}</view>
<view class="friendsCircle-content-text">{{ v.text }}</view>
<view class="friendsCircle-content-imgs" v-if="v.topicType=='IMAGE'&&v.files.length>0">
<image v-for="(item, ii) in v.files" :key="ii" class="friendsCircle-content-img" :class="'fci' + v.files.length" :src="item.url" mode="aspectFill" @click="pimgs(v.files,ii)"></image>
</view>
<view class="friendsCircle-content-video" @click="openVideo(v.files[0].videoUrl)" v-if="v.topicType=='VIDEO'&&v.files.length>0">
<image class="friendsCircle-content-video-icon" src="../../static/img/bf.png" mode="aspectFill"></image>
<image class="friendsCircle-content-video-img" :src="v.files[0].url" mode="aspectFill"></image>
</view>
<view class="friendsCircle-content-location" v-if="v.location.name" @click="goMap(v.location)">{{ v.location.name }}</view>
<view class="friendsCircle-content-tools">
<view class="friendsCircle-content-time">{{ v.time }}</view>
<view class="friendsCircle-content-tool" :class="{ tabon: i == showToolIndex }">
<view class="wxfont caidan" @click="showTool(i)"></view>
<view class="friendsCircle-content-tool-absolute">
<view class="friendsCircle-popup">
<view class="friendsCircle-popup-item" @click="zan(v,i)">
<view class="friendsCircle-popup-icon wxfont zan"></view>
<view class="friendsCircle-popup-text" v-if="v.like=='Y'">取消</view>
<view class="friendsCircle-popup-text" v-else></view>
</view>
<view class="friendsCircle-popup-item" @click="comment(v)">
<view class="friendsCircle-popup-icon wxfont pinglun"></view>
<view class="friendsCircle-popup-text">评论</view>
</view>
</view>
</view>
</view>
</view>
<view class="friendsCircle-like" v-if="v.likeList&&v.likeList.length>0">
<view class="friendsCircle-like-icon wxfont zan"></view>
<text class="friendsCircle-like-text" v-for="(z,zindex) in v.likeList">{{z.nickName}}</text>
</view>
<view class="friendsCircle-comment" v-if="v.replyList&&v.replyList.length>0">
<view class="friendsCircle-comment-item" v-for="(c,ci) in v.replyList" :key="ci">
<text class="friendsCircle-comment-text" @click="gofriend(c)">{{c.nickName}}</text>
<view class="friendsCircle-comment-feedback" v-if="c.replyType=='2'">
回复
<text class="friendsCircle-comment-text" @click="gofriend(c)">{{c.toNickName}}</text>
</view>
<view class="friendsCircle-comment-content" v-if="c.content" @click="replyclick(c,ci,i)">
<text>{{c.content}}</text>
</view>
</view>
</view>
</view>
</view>
<view class="zfb-tk-send-tool" v-if="toggleMsgBox" :style="{bottom:keyboardHeight+'px'}">
<form @submit="sendMsg(msg)">
<view class="zfb-tk-send-tool-c">
<view class="zfb-tk-send-tool-input-box" @click="msgFocus=true">
<textarea class="zfb-tk-send-tool-input" :adjust-position="false" :focus="msgFocus" v-model="msg" :placeholder="placeholder" confirm-type="send" @confirm="sendMsg(msg)" hold-keyboard :maxlength="-1" auto-height />
</view>
<view class="zfb-tk-send-tool-text" @click="sendMsg(msg)" :style="{ background: msg !== '' ? '#1BC418' : '#F7F7F7', color: msg !== '' ? '#fff' : '#ddd', 'border-color': msg !== '' ? '#1BC418' : '#ddd' }">发送</view>
</view>
</form>
</view>
</template>
<script>
export default {
// 朋友圈列表内容区
data() {
return {
keyboardHeight:0,
msg: '',
msgFocus:false,
toggleMsgBox: false,
showToolIndex: null,
chooseUserIndex:null,
type:'msg',
placeholder:'评论',
replydata:''
};
},
props:{
content:{
type:Array,
default:[]
}
},
computed:{
userInfo(){
return this.$store.state.userInfo
}
},
mounted() {
// #ifdef APP-PLUS
uni.onKeyboardHeightChange(res => {
this.keyboardHeight=res.height
})
// #endif
},
methods: {
replyclick(e,ci,i){
this.chooseUserIndex=i
if(e.canDeleted=='Y'){
this.hidenTool()
uni.showActionSheet({
itemList: ['复制','删除'],
success: (res) => {
switch (res.tapIndex){
case 0:
uni.setClipboardData({
data: e.content,
success: function() {
uni.showToast({
title: '复制成功',
icon: 'none',
position: 'bottom'
})
}
});
break;
case 1:
this.$http.request({
url: '/topic/removeReply/'+e.replyId,
success: (res) => {
if (res.data.code == 200) {
uni.showToast({
title:'删除成功',
icon:'none'
})
this.content[i].replyList.splice(ci,1)
}
}
});
break;
default:
break;
}
}
});
}else{
this.replydata=e
this.type='reply'
this.placeholder='回复'+e.nickName
this.$nextTick(()=>{
this.toggleMsgBox = true;
this.msgFocus=true
})
}
},
gofriend(e){
uni.navigateTo({
url:'../../wx/personInfo/detail?param='+e.userId
})
},
pimgs(arr,ii){
var imgs=[]
for (var i = 0; i < arr.length; i++) {
imgs.push(arr[i].url)
}
this.$fc.previewImages(imgs, ii)
},
goMap(e) {
uni.openLocation({
latitude: e.latitude,
longitude: e.longitude,
success: function() {}
});
},
openVideo(e){
this.$fc.plusDownload({onlinePath:e}).then(res=>{
this.$fc.plusOpenFile({filePath:res})
})
},
returnParse(txt) {
return JSON.parse(txt);
},
showTool(e) {
this.chooseUserIndex=e
if (this.showToolIndex === e) {
this.showToolIndex = null;
} else {
this.showToolIndex = e;
}
},
comment(e) {
//评论
this.showToolIndex = null;
this.type='msg'
this.placeholder='评论'
this.$nextTick(()=>{
this.toggleMsgBox = true;
this.msgFocus=true
})
},
zan(e,i){//点赞
switch (e.like){
case 'N':
this.$http.request({
url: '/topic/like/'+e.topicId,
success: (res) => {
if (res.data.code == 200) {
this.hidenTool()
var like=e.like=='N' ? e.like='Y' : e.like='N'
this.content[this.chooseUserIndex].like=like
this.content[this.chooseUserIndex].likeList.push({
userId: this.userInfo.userId,
nickName: this.userInfo.nickName,
portrait: this.userInfo.portrait
})
}
}
});
break;
case 'Y':
this.$http.request({
url: '/topic/cancelLike/'+e.topicId,
success: (res) => {
if (res.data.code == 200) {
this.hidenTool()
var like=e.like=='N' ? e.like='Y' : e.like='N'
this.content[this.chooseUserIndex].like=like
var thisObj=this.$fc.arrFindkey({arr:this.content[this.chooseUserIndex].likeList,key:'userId',val:this.userInfo.userId})
this.content[this.chooseUserIndex].likeList.splice(thisObj.index,1)
}
}
});
break;
default:
break;
}
},
sendMsg(e) {
if (!e) {
return;
}
var replyId=''
var replyType=''
if(this.type=='msg'){
replyId=this.content[this.chooseUserIndex].topicId
replyType='1'
}
if(this.type=='reply'){
replyId=this.replydata.replyId
replyType='2'
}
this.$http.request({
url: '/topic/reply',
method: 'POST',
data:JSON.stringify({
replyId: replyId,
replyType: replyType,
content: e
}),
success: (res) => {
if (res.data.code == 200) {
this.hidenTool()
this.content[this.chooseUserIndex].replyList.push(res.data.data)
}
}
});
this.msg=''
},
hidenTool() {//隐藏选项和输入框
this.showToolIndex = null;
this.toggleMsgBox = false;
}
}
};
</script>
<style scoped lang="scss">
.zfb-tk-send-tool {
background: #f7f7f7;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
.zfb-tk-send-tool-c {
padding: 16rpx 12rpx;
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
border: 1px #ddd solid;
border-left: none;
border-right: none;
}
.zfb-tk-send-tool-c .zfb-tk-send-tool-btn {
transition: color 0.5s;
}
.zfb-tk-send-tool .zfb-tk-send-tool-input {
padding:0 24rpx;
box-sizing: border-box !important;
width: 100%;
background: #fff;
}
.zfb-tk-send-tool-text {
white-space: nowrap;
padding: 10rpx 24rpx;
border-radius: 12rpx;
border: 1px #ddd solid;
background: #f7f7f7;
color: #ddd;
}
.friendsCircle-content-item{
display: flex;flex-direction: row;
padding:24rpx 34rpx;
border-bottom: 1px #F2F2F2 solid;
}
.friendsCircle-content-avatar{
border-radius: 10rpx;
width: 90rpx;
height: 90rpx;
min-width: 90rpx;
}
.friendsCircle-content-right{
display: flex;flex-direction: column;
padding-left: 18rpx;
flex: 1;
box-sizing: border-box;
}
.friendsCircle-content-nickName{
font-size: 32rpx;
color: #5F698C;
margin-bottom: 10rpx;
}
.friendsCircle-content-text{
font-size: 32rpx;
color: #333;
}
.friendsCircle-content-imgs{
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex: 1;
margin-top: 24rpx;
}
.friendsCircle-content-img{
max-width: 100%;
}
.friendsCircle-content-img.fci1{
height: 550rpx;
max-width: 500rpx;
margin-right: 5px;
}
.friendsCircle-content-img.fci2{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci2:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci3{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci3:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci4{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci4:nth-child(2n){
margin-right: 185rpx;
}
.friendsCircle-content-img.fci5{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci5:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci6{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci6:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci7{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci7:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci8{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci8:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-img.fci9{
width: 185rpx;
height: 185rpx;
margin-right: 5rpx;
margin-bottom: 5rpx;
}
.friendsCircle-content-img.fci9:nth-child(3n){
margin-right: 0;
}
.friendsCircle-content-location{
font-size: 24rpx;
color: #5F698C;
margin-top: 12rpx;
}
.friendsCircle-content-time{
font-size: 24rpx;
color: #666666;
margin-right: auto;
}
.friendsCircle-content-tools{
margin-top: 24rpx;
display: flex;flex-direction: row;align-items: center;
margin-bottom: 14rpx;
}
.friendsCircle-content-tool{
padding:4rpx 16rpx;
border-radius: 10rpx;
background-color: #F8F8FA;
color: #63678C;
display: flex;flex-direction: row;
position: relative;
}
.tabon .friendsCircle-content-tool-absolute{
display: block;
}
.friendsCircle-content-tool-absolute{
position: absolute;
right: 100%;
top: 50%;
transform: translateY(-50%);
display: none;
}
.friendsCircle-popup{
margin-right: 24rpx;
border-radius: 12rpx;
background-color: rgba(0,0,0,0.7);
height: 75rpx;
display: flex;flex-direction: row;align-items: center;
padding:0 24rpx;
}
.friendsCircle-popup-item{
color: #fff;
padding:0 25rpx;
height: 100%;
display: flex;flex-direction: row;align-items: center;
}
.friendsCircle-popup-item:nth-child(1):active .friendsCircle-popup-icon{
font-size: 56rpx;
}
.friendsCircle-popup-icon{
font-size: 46rpx;
}
.friendsCircle-popup-text{
white-space: nowrap;
}
.friendsCircle-like{
border-radius: 8rpx;
padding: 12rpx;
background-color: #F7F7F7;
display: flex;flex-direction: row;align-items: center;flex-wrap: wrap;
margin-bottom: 1px;
}
.friendsCircle-like-icon,.friendsCircle-like-text,.friendsCircle-comment-text{
color: #5F698C !important;
font-size: 28rpx;
}
.friendsCircle-comment-feedback .friendsCircle-comment-text{
margin:0 6rpx;
}
.friendsCircle-comment-text::after{
content: ":";
color: #333;
}
.friendsCircle-like-text{
margin-left: 4rpx;
margin-right: 10rpx;
}
.friendsCircle-like-text::after{
content: ",";
}
.friendsCircle-like-text:nth-last-child(1)::after{
content: "";
}
.friendsCircle-comment{
background-color: #F7F7F7;
border-radius: 8rpx;
}
.friendsCircle-comment-item{
line-height: 40rpx;
font-size: 28rpx;
padding: 12rpx;
white-space: pre-wrap;
display: flex;flex-direction: row;flex-wrap: wrap;
}
.friendsCircle-comment-feedback{
display: inline-block;
}
.friendsCircle-content-video{
width: auto;
height: 550rpx;
max-width: 400rpx;
position: relative;
margin-top: 24rpx;
}
.friendsCircle-content-video-img{
width: 100%;
height: 100%;
}
.friendsCircle-content-video-icon{
z-index: 1;
position: absolute;
left: 50%;
top: 50%;
width: 80rpx !important;
height: 80rpx !important;
transform: translate(-50%,-50%);
}
.friendsCircle-comment-content{
}
.friendsCircle-comment-content text{
word-break: break-all;
}
.zfb-tk-send-tool-input-box{
overflow: auto;
width: 100%;
margin: 0 12rpx;
min-height: 75rpx;
background-color: #fff;
border-radius: 24rpx;
padding-top: 18rpx;
max-height: 225rpx;
box-sizing: border-box;
}
</style>

View File

@@ -0,0 +1,230 @@
<template>
<view class="friends-circle-person-item" v-for="(v, i) in content" :key="i">
<view class="friends-circle-person-item-date">
<view class="friends-circle-person-item-date-top">
<text class="day">{{returnDate(v.time,'d')}}</text>
<text class="month">{{returnDate(v.time,'m')}}</text>
</view>
<view class="year">{{returnDate(v.time,'y')}}</view>
<view class="year" v-if="v.location.name">{{v.location.name}}</view>
</view>
<view class="friends-circle-person-view" @click="clickItem(v)">
<view class="friends-circle-person-content" v-if="v.topicType=='IMAGE'&&v.files.length>0">
<view class="friends-circle-person-imgs">
<image v-for="(item, ii) in v.files.slice(0,4)" :key="ii" :class="'fci' + v.files.slice(0,4).length" :src="item.url" mode="aspectFill"></image>
</view>
<view class="friends-circle-person-imgs-text">
<text>{{v.text}}</text>
<view class="friends-circle-person-imgs-total">{{v.files.length}}</view>
</view>
</view>
<view class="friends-circle-person-content" v-if="v.topicType=='VIDEO'&&v.files.length>0">
<view class="friendsCircle-content-video">
<image class="friendsCircle-content-video-icon" src="../../static/img/bf.png" mode="aspectFill"></image>
<image class="friendsCircle-content-video-img" :src="v.files[0].url" mode="aspectFill"></image>
</view>
<view class="friends-circle-person-imgs-text">
<text>{{v.text}}</text>
</view>
</view>
<view v-if="v.topicType=='TEXT'" class="friends-circle-person-content">
<view class="friends-circle-person-text">
<text>{{v.text}}</text>
</view>
</view>
</view>
</view>
<view class="friends-circle-nodata" v-if="content.length<=0">
<view class="friends-circle-nodata-line"></view>
<view class="friends-circle-nodata-text">未发布朋友圈</view>
</view>
</template>
<script>
export default {
// 朋友圈单人列表
emits:['clickItem'],
data() {
return {
};
},
props:{
content:{
type:Array,
default:[]
}
},
methods: {
returnDate(e,format){
return this.$fc.getNewDate(format,true,e)
},
clickItem(e){
this.$emit('clickItem',e)
}
}
};
</script>
<style scoped lang="scss">
.friends-circle-person-item{
display: flex;flex-direction: row;
margin-bottom: 60rpx;
width: 100%;
}
.friends-circle-person-view{
flex: 1;
}
.friends-circle-person-item-date{
display: flex;
flex-direction: column;
margin-right: 40rpx;
width: 115rpx;
min-width: 115rpx;
text-align: right;
}
.friends-circle-person-item-date-top{
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: flex-end;
}
.friends-circle-person-item-date .day{
font-size: 38rpx;
}
.friends-circle-person-item-date .month{
font-size: 26rpx;
margin-bottom: 4rpx;
}
.friends-circle-person-item-date .year{
width: 100%;
min-width: 100%;
font-size: 24rpx;
color: #999;
line-height: initial;
}
.friends-circle-person-content{
flex: 1;
display: flex;flex-direction: row;
}
.friends-circle-person-text{
padding: 12rpx;
background-color: #eee;
border-radius: 4rpx;
}
.friends-circle-person-text text{
font-size: 28rpx;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.friends-circle-person-imgs{
width: 140rpx;
min-width: 140rpx;
height: 140rpx;
margin-right: 14rpx;
}
.friends-circle-person-imgs image{float: left;}
.friends-circle-person-imgs .fci1{
width: 100%;
height: 100%;
}
.friends-circle-person-imgs .fci2{
margin-right: 2%;
width: 49%;
height: 100%;
}
.friends-circle-person-imgs .fci2:nth-child(2n){
margin-right: 0;
}
.friends-circle-person-imgs .fci3{
margin-right: 2%;
width: 49%;
height: 48%;
}
.friends-circle-person-imgs .fci3:nth-child(1){
height: 98%;
}
.friends-circle-person-imgs .fci3:nth-child(2){
margin-bottom: 2%;
}
.friends-circle-person-imgs .fci3:nth-child(2),.friends-circle-person-imgs .fci3:nth-child(3){
margin-right: 0;
}
.friends-circle-person-imgs .fci4{
margin-right: 2%;
width: 49%;
height: 49%;
margin-bottom: 2%;
}
.friends-circle-person-imgs .fci4:nth-child(2n){
margin-right: 0;
}
.friends-circle-person-imgs-text{
display: flex;
flex-direction: column;
justify-content: space-between;
}
.friends-circle-person-imgs-text text{
line-height: 1.2;
font-size: 28rpx;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.friends-circle-person-imgs-total{
color: #999;
font-size: 24rpx;
}
.friends-circle-nodata{
display: flex;flex-direction: column;
}
.friends-circle-nodata-line{
margin: 50rpx;
margin-bottom: 30rpx;
height: 1px;
position: relative;
background-color: #eee;
}
.friends-circle-nodata-line::after{
content: " ";
width: 13rpx;
height: 13rpx;
border-radius: 50%;
background-color: #eee;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.friends-circle-nodata-text{
font-size: 24rpx;
text-align: center;
color: #999;
}
.friendsCircle-content-video{
width: 140rpx;
height: 140rpx;
position: relative;
margin-right: 14rpx;
}
.friendsCircle-content-video-img{
width: 100%;
height: 100%;
}
.friendsCircle-content-video-icon{
z-index: 1;
position: absolute;
left: 50%;
top: 50%;
width: 60rpx !important;
height: 60rpx !important;
transform: translate(-50%,-50%);
}
</style>

View File

@@ -0,0 +1,327 @@
<template>
<view class="friendsCircle-top" :class="{ 'friendsCircle-top-opend': CircleTop, 'friendsCircle-top-type-img': cover.type == 'img' }" :key="ikey">
<view style="width: 100%;height: 100%;" v-if="cover.type == 'img'">
<image class="friendsCircle-top-img" @click="changeCircleTop" :src="cover.url" mode="aspectFill"></image>
<view class="friendsCircle-top-post" @click="changePoster" v-if="showChangePoster">
<view class="wxfont tupian"></view>
<text class="text">换封面</text>
</view>
<view class="friendsCircle-top-information" @click="userClick" v-if="userInfo">
<view class="friendsCircle-top-information-user">
<view class="friendsCircle-top-information-nikeName">{{userInfo.nickName}}</view>
<image class="friendsCircle-top-information-avatar" :src="userInfo.portrait" mode="aspectFill"></image>
</view>
<view class="friendsCircle-top-information-signature">{{userInfo.intro}}</view>
</view>
</view>
<video v-else class="friendsCircle-top-video" id="videodemo" ref="videodemo" :key="vkey" :autoplay="false" :src="cover.url" :controls="false" :loop="true" :show-center-play-btn="false" object-fit="cover" muted>
<cover-view class="friendsCircle-top-video-model-img-box"><cover-image class="friendsCircle-top-video-model-img" :src="cover.screenShot"></cover-image></cover-view>
<cover-view class="friendsCircle-top-video-model" @click="changeCircleTop"></cover-view>
<cover-view class="friendsCircle-top-post" @click="changePoster" v-if="showChangePoster">
<cover-image @click="changePoster" class="friendsCircle-top-post-img" src="../../static/img/f01.png"></cover-image>
<cover-view @click="changePoster" class="text">换封面</cover-view>
</cover-view>
<cover-view class="friendsCircle-top-information" @click="userClick" v-if="userInfo">
<cover-view class="friendsCircle-top-information-user">
<cover-view class="friendsCircle-top-information-nikeName">{{userInfo.nickName}}</cover-view>
<cover-image class="friendsCircle-top-information-avatar" :src="userInfo.portrait" mode="aspectFill"></cover-image>
</cover-view>
<cover-view class="friendsCircle-top-information-signature">{{userInfo.intro}}</cover-view>
</cover-view>
</video>
</view>
</template>
<script>
export default {
emits:['userClick'],
data() {
return {
CircleTop: false,
vkey: 0,
ikey:0,
videodemo: null
};
},
props:{
cover:{
type:Object,
default(){
return{
type:'img',
name:'',
url:''
}
}
},
userInfo:{
type:[Object,String]
},
showChangePoster:{
type:[Boolean],
default:true
},
},
watch:{
cover(v){
this.ikey++
this.vkey++;
}
},
methods: {
userClick(){//前往个人朋友圈
this.$emit('userClick',this.cover,this.userInfo)
},
changeCircleTop() {//顶部预览
this.CircleTop = !this.CircleTop;
if(this.type=='img'){
return
}
this.videodemo = uni.createVideoContext('videodemo', this);
this.$nextTick(() => {
setTimeout(() => {
this.vkey++;
this.$nextTick(() => {
if (this.CircleTop) {
this.videodemo.seek(0);
this.videodemo.play();
} else {
this.videodemo.pause();
this.videodemo.seek(0);
}
});
}, 105);
});
},
updateCover(formdata){
this.$http.request({
url: '/topic/editCover',
method: 'POST',
data:JSON.stringify({
cover:JSON.stringify(formdata)
}),
success: (res) => {
if (res.data.code == 200) {
this.$store.dispatch('get_UserInfo')
this.changeCircleTop()
}
}
});
},
changePoster() {//修改封面
uni.showActionSheet({
// itemList: ['图片封面', '视频封面'],
itemList: ['图片封面'],
success: (res) => {
switch (res.tapIndex){
case 0:
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album','camera'], //从相册选择
success: (res) => {
uni.showLoading({
title:'上传中'
})
this.$http.uploadFile({
url: '/file/upload',
filePath: res.tempFilePaths[0],
name: 'file',
fileType: 'image',
success: (res) => {
var data=JSON.parse(res.data)
if (data.code == 200) {
var formdata={
type:'img',
name:data.data.fileName,
url:data.data.fullPath
}
this.updateCover(formdata)
}
}
})
}
});
break;
case 1:
uni.chooseVideo({
sourceType: ['camera', 'album'],
success: (res) => {
uni.showLoading({
title:'上传中'
})
this.$http.uploadFile({
url: '/file/uploadVideo',
filePath: res.tempFilePath,
name: 'file',
fileType: 'video',
success: (res) => {
var data=JSON.parse(res.data)
if (data.code == 200) {
var formdata={
type:'video',
name:data.data.fileName,
url:data.data.fullPath,
screenShot:data.data.screenShot
}
this.updateCover(formdata)
}
}
})
}
});
break;
default:
break;
}
},
fail: function (res) {
console.log(res.errMsg);
}
});
},
},
};
</script>
<style scoped lang="scss">
.friendsCircle-top{
transition: all 0.1s;
width: 750rpx;
height: 590rpx;
position: relative;
background-image: linear-gradient( 135deg, #9708CC 10%, #43CBFF 100%);
}
.friendsCircle-top-type-img{
transition: all 0.3s;
}
.friendsCircle-top-img{
width: 100%;
height: 100%;
}
.friendsCircle-top-opend{
height: 80vh;
}
.friendsCircle-top-post-img{
width: 40rpx;
height: 40rpx;
margin: 0 auto;
}
.friendsCircle-top-post{
text-align: center;
z-index:99;
position: absolute;
bottom: 24rpx;
right: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
display: none;
}
.friendsCircle-top-post .tupian{
color: #f5f5f5;
font-size: 38rpx;
}
.friendsCircle-top-post .text{
font-size: 18rpx;
color: #f5f5f5;
}
.friendsCircle-top-video-model-img-box{
position: absolute;
width: 100%;
height: 80vh;
bottom: 0;
left: 0;
z-index: 2;
}
.friendsCircle-top-video-model-img{
width: 100%;
height: 100%;
}
.friendsCircle-top-video-model{
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 2;
// background-color: rgba(255,0,0,0.3);
}
.friendsCircle-top-opend .friendsCircle-top-post{
display: block;
}
.friendsCircle-top-video{
width: 100%;
height: 100%;
}
.friendsCircle-top-opend .friendsCircle-top-video-model-img-box{
display: none;
}
.friendsCircle-top-opend .friendsCircle-top-video{
height: 80vh;
}
.friendsCircle-top-information{
}
.friendsCircle-top-information-nikeName{
font-size: 32rpx;
color: #fff;
margin-top: 20rpx;
margin-right: 14rpx;
font-weight: bold;
text-shadow: 0px 0px 5px rgba(0,0,0,0.9);
}
.friendsCircle-top-information-avatar{
width: 120rpx;
min-width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
}
.friendsCircle-top-information{
z-index: 99;
display: flex;flex-direction: row;flex-wrap: wrap;
position: absolute;
bottom: -45rpx;
right: 24rpx;
display: flex;flex-direction: column;
}
.friendsCircle-top-information-signature{
position: absolute;
right: 0;
bottom: -45rpx;
width: 100%;
font-size: 24rpx;
color: #666;
text-align: right;
}
.friendsCircle-top-information-user{
display: flex;
flex-direction: row;
// border-radius: 12rpx;
// background-color: #f00;
}
.friendsCircle-top-opend .friendsCircle-top-information{
display: none;
}
.friendsCircle-top-video .friendsCircle-top-information{
bottom: -65rpx;
}
.friendsCircle-top-video .friendsCircle-top-information-user{
display: flex;
flex-direction: row;
}
.friendsCircle-top-video .friendsCircle-top-information-avatar{
float: left;
}
.friendsCircle-top-video .friendsCircle-top-information-nikeName{
float: left;
}
.friendsCircle-top-video .friendsCircle-top-information-signature{
position: inherit;
float: left;
margin-top: 10rpx;
}
</style>

View File

@@ -0,0 +1,145 @@
<template>
<view class="xw-tool-list">
<view class="xw-tool-list-content" v-if="type=='list'">
<template v-for="(item, i) in list" :key="i">
<view class="xw-tool-item" @click="onClick(item,i)" @longpress="onlongpress(item,i)" v-if="item.title">
<image v-if="item.icon" class="xw-tool-img" :src="item.icon" mode="aspectFill"></image>
<view class="xw-tool-text">
<uni-badge v-if="item.type == 'dottext'" text="1" is-dot absolute="rightTop" size="normal">
<text>{{ item.title }}</text>
</uni-badge>
<text v-else>{{ item.title }}</text>
</view>
<view class="xw-tool-else">
<view v-for="(v, index) in item.else" :key="index">
<uni-badge v-if="v.type == 'dotimg'" class="xw-tool-badge" text="1" is-dot absolute="rightTop" size="normal"><image :src="v.content" mode="aspectFill"></image></uni-badge>
<image v-if="v.type == 'img'" :src="v.content" mode="aspectFill"></image>
<uni-badge v-if="v.type == 'dottext'" class="xw-tool-badge" text="1" is-dot absolute="rightTop" size="normal"><view class="text">{{ v.content }}</view></uni-badge>
<view class="text" v-if="v.type == 'text'">{{ v.content }}</view>
</view>
</view>
<uni-icons v-if="!item.hideRight" class="xw-tool-right" type="right" size="16" color="#b5b5b5"></uni-icons>
</view>
</template>
</view>
<view class="xw-tool-list-content" v-if="type=='btns'">
<view class="xw-tool-btn-item" v-for="(item, i) in list" :key="i" @click="onClick(item,i)" @longpress="onlongpress(item,i)">
<view class="xw-tool-btn-icon wxfont " :class="item.icon"></view>
<view class="xw-tool-btn-text">{{item.title}}</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'toolListWx', //微信功能列表
data() {
return {};
},
emits: ['itemClick','onlongpress'],
props: {
list: {
type: Array
},
type: {
type: String,
default: 'list' //list列表icon为图片btns按钮组icon为字体
}
},
methods: {
onlongpress(e,i){
this.$emit('onlongpress', e,i);
},
onClick(e,i) {
this.$emit('itemClick', e,i);
if (e.path=='#') {
return;
}
if (!e.path&&!e.hideRight) {
uni.showToast({
title: '未开通',
icon: 'none'
});
return;
}
uni.navigateTo({
url: e.path
});
}
}
};
</script>
<style scoped>
.xw-tool-list {
display: flex;
flex-direction: column;
background-color: #ffffff;
margin-bottom: 18rpx;
}
.xw-tool-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 26rpx 24rpx;
border-bottom: 1px #eee solid;
}
.xw-tool-item:nth-last-child(1) {
border: none;
}
.xw-tool-img {
width: 52rpx;
height: 52rpx;
margin-right: 24rpx;
}
.xw-tool-text {
white-space: nowrap;
margin-right: auto;
}
.xw-tool-badge {
}
.xw-tool-else {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
}
.xw-tool-else image {
width: 60rpx;
height: 60rpx;
border-radius: 6rpx;
}
.xw-tool-else .text {
color: #666;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
max-width: 520rpx;
}
.xw-tool-else image,
.xw-tool-else .text {
margin-left: 12rpx;
}
.xw-tool-right {
margin-left: 12rpx;
}
.xw-tool-btn-item{
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 34rpx 44rpx;
border-bottom: 1px #eee solid;
font-weight: bold;
color: #5F698C;
}
.xw-tool-btn-icon{
margin-right: 14rpx;
}
</style>

View File

@@ -0,0 +1,156 @@
<template>
<view @touchmove.stop.prevent="moveHandle('touchmove')" @click="moveHandle('click')" v-if="show">
<view class="top-right-tool-wx" :animation="animationData" :style="{ top: height + 'px' }">
<view class="top-right-tool-wx-icon"></view>
<view class="top-right-tool-wx-list">
<view class="top-right-tool-wx-list-item" @click="groupChat">
<view class="top-right-tool-wx-list-item-icon"><view class="wxfont xiaoxi"></view></view>
<view class="text">发起群聊</view>
</view>
<view class="top-right-tool-wx-list-item" @click="goSearchFriends">
<view class="top-right-tool-wx-list-item-icon"><view class="wxfont jiahaoyou"></view></view>
<view class="text">添加朋友</view>
</view>
<view class="top-right-tool-wx-list-item" @click="saoyisao">
<view class="top-right-tool-wx-list-item-icon"><view class="wxfont saoyisao"></view></view>
<view class="text">扫一扫</view>
</view>
</view>
</view>
<view class="top-right-tool-wx-model"></view>
</view>
</template>
<script>
export default {
data() {
return {
height: 0 ,//距离顶部高度
show:false,
animationData: {}
};
},
props: {
list: {
type: Array,
default() {
return [{}];
}
}
},
onShow() {
},
mounted() {
this.getstatusBarHeight();
var animation = uni.createAnimation({
duration: 300,
timingFunction: 'linear'
});
this.animation = animation;
},
methods: {
groupChat(){
uni.navigateTo({
url:'../../wx/group/createGroup'
})
},
goSearchFriends(){
uni.navigateTo({
url:'../../wx/search-friends/index'
})
},
saoyisao(){
this.$fc.saoyisao()
},
showAnimation() {
this.animation.opacity(1).step();
this.animationData = this.animation.export();
},
hideAnimation() {
this.animation.opacity(0).step();
this.animationData = this.animation.export();
},
moveHandle(e) {
this.hiddenTab()
},
showTab(){
this.show=true
setTimeout(()=>{
this.showAnimation()
},30)
},
hiddenTab(){
this.show=false
this.hideAnimation()
},
getstatusBarHeight() {
var SystemInfo = uni.getSystemInfoSync();
// #ifdef H5
this.height = SystemInfo.safeArea.top + SystemInfo.windowTop;
// #endif
}
}
};
</script>
<style scoped>
.top-right-tool-wx {
width: 300rpx;
position: fixed;
z-index: 9999;
top: -10px;
right: 16rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
opacity: 0;
}
.top-right-tool-wx-model{
background-color: rgba(0,0,0,0);
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 9998;
}
.top-right-tool-wx-icon {
width: 0px;
height: 0px;
border: 10px solid transparent;
border-bottom-color: #4C4C4C;
margin-left: auto;
margin-right: 20rpx;
}
.top-right-tool-wx-list {
width: 100%;
background-color: #4C4C4C;
border-radius: 10rpx;
}
.top-right-tool-wx-list-item {
display: flex;
flex-direction: row;
align-items: center;
padding: 0rpx 36rpx;
padding-right: 0;
}
.top-right-tool-wx-list-item-icon {
width: 38rpx;
height: 38rpx;
margin-right: 28rpx;
color: #fff;
}
.top-right-tool-wx-list-item-icon .wxfont {
font-size: 40rpx;
}
.top-right-tool-wx-list-item .text {
color: #fff;
font-size: 32rpx;
border-bottom: 1px #535353 solid;
padding: 30rpx 0rpx;
flex: 1;
}
.top-right-tool-wx-list-item:nth-last-child(1) .text{
border: none;
}
</style>

View File

@@ -0,0 +1,105 @@
<template>
<view>
<view v-if="loaded || list.itemIndex < 15" class="xw-book-wrapper">
<view v-if="list.items && list.items.length > 0" class="xw-book-sort">{{ list.key }}</view>
</view>
<view v-if="(loaded || list.itemIndex < 15) && list.items && list.items.length > 0" class="xw-book-userlist">
<view v-for="(item, index) in list.items" :key="index">
<view class="xw-book-user" @click="onClick(idx, index)">
<view v-if="showSelect" class="xw-book-user-checked">
<uni-icons :type="item.checked ? 'checkbox-filled' : 'circle'" :color="item.checked ? '#09C160' : '#C0C0C0'" size="28" />
</view>
<image class="xw-book-user-avatar" :src="item.data.avatar" mode="aspectFill"></image>
<view class="xw-book-user-name">{{item.data.name}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'UniIndexedListWX',
emits: ['itemClick'],
props: {
loaded: {
type: Boolean,
default: false
},
idx: {
type: Number,
default: 0
},
list: {
type: Object,
default () {
return {}
}
},
showSelect: {
type: Boolean,
default: false
}
},
methods: {
onClick(idx, index) {
this.$emit("itemClick", {
idx,
index
})
}
}
}
</script>
<style lang="scss" scoped>
.xw-book-wrapper {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
/* #endif */
}
.xw-book-sort {
padding: 0 24rpx;
flex: 1;
line-height: 60rpx;
background-color: #fafafa;
font-size: 26rpx;
}
.xw-book-userlist {
padding: 0 24rpx;
padding-right: 0;
border-radius: 24rpx;
box-shadow: 0px 0px 10rpx rgba(0, 0, 0, 0.05);
}
.xw-book-user {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
}
.xw-book-user-avatar {
width: 90rpx;
height: 90rpx;
border-radius: 10rpx;
}
.xw-book-user-name {
font-size: 32rpx;
margin-left: 26rpx;
height: 90rpx;
line-height: 90rpx;
padding-bottom: 13rpx;
padding-top: 13rpx;
border-bottom: 1px #f8f8f8 solid;
max-width: 560rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.xw-book-user-checked{
margin-right: 20rpx;
}
</style>

View File

@@ -0,0 +1,456 @@
<template>
<view class="uni-indexed-list" ref="list" id="list">
<!-- #ifdef APP-NVUE -->
<list class="uni-indexed-list__scroll" scrollable="true" show-scrollbar="false">
<cell v-for="(list, idx) in lists" :key="idx" :ref="'uni-indexed-list-' + idx">
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<scroll-view :scroll-into-view="scrollViewId" class="uni-indexed-list__scroll" scroll-y>
<view class="xw-book-add" v-if="showAdd">
<view class="xw-book-add-item" v-for="(v,i) in addlist" :key="i" @click="gopath(v)">
<uni-badge v-if="v.num" :text="v.num+''" absolute="rightTop">
<view class="xw-book-add-icon">
<view class="wxfont jiahaoyou"></view>
</view>
</uni-badge>
<view v-else class="xw-book-add-icon" :style="{background:v.color}">
<view class="wxfont jiahaoyou"></view>
</view>
<view class="xw-book-add-item-text">{{v.title}}</view>
</view>
</view>
<view v-for="(list, idx) in lists" :key="idx" :id="'uni-indexed-list-' + idx">
<!-- #endif -->
<indexed-list-item :list="list" :loaded="loaded" :idx="idx" :showSelect="showSelect"
@itemClick="onClick"></indexed-list-item>
<!-- #ifndef APP-NVUE -->
</view>
</scroll-view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
</cell>
</list>
<!-- #endif -->
<view class="uni-indexed-list__menu" @touchstart="touchStart" @touchmove.stop.prevent="touchMove"
@touchend="touchEnd" @mousedown.stop="mousedown" @mousemove.stop.prevent="mousemove"
@mouseleave.stop="mouseleave">
<view v-for="(list, key) in lists" :key="key" class="uni-indexed-list__menu-item"
:class="touchmoveIndex == key ? 'uni-indexed-list__menu--active' : ''">
<text class="uni-indexed-list__menu-text"
:class="touchmoveIndex == key ? 'uni-indexed-list__menu-text--active' : ''">{{ list.key }}</text>
</view>
</view>
<view v-if="touchmove" class="uni-indexed-list__alert-wrapper">
<text class="uni-indexed-list__alert">{{ lists[touchmoveIndex].key }}</text>
</view>
</view>
</template>
<script>
import indexedListItem from './uni-indexed-list-item.vue'
// #ifdef APP-NVUE
const dom = weex.requireModule('dom');
// #endif
// #ifdef APP-PLUS
function throttle(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function touchMove(e) {
let pageY = e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
if (this.touchmoveIndex === index) {
return false
}
let item = this.lists[index]
if (item) {
// #ifndef APP-NVUE
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
// #endif
// #ifdef APP-NVUE
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], {
animated: false
})
this.touchmoveIndex = index
// #endif
}
}
const throttleTouchMove = throttle(touchMove, 40)
// #endif
/**
* IndexedList 索引列表 微信版
* @description 用于展示索引列表
* @tutorial https://ext.dcloud.net.cn/plugin?id=375
* @property {Boolean} showSelect = [true|false] 展示模式
* @value true 展示模式
* @value false 选择模式
* @property {Object} options 索引列表需要的数据对象
* @event {Function} click 点击列表事件 ,返回当前选择项的事件对象
* @example <uni-indexed-list options="" showSelect="false" @click=""></uni-indexed-list>
*/
export default {
name: 'UniIndexedListWX',
components: {
indexedListItem
},
emits: ['click'],
props: {
options: {
type: Array,
default () {
return []
}
},
showSelect: {
type: Boolean,
default: false
},
showAdd: {
type: Boolean,
default: true
}
},
data() {
return {
lists: [],
winHeight: 0,
itemHeight: 0,
winOffsetY: 0,
touchmove: false,
touchmoveIndex: -1,
scrollViewId: '',
touchmovable: true,
loaded: false,
isPC: false
}
},
computed:{
friendApply() {
return this.$store.state.friendApply
},
addlist(){
return [{
title:'新的朋友',
path:'../../wx/search-friends/index',
num:this.$store.state.friendApply.count ? this.$store.state.friendApply.count : '',
icon:'jiahaoyou',
color:'#FB9E3E'
},{
title:'群聊',
path:'../../wx/groupInfo/grouplist',
icon:'qunl',
num:'',
color:'#0ABF62'
}]
}
},
watch: {
options: {
handler: function() {
this.setList()
},
deep: true
}
},
mounted() {
// #ifdef H5
this.isPC = this.IsPC()
// #endif
setTimeout(() => {
this.setList()
}, 50)
setTimeout(() => {
this.loaded = true
}, 300);
},
methods: {
gopath(e){
uni.navigateTo({
url:e.path
})
},
setList() {
let index = 0;
this.lists = []
this.options.forEach((value, index) => {
if (value.data.length === 0) {
return
}
let indexBefore = index
let items = value.data.map(item => {
let obj = {}
obj['key'] = value.letter
obj['data'] = item
obj['itemIndex'] = index
index++
obj.checked = item.checked ? item.checked : false
return obj
})
this.lists.push({
title: value.letter,
key: value.letter,
items: items,
itemIndex: indexBefore
})
})
// #ifndef APP-NVUE
uni.createSelectorQuery()
.in(this)
.select('#list')
.boundingClientRect()
.exec(ret => {
this.winOffsetY = ret[0].top
this.winHeight = ret[0].height
this.itemHeight = this.winHeight / this.lists.length
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['list'], (res) => {
this.winOffsetY = res.size.top
this.winHeight = res.size.height
this.itemHeight = this.winHeight / this.lists.length
})
// #endif
},
touchStart(e) {
this.touchmove = true
let pageY = this.isPC ? e.pageY : e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
let item = this.lists[index]
if (item) {
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
// #ifdef APP-NVUE
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], {
animated: false
})
// #endif
}
},
touchMove(e) {
// #ifndef APP-PLUS
let pageY = this.isPC ? e.pageY : e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
if (this.touchmoveIndex === index) {
return false
}
let item = this.lists[index]
if (item) {
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
}
// #endif
// #ifdef APP-PLUS
throttleTouchMove.call(this, e)
// #endif
},
touchEnd() {
this.touchmove = false
// this.touchmoveIndex = -1
},
/**
* 兼容 PC @tian
*/
mousedown(e) {
if (!this.isPC) return
this.touchStart(e)
},
mousemove(e) {
if (!this.isPC) return
this.touchMove(e)
},
mouseleave(e) {
if (!this.isPC) return
this.touchEnd(e)
},
// #ifdef H5
IsPC() {
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (let v = 0; v < Agents.length - 1; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
},
// #endif
onClick(e) {
let {
idx,
index
} = e
let obj = {}
for (let key in this.lists[idx].items[index]) {
obj[key] = this.lists[idx].items[index][key]
}
let select = []
if (this.showSelect) {
this.lists[idx].items[index].checked = !this.lists[idx].items[index].checked
this.lists.forEach((value, idx) => {
value.items.forEach((item, index) => {
if (item.checked) {
let obj = {}
for (let key in this.lists[idx].items[index]) {
obj[key] = this.lists[idx].items[index][key]
}
select.push(obj)
}
})
})
}
this.$emit('click', {
item: obj,
select: select
})
}
}
}
</script>
<style lang="scss" scoped>
.uni-indexed-list {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
}
.uni-indexed-list__scroll {
flex: 1;
height: 100%;
}
.uni-indexed-list__menu {
width: 24px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-indexed-list__menu-item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
align-items: center;
justify-content: center;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-indexed-list__menu-text {
font-size: 12px;
text-align: center;
color: #aaa;
}
.uni-indexed-list__menu--active {
// background-color: rgb(200, 200, 200);
}
.uni-indexed-list__menu--active {}
.uni-indexed-list__menu-text--active {
border-radius: 16px;
width: 16px;
height: 16px;
line-height: 16px;
// background-color: #007aff;
// color: #fff;
}
.uni-indexed-list__alert-wrapper {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
}
.uni-indexed-list__alert {
width: 80px;
height: 80px;
border-radius: 80px;
text-align: center;
line-height: 80px;
font-size: 35px;
color: #fff;
background-color: rgba(0, 0, 0, 0.5);
}
.h5-buchang{
height: 140rpx;
display: none;
}
.uni-scroll-view-content view:nth-last-child(1) .h5-buchang{
display: block;
}
.xw-book-add{
width: 100%;
display: flex;
flex-direction: column;
padding:0 24rpx;
box-sizing: border-box;
// height: 120rpx;
}
.xw-book-add-item{
display: flex;flex-direction: row;align-items: center;
// height: 90rpx;
// line-height: 90rpx;
padding-bottom: 16rpx;
padding-top: 16rpx;
// border-bottom: 1px #f8f8f8 solid;
}
.xw-book-add-icon{
background: #FB9E3E;
border-radius: 10rpx;
width: 90rpx;
height: 90rpx;
display: flex;flex-direction: row;align-items: center;justify-content: center;
}
.xw-book-add-icon .wxfont{
color: #fff;
font-size: 58rpx;
}
.xw-book-add-item-text{
flex: 1;
font-size: 32rpx;
margin-left: 26rpx;
// height: 90rpx;
// line-height: 90rpx;
// border-bottom: 1px #f8f8f8 solid;
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<view @touchmove.stop.prevent="moveHandle('touchmove')" @click="moveHandle('click')" v-if="show">
<view class="openTool-wx" :animation="animationData">
<view class="openTool-wx-list" v-if="data">
<view class="openTool-wx-list-item" @click="zhiding">
<view class="text" v-if="data.top=='Y'">取消置顶</view>
<view class="text" v-if="data.top=='N'">置顶该聊天</view>
</view>
<view class="openTool-wx-list-item" @click="shanchu">
<view class="text">删除该聊天</view>
</view>
</view>
</view>
<view class="openTool-wx-model"></view>
</view>
</template>
<script>
export default {
data() {
return {
show:false,
animationData: {}
};
},
props: {
data:{
type:[Object,String]
},
itemKey:{
type:[Object,String,Number]
},
list: {
type: Array,
default() {
return [{}];
}
}
},
onShow() {
},
computed: {
chatList() {
return this.$store.state.chatlist
}
},
mounted() {
var animation = uni.createAnimation({
duration: 300,
timingFunction: 'linear'
});
this.animation = animation;
},
methods: {
zhiding(){
var data=JSON.parse(JSON.stringify(this.data))
var yn = data.top=='N' ? 'Y' : 'N';
data.top=yn
this.$store.dispatch('updateChatListInfoById', {
userId: this.data.userId,
data: data
})
this.$store.dispatch('getChatList')
if(data.windowType=='GROUP'){
var formData = {
groupId: this.data.userId,
top: yn
};
this.$http.request({
url: '/group/editTop',
method: 'POST',
data: JSON.stringify(formData),
success: res => {
if (res.data.code == 200) {
}
}
});
}
if(data.windowType=='SINGLE'){
var formData = {
userId: this.data.userId,
top: yn
};
this.$http.request({
url: '/friend/top',
method: 'POST',
data: JSON.stringify(formData),
success: res => {
if (res.data.code == 200) {
}
}
});
}
},
shanchu(){
delete this.chatList[this.data.userId]
this.$store.dispatch('updateChatListInfoById',{
userId: this.data.userId,
data: {}
});
this.$store.dispatch('updateChatById', {
userId: this.data.userId,
data: []
});
},
showAnimation() {
this.animation.opacity(1).step();
this.animationData = this.animation.export();
},
hideAnimation() {
this.animation.opacity(0).step();
this.animationData = this.animation.export();
},
moveHandle(e) {
this.hiddenTab()
},
showTab(){
this.show=true
setTimeout(()=>{
this.showAnimation()
},30)
},
hiddenTab(){
this.show=false
this.hideAnimation()
},
}
};
</script>
<style scoped>
.openTool-wx {
display: flex;
flex-direction: column;
flex-wrap: wrap;
opacity: 0;
position: relative;
z-index: 2;
}
.openTool-wx-model{
background-color: rgba(0,0,0,0);
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 1;
}
.openTool-wx-list {
width: 100%;
box-sizing: border-box;
background-color: #fff;
box-shadow: 0px 0px 10px rgba(0,0,0,0.3);
border-radius: 10rpx;
display: flex;
flex-direction: column;
}
.openTool-wx-list-item {
padding: 24rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.openTool-wx-list-item .text {
color: #333;
font-size: 28rpx;
flex: 1;
}
.openTool-wx-list-item:nth-last-child(1) .text{
border: none;
}
</style>

View File

@@ -0,0 +1,583 @@
<template>
<!-- #ifdef APP-NVUE -->
<cell>
<!-- #endif -->
<view :hover-class="!clickable && !link ? '' : 'uni-list-chat--hover'" :style="{background:color}" class="uni-list-chat" @longpress="longpressItem($event,itemKey,item)">
<openTool class="openTool" :ref="'toolx'+itemKey" :data="item" :itemKey="itemKey"></openTool>
<view :class="{ 'uni-list--border': border, 'uni-list-chat--first': isFirstChild }"></view>
<view class="uni-list-chat__container" @click="onClick">
<view class="uni-list-chat__header-warp">
<view v-if="item.windowType=='SINGLE'" class="uni-list-chat__header" :class="{ 'header--circle': avatarCircle }">
<image class="uni-list-chat__header-image" :src="item.portrait" mode="aspectFill"></image>
</view>
<!-- 头像组 -->
<view v-if="item.windowType=='GROUP'" class="uni-list-chat__header">
<view v-for="(item, index) in avatarList" :key="index" class="uni-list-chat__header-box" :class="computedAvatar"
:style="{ width: imageWidth + 'px', height: imageWidth + 'px' }">
<image class="uni-list-chat__header-image" :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }" :src="item.url"
mode="aspectFill"></image>
</view>
</view>
</view>
<view v-if="badgeText && badgePositon === 'left'" class="uni-list-chat__badge uni-list-chat__badge-pos" :class="[isSingle]">
<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
</view>
<view class="uni-list-chat__content">
<view class="uni-list-chat__content-main">
<text class="uni-list-chat__content-title uni-ellipsis">{{ title }}</text>
<text class="uni-list-chat__content-note uni-ellipsis">{{ note }}</text>
</view>
<view class="uni-list-chat__content-extra">
<slot>
<text class="uni-list-chat__content-extra-text">{{ time }}</text>
<view v-if="badgeText && badgePositon === 'right'" class="uni-list-chat__badge" :class="[isSingle, badgePositon === 'right' ? 'uni-list-chat--right' : '']">
<text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
</view>
</slot>
</view>
</view>
</view>
</view>
<!-- #ifdef APP-NVUE -->
</cell>
<!-- #endif -->
</template>
<script>
import openTool from './openTool.vue'
// 头像大小
const avatarWidth = 45;
/**
* ListChat 聊天列表
* @description 聊天列表,用于创建聊天类列表
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
* @property {String} title 标题
* @property {String} note 描述
* @property {Boolean} clickable = [true|false] 是否开启点击反馈默认为false
* @property {String} badgeText 数字角标内容
* @property {String} badgePositon = [left|right] 角标位置,默认为 right
* @property {String} link = [falsenavigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈默认为false
* @value false 不开启
* @value navigateTo 同 uni.navigateTo()
* @value redirectTo 同 uni.redirectTo()
* @value reLaunch 同 uni.reLaunch()
* @value switchTab 同 uni.switchTab()
* @property {String | PageURIString} to 跳转目标页面
* @property {String} time 右侧时间显示
* @property {Boolean} avatarCircle = [true|false] 是否显示圆形头像默认为false
* @property {String} avatar 头像地址avatarCircle 不填时生效
* @property {Array} avatarList 头像组,格式为 [{url:''}]
* @event {Function} click 点击 uniListChat 触发事件
*/
export default {
components:{
openTool
},
name: 'UniListChatWx',
emits:['click','longpressItem'],
props: {
color: {
type: String,
default: '#fff'
},
title: {
type: String,
default: ''
},
note: {
type: String,
default: ''
},
clickable: {
type: Boolean,
default: false
},
link: {
type: [Boolean, String],
default: false
},
to: {
type: String,
default: ''
},
badgeText: {
type: [String, Number],
default: ''
},
badgePositon: {
type: String,
default: 'right'
},
time: {
type: String,
default: ''
},
avatarCircle: {
type: Boolean,
default: false
},
avatar: {
type: String,
default: ''
},
// avatarList: {
// type: Array,
// default () {
// return [];
// }
// },
item: {
type: Object,
default: {}
},
itemKey: {
type: Number
},
longTapItemKey: {
type: [Number,String],
default:''
}
},
// inject: ['list'],
computed: {
isSingle() {
if (this.badgeText === 'dot') {
return 'uni-badge--dot';
} else {
const badgeText = this.badgeText.toString();
if (badgeText.length > 1) {
return 'uni-badge--complex';
} else {
return 'uni-badge--single';
}
}
},
avatarList(){
return this.returnAvatar(this.item.portrait)
},
computedAvatar() {
if (this.avatarList.length > 4) {
this.imageWidth = avatarWidth * 0.31;
return 'avatarItem--3';
} else if (this.avatarList.length > 1) {
this.imageWidth = avatarWidth * 0.47;
return 'avatarItem--2';
} else {
this.imageWidth = avatarWidth;
return 'avatarItem--1';
}
}
},
data() {
return {
isFirstChild: false,
border: true,
// avatarList: 3,
imageWidth: 50
};
},
mounted() {
this.list = this.getForm()
if (this.list) {
if (!this.list.firstChildAppend) {
this.list.firstChildAppend = true;
this.isFirstChild = true;
}
this.border = this.list.border;
}
},
methods: {
returnAvatar(text){
var data=JSON.parse(text)
var avatars=[]
for(var i=0;i<data.length;i++){
avatars.push({
url:data[i]
})
}
return avatars
},
longpressItem(e,i,v) {//长按回调
this.$emit('longpressItem',e,i,v)
if(this.itemKey==this.longTapItemKey){
this.$refs['toolx'+this.itemKey].showTab();
}
},
/**
* 获取父元素实例
*/
getForm(name = 'uniList') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false
parentName = parent.$options.name;
}
return parent;
},
onClick() {
if (this.to !== '') {
this.openPage();
return;
}
if (this.clickable || this.link) {
this.$emit('click', {
data: {}
});
}
},
openPage() {
if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
this.pageApi(this.link);
} else {
this.pageApi('navigateTo');
}
},
pageApi(api) {
uni[api]({
url: this.to,
success: res => {
this.$emit('click', {
data: res
});
},
fail: err => {
this.$emit('click', {
data: err
});
console.error(err.errMsg);
}
});
}
}
};
</script>
<style lang="scss" scoped>
$uni-font-size-lg:16px;
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
$background-color: #fff;
$divide-line-color: #e5e5e5;
$avatar-width: 45px;
$avatar-border-radius: 5px;
$avatar-border-color: #eee;
$avatar-border-width: 1px;
$title-size: 16px;
$title-color: #3b4144;
$title-weight: normal;
$note-size: 12px;
$note-color: #999;
$note-weight: normal;
$right-text-size: 12px;
$right-text-color: #999;
$right-text-weight: normal;
$badge-left: 0px;
$badge-top: 0px;
$dot-width: 10px;
$dot-height: 10px;
$badge-size: 18px;
$badge-font: 12px;
$badge-color: #fff;
$badge-background-color: #ff5a5f;
$badge-space: 6px;
$hover: #f5f5f5;
.openTool{
width: 100%;
position: absolute;
top: 50%;
display: flex;flex-direction: row;justify-content: center;
}
.uni-list-chat {
font-size: $uni-font-size-lg;
position: relative;
flex-direction: column;
justify-content: space-between;
background-color: $background-color;
position: relative;
}
// .uni-list-chat--disabled {
// opacity: 0.3;
// }
.uni-list-chat--hover {
background-color: $hover;
}
.uni-list--border {
position: relative;
margin-left: $uni-spacing-row-lg;
/* #ifdef APP-PLUS */
border-top-color: $divide-line-color;
border-top-style: solid;
border-top-width: 0.5px;
/* #endif */
}
/* #ifndef APP-NVUE */
.uni-list--border:after {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $divide-line-color;
}
.uni-list-item--first:after {
height: 0px;
}
/* #endif */
.uni-list-chat--first {
border-top-width: 0px;
}
.uni-ellipsis {
/* #ifndef APP-NVUE */
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
/* #endif */
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
}
.uni-ellipsis-2 {
/* #ifndef APP-NVUE */
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
/* #endif */
/* #ifdef APP-NVUE */
lines: 2;
/* #endif */
}
.uni-list-chat__container {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex: 1;
padding: $uni-spacing-row-base $uni-spacing-row-lg;
position: relative;
overflow: hidden;
}
.uni-list-chat__header-warp {
position: relative;
}
.uni-list-chat__header {
/* #ifndef APP-NVUE */
display: flex;
align-content: center;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap-reverse;
/* #ifdef APP-NVUE */
width: 50px;
height: 50px;
/* #endif */
/* #ifndef APP-NVUE */
width: $avatar-width;
height: $avatar-width;
/* #endif */
border-radius: $avatar-border-radius;
border-color: $avatar-border-color;
border-width: $avatar-border-width;
border-style: solid;
overflow: hidden;
}
.uni-list-chat__header-box {
/* #ifndef APP-PLUS */
box-sizing: border-box;
display: flex;
width: $avatar-width;
height: $avatar-width;
/* #endif */
/* #ifdef APP-NVUE */
width: 50px;
height: 50px;
/* #endif */
overflow: hidden;
border-radius: 2px;
}
.uni-list-chat__header-image {
margin: 1px;
/* #ifdef APP-NVUE */
width: 50px;
height: 50px;
/* #endif */
/* #ifndef APP-NVUE */
width: $avatar-width;
height: $avatar-width;
/* #endif */
}
/* #ifndef APP-NVUE */
.uni-list-chat__header-image {
display: block;
width: 100%;
height: 100%;
}
.avatarItem--1 {
width: 100%;
height: 100%;
}
.avatarItem--2 {
width: 47%;
height: 47%;
}
.avatarItem--3 {
width: 32%;
height: 32%;
}
/* #endif */
.header--circle {
border-radius: 50%;
}
.uni-list-chat__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex: 1;
overflow: hidden;
padding: 2px 0;
}
.uni-list-chat__content-main {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: space-between;
padding-left: $uni-spacing-row-base;
flex: 1;
overflow: hidden;
}
.uni-list-chat__content-title {
font-size: $title-size;
color: $title-color;
font-weight: $title-weight;
overflow: hidden;
}
.uni-list-chat__content-note {
margin-top: 3px;
color: $note-color;
font-size: $note-size;
font-weight: $title-weight;
overflow: hidden;
}
.uni-list-chat__content-extra {
/* #ifndef APP-NVUE */
flex-shrink: 0;
display: flex;
/* #endif */
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
margin-left: 5px;
}
.uni-list-chat__content-extra-text {
color: $right-text-color;
font-size: $right-text-size;
font-weight: $right-text-weight;
overflow: hidden;
}
.uni-list-chat__badge-pos {
position: absolute;
/* #ifdef APP-NVUE */
left: 55px;
top: 3px;
/* #endif */
/* #ifndef APP-NVUE */
left: calc(#{$avatar-width} + 10px - #{$badge-space} + #{$badge-left});
top: calc(#{$uni-spacing-row-base}/ 2 + 1px + #{$badge-top});
/* #endif */
}
.uni-list-chat__badge {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
border-radius: 100px;
background-color: $badge-background-color;
}
.uni-list-chat__badge-text {
color: $badge-color;
font-size: $badge-font;
}
.uni-badge--single {
/* #ifndef APP-NVUE */
// left: calc(#{$avatar-width} + 7px + #{$badge-left});
/* #endif */
width: $badge-size;
height: $badge-size;
}
.uni-badge--complex {
/* #ifdef APP-NVUE */
left: 50px;
/* #endif */
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
height: $badge-size;
padding: 0 $badge-space;
}
.uni-badge--dot {
/* #ifdef APP-NVUE */
left: 60px;
top: 6px;
/* #endif */
/* #ifndef APP-NVUE */
left: calc(#{$avatar-width} + 15px - #{$dot-width}/ 2 + 1px + #{$badge-left});
/* #endif */
width: $dot-width;
height: $dot-height;
padding: 0;
}
.uni-list-chat--right {
/* #ifdef APP-NVUE */
left: 0;
/* #endif */
}
</style>

View File

@@ -0,0 +1,108 @@
<template>
<!-- #ifndef APP-NVUE -->
<view class="uni-list uni-border-top-bottom">
<view v-if="border" class="uni-list--border-top"></view>
<slot />
<view v-if="border" class="uni-list--border-bottom"></view>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<list class="uni-list" :class="{ 'uni-list--border': border }" :enableBackToTop="enableBackToTop" loadmoreoffset="15"><slot /></list>
<!-- #endif -->
</template>
<script>
/**
* List 列表
* @description 列表组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=24
* @property {String} border = [true|false] 标题
*/
export default {
name: 'uniListWx',
'mp-weixin': {
options: {
multipleSlots: false
}
},
props: {
enableBackToTop: {
type: [Boolean, String],
default: false
},
scrollY: {
type: [Boolean, String],
default: false
},
border: {
type: Boolean,
default: true
}
},
// provide() {
// return {
// list: this
// };
// },
created() {
this.firstChildAppend = false;
},
methods: {
loadMore(e) {
this.$emit('scrolltolower');
}
}
};
</script>
<style lang="scss" scoped>
$uni-bg-color:#ffffff;
$uni-border-color:#e5e5e5;
.uni-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
background-color: $uni-bg-color;
position: relative;
flex-direction: column;
}
.uni-list--border {
position: relative;
/* #ifdef APP-NVUE */
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 0.5px;
border-bottom-color: $uni-border-color;
border-bottom-style: solid;
border-bottom-width: 0.5px;
/* #endif */
z-index: -1;
}
/* #ifndef APP-NVUE */
.uni-list--border-top {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;
z-index: 1;
}
.uni-list--border-bottom {
position: absolute;
bottom: 0;
right: 0;
left: 0;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
background-color: $uni-border-color;
}
/* #endif */
</style>

View File

@@ -0,0 +1,140 @@
<template>
<view class="uni-section">
<view class="uni-section-header" nvue>
<view v-if="type" class="uni-section__head">
<view :class="type" class="uni-section__head-tag"/>
</view>
<view class="uni-section__content">
<text :class="{'distraction':!subTitle}" :style="{color:color}" class="uni-section__content-title">{{ title }}</text>
<text v-if="subTitle" class="uni-section__content-sub">{{ subTitle }}</text>
</view>
</view>
<view :style="{padding: padding ? '10px' : ''}">
<slot/>
</view>
</view>
</template>
<script>
/**
* Section 标题栏
* @description 标题栏
* @property {String} type = [line|circle] 标题装饰类型
* @value line 竖线
* @value circle 圆形
* @property {String} title 主标题
* @property {String} subTitle 副标题
*/
export default {
name: 'UniSection',
emits:['click'],
props: {
type: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
color:{
type: String,
default: '#333'
},
subTitle: {
type: String,
default: ''
},
padding: {
type: Boolean,
default: false
}
},
data() {
return {}
},
watch: {
title(newVal) {
if (uni.report && newVal !== '') {
uni.report('title', newVal)
}
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
$uni-primary: #2979ff !default;
.uni-section {
background-color: #fff;
// overflow: hidden;
margin-top: 10px;
}
.uni-section-header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 12px 10px;
// height: 50px;
font-weight: normal;
}
.uni-section__head {
flex-direction: row;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.line {
height: 12px;
background-color: $uni-primary;
border-radius: 10px;
width: 4px;
}
.circle {
width: 8px;
height: 8px;
border-top-right-radius: 50px;
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
background-color: $uni-primary;
}
.uni-section__content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
flex: 1;
color: #333;
}
.uni-section__content-title {
font-size: 14px;
color: $uni-primary;
}
.distraction {
flex-direction: row;
align-items: center;
}
.uni-section__content-sub {
font-size: 12px;
color: #999;
line-height: 16px;
margin-top: 2px;
}
</style>

View File

@@ -0,0 +1,20 @@
<template>
<zmm-watermark :opacity="0.05" :watermark="watermark"></zmm-watermark>
</template>
<script>
export default {
name: 'watermark',
data() {
return {};
},
computed: {
watermark() {
return this.$store.state.watermark;
}
}
};
</script>
<style scoped lang="scss">
</style>

View File

@@ -0,0 +1,187 @@
<template>
<view class="zmm-picker-region" :style="{'cursor':disabled ? 'move' : 'default'}">
<picker
:disabled="disabled"
mode="multiSelector"
@columnchange="Citycolumnchange($event)"
@change="pickerchange"
:value="Index"
:range="pickerArr"
range-key="label"
@tap="iconopen"
@cancel="opend = false"
>
<view class="zmm-picker-region-uni-input" :style="{'color':disabled ? '#666' : '#333'}" :class="{ 'zmm-picker-region-placeholder': modelValue == '' }">
<text :style="{ 'text-align': textAlign }" v-if="modelValue == ''">{{ placeholder }}</text>
<text :style="{ 'text-align': textAlign }" v-else>{{ modelValue }}</text>
</view>
</picker>
</view>
</template>
<script>
import citydata from '@/common/city.js';
export default {
emits: ['update:modelValue','change'],
data() {
return {
opend: false,
Index: [0,0,0],
citydata:citydata.data
};
},
behaviors: ['uni://form-field'], //必须要写不然微信小程序收不到值
props: {
rangeLeave:{//联动级别
type:Number,
default:2
},
textAlign: {
type: String,
default: 'center'
},
disabled: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: '请点击选择'
},
modelValue: {
type: [String]
}
},
mounted() {
},
computed:{
pickerArr(){
var arr=[]
function findarr(arrx){
var arr=[]
for (var i = 0; i < arrx.length; i++) {
var item = arrx[i]
arr.push({
label:item.label,
value:item.value,
position:item.position
})
}
return arr
}
for (var i = 0; i < this.rangeLeave; i++) {
arr.push([])
if(i==0){//一级数据
arr[i]=findarr(this.citydata)
}
if(i==1){//二级数据
if(this.citydata[this.Index[0]]){
arr[i]=findarr(this.citydata[this.Index[0]]['children'])
}else{
arr[i]=[]
}
}
if(i==2){//三级数据
if(this.citydata[this.Index[0]]&&this.citydata[this.Index[0]]['children'][this.Index[1]]){
arr[i]=findarr(this.citydata[this.Index[0]]['children'][this.Index[1]]['children'])
}else{
arr[i]=[]
}
}
}
return arr
}
},
watch: {
modelValue:{
deep: true,
immediate:true,
handler(val) {
this.iniIndex()
}
}
},
methods: {
iniIndex(){
var arr=this.modelValue.split(',')
function findLabelIndex(arr,label){
if(!label){
return 0
}
for (var i = 0; i < arr.length; i++) {
if(arr[i].label==label){
return i
break;
}
}
return 0
}
for (var i = 0; i < arr.length; i++) {
this.Index[i]=findLabelIndex(this.pickerArr[i],arr[i])
}
},
iconopen() {
if (this.disabled) {
return;
}
this.opend = true;
},
pickerchange(e) {
var text=[]
if(this.rangeLeave==1){
text.push(this.pickerArr[0][e.detail.value[0]].label)
}
if(this.rangeLeave==2){
text.push(this.pickerArr[0][e.detail.value[0]].label)
text.push(this.pickerArr[1][e.detail.value[1]].label)
}
if(this.rangeLeave==3){
text.push(this.pickerArr[0][e.detail.value[0]].label)
text.push(this.pickerArr[1][e.detail.value[1]].label)
text.push(this.pickerArr[2][e.detail.value[2]].label)
}
this.opend = !this.opend;
this.$emit('update:modelValue', text.toString());
this.$emit('change', text.toString())
},
Citycolumnchange(e) {
if (e.detail.column == 0&&this.rangeLeave>1) {//第一行发生变化重置第二列索引
this.Index.splice(1, 1, 0);
}
if (e.detail.column == 1&&this.rangeLeave>2) {
this.Index.splice(2, 1, 0);
}
this.Index[e.detail.column] = e.detail.value;//设置index
this.$forceUpdate();
},
}
};
</script>
<style>
.zmm-picker-region {
}
.zmm-picker-region-uni-input {
height: 90rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: #fff;
}
.zmm-picker-region-uni-input text {
flex: 1;
font-size: 28rpx;
padding:0 12rpx;
}
.zmm-picker-region-placeholder {
width: 100%;
}
.zmm-picker-region-placeholder text{
color: #666;
}
</style>

View File

@@ -0,0 +1,105 @@
<template>
<view>
<radio-group class="zmm-radio-group" @change="radioChange">
<label class="zmm-radio-group-label" v-for="(item,index) in ranges" :key="index" :class="{'checked':index === current}">
<view class="zmm-radio-group-radio">
<radio style="transform:scale(0.9)" :value="item.value" :checked="index === current" />
</view>
<view class="zmm-radio-group-label-text">{{ item.label }}</view>
<uni-icons class="zmm-radio-group-label-icon" type="checkmarkempty" color="#09C160" size="20"></uni-icons>
</label>
</radio-group>
</view>
</template>
<script>
export default {
emits: ['update:modelValue','change'],
data() {
return {
current: '',
val: '',
ranges: []
};
},
props: {
modelValue: {
type: [String]
},
range: {
//数组label value
type: Array,
default: []
}
},
watch: {
range(v) {
this.init();
},
modelValue(val) {
this.init();
},
},
created() {
this.init();
},
methods: {
init() {
this.ranges = JSON.parse(JSON.stringify(this.range));
this.getval(this.modelValue);
},
getval(e) {
if (!e) {
return;
}
var val = e;
var items = this.ranges;
for (var i = 0; i < items.length; ++i) {
const item = items[i];
if (item.value==val) {
this.current=i
break;
}
}
},
radioChange(e) {
this.getval(e.detail.value);
this.$emit('update:modelValue', e.detail.value)
this.$emit('change', e.detail.value)
}
}
};
</script>
<style>
.zmm-radio-group {
display: flex;
flex-direction: column;
}
.zmm-radio-group-radio{
display: none;
}
.zmm-radio-group-label.checked{
}
.zmm-radio-group-label-icon{display: none;}
.zmm-radio-group-label.checked .zmm-radio-group-label-icon{
display: block;
}
.zmm-radio-group-label {
height: 90rpx;
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
background-color: #fff;
border-bottom: 1px #eee solid;
padding: 24rpx;
}
.zmm-radio-group-label:nth-last-child(1){
margin-right: 0;
}
.zmm-radio-group-label-text{
margin-left: 10rpx;
font-size: 28rpx;
margin-right: auto;
}
</style>

View File

@@ -0,0 +1,277 @@
<template>
<view v-if="show">
<view class="uni-padding-wrap">
<block v-if="!recording && !playing && !hasRecord">
<view class="page-body-time">
<text class="time-big">{{formatedRecordTime}}</text>
</view>
<view class="page-body-buttons">
<view class="page-body-button" @click="startRecord">
<image src="@/static/record.png"></image>
</view>
</view>
</block>
<block v-if="recording === true">
<view class="page-body-time">
<text class="time-big">{{formatedRecordTime}}</text>
</view>
<view class="page-body-buttons">
<view class="page-body-button" @click="stopRecord">
<view class="button-stop-record"></view>
</view>
</view>
</block>
<block v-if="hasRecord === true && playing === false">
<view class="page-body-time">
<text class="time-big">{{formatedPlayTime}}</text>
<text class="time-small">{{formatedRecordTime}}</text>
</view>
<view class="page-body-buttons">
<view class="page-body-button" @click="playVoice">
<image src="@/static/play.png"></image>
</view>
<view class="page-body-button" @click="clear">
<image src="@/static/trash.png"></image>
</view>
</view>
</block>
<block v-if="hasRecord === true && playing === true">
<view class="page-body-time">
<text class="time-big">{{formatedPlayTime}}</text>
<text class="time-small">{{formatedRecordTime}}</text>
</view>
<view class="page-body-buttons">
<view class="page-body-button" @click="stopVoice">
<image src="@/static/stop.png"></image>
</view>
<view class="page-body-button" @click="clear">
<image src="@/static/trash.png"></image>
</view>
</view>
</block>
</view>
</view>
</template>
<script>
// #ifdef APP-PLUS
import permision from "@/common/permission.js"
// #endif
var playTimeInterval = null;
var recordTimeInterval = null;
var recorderManager = null;
var music = null;
export default {
props:{
show:{
type:Boolean,
default:true
}
},
emits:['recorderStop'],
data() {
return {
recording: false, //录音中
playing: false, //播放中
hasRecord: false, //是否有了一个
tempFilePath: '',
recordTime: 0,
playTime: 0,
formatedRecordTime: '00:00:00', //录音的总时间
formatedPlayTime: '00:00:00' //播放录音的当前时间
}
},
beforeDestroy: function() {
this.clear();
},
mounted() {
music = uni.createInnerAudioContext();
music.onEnded(() => {
clearInterval(playTimeInterval)
var playTime = 0
// console.log('play voice finished')
this.playing = false;
this.formatedPlayTime = this.formatTime(playTime);
this.playTime = playTime;
});
recorderManager = uni.getRecorderManager();
recorderManager.onStart(() => {
// console.log('recorder start');
this.recording = true;
recordTimeInterval = setInterval(() => {
this.recordTime += 1;
this.formatedRecordTime = this.formatTime(this.recordTime);
}, 1000)
});
recorderManager.onStop((res) => {
// console.log('on stop');
music.src = res.tempFilePath;
this.hasRecord = true;
this.recording = false;
this.$emit('recorderStop',{
formatedRecordTime:this.formatedRecordTime,
recordTime:this.recordTime<1 ? this.recordTime+1 : this.recordTime,
recordFilePath:res.tempFilePath
})
this.clear()
});
recorderManager.onError(() => {
console.log('recorder onError');
});
},
methods: {
formatTime(time) {
if (typeof time !== 'number' || time < 0) {
return time
}
var hour = parseInt(time / 3600)
time = time % 3600
var minute = parseInt(time / 60)
time = time % 60
var second = time
return ([hour, minute, second]).map(function(n) {
n = n.toString()
return n[1] ? n : '0' + n
}).join(':')
},
async startRecord() { //开始录音
// #ifdef APP-PLUS
let status = await this.checkPermission();
if (status !== 1) {
return;
}
// #endif
// TODO ios 在没有请求过权限之前无法得知是否有相关权限,这种状态下需要直接调用录音,但没有状态或回调判断用户拒绝
recorderManager.start({
duration:600000,
sampleRate:44100,
format:'mp3'
});
},
stopRecord() { //停止录音
recorderManager.stop();
},
playVoice() {
// console.log('play voice');
this.playing = true;
playTimeInterval = setInterval(() => {
this.playTime += 1;
this.formatedPlayTime = this.formatTime(this.playTime);
}, 1000)
music.play();
},
stopVoice() {
clearInterval(playTimeInterval)
this.playing = false;
this.formatedPlayTime = this.formatTime(0);
this.playTime = 0;
music.stop();
},
end() {
music.stop();
recorderManager.stop();
clearInterval(recordTimeInterval)
clearInterval(playTimeInterval);
this.recording = false, this.playing = false, this.hasRecord = false;
this.playTime = 0, this.recordTime = 0;
this.formatedRecordTime = "00:00:00", this.formatedRecordTime = "00:00:00";
},
clear() {
this.end();
}
// #ifdef APP-PLUS
,
async checkPermission() {
let status = permision.isIOS ? await permision.requestIOS('record') :
await permision.requestAndroid('android.permission.RECORD_AUDIO');
if (status === null || status === 1) {
status = 1;
} else if (status === 2) {
uni.showModal({
content: "系统麦克风已关闭",
confirmText: "确定",
showCancel: false,
success: function(res) {
}
})
} else {
uni.showModal({
content: "需要麦克风权限",
confirmText: "设置",
success: function(res) {
if (res.confirm) {
permision.gotoAppSetting();
}
}
})
}
return status;
}
// #endif
}
}
</script>
<style scoped>
.uni-padding-wrap{}
image {
width: 130rpx;
height: 130rpx;
}
.page-body-wrapper {
justify-content: space-between;
flex-grow: 1;
margin-bottom: 300rpx;
}
.page-body-time {
display: flex;
flex-direction: column;
align-items: center;
}
.time-big {
font-size: 26rpx;
margin: 20rpx;
}
.time-small {
font-size: 26rpx;
}
.page-body-buttons{
display: flex;
justify-content: space-around;
}
.page-body-button {
/* width: 250rpx; */
text-align: center;
}
.button-stop-record {
box-sizing: border-box;
width: 130rpx;
height: 130rpx;
border: 20rpx solid #fff;
background-color: #4CD964;
border-radius: 50%;
animation: colors 1s linear infinite;
}
@keyframes colors {
0% {
opacity: 1;
}
50% {
opacity: .7;
}
100% {
opacity: 1;
}
}
</style>

View File

@@ -0,0 +1,158 @@
<template>
<view>
<image class="zmm-upload-avatar" :src="modelValue" :style="{ width: imgSize + 'rpx', height: imgSize + 'rpx', 'border-radius': imgRadius + 'rpx' }" mode="aspectFill" @click="selectImage"></image>
</view>
</template>
<script>
import http from '@/common/request.js';
export default {
name: 'zmm-upload-avatar',
emits: ['update:modelValue','change'],
props: {
modelValue: {
type: [String]
},
imgSize: {
//图片大小
type: Number,
default: 120
},
imgRadius: {
//图片圆角
type: Number,
default: 12
},
disabled: {
type: Boolean,
default: false
},
action: {
//后台上传接口
type: String,
default: http.baseUrl + '/file/upload'
},
formData: {
//上传所附带数据
type: Object
},
header: {
//自定义头
type: Object,
default() {
return {
Authorization: uni.getStorageSync('Authorization'),
device: uni.getStorageSync('device'),
version: uni.getStorageSync('version')
};
}
},
fileKey: {
//后端接受的filekey
type: String,
default: 'file'
}
},
data() {
return {
isDestroyed: false,
showUploadProgress: true
};
},
mounted: function() {},
destroyed: function() {
this.isDestroyed = true;
},
computed: {},
methods: {
selectImage: function() {
var _self = this;
uni.chooseImage({
count: 1,
sourceType: ['album', 'camera'],
success: function(e) {
var imagePathArr = e.tempFilePaths;
//检查服务器地址是否设置,设置即表示图片要上传到服务器
if (_self.action) {
uni.showToast({
title: '上传中',
icon: 'none',
mask: false
});
var remoteIndexStart = 1 - imagePathArr.length;
var promiseWorkList = [];
var keyname = _self.fileKey ? _self.fileKey : 'upload-images';
var completeImages = 0;
for (let i = 0; i < imagePathArr.length; i++) {
promiseWorkList.push(
new Promise((resolve, reject) => {
let remoteUrlIndex = remoteIndexStart + i;
uni.uploadFile({
url: _self.action,
fileType: 'image',
header: _self.header,
formData: _self.formData,
filePath: imagePathArr[i],
name: keyname,
success: function(res) {
if (res.statusCode === 200) {
if (_self.isDestroyed) {
return;
}
completeImages++;
if (_self.showUploadProgress) {
uni.showToast({
title: '上传中',
icon: 'none',
mask: false,
duration: 500
});
}
// console.log('success to upload image: ' + res.data)
resolve(res.data);
} else {
console.log('fail to upload image:' + res.data);
reject('fail to upload image:' + remoteUrlIndex);
}
},
fail: function(res) {
uni.showToast({
title: '上传失败请检查网络',
icon: 'none'
});
console.log('fail to upload image:' + res);
reject('fail to upload image:' + remoteUrlIndex);
}
});
})
);
}
Promise.all(promiseWorkList).then(result => {
if (_self.isDestroyed) {
return;
}
for (let i = 0; i < result.length; i++) {
var resItem = JSON.parse(result[i]);
_self.$emit('update:modelValue', resItem.data.fullPath);
_self.$emit('change', resItem.data.fullPath);
}
});
} else {
_self.$emit('update:modelValue', '../../static/img/avatar/avatar2.jpg');
_self.$emit('change', '../../static/img/avatar/avatar2.jpg');
}
}
});
}
}
};
</script>
<style scoped>
.zmm-upload-avatar {
}
</style>

View File

@@ -0,0 +1,319 @@
<template>
<view @touchmove.stop.prevent="moveHandle" class="moveWrap">
<movable-area class="movarea" ref="areaBox" id="areaBox" :style="{height:imgSize*rowNum +200+ 'rpx'}">
<view class="imgBox" :style="{height:imgSize*rowNum + 'rpx'}">
<view :id="'img' + idx" class="imgItem" v-for="(item, idx) in imgList" :key="idx"
:style="{transition:addJump?' all 0.5s':'',opacity:idx===selectIdx?'0':'1', width: imgSize + 'rpx', height: imgSize + 'rpx', borderRadius:imgRadius+'rpx',padding:imgPadding+'rpx',left:(hoverImgIdx==='img'+idx?curHoverBoxMove.x+'rpx':''),top:(hoverImgIdx==='img'+idx?curHoverBoxMove.y+'rpx':'')}">
<view class="imgItem-img" @tap="itemclick(item,idx)" @touchstart="tstr(idx, $event)" @touchmove="tsmo" @touchend="toend">
<image v-if="item.videoUrl" class="imgItem-play" src="../../static/img/bf.png" mode="aspectFill"></image>
<image :style="{borderRadius:imgRadius+'rpx' }" :ref="'img' + idx" :src="item.url" mode="aspectFill"></image>
</view>
</view>
<slot></slot>
</view>
<movable-view v-if="moveSrc" :animation="false" class="moveV" :x="x" :y="y" direction="all"
@change="onChange"
:style="{ width: imgSize + 'rpx', height: imgSize + 'rpx',padding:imgPadding+'rpx' }">
<image v-if="moveSrc.videoUrl" class="imgItem-play" src="../../static/img/bf.png" mode="aspectFill"></image>
<image :style="{borderRadius:imgRadius+'rpx' }" :src="moveSrc.url" mode="aspectFill"></image>
</movable-view>
</movable-area>
<view v-if="showDelete">
<view class="delete" :class="{'deleteType':deleteType}">
<text v-if="deleteType">松开删除</text>
<text v-else>拖动到此处删除</text>
</view>
</view>
</view>
</template>
<script>
export default {
emits:['itemclick','update:imgList','deleteImage','change','moveEndList'],
props: {
//图片列表
imgList: {
type: Array,
default: function() {
return [];
}
},
//图片大小
imgSize: {
type: Number
},
//图片间距
imgPadding: {
type: Number
},
//图片行数
rowNum: {
type: Number
},
//图片圆角
imgRadius: {
type: Number
}
},
components: {},
data() {
return {
showDelete:false,
touchobj:null,
deleteType:false,
addJump:false,
areaBoxInfo: {},
x: 0,
y: 0,
selectIdx: null,
moveSrc: null,
areaBoxTop: 0,
hoverImgIdx: '',
inBoxXY: {},
curHoverBoxMove: {
x: 0,
y: 0
}
};
},
watch: {
hoverImgIdx(e) {
let idx = this.selectIdx
let hoverIdx = parseInt(e.split('img')[1]);
if (this.imgList[idx]) {
let selectRow = this.imgList[idx].y / uni.upx2px(this.imgSize)
let selectColum= this.imgList[idx].x / uni.upx2px(this.imgSize)
let hoverRow = this.imgList[hoverIdx].y / uni.upx2px(this.imgSize)
let hoverColum= this.imgList[hoverIdx].x / uni.upx2px(this.imgSize)
let left = -(this.imgSize * (hoverColum - selectColum))
let top= -(this.imgSize * (hoverRow - selectRow))
this.curHoverBoxMove = {
x: left,
y: top,
}
}
},
// imgList(e){
// console.log('变化了item')
// this.$nextTick(()=>{
// this.setImgXy()
// })
// }
imgList: {
deep: true,//深度监听可见听对象中的元素变化例:obj.id
immediate:false,//在进入页面时第一次绑定值不会立刻执行监听只有数据发生改变才会执行handler中的操作
handler(val) {//watch事件
// console.log('变化了item')
this.$nextTick(()=>{
this.setImgXy()
})
}
}
},
methods: {
itemclick(e,i){
this.$emit('itemclick',e,i)
},
moveHandle() {
return;
},
deleteImage: function(e) {
var index = e
var deletedImage = this.imgList[index]
this.imgList.splice(index, 1)
this.$emit('deleteImage', deletedImage)
},
onChange(e) {
var boxHeight=this.imgSize * this.rowNum
var deleteHeight=(boxHeight-80)/2
if(e.detail.y>deleteHeight){
this.deleteType=true
}else{
this.deleteType=false
}
this.showDelete=true
this.$emit('change',e)
},
tstr(e, s) {
this.touchobj=this.imgList[e]
this.addJump=true
this.getDomInfo('areaBox', info => {
this.areaBoxInfo = info;
//获取拖拽区域的上边距和下边距
let areaBoxTop = this.areaBoxInfo.top;
let areaBoxLeft = this.areaBoxInfo.left;
// 设置可移动方块的初始位置为当前所选中图片的位置坐标
this.x = this.imgList[e].x;
this.y = this.imgList[e].y;
//显示可移动方块
this.moveSrc = this.imgList[e];
//保存当前所选择的图片索引
this.selectIdx = e;
var x = s.changedTouches[0].clientX - areaBoxLeft;
var y = s.changedTouches[0].clientY - areaBoxTop;
// 保存鼠标在图片内的坐标
this.inBoxXY = {
x: x - this.imgList[e].x,
y: y - this.imgList[e].y,
}
});
},
tsmo(e) {
let areaBoxTop = this.areaBoxInfo.top;
let areaBoxLeft = this.areaBoxInfo.left;
let imgSize = this.imgSize;
//重置为以拖拽盒子左上角为坐标原点
var x = e.changedTouches[0].clientX - areaBoxLeft;
var y = e.changedTouches[0].clientY - areaBoxTop;
this.x = x - this.inBoxXY.x;
this.y = y - this.inBoxXY.y;
this.imgList.forEach((item, idx) => {
if (x > item.x && x < item.x + imgSize && y > item.y && y < item.y + imgSize) {
this.hoverImgIdx = 'img' + idx
}
});
},
toend(e) {
this.addJump=false
if(this.deleteType){
this.deleteImage(this.selectIdx)
}else{
// 移动结束隐藏可移动方块
let beforeIdx = this.selectIdx;
let afterIdx = parseInt(this.hoverImgIdx.split('img')[1]);
if (this.hoverImgIdx !== '' && beforeIdx !== afterIdx) {
this.imgList[beforeIdx] = this.imgList[afterIdx];
this.imgList[afterIdx] = this.moveSrc;
this.$emit('moveEndList', this.imgList);
}
}
this.moveSrc = '';
this.hoverImgIdx = ''
this.selectIdx = null
this.deleteType=false
this.showDelete=false
this.$nextTick(()=>{
this.setImgXy()
})
},
getDomInfo(id, callBack) {
const query = uni.createSelectorQuery().in(this);
query.select('#' + id)
.boundingClientRect()
.exec(function(res) {
callBack(res[0]);
});
},
setImgXy(){//设置每个图片的基础xy轴
this.getDomInfo('areaBox', info => {
this.areaBoxInfo = info;
// 设置区域内所有图片的左上角坐标
this.imgList.forEach((item, idx) => {
this.getDomInfo('img' + idx, res => {
item.x = res.left - info.left;
});
this.getDomInfo('img' + idx, res => {
item.y = res.top - info.top;
});
});
});
}
},
mounted() {
this.setImgXy()
}
};
</script>
<style lang="scss" scoped>
.imgItem-play{
z-index: 1;
position: absolute;
left: 50%;
top: 50%;
width: 80rpx !important;
height: 80rpx !important;
transform: translate(-50%,-50%);
}
.movarea {
width: 100%;
height: 320rpx;
display: flex;
flex-direction: row;
}
.imgBox {
position: relative;
z-index: 1;
width: 100%;
height: 320rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
.imgItem {
position: relative;
box-sizing: border-box;
left: 0;
top: 0;
box-sizing: border-box;
image {
width: 100%;
height: 100%;
// transition: all 0.2s;
vertical-align: top;
}
}
}
.moveV {
opacity: 0.6;
z-index: 0;
box-sizing: border-box;
image {
width: 100%;
height: 100%;
}
}
.select {
opacity: 0;
}
.zmm-upload-image-deleteIcon {
right: 0rpx;
top: 0rpx;
position: absolute;
background-color: rgba(0, 0, 0, 0.3);
width: 36rpx;
height: 36rpx;
text-align: center;
border-radius: 50%;
color: white;
font-size: 30rpx;
z-index: 2;
display: flex;flex-direction: row;align-items: center;justify-content: center;
}
.delete{
position: absolute;
bottom: 0rpx;
left: 0;
width: 100%;
height: 80rpx;
line-height: 80rpx;
background: #C04A42;
text-align: center;
transition: all 0.3s;
}
.delete text{
color: #fff;
}
.deleteType{
transform: scale(1.1);
}
.moveWrap{
position: relative;
}
.imgItem-img{
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,431 @@
<template>
<view class="zmm-upload-image" v-if="show">
<zmm-upload-image-drag :key="key" :rowNum="rows" :imgRadius="imgRadius" :imgSize="imgSize" :imgPadding="imgPadding" :imgList="fileList" @deleteImage="deleteImage" @itemclick="itemclick">
<view v-if="showAdd && fileList.length < limit" @tap="chooseTap" :style="{ width: imgSize + 'rpx', height: imgSize + 'rpx',padding:imgPadding+'rpx' }" class="zmm-upload-image-item-slot">
<view class="zmm-upload-image-item-slotIcon">
<uni-icons type="plusempty" color="#6E6E6E" size="24" />
</view>
</view>
</zmm-upload-image-drag>
</view>
</template>
<script>
import zmmUploadImageDrag from './zmm-upload-image-drag.vue';
import http from '@/common/request.js';
export default {
components: {
zmmUploadImageDrag
},
name: 'zmm-upload-image',
emits: ['update:modelValue', 'deleteImage','allComplete','oneComplete'],
props: {
modelValue: {
type: [Array]
},
chooseType:{
type:String,
default:'chooseImage'//chooseImage图片 chooseVideo视频 chooseMedia图片或视频
},
imgSize: {
//图片大小
type: Number,
default: 214
},
imgPadding: {
//图片间距
type: Number,
default: 6
},
imgRadius: {
//图片圆角
type: Number,
default: 4
},
fileList: {
//图片数据
type: Array,
default(){
return []
}
},
rowNumber: {
//一行多少个图片
type: Number,
default: 3
},
showAdd: {
//增加按钮
type: Boolean,
default: true
},
show: {
//是否显示
type: Boolean,
default: true
},
fileAction: {
//后台文件上传接口
type: String,
default: http.baseUrl + '/file/upload'
},
videoAction: {
//后台上传接口
type: String,
default: http.baseUrl + '/file/uploadVideo'
},
formData: {
//上传所附带数据
type: Object
},
header: {
//自定义头
type: Object,
default() {
return {
Authorization: uni.getStorageSync('Authorization'),
device: uni.getStorageSync('device'),
version: uni.getStorageSync('version')
};
}
},
limit: {
//图片数量
type: Number,
default: 9
},
fileKey: {
//后端接受的filekey
type: String,
default: 'file'
}
},
data() {
return {
key:0,
isDestroyed: false,
showUploadProgress:true
};
},
watch: {
modelValue(val) {
console.log(val);
},
fileList(e){
// console.log('变化了list')
this.key++
},
rows(e){
this.key++
}
// fileList: {
// deep: true,//深度监听可见听对象中的元素变化例:obj.id
// immediate:false,//在进入页面时第一次绑定值不会立刻执行监听只有数据发生改变才会执行handler中的操作
// handler(val) {//watch事件
// console.log('变化了list')
// this.key++
// }
// }
},
mounted: function() {},
destroyed: function() {
this.isDestroyed = true;
},
computed: {
rows() {
var buzhu=this.showAdd && this.fileList.length < this.limit ? 1 : 0;
var rows=Math.ceil((this.fileList.length+buzhu) / this.rowNumber);
return rows
}
},
methods: {
itemclick(e,i){
if(!e.videoUrl){
var imgs=[]
for (var i = 0; i < this.fileList.length; i++) {
var item=this.fileList[i]
if(!item.videoUrl){
imgs.push(item.url)
}
}
this.previewImage(imgs,i)
}else{
this.$fc.plusDownload({onlinePath:e.videoUrl}).then(res=>{
this.$fc.plusOpenFile({filePath:res})
})
}
},
chooseTap(){
switch (this.chooseType){
case 'chooseImage':
this.selectImage()
break;
case 'chooseVideo':
this.selectVideo()
break;
case 'chooseMedia':
uni.showActionSheet({
itemList: ['图片', '视频'],
success: (res) => {
switch (res.tapIndex){
case 0:
this.selectImage()
break;
case 1:
this.selectVideo()
break;
default:
break;
}
}
});
break;
default:
break;
}
},
selectImage: function() {
var _self = this;
if (!_self.fileList) {
_self.fileList = [];
}
uni.chooseImage({
count: _self.limit ? _self.limit - _self.fileList.length : 999,
sourceType: ['album', 'camera'],
sizeType:['original','compressed'],
success: function(e) {
var imagePathArr = e.tempFilePaths;
//如果设置了limit限制在web上count参数无效这里做判断控制选择的数量是否合要求
//在非微信小程序里,虽然可以选多张,但选择的结果会被截掉
//在app里会自动做选择数量的限制
if (_self.limit) {
var availableImageNumber = _self.limit - _self.fileList.length;
if (availableImageNumber < imagePathArr.length) {
uni.showToast({
title: '图片总数限制为' + _self.limit + '张,当前还可以选' + availableImageNumber + '张',
icon: 'none',
mask: false,
duration: 2000
});
return;
}
}
//检查服务器地址是否设置,设置即表示图片要上传到服务器
if (_self.fileAction) {
uni.showToast({
title: '上传进度0/' + imagePathArr.length,
icon: 'none',
mask: false
});
var remoteIndexStart = _self.fileList.length - imagePathArr.length;
var promiseWorkList = [];
var keyname = _self.fileKey ? _self.fileKey : 'upload-images';
var completeImages = 0;
for (let i = 0; i < imagePathArr.length; i++) {
promiseWorkList.push(
new Promise((resolve, reject) => {
let remoteUrlIndex = remoteIndexStart + i;
uni.uploadFile({
url: _self.fileAction,
fileType: 'image',
header: _self.header,
formData: _self.formData,
filePath: imagePathArr[i],
name: keyname,
success: function(res) {
if (res.statusCode === 200) {
if (_self.isDestroyed) {
return;
}
completeImages++;
if (_self.showUploadProgress) {
uni.showToast({
title: '上传进度:' + completeImages + '/' + imagePathArr.length,
icon: 'none',
mask: false,
duration: 500
});
}
// console.log('success to upload image: ' + res.data)
var resItem=JSON.parse(res.data)
_self.$emit('oneComplete', {
name: resItem.data.fileName,
url: resItem.data.fullPath,
type:'IMAGE'
},_self.chooseType);
resolve(res.data);
} else {
console.log('fail to upload image:' + res.data);
reject('fail to upload image:' + remoteUrlIndex);
}
},
fail: function(res) {
uni.showToast({
title: '上传失败请检查网络',
icon: 'none'
});
console.log('fail to upload image:' + res);
reject('fail to upload image:' + remoteUrlIndex);
}
});
})
);
}
Promise.all(promiseWorkList).then(result => {
if (_self.isDestroyed) {
return;
}
var fresult=[]
for (let i = 0; i < result.length; i++) {
var resItem=JSON.parse(result[i])
_self.fileList.push({
name: resItem.data.fileName,
url: resItem.data.fullPath,
type:'IMAGE'
});
fresult.push({
name: resItem.data.fileName,
url: resItem.data.fullPath,
type:'IMAGE'
})
}
_self.$emit('allComplete', fresult,_self.chooseType);
});
} else {
var testImg='图片地址'
for (let i = 0; i < imagePathArr.length; i++) {
_self.fileList.push({
name: 'avatar'+i+'.jpg',
url: testImg
});
}
}
}
});
},
selectVideo: function() {
var _self = this;
if (!_self.fileList) {
_self.fileList = [];
}
uni.chooseVideo({
sourceType: ['album', 'camera'],
compressed:true,
success: function(e) {
if (_self.showUploadProgress) {
uni.showLoading({
title:'上传中...'
})
}
uploadVideo(e).then(res=>{
uni.hideLoading()
_self.fileList.push(res);
_self.$emit('allComplete', res ,_self.chooseType);
})
function uploadVideo(e){
return new Promise((resolve, reject) => {
uni.uploadFile({
url: _self.videoAction,
fileType: 'video',
header: _self.header,
formData: _self.formData,
filePath: e.tempFilePath,
name: _self.fileKey,
success: function(res) {
if (res.statusCode === 200) {
if (_self.isDestroyed) {
return;
}
var resItem=JSON.parse(res.data)
var fresult={
name: resItem.data.fileName,
videoUrl: resItem.data.fullPath,
url: resItem.data.screenShot,
type:'VIDEO'
}
_self.$emit('oneComplete', {
name: resItem.data.fileName,
videoUrl: resItem.data.fullPath,
url: resItem.data.screenShot,
type:'VIDEO'
},_self.chooseType);
resolve(fresult)
} else {
reject(res)
}
},
fail: function(res) {
uni.showToast({
title: '上传失败请检查网络',
icon: 'none'
});
reject(res)
}
});
})
}
}
});
},
deleteImage: function(e) {
this.$emit('deleteImage', e);
},
previewImage: function(arr,index) {
uni.previewImage({
current: index,
indicator: 'number',
loop: true,
urls: arr
});
},
}
};
</script>
<style scoped>
.zmm-upload-image {
width: 100%;
position: relative;
/* display: flex;flex-direction: row;justify-content: center; */
}
.zmm-upload-image-list {
/* width: 714rpx; */
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.zmm-upload-image-item {
width: 214rpx;
height: 214rpx;
margin: 12rpx;
box-sizing: border-box;
position: relative;
border-radius: 4rpx;
}
.zmm-upload-image-item-img {
width: 100%;
height: 100%;
border-radius: 4rpx;
}
.zmm-upload-image-item-slot{
box-sizing: border-box;
}
.zmm-upload-image-item-slotIcon {
box-sizing: border-box;
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: #f7f7f7;
}
</style>

View File

@@ -0,0 +1,568 @@
<template name="zy-search">
<view class="good-search-page" :class="Theme">
<view class="good-search-head">
<input :class="{'clearvalue':clearValuebtn}" :maxlength="maxLength" :style="{'line-height': inputHeight+'px','height': inputHeight+'px'}" :focus="isFocus" type="text" confirm-type="search" @confirm="searchStart()" :placeholder="inputPlaceholder" :confirm-hold="true" v-model="searchText" />
<!-- <view v-if="searchText.length>0&&clearValuebtn" class="good-search-icon clearvalue-icon iconfont iconshanchu1" @click="clearvalue()"></view> -->
<view class="good-search-icon search-icon2" @click="goback()">取消</view>
<view class="good-search-icon search-icon iconfont iconsousuo-copy" @click="searchStart()"></view>
<scroll-view class="autocomplay" :style="{'top': inputHeight+5+'px'}" v-if="autocomplaystate" scroll-y>
<view class="autocomplay-item" v-for="(item,index) in autocomplayarr" :key="index" @click="tagsClick(item.value)">
<rich-text :nodes="item.richtxt"></rich-text>
</view>
<view style="color: #999;text-align: center;justify-content: center; line-height: 70rpx;" v-if="autocomplayarr.length<1">没有相关信息</view>
</scroll-view>
</view>
<view class="good-search-body">
<view class="search-history" v-if="hList.length > 0">
<view class="header">
<text>历史记录</text>
<view class="good-search-icon delete-icon iconfont iconshanchu" @click="delhistory()"></view>
</view>
<view class="list">
<view v-for="(item,index) in hList" :key="index" @click="tagsClick(item)">{{item}}</view>
</view>
</view>
<view class="search-showhot" v-if="hotList.length>0">
<view class="header">
<text>猜你想搜的</text>
</view>
<view class="list">
<view v-for="(item,index) in hotList" :key="index" @click="tagsClick(item)">{{item}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
clearValuebtn: { //是否显示清空按钮
type: Boolean,
default: true
},
isFocus: { //是否自动获取焦点
type: Boolean,
default: false
},
Theme: { //选择主题class
type: String,
default: 'good-search-circle'
},
maxLength: { //字符最大长度
type: [String, Number],
default: '140'
},
inputHeight: { //搜索框高度单位px
type: [String, Number],
default: '35'
},
inputPlaceholder: { //搜索框默认提示
type: String,
default: '请输入关键词搜索'
},
autoComplaylist: { //自动联想数据
type: Array,
default () {
return []
}
},
historyNum: { //历史记录保存数量
type: Number,
default: 6
},
hotList: { //推荐列表数据
type: Array,
default () {
return []
}
},
speechEngine: { //语音引擎=>讯飞:iFly,百度:'baidu'
type: String,
default: 'iFly'
},
Punctuation: { //是否开启语音识别标点符号
type: Boolean,
default: false
},
callbackTime: { //input回调缓冲时间(不返回500毫秒以内输入的数据防止每输入一个值就会触发一次)
type: Number,
default: 500
},
},
data() {
return {
speechengine: this.speechEngine,
punctuation: this.Punctuation,
historynum: this.historyNum,
callbacktime: this.callbackTime,
autocomplaylist: this.getcomplaylist(this.autoComplaylist),
autocomplayarr: [],
autocomplaystate: false,
searchText: '',
hList: uni.getStorageSync('search_cache'),
};
},
watch: {
historyNum: function(val) {
this.historynum = val;
},
speechEngine: function(val) {
this.engine = val;
},
hotList: function(val) {
this.hotList = val;
},
autoComplaylist: function(val) {
this.autocomplaylist = this.getcomplaylist(val);
if (!this.searchText || this.searchText == '') {
this.autocomplaystate = false
return
}
this.autocomplayarr = this.replacekeyword(this.autocomplaylist, this.searchText)
this.autocomplaystate = this.autocomplayarr.length > 0 ? true : false;
},
searchText: function(val) {
let _this = this;
var searchWords = val.replace(/^ +| +$/g, '');
if (!searchWords || searchWords == '') {
this.autocomplaystate = false
return
}
if (this.calbacktime) {
clearTimeout(_this.calbacktime)
}
this.calbacktime = setTimeout(function() {
_this.inputChange(searchWords)
}, _this.callbackTime);
this.autocomplayarr = this.replacekeyword(this.autocomplaylist, searchWords)
this.autocomplaystate = this.autocomplayarr.length > 0 ? true : false;
},
},
methods: {
goback(){
uni.navigateBack({
delta:1
})
},
clearvalue() { //删除input值
let _this = this;
setTimeout(function() { //增加延时解决键盘收回时导致的@input事件
_this.searchText = ''
}, 20);
this.searchText = ''
},
getcomplaylist(arr) { //初始化自动联想数组
var data = []
for (var i = 0; i < arr.length; i++) {
data.push({
richtxt: arr[i],
value: arr[i]
})
}
return data
},
replacekeyword(arr, searchWords) { //返回符合关键词的高亮数组
var data = []
for (var i = 0; i < arr.length; i++) {
if (arr[i].richtxt.search(searchWords) != -1) {
data.push({
richtxt: arr[i].richtxt.replace(searchWords, "<span style='color: #333;font-weight:bold'>" + searchWords +
"</span>"),
value: arr[i].value
})
}
}
return data
},
tagsClick(item) { //标签点击事件
let _this = this;
setTimeout(function() { //增加延时解决键盘收回时导致的@input事件
_this.searchText = item
_this.searchStart()
}, 20);
this.$emit('tagsClick', item)
},
inputChange(e) { //input回调
this.$emit('inputChange', e)
},
notSupport() { //不支持提醒
uni.showToast({
title: '该平台暂不支持',
icon: 'none',
duration: 1000
});
},
searchStart() { //触发搜索
let _this = this;
if (_this.searchText == '') {
uni.showToast({
title: '请输入关键字',
icon: 'none',
duration: 1000
});
return false;
}
// else {
// if(this.autocomplayarr.length<1){
// this.autocomplaystate=true
// return
// }
// uni.getStorage({
// key: 'search_cache',
// success(res) {
// let list = res.data;
// if (list.length >= _this.historynum) {
// for (let item of list) {
// if (item == _this.searchText) {
// return false;
// }
// }
// list.pop();
// list.unshift(_this.searchText);
// } else {
// for (let item of list) {
// if (item == _this.searchText) {
// return false;
// }
// }
// list.unshift(_this.searchText);
// }
// _this.hList = list;
// uni.setStorage({
// key: 'search_cache',
// data: _this.hList
// });
// },
// fail() {
// _this.hList = [];
// _this.hList.push(_this.searchText);
// uni.setStorage({
// key: 'search_cache',
// data: _this.hList
// });
// }
// })
// }
this.$emit('clickSearch', _this.searchText)
},
delhistory() { //清空历史记录
this.hList = [];
uni.setStorage({
key: 'search_cache',
data: []
});
this.$emit('delhHistory')
},
startRecognize() { //语音输入
let _this = this;
let options = {};
options.engine = _this.speechengine;
options.punctuation = _this.punctuation; // 是否需要标点符号
options.timeout = 1000;
plus.speech.startRecognize(options, function(s) {
_this.searchText = _this.searchText + s;
});
}
}
}
</script>
<style scoped>
@font-face {
font-family: 'iconfont';
src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAARsAAsAAAAACTAAAAQeAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDMgqFOIR/ATYCJAMUCwwABCAFhG0HXhshCBEVnP3IfiTGtg+yYk9cckRpaoLn+Ty/c9976WTSnw8NxB3gNgOIO3pXjJjRVmgD9Ab4PpuONYw5YTol8dSz/I/7dt/vpPE4jVIIiZD8//ctbT0e2HotiyTD+1qXxepTJ4rjgALadwoja4DGBsTHZGxxVg7MnJ/5HAI4FKQ80rBxy47YGGidADJs8MDe2B0bZoEj2MbAxFGDrMLCVovVA2Bl8fPyhapig8LS0Na2Axr1o66P31LPSsyiW0ZDfjgPYJ0CDZQHDMiYSd8wdJUrj8YJfs9QF3CwUSgfP9sv7bdMJCBU3ZDBkT5QN/OPp0ECkC4J7Lp5Az6JCAr8bBEE/NKyZX1L2NA60zI4Byq8AakDdnGd+mjadOnkCgUCQZe2JBWQrrOPLDlENBrCKQ7NOhx0lx6dfcRxJB73ZLxDIpGOsVjY60kZ8igzOXw9LgUBGelc6m3cuuVAZsRx5GvKIpG66zZnkSW0fl+aqQyrs2/PC4MqGm3k3o57OnjwGM/GYh13Xl76sMCgA5cKaldtu1A8yVt6VE6qgY0tiXyypWtSP/W45FhtsVi3dUuywx3Tq47MzuWFN8w+ujQr5G1cenhWZsfQenHrt0Nual5cNWf/2RnJgwa45BXXcaVvHjDIwtCj5mC0pbqoUevXj0rVykS01XygQmPGhkWi1q5CD1V4zJiwAgLTK6ixKmnjng+VFzQ3pz5/PqlPaRCoT+KaU6ZLu+LnFx6adKNhoZbr9a1bap1EeNbrdQ2mn6ZhlWmvN9uLq2TsP7U4b5W8FB5bv7F076IbRQtPLDExo9Ibadiy2+o5q1t1pdHrcsP37+hG3bvu21zld1OnSNq6uuWtV79fm/JtF9YYl+plfM3wiugNm1M99VW1huenTU6hsK5/2fz9ay5L1EmqairU5E15Nq0kzL1F8ywu6YspBjsP5znMJAAS1011/YKXvq7rYabb2/VcX9P+QgCB5CWns3um1PxmBw0AT9ymU0Q0kYEv+0/oCeR/Hjmzz4RKslvG701kftwixF9Dp4KSAyQQSufFYQxZ7EYQbLIaUOSgAGhsitMNuzxYBKkOAWzqgEM5PdXpIBlYa8TkBMryFiCk8gFFMpdBk8qXbtg/sMjmDwFSZQ0O4WVcGaSktKcGFplHCXyGVtCklNOfyuYb1mFgtq0suC+0rk1Ckeb9YoUT2kPscLEuvVegLI1wFa/hMBBoSx0Knzbe60uWqakPpYLGxYkGLMR4SAK4GdASyERlo73T4Ps3qBYMGLtAGYi/IMtpJwcKUnIGvdJNLMpLme1EtRLPU/oqxSIj4AoPGmSOAHp6UQcJXkqzQ0a7kGmDFFeXnt4wvsdjgAPNtkSJFiOWBEi7b3fydkLpGqZRkJ7PYym4QEmj2U8UJtGEQ+EtFgsAAA==') format('woff2');
}
.iconfont {
font-family: 'iconfont' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.iconcombinedshapecopy:before {
content: "\e616";
}
.iconsousuo-copy:before {
content: "\e600";
}
.iconshanchu:before {
content: "\e64c";
}
.iconshanchu1:before {
content: "\e628";
}
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #F5F5F5;
}
view {
display: flex;
font-size: 28upx;
line-height: inherit
}
.good-search-page {
box-sizing: border-box;
width: 750rpx;
padding: 30rpx;
display: flex;
flex-direction: column;
}
.good-search-head {
position: relative;
}
.good-search-head input {
box-sizing: border-box;
width: 100%;
background-color: #F7F7F7;
font-size: 28rpx;
border-radius: 50rpx;
padding: 0 73rpx;
padding-left: 34rpx;
padding-right: 160rpx;
}
.good-search-head input.clearvalue{
}
.good-search-icon {
color: #888;
justify-content: center;
align-items: center;
font-size: 38rpx;
}
.good-search-head .good-search-icon {
width: 73rpx;
height: 100%;
position: absolute;
z-index: 2;
top: 0rpx;
}
.good-search-head .voice-icon {
left: 0;
}
.good-search-head .search-icon {
width: 63rpx;
right: 97rpx;
}
.good-search-head .search-icon2 {
font-size: 28rpx;
right: 0;
width: 73rpx;
padding-right: 24rpx;
}
.good-search-head .clearvalue-icon {
width: auto;
right: 146rpx;
color: #ccc;
}
.good-search-head .autocomplay {
left: 0;
top: 80rpx;
border-radius: 20rpx;
height: 70vh;
background: #f7f7f7;
position: absolute;
z-index: 9;
}
.good-search-head .autocomplay .autocomplay-item {
padding: 0 24rpx;
line-height: 70rpx;
height: 70rpx;
border-bottom: 1px #eee solid;
color: #999;
}
.good-search-body {
display: flex;
flex-direction: column;
}
.good-search-page .search-history {
display: flex;
flex-direction: column;
}
.good-search-page .search-showhot {
display: flex;
flex-direction: column;
}
/* 主题1 */
.good-search-rect {}
.good-search-rect .good-search-head input {
border-radius: 0;
}
.good-search-rect .good-search-head input.clearvalue{
}
.good-search-rect .good-search-head .voice-icon {}
.good-search-rect .good-search-head .search-icon {}
.good-search-rect .good-search-head .clearvalue-icon {}
.good-search-rect .header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin: 24rpx 0;
padding: 0 12rpx;
}
.good-search-rect .header text {
color: #666;
font-weight: bold;
font-size: 32rpx;
margin-right: auto;
}
.good-search-rect .list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.good-search-rect .list view {
display: block;
width: 49%;
color: #8A8A8A;
font-size: 28rpx;
box-sizing: border-box;
text-align: center;
padding: 20rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
background-color: #F7F7F7;
margin: 0.5%;
}
.good-search-rect .search-showhot {}
/* 主题2 */
.good-search-circle {}
.good-search-circle .good-search-head input {
border-radius: 50rpx;
}
.good-search-circle .good-search-head input.clearvalue{
}
.good-search-circle .good-search-head .voice-icon {}
.good-search-circle .good-search-head .search-icon {}
.good-search-circle .good-search-head .clearvalue-icon {}
.good-search-circle .header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin: 24rpx 0;
padding: 0 12rpx;
}
.good-search-circle .header text {
color: #666;
font-weight: bold;
font-size: 32rpx;
margin-right: auto;
}
.good-search-circle .list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.good-search-circle .list view {
display: block;
padding: 8rpx 18rpx;
margin: 12rpx;
margin-top: 0;
font-size: 28rpx;
color: #8A8A8A;
background-color: #F7F7F7;
box-sizing: border-box;
text-align: center;
border-radius: 20rpx;
}
.good-search-circle .search-showhot {}
/* 主题3 */
.good-search-tb {}
.good-search-tb .good-search-head input {
border-radius: 0;
}
.good-search-tb .good-search-head input.clearvalue{
padding-right: 133rpx;
}
.good-search-tb .good-search-head .voice-icon {}
.good-search-tb .good-search-head .search-icon {
background: #FF9A33;
color: #fff;
}
.good-search-tb .good-search-head .clearvalue-icon {
width: 60rpx;
}
.good-search-tb .header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin: 24rpx 0;
padding: 0 12rpx;
}
.good-search-tb .header text {
color: #666;
font-weight: bold;
font-size: 32rpx;
margin-right: auto;
}
.good-search-tb .list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.good-search-tb .list view {
display: block;
padding: 8rpx 30rpx;
margin: 12rpx;
margin-top: 0;
font-size: 28rpx;
color: #8A8A8A;
background-color: #F7F7F7;
box-sizing: border-box;
text-align: center;
border-radius: 20rpx;
}
.good-search-tb .search-showhot {}
</style>

14
index.html Normal file
View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

BIN
key/weiliao.keystore Normal file

Binary file not shown.

49
main.js Normal file
View File

@@ -0,0 +1,49 @@
import http from '@/common/request'
import store from './store'
import md5 from "@/common/md5.js";
import publicFc from "@/common/publicFc.js";
// import socketTask from "@/common/socketTask.js";
import * as socketTask from "@/common/socketTask.js";
import zmmFormCheck from './common/zmmFormCheck.js';
import pinyin from './common/pinyin.js';
// #ifndef VUE3
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
Vue.prototype.$http = http
Vue.prototype.$store = store
Vue.prototype.$fc = publicFc;
Vue.prototype.$md5 = md5
Vue.prototype.$zmmFormCheck = zmmFormCheck;
Vue.prototype.$pinyin = pinyin;
Vue.prototype.$socketTask = socketTask;
App.mpType = 'app'
const app = new Vue({
...App,
store
})
app.$mount()
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
import App from './App.vue'
export function createApp() {
const app = createSSRApp(App)
app.config.globalProperties.$http = http
app.config.globalProperties.$fc = publicFc
app.config.globalProperties.$md5 = md5
app.config.globalProperties.$zmmFormCheck = zmmFormCheck
app.config.globalProperties.$pinyin = pinyin
app.config.globalProperties.$socketTask = socketTask
app.use(store);
return {
app
}
}
// #endif

231
manifest.json Normal file
View File

@@ -0,0 +1,231 @@
{
"name" : "微聊",
"appid" : "__UNI__CA19A2D",
"description" : "考拉Team微聊",
"versionName" : "1.2.2",
"versionCode" : 122,
"developer" : {
"name" : "zmm2113@qq.com",
"email" : "zmm2113@qq.com"
},
"transformPx" : false,
"app-plus" : {
"compatible" : {
"ignoreVersion" : true //是否忽略版本兼容检查提示
},
/* 5+App */
"permissions" : {
"File" : {
"description" : "文件系统"
}
},
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"splashscreen" : {
"alwaysShowBeforeRender" : false,
"waiting" : false,
"autoclose" : false,
"delay" : 0
},
"modules" : {
"Geolocation" : {},
"Maps" : {},
"Push" : {},
"Speech" : {},
"VideoPlayer" : {},
"iBeacon" : {},
"Barcode" : {},
"Camera" : {}
},
/* */
"distribute" : {
/* */
"android" : {
/* android */
"permissions" : [
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
"<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>"
],
"minSdkVersion" : 21
},
"ios" : {
"dSYMs" : false
},
/* ios */
"sdkConfigs" : {
"geolocation" : {
"system" : {
"__platform__" : [ "ios", "android" ]
},
"amap" : {
"__platform__" : [ "ios", "android" ],
"appkey_ios" : "81cc6c72aeb6a1946510cc1e9f87ee80",
"appkey_android" : "81cc6c72aeb6a1946510cc1e9f87ee80"
}
},
"maps" : {
"amap" : {
"appkey_ios" : "81cc6c72aeb6a1946510cc1e9f87ee80",
"appkey_android" : "81cc6c72aeb6a1946510cc1e9f87ee80"
}
},
"push" : {
"unipush" : {
"icons" : {
"small" : {
"ldpi" : "static/push/18.png",
"mdpi" : "static/push/24.png",
"hdpi" : "static/push/36.png",
"xhdpi" : "static/push/48.png",
"xxhdpi" : "static/push/72.png"
}
}
}
},
"speech" : {
"ifly" : {}
},
"ad" : {}
},
"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"
}
}
},
"splashscreen" : {
"androidStyle" : "default",
"android" : {
"hdpi" : "unpackage/res/splash/splash480.9.png",
"xhdpi" : "unpackage/res/splash/splash750.9.png",
"xxhdpi" : "unpackage/res/splash/splash1080.9.png"
},
"useOriginalMsgbox" : true
}
},
"uniStatistics" : {
"enable" : true
},
"nativePlugins" : {
"TUICallingUniPlugin-TUICallingModule" : {
"__plugin_info__" : {
"name" : "TUICallingUniPlugin-TUICallingModule",
"description" : "腾讯云音视频插件",
"platforms" : "Android,iOS",
"url" : "",
"android_package_name" : "",
"ios_bundle_id" : "",
"isCloud" : false,
"bought" : -1,
"pid" : "",
"parameters" : {}
}
}
}
},
/* SDK */
"quickapp" : {},
/* */
"mp-weixin" : {
/* */
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"uniStatistics" : {
"enable" : true
}
},
"vueVersion" : "3",
"uniStatistics" : {
"enable" : true,
"version" : "1"
},
"h5" : {
"uniStatistics" : {
"enable" : true
},
"sdkConfigs" : {
"maps" : {
"qqmap" : {
"key" : "3U7BZ-AZZKD-IXC4C-HZA7T-2PGKT-EZFER"
}
}
}
},
"mp-alipay" : {
"uniStatistics" : {
"enable" : true
}
},
"mp-baidu" : {
"uniStatistics" : {
"enable" : true
}
},
"mp-kuaishou" : {
"uniStatistics" : {
"enable" : true
}
},
"mp-lark" : {
"uniStatistics" : {
"enable" : true
}
},
"mp-qq" : {
"uniStatistics" : {
"enable" : true
}
},
"mp-toutiao" : {
"uniStatistics" : {
"enable" : true
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,55 @@
/*
CallingLocalized.strings
TRTCCalling
Created by adams on 2021/5/13.
*/
"LoginNetwork.ProfileManager.sendfailed" = "Send failed. Please try again later.";
"V2.Live.LoginMock.sendtheverificatcode" = "Please send the verification code";
"LoginNetwork.ProfileManager.loginfailed" = "Login failed. Please try again later.";
"LoginNetwork.ProfileManager.queryfailed" = "Query failed. Please try again later.";
"LoginNetwork.ProfileManager.registerfailed" = "Registration failed. Please try again later";
"Demo.TRTC.calling.callingrequest" = "You have a call invitation.";
"Demo.TRTC.calling.syserror"= "System error";
"Demo.TRTC.calling.yourphonenumber" = "Your mobile number ";
"Demo.TRTC.calling.searchphonenumber" = "Mobile number";
"Demo.TRTC.calling.searching" = "Search";
"Demo.TRTC.calling.searchandcall" = "Search for a registered user\n to start a call";
"Demo.TRTC.calling.callingbegan" = "Joined call";
"Demo.TRTC.calling.callingcancel" = "Cancelled the call";
"Demo.TRTC.calling.callingtimeout" = "Call timed out";
"Demo.TRTC.calling.callingrefuse" = "declined the call";
"Demo.TRTC.calling.callingleave" = "left the call";
"Demo.TRTC.calling.callingnoresponse" = "didnt answer";
"Demo.TRTC.calling.callingbusy" = "is busy";
"Demo.TRTC.calling.searchingfailed" = "Search failed";
"Demo.TRTC.calling.cantinviteself" = "You cannot invite yourself.";
"Demo.TRTC.calling.muteon" = "Muted";
"Demo.TRTC.calling.muteoff" = "Unmuted";
"Demo.TRTC.calling.handsfreeon" = "Speaker on";
"Demo.TRTC.calling.handsfreeoff" = "Speaker off";
"LoginNetwork.AppUtils.warmprompt" = "Note";
"LoginNetwork.AppUtils.tomeettheregulatory" = "In accordance with relevant regulations, the app forbids pornographic, abusive, violent, terrorist, and politically sensitive content. All audio/video calls and live streams are recorded and archived.";
"LoginNetwork.AppUtils.determine" = "OK";
"Demo.TRTC.calling.invitetovideocall" = "invites you to a video call";
"Demo.TRTC.calling.invitetoaudiocall" = "invites you to a audio call";
"Demo.TRTC.Streaming.call" = "Call";
"Demo.TRTC.Calling.waitaccept" = "Waiting for the user to accept...";
"Demo.TRTC.Calling.hangup" = "Hang Up";
"Demo.TRTC.Calling.decline" = "Decline";
"Demo.TRTC.Calling.mic" = "Mic";
"Demo.TRTC.Calling.speaker" = "Speaker";
"Demo.TRTC.Calling.camera" = "Camera";
"Demo.TRTC.Calling.switchtoaudio" = "Switch to Audio Call";
"Demo.TRTC.Calling.answer" = "Answer";
"Demo.TRTC.Calling.othernetworkpoor" = "The other party's network connection is poor";
"Demo.TRTC.Calling.yournetworkpoor" = "Your network connection is poor";
"Demo.TRTC.Salon.invitelimited" = "The request is being processed, please try again later";
"Demo.TRTC.Login.countrycode" = "Country Code";
"Demo.TRTC.Calling.failedtogetcamerapermission" = "Failed to get camera permission. Please go to Privacy > Camera to grant the permission";
"Demo.TRTC.Calling.failedtogetmicrophonepermission" = "Failed to get mic permission. Please go to Privacy > Microphone to grant the permission";
"Demo.TRTC.Calling.calleeTip" = "They also";

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,55 @@
/*
CallingLocalized.strings
TRTCCalling
Created by adams on 2021/5/13.
*/
"LoginNetwork.ProfileManager.sendfailed" = "发送失败,请稍后重试";
"V2.Live.LoginMock.sendtheverificatcode" = "请发送验证码";
"LoginNetwork.ProfileManager.loginfailed" = "登录失败,请稍后重试";
"LoginNetwork.ProfileManager.queryfailed" = "查询失败,请稍候重试";
"LoginNetwork.ProfileManager.registerfailed" = "注册失败,请稍后重试";
"Demo.TRTC.calling.callingrequest" = "您有一个通话请求";
"Demo.TRTC.calling.syserror"= "系统错误";
"Demo.TRTC.calling.yourphonenumber" = "您的手机号 ";
"Demo.TRTC.calling.searchphonenumber" = "搜索手机号";
"Demo.TRTC.calling.searching" = "搜索";
"Demo.TRTC.calling.searchandcall" = "搜索添加已注册用户\n以发起通话";
"Demo.TRTC.calling.callingbegan" = "进入通话";
"Demo.TRTC.calling.callingcancel" = "取消了通话";
"Demo.TRTC.calling.callingtimeout" = "通话超时";
"Demo.TRTC.calling.callingrefuse" = "拒绝了通话";
"Demo.TRTC.calling.callingleave" = "离开了通话";
"Demo.TRTC.calling.callingnoresponse" = "未响应";
"Demo.TRTC.calling.callingbusy" = "忙线";
"Demo.TRTC.calling.searchingfailed" = "查询失败";
"Demo.TRTC.calling.cantinviteself" = "不能邀请自己";
"Demo.TRTC.calling.muteon" = "开启静音";
"Demo.TRTC.calling.muteoff" = "关闭静音";
"Demo.TRTC.calling.handsfreeon" = "开启免提";
"Demo.TRTC.calling.handsfreeoff" = "关闭免提";
"LoginNetwork.AppUtils.warmprompt" = "温馨提示";
"LoginNetwork.AppUtils.tomeettheregulatory" = "为配合相关部门监管要求本App内音视频互动全程均有录音录像存档严禁色情、辱骂、暴恐、涉政等违规内容。";
"LoginNetwork.AppUtils.determine" = "确定";
"Demo.TRTC.calling.invitetovideocall" = "邀请你视频通话";
"Demo.TRTC.calling.invitetoaudiocall" = "邀请你音频通话";
"Demo.TRTC.Streaming.call" = "呼叫";
"Demo.TRTC.Calling.waitaccept" = "等待对方接受";
"Demo.TRTC.Calling.hangup" = "挂断";
"Demo.TRTC.Calling.decline" = "拒接";
"Demo.TRTC.Calling.mic" = "麦克风";
"Demo.TRTC.Calling.speaker" = "扬声器";
"Demo.TRTC.Calling.camera" = "摄像头";
"Demo.TRTC.Calling.switchtoaudio" = "切换到语音通话";
"Demo.TRTC.Calling.answer" = "接听";
"Demo.TRTC.Calling.othernetworkpoor" = "对方网络不佳";
"Demo.TRTC.Calling.yournetworkpoor" = "己方网络不佳";
"Demo.TRTC.Salon.invitelimited" = "请求正在处理,请稍后再试";
"Demo.TRTC.Login.countrycode" = "国际电话区号";
"Demo.TRTC.Calling.failedtogetcamerapermission" = "获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限";
"Demo.TRTC.Calling.failedtogetmicrophonepermission" = "获取麦克风权限失败,请前往隐私-麦克风设置里面打开应用权限";
"Demo.TRTC.Calling.calleeTip" = "他们也在";

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,563 @@
/*
Localizable.strings
English
Created by harvy on 2020/10/9.
*/
"TUIKitTipsMostSelectTextFormat" = "Select %ld at most";
"Confirm" = "OK";
"Cancel" = "Cancel";
"Send" = "Send";
"Save" = "Save";
"You" = "You";
"you" = "you";
"Male" = "Male";
"Female" = "Female";
"File" = "Files";
"Download" = "Download";
"Unsetted" = "Not set";
"Monday" = "Mon";
"Tuesday" = "Tue";
"Wednesday" = "Wed";
"Thursday" = "Thur";
"Friday" = "Fri";
"Saturday" = "Sat";
"Sunday" = "Sun";
"Yesterday" = "Yesterday";
"am" = "AM";
"pm" = "PM";
"YesterdayDateFormat" = "HH:mma"; // 英文是 HH:mma 不要动
"Read" = "Read";
"Unread" = "Unread";
"Copy" = "Copy";
"Delete" = "Delete";
"Revoke" = "Recall";
"Retry" = "Retry";
"Re-send" = "Resend";
"Make-a-call" = "Start Call";
"Done" = "OK";
"All" = "All";
"Living" = "In Progress";
"Live-finished" = "Ended";
"Agreed" = "Agreed";
"Disclined" = "Declined";
"Agree" = "Agree";
"Have-been-sent" = "Sent";
"View-the-original" = "View Full Image";
"TUIKitWelcome" = "Welcome to join the Tencent Cloud Communications family!";
"TUIKitMicCamerAuthTips" = "Enable mic and camera permissions";
"TUIKitMicAuth" = "Enable mic permission";
"TUIKitTipsConfirmResendMessage" = "Resend this message? ";
"TUIKitTipsSystemError" = "System error";
"TUIKitTipsEnterRoomErrorFormat" = "Failed to enter the room: %d";
"TUIKitWhosLiveFormat" = "%@'s live stream";
"TUIKitWhoRequestForJoinGroupFormat" = "%@ requests to join group chat.";
"TUIKitAgreedByAdministor" = "Request approved by admin";
"TUIkitDiscliedByAdministor" = "Admin declined the request.";
"TUIKitDownloadProgressFormat" = "Downloading %d%%";
"TUIKitOpenWithOtherApp" = "Open with another app";
"TUIKitTipsContactListNil" = "Contact list is empty. Add friends first.";
"TUIKitInputHoldToTalk" = "Hold to Talk";
"TUIKitInputReleaseToSend" = "Release to End";
"TUIKitInputReleaseToCancel" = "Release to Cancel";
"TUIKitInputNoMicTitle" = "Failed to access mic";
"TUIKitInputNoMicTips" = "Enable mic permission to send voice messages";
"TUIKitInputNoMicOperateLater" = "Later";
"TUIKitInputNoMicOperateEnable" = "Enable";
"TUIKitInputBlankMessageTitle" = "Unable to send blank message";
"TUIKitInputWillFinishRecordInSeconds" = "Recording will end in %ld seconds.";
"TUIKitInputRecordSlideToCancel" = "Slide up to cancel";
"TUIKitInputRecordReleaseToCancel" = "Release to Cancel";
"TUIKitInputRecordTimeshort" = "Message too short";
"TUIKitInputRecordTimeLong" = "Message too long";
"TUIKitGroupProfileDetails" = "Details";
"TUIKitGroupProfileMember" = "Group Members";
"TUIKitGroupProfileMemberCount" = "%d member(s)";
"TUIKitGroupProfileMemberCountlu" = "%lu member(s)";
"TUIKitGroupProfileType" = "Group Type";
"TUIKitGroupProfileJoinType" = "Group Joining Method";
"TUIKitGroupProfileInviteJoin" = "Invite";
"TUIKitGroupProfileAutoApproval" = "Auto Approval";
"TUIKitGroupProfileAlias" = "My Alias in Group";
"TUIKitGroupProfileMessageDoNotDisturb" = "Message Do Not Disturb";
"TUIKitGroupProfileStickyOnTop" = "Sticky on Top";
"TUIKitGroupProfileDeleteAndExit" = "Delete and Leave";
"TUIKitGroupProfileDissolve" = "Disband Group";
"TUIKitGroupProfileJoinDisable" = "Prohibited from Joining";
"TUIKitGroupProfileAdminApprove" = "Admin Approval";
"TUIKitGroupProfileEditAlias" = "Edit My Alias in Group";
"TUIKitGroupProfileEditGroupName" = "Edit Group Name";
"TUIKitGroupProfileEditAnnouncement" = "Edit Group Notice";
"TUIKitGroupProfileEditAvatar" = "Change Group Profile Photo";
"TUIKitGroupProfileDeleteGroupTips" = "After leaving, you will no longer receive messages from this group chat.";
"TUIKitGroupProfileGroupCountFormat" = "Group members (%ld in total)";
"TUIKitGroupProfileManage" = "Manage";
"TUIKitGroupProfileManageAdd" = "Add Member";
"TUIKitGroupProfileManageDelete" = "Delete Member";
"TUIKitGroupApplicant" = "Request to Join Group";
"TUIKitGroupDismssTipsFormat" = "Group %@ disbanded";
"TUIKitGroupRecycledTipsFormat" = "%@ group has been reclaimed.";
"TUIKitGroupKickOffTipsFormat" = "You were removed from the group %@.";
"TUIKitGroupDropoutTipsFormat" = "You have left the group %@.";
"TUIKitMessageTipsYouRecallMessage" = "You recalled a message.";
"TUIKitMessageTipsReEditMessage" = "re-edit";
"TUIKitMessageTipsRecallMessageFormat" = "\"%@\" recalled a message.";
"TUIkitMessageTipsOthersRecallMessage" = "The other user recalled a message.";
"TUIKitMessageTipsJoinGroupFormat" = "\"%@\" joined the group.";
"TUIKitMessageTipsInviteJoinGroupFormat" = "\"%@\" invited \"%@\" to join the group.";
"TUIKitMessageTipsLeaveGroupFormat" = "\"%@\" left the group chat.";
"TUIKitMessageTipsKickoffGroupFormat" = "\"%@\" removed \"%@\" from the group.";
"TUIKitMessageTipsSettAdminFormat" = "\"%@\" is set as admin.";
"TUIKitMessageTipsCancelAdminFormat" = "The admin status of \"%@\" is terminated.";
"TUIkitMessageTipsEditGroupNameFormat" = "%@ changed the group name to\"%@\",";
"TUIKitMessageTipsEditGroupIntroFormat" = "%@ changed the group description to \"%@\".";
"TUIKitMessageTipsEditGroupAnnounceFormat" = "%@ changed the group notice to \"%@\".";
"TUIKitMessageTipsEditGroupAvatarFormat" = "%@ changed the group profile photo.";
"TUIKitMessageTipsEditGroupOwnerFormat" = "%@ changed the group owner to \"%@\".";
"TUIKitMessageTipsCreateGroupFormat" = "\"%@\" created a group.";
"TUIKitMessageTipsUnsupportCustomMessage" = "[Custom Messages]";
"TUIKitMessageTipsMute" = "is blocked from posting";
"TUIKitMessageTipsUnmute" = "Unblocked";
"TUIKitSignalingFinishGroupChat" = "End Group Chat";
"TUIKitSignalingFinishConversationAndTimeFormat" = "Duration: %.2d:%.2d.";
"TUIKitSignalingNewCall" = "Start Call";
"TUIKitSignalingNewGroupCallFormat" = "\"%@\" initiated a group call.";
"TUIkitSignalingCancelCall" = "Cancel Call";
"TUIkitSignalingCancelGroupCallFormat" = "\"%@\" canceled the group call.";
"TUIkitSignalingHangonCall" = "Answered";
"TUIKitSignalingHangonCallFormat" = "\"%@\" answered.";
"TUIKitSignalingBusyFormat" = "\"%@\" is busy.";
"TUIKitSignalingDeclineFormat" = "\"%@\" declined the call.";
"TUIKitSignalingCallBusy" = "Line busy";
"TUIkitSignalingDecline" = "Decline Call";
"TUIKitSignalingNoResponse" = "No answer";
"TUIkitSignalingUnrecognlize" = "Unrecognized call instruction";
"TUIkitMessageTypeImage" = "[Image]";
"TUIKitMessageTypeVoice" = "[Voice]";
"TUIkitMessageTypeVideo" = "[Video]";
"TUIkitMessageTypeFile" = "[File]";
"TUIKitMessageTypeAnimateEmoji" = "[Animated Sticker]";
"TUIKitMessageTypeDraftFormat" = "[Drafts]";
"TUIKitMoreCamera" = "Take Photo";
"TUIKitMorePhoto" = "Album";
"TUIKitMoreVideo" = "Video";
"TUIKitMoreVideoCaptureDurationTip" = "record time is too short";
"TUIKitMoreFile" = "Files";
"TUIKitMoreVideoCall" = "Video Call";
"TUIKitMoreVoiceCall" = "Voice Call";
"TUIKitMoreGroupLive" = "Group Live";
"TUIKitMoreLink" = "Custom";
"TUIKitMoreLinkDetails" = "View Details>>";
"TUIKitCallInviteYouVideoCall" = "invited you to a video call.";
"TUIKitCallTurningOnMute" = "Mute On";
"TUIKitCallTurningOffMute" = "Mute Off";
"TUIKitCallUsingSpeaker" = "Turn On Speaker";
"TUIKitCallUsingHeadphone" = "Turn Off Speaker";
"TUIKitCallCancelCallingFormat" = "%@ canceled the call.";
"TUIKitAtSelectMemberTitle" = "Select Group Members";
"TUIKitConversationTipsAtMe" = "[You were mentioned]";
"TUIKitConversationTipsAtAll" = "[@All]";
"TUIKitConversationTipsAtMeAndAll" = "[I was mentioned][@All]";
"TUIKitPublicGroup" = "Public Group";
"TUIKitWorkGroup" = "Discussion Group";
"TUIKitChatRoom" = "Chatroom";
"TUIKitCommunity" = "Community";
"TUIKitContactsNewFriends" = "New Contacts";
"TUIKitContactsGroupChats" = "Group Chat";
"TUIKitContactsBlackList" = "Blocked List";
"TUIKitAddFriendSourceFormat" = "Source: %@";
"TUIKitFriendApplicationApproved" = "Friend request accepted";
"TUIKitFirendRequestRejected" = "Friend request declined";
"TUIKitOfflinePushCallTips" = "You have a call request.";
"TUIKitChatPendencyTitle" = "Tap to Process";
"TUIKitChatPendencyRequestToJoinGroupFormat" = "%@ group joining request(s)";
"TUIKitSignalingLiveRequestForMic" = "Apply to Turn on Mic in Live Room";
"TUIKitSignalingLiveRequestForMicRejected" = "Application for turning on mic in live room declined";
"TUIKitSignalingAgreeMicRequest" = "Application for turning on mic in live room approved";
"TUIKitSignalingCloseLinkMicRequest" = "Apply to End Co-anchor in Live Room";
"TUIKitSignalingCloseLinkMic" = "End Co-anchor in Live Room";
"TUIKitSignalingRequestForPK" = "Request to PK in Live Room";
"TUIKitSignalingRequestForPKRejected" = "Request to PK in live room declined";
"TUIKitSignalingRequestForPKAgree" = "Request to PK in live room approved";
"TUIKitSignalingPKExit" = "Exit PK in Live Room";
"TUIKitAllowTypeAcceptOne" = "Allow any user to add you as friend";
"TUIKitAllowTypeNeedConfirm" = "Anyone upon Request";
"TUIKitAllowTypeDeclineAll" = "Decline friend request from any user";
"TUIKitErrorInProcess" = "Executing";
"TUIKitErrorInvalidParameters" = "Invalid parameter";
"TUIKitErrorIOOperateFaild" = "Local IO operation error";
"TUIKitErrorInvalidJson" = "Invalid JSON format";
"TUIKitErrorOutOfMemory" = "Out of storage";
"TUIKitErrorParseResponseFaild" = "PB parsing failed";
"TUIKitErrorSerializeReqFaild" = "PB serialization failed";
"TUIKitErrorSDKNotInit" = "IM SDK is not initialized.";
"TUIKitErrorLoadMsgFailed" = "Failed to load local database";
"TUIKitErrorDatabaseOperateFailed" = "Local database operation failed";
"TUIKitErrorCrossThread" = "Cross-thread error";
"TUIKitErrorTinyIdEmpty" = "User info is empty.";
"TUIKitErrorInvalidIdentifier" = "Invalid identifier";
"TUIKitErrorFileNotFound" = "File not found";
"TUIKitErrorFileTooLarge" = "File size exceeds the limit.";
"TUIKitErrorEmptyFile" = "Empty file";
"TUIKitErrorFileOpenFailed" = "Failed to open file";
"TUIKitErrorNotLogin" = "Not logged in to IM SDK";
"TUIKitErrorNoPreviousLogin" = "Not logged in to the user's account.";
"TUIKitErrorUserSigExpired" = "UserSig expired";
"TUIKitErrorLoginKickedOffByOther" = "Log in to the same account on other devices";
"TUIKitErrorTLSSDKInit" = "TLS SDK initialization failed";
"TUIKitErrorTLSSDKUninit" = "TLS SDK is not initialized.";
"TUIKitErrorTLSSDKTRANSPackageFormat" = "Invalid TLS SDK TRANS packet format";
"TUIKitErrorTLSDecrypt" = "TLS SDK decryption failed";
"TUIKitErrorTLSSDKRequest" = "TLS SDK request failed";
"TUIKitErrorTLSSDKRequestTimeout" = "TLS SDK request timed out";
"TUIKitErrorInvalidConveration" = "Invalid session";
"TUIKitErrorFileTransAuthFailed" = "Authentication failed during file transfer.";
"TUIKitErrorFileTransNoServer" = "Failed to get the server list via FTP.";
"TUIKitErrorFileTransUploadFailed" = "Failed to upload the file via FTP. Check your network connection.";
"TUIKitErrorFileTransUploadFailedNotImage" = "Failed to upload the file via FTP. Check if the uploaded image can be opened normally.";
"TUIKitErrorFileTransDownloadFailed" = "Failed to download the file via FTP. Check whether your network is connected or the file or audio has expired.";
"TUIKitErrorHTTPRequestFailed" = "HTTP request failed";
"TUIKitErrorInvalidMsgElem" = "Invalid IM SDK message elem";
"TUIKitErrorInvalidSDKObject" = "Invalid object";
"TUIKitSDKMsgBodySizeLimit" = "Message length exceeds the limit.";
"TUIKitErrorSDKMsgKeyReqDifferRsp" = "Message key error";
"TUIKitErrorSDKGroupInvalidID" = "Invalid group ID. Custom group ID must be printable ASCII characters (0x20-0x7e), with maximum length of 48 bytes, and cannot be prefixed with @TGS#.";
"TUIKitErrorSDKGroupInvalidName" = "Group name is invalid, which cannot exceed 30 bytes.";
"TUIKitErrorSDKGroupInvalidIntroduction" = "Group description is invalid, which cannot exceed 240 bytes.";
"TUIKitErrorSDKGroupInvalidNotification" = "Group notice is invalid, which cannot exceed 300 bytes.";
"TUIKitErrorSDKGroupInvalidFaceURL" = "Group profile photo URL is invalid, which should not exceed 100 bytes.";
"TUIKitErrorSDKGroupInvalidNameCard" = "Group card is invalid, which cannot exceed 50 bytes.";
"TUIKitErrorSDKGroupMemberCountLimit" = "The maximum number of group members is exceeded.";
"TUIKitErrorSDKGroupJoinPrivateGroupDeny" = "Request to join private groups is not allowed.";
"TUIKitErrorSDKGroupInviteSuperDeny" = "Group owners cannot be invited.";
"TUIKitErrorSDKGroupInviteNoMember" = "The number of members to be invited cannot be 0.";
"TUIKitErrorSDKFriendShipInvalidProfileKey" = "Invalid data field";
"TUIKitErrorSDKFriendshipInvalidAddRemark" = "The remark field exceeds the limit of 96 bytes.";
"TUIKitErrorSDKFriendshipInvalidAddWording" = "The description field in the friend request is invalid, which should not exceed 120 bytes.";
"TUIKitErrorSDKFriendshipInvalidAddSource" = "The source field in the friend request is invalid, which should be prefixed with \"AddSource_Type_\".";
"TUIKitErrorSDKFriendshipFriendGroupEmpty" = "The friend list field is invalid. It is required with each list name of 30 bytes at most.";
"TUIKitErrorSDKNetEncodeFailed" = "Network link encryption failed";
"TUIKitErrorSDKNetDecodeFailed" = "Network link decryption failed";
"TUIKitErrorSDKNetAuthInvalid" = "Network link authentication not completed";
"TUIKitErrorSDKNetCompressFailed" = "Unable to compress data packet";
"TUIKitErrorSDKNetUncompressFaile" = "Packet decompression failed";
"TUIKitErrorSDKNetFreqLimit" = "Call frequency is limited, with up to 5 requests per second.";
"TUIKitErrorSDKnetReqCountLimit" = "Request queue is full. The number of concurrent requests exceeds the limit of 1000.";
"TUIKitErrorSDKNetDisconnect" = "Network disconnected. No connection is established, or no network is detected when a socket connection is established.";
"TUIKitErrorSDKNetAllreadyConn" = "Network connection has been established.";
"TUIKitErrorSDKNetConnTimeout" = "Network connection timed out. Try again once network connection is restored.";
"TUIKitErrorSDKNetConnRefuse" = "Network connection denied. Too many attempts. Service denied by the server.";
"TUIKitErrorSDKNetNetUnreach" = "No available route to the network. Try again once network connection is restored.";
"TUIKitErrorSDKNetSocketNoBuff" = "Call failed to due to insufficient buffer resources in the system. System busy. Internal error.";
"TUIKitERRORSDKNetResetByPeer" = "The peer resets the connection.";
"TUIKitErrorSDKNetSOcketInvalid" = "Invalid socket";
"TUIKitErrorSDKNetHostGetAddressFailed" = "IP address resolution failed";
"TUIKitErrorSDKNetConnectReset" = "Network is connected to an intermediate node or connection to the server is reset.";
"TUIKitErrorSDKNetWaitInQueueTimeout" = "Timed out waiting for request packet to enter the to-be-sent queue.";
"TUIKitErrorSDKNetWaitSendTimeout" = "Request packet has entered the to-be-sent queue. Timed out waiting to enter the network buffer of the system.";
"TUIKitErrorSDKNetWaitAckTimeut" = "Request packet has entered the network buffer of the system. Timed out waiting for response from server.";
"TUIKitErrorSDKSVRSSOConnectLimit" = "The number of Server connections exceeds the limit. Service denied by the server.";
"TUIKitErrorSDKSVRSSOVCode" = "Sending verification code timeout.";
"TUIKitErrorSVRSSOD2Expired" = "Key expired. Key is an internal bill generated according to usersig. The validity period of the key is less than or equal to the validity period of usersig. Please call timmanager again getInstance(). The login interface generates a new key.";
"TUIKitErrorSVRA2UpInvalid" = "Ticket expired. Ticket is an internal bill generated according to usersig. The validity period of ticket is less than or equal to that of usersig. Please call timmanager again getInstance(). The login interface generates a new ticket.";
"TUIKitErrorSVRA2DownInvalid" = "The bill failed verification or was hit by security. Please call timmanager again getInstance(). The login interface generates a new ticket.";
"TUIKitErrorSVRSSOEmpeyKey" = "Empty key is not allowed.";
"TUIKitErrorSVRSSOUinInvalid" = "The account in the key does not match the account in the request header.";
"TUIKitErrorSVRSSOVCodeTimeout" = "Timed out sending verification code.";
"TUIKitErrorSVRSSONoImeiAndA2" = "You need to bring your key and ticket.";
"TUIKitErrorSVRSSOCookieInvalid" = "Cookie check mismatch.";
"TUIKitErrorSVRSSODownTips" = "Send a prompt: Key expired.";
"TUIKitErrorSVRSSODisconnect" = "Link disconnected and screen locked.";
"TUIKitErrorSVRSSOIdentifierInvalid" = "Invalid identity.";
"TUIKitErrorSVRSSOClientClose" = "The device automatically logs out.";
"TUIKitErrorSVRSSOMSFSDKQuit" = "MSFSDK automatically logs out.";
"TUIKitErrorSVRSSOD2KeyWrong" = "the number of decryption failures exceeds the threshold, notify the terminal that it needs to be reset, please call timmanager again getInstance(). The login interface generates a new key.";
"TUIKitErrorSVRSSOUnsupport" = "Aggregation is not supported. A unified error code is returned to devices. The device stops aggregation on the persistent TCP connection.";
"TUIKitErrorSVRSSOPrepaidArrears" = "Prepaid service is in arrears.";
"TUIKitErrorSVRSSOPacketWrong" = "Invalid request packet format.";
"TUIKitErrorSVRSSOAppidBlackList" = "SDKAppID blocked list.";
"TUIKitErrorSVRSSOCmdBlackList" = "SDKAppID sets the service cmd blocked list.";
"TUIKitErrorSVRSSOAppidWithoutUsing" = "SDKAppID is disabled.";
"TUIKitErrorSVRSSOFreqLimit" = "Frequency limit (user), which is to limit the number of requests per second of a protocol.";
"TUIKitErrorSVRSSOOverload" = "Packet loss due to overload (system). Service denied by the connected server that failed to process too many requests.";
"TUIKitErrorSVRResNotFound" = "The resource file to be sent does not exist.";
"TUIKitErrorSVRResAccessDeny" = "Unable to access the resource file to be sent.";
"TUIKitErrorSVRResSizeLimit"= "File size exceeds the limit.";
"TUIKitErrorSVRResSendCancel" = "Sending is canceled by the user due to reasons like logging out when sending a message.";
"TUIKitErrorSVRResReadFailed" = "Failed to access the file content.";
"TUIKitErrorSVRResTransferTimeout" = "Timed out transferring the resource file.";
"TUIKitErrorSVRResInvalidParameters" = "Invalid parameter.";
"TUIKitErrorSVRResInvalidFileMd5" = "File MD5 verification failed.";
"TUIKitErrorSVRResInvalidPartMd5" = "Sharding MD5 verification failed.";
"TUIKitErrorSVRCommonInvalidHttpUrl" = "HTTP parsing error. Check the HTTP request URL format.";
"TUIKitErrorSVRCommomReqJsonParseFailed" = "JSON parsing error in the HTTP request. Check the JSON format.";
"TUIKitErrorSVRCommonInvalidAccount" = "The Identifier or UserSig in the request URI or JSON packet is incorrect.";
"TUIKitErrorSVRCommonInvalidSdkappid" = "Invalid SDKAppID. Check the SDKAppID validity.";
"TUIKitErrorSVRCommonRestFreqLimit" = "The REST API call frequency exceeds the limit. Reduce the request rate.";
"TUIKitErrorSVRCommonRequestTimeout" = "The service request timed out or the HTTP request format is incorrect. Check the error and try again.";
"TUIKitErrorSVRCommonInvalidRes" = "Requested resource error. Check the request URL.";
"TUIKitErrorSVRCommonIDNotAdmin" = "Fill in the Identifier field of the REST API request with the app admin's account.";
"TUIKitErrorSVRCommonSdkappidFreqLimit" = "SDKAppID request rate exceeds the limit. Reduce the request rate.";
"TUIKitErrorSVRCommonSdkappidMiss" = "SDKAppID is required for the REST API. Check the SDKAppID in the request URL.";
"TUIKitErrorSVRCommonRspJsonParseFailed" = "JSON parsing error in the HTTP response packet.";
"TUIKitErrorSVRCommonExchangeAccountTimeout" = "Account switching timed out.";
"TUIKitErrorSVRCommonInvalidIdFormat" = "The Identifier type of the request packet body is incorrect. Confirm that the Identifier is a string.";
"TUIKitErrorSVRCommonSDkappidForbidden" = "SDKAppID is disabled.";
"TUIKitErrorSVRCommonReqForbidden" = "Request is disabled.";
"TUIKitErrorSVRCommonReqFreqLimit" = "Too many requests. Try again later.";
"TUIKitErrorSVRCommonInvalidService" = "Your professional package has expired and been deactivated. Please log in to the im purchase page to re purchase the package. After purchase, it will take effect in 5 minutes.";
"TUIKitErrorSVRCommonSensitiveText" = "Text is filtered due to security reasons, which may contain sensitive words.";
"TUIKitErrorSVRCommonBodySizeLimit" = "The sending message package is too long. Currently, the maximum 8K message package length is supported. Please reduce the package size and try again.";
"TUIKitErrorSVRAccountUserSigExpired" = "UserSig has expired. Generate a new one.";
"TUIKitErrorSVRAccountUserSigEmpty" = "UserSig length is 0.";
"TUIKitErrorSVRAccountUserSigCheckFailed" = "UserSig verification failed.";
"TUIKitErrorSVRAccountUserSigMismatchPublicKey" = "Failed to verify UserSig with public key";
"TUIKitErrorSVRAccountUserSigMismatchId" = "The requested Identifier does not match the Identifier that is used to generate the UserSig.";
"TUIKitErrorSVRAccountUserSigMismatchSdkAppid" = "The requested SDKAppID does not match the SDKAppID of the generated UserSig.";
"TUIKitErrorSVRAccountUserSigPublicKeyNotFound" = "Public key does not exist when verifying UserSig.";
"TUIKitErrorSVRAccountUserSigSdkAppidNotFount" = "SDKAppID not found. Check the app information in the IM console.";
"TUIKitErrorSVRAccountInvalidUserSig" = "UserSig has expired. Generate a new one and try again.";
"TUIKitErrorSVRAccountNotFound" = "Requested user account not found.";
"TUIKitErrorSVRAccountSecRstr" = "Restricted for security reasons.";
"TUIKitErrorSVRAccountInternalTimeout" = "Internal server timeout. Try again.";
"TUIKitErrorSVRAccountInvalidCount" = "Invalid batch quantity in the request.";
"TUIkitErrorSVRAccountINvalidParameters" = "Invalid parameter. Check whether the fields are entered as required in the protocol.";
"TUIKitErrorSVRAccountAdminRequired" = "The request requires app admin permissions.";
"TUIKitErrorSVRAccountFreqLimit" = "Restricted due to too many failures and retries. Check if the UserSig is correct and try again after one minute.";
"TUIKitErrorSVRAccountBlackList" = "The account is added to the blocked list.";
"TUIKitErrorSVRAccountCountLimit" = "The number of accounts created exceeds that allowed in the free trial version. Upgrade to the professional version.";
"TUIKitErrorSVRAccountInternalError" = "Internal server error. Try again.";
"TUIKitErrorSVRProfileInvalidParameters" = "Request parameter error. Check if the request is correct according to the error message.";
"TUIKitErrorSVRProfileAccountMiss" = "Request parameter error. No user account specified to pull data.";
"TUIKitErrorSVRProfileAccountNotFound" = "Requested user account not found.";
"TUIKitErrorSVRProfileAdminRequired" = "The request requires app admin permissions.";
"TUIKitErrorSVRProfileSensitiveText" = "The data field contains sensitive words.";
"TUIKitErrorSVRProfileInternalError" = "Server internal error. Try again later.";
"TUIKitErrorSVRProfileReadWritePermissionRequired" = "You have no permission to read the data field. See the data field for details.";
"TUIKitErrorSVRProfileTagNotFound" = "The tag of the data field does not exist.";
"TUIKitErrorSVRProfileSizeLimit" = "The value of the data field exceeds 500 bytes.";
"TUIKitErrorSVRProfileValueError" = "The value of the standard data field is incorrect. See the standard data field for details.";
"TUIKitErrorSVRProfileInvalidValueFormat" = "The value type of the data field does not match. See the standard data field for details.";
"TUIKitErrorSVRFriendshipInvalidParameters" = "Request parameter error. Check if the request is correct according to the error message.";
"TUIKitErrorSVRFriendshipInvalidSdkAppid" = "SDKAppID does not match.";
"TUIKitErrorSVRFriendshipAccountNotFound" = "Requested user account not found.";
"TUIKitErrorSVRFriendshipAdminRequired" = "The request requires app admin permissions.";
"TUIKitErrorSVRFriendshipSensitiveText" = "The relation chain field contains sensitive words.";
"TUIKitErrorSVRFriendshipNetTimeout" = "Network timed out. Try again later.";
"TUIKitErrorSVRFriendshipWriteConflict" = "A write conflict occurred due to concurrent writes. The batch mode is recommended.";
"TUIKitErrorSVRFriendshipAddFriendDeny" = "The backend blocks the user from initiating friend requests.";
"TUIkitErrorSVRFriendshipCountLimit" = "The number of your friends exceeds the limit.";
"TUIKitErrorSVRFriendshipGroupCountLimit" = "The number of lists exceeds the limit.";
"TUIKitErrorSVRFriendshipPendencyLimit" = "You have reached the limit of pending friend requests.";
"TUIKitErrorSVRFriendshipBlacklistLimit" = "The number of accounts in the blocked list exceeds the limit.";
"TUIKitErrorSVRFriendshipPeerFriendLimit" = "The number of the other user's friends exceeds the limit.";
"TUIKitErrorSVRFriendshipInSelfBlacklist" = "You have blocked the other user. Unable to send friend request.";
"TUIKitErrorSVRFriendshipAllowTypeDenyAny" = "The other user's friend request verification mode is \"Decline friend request from any user\".";
"TUIKitErrorSVRFriendshipInPeerBlackList" = "You are blocked by the other user. Unable to send friend request.";
"TUIKitErrorSVRFriendshipAllowTypeNeedConfirm" = "Request sent. Wait for acceptance.";
"TUIKitErrorSVRFriendshipAddFriendSecRstr" = "The friend request was filtered by the security policy. Do not initiate friend requests too frequently.";
"TUIKitErrorSVRFriendshipPendencyNotFound" = "The pending friend request does not exist.";
"TUIKitErrorSVRFriendshipDelFriendSecRstr" = "The friend deletion request was filtered by the security policy. Do not initiate friend deletion requests too frequently.";
"TUIKirErrorSVRFriendAccountNotFoundEx" = "Requested user account not found.";
"TUIKitErrorSVRMsgPkgParseFailed" = "Failed to parse the request packet.";
"TUIKitErrorSVRMsgInternalAuthFailed" = "Internal authentication failed.";
"TUIKitErrorSVRMsgInvalidId" = "Invalid identifier";
"TUIKitErrorSVRMsgNetError" = "Network error. Try again.";
"TUIKitErrorSVRMsgPushDeny" = "A callback is triggered before sending a message in the private chat, and the App backend returns \"The message is prohibited from sending\".";
"TUIKitErrorSVRMsgInPeerBlackList" = "Unable to send messages in the private chat as you are blocked by the other user.";
"TUIKitErrorSVRMsgBothNotFriend" = "You are not a friend of this user. Unable to send messages.";
"TUIKitErrorSVRMsgNotPeerFriend" = "Unable to send messages in the private chat as you are not the other user's friend (one-way friend).";
"TUIkitErrorSVRMsgNotSelfFriend" = "Unable to send messages in the private chat as the other user is not your friend (one-way friend).";
"TUIKitErrorSVRMsgShutupDeny" = "Blocked from posting. Unable to send messages.";
"TUIKitErrorSVRMsgRevokeTimeLimit" = "Timed out recalling the message (default is 2 min).";
"TUIKitErrorSVRMsgDelRambleInternalError" = "An internal error occurred while deleting roaming messages.";
"TUIKitErrorSVRMsgJsonParseFailed" = "Failed to parse the JSON packet. Check whether the request packet meets the JSON specifications.";
"TUIKitErrorSVRMsgInvalidJsonBodyFormat" = "MsgBody in the JSON request packet does not conform to the message format description.";
"TUIKitErrorSVRMsgInvalidToAccount" = "The To_Account field is missing from the JSON request packet body or the type of the To_Account field is not Integer.";
"TUIKitErrorSVRMsgInvalidRand" = "The MsgRandom field is missing from the JSON request packet body or the type of the MsgRandom field is not Integer.";
"TUIKitErrorSVRMsgInvalidTimestamp" = "The MsgTimeStamp field is missing from the JSON request packet body or the type of the MsgTimeStamp field is not Integer.";
"TUIKitErrorSVRMsgBodyNotArray" = "The MsgBody type in the JSON request packet body is not Array.";
"TUIKitErrorSVRMsgInvalidJsonFormat" = "The JSON request packet does not conform to the message format description.";
"TUIKitErrorSVRMsgToAccountCountLimit" = "The number of accounts to which messages are sent in batch exceeds 500.";
"TUIKitErrorSVRMsgToAccountNotFound" = "To_Account is not registered or does not exist.";
"TUIKitErrorSVRMsgTimeLimit" = "Invalid offline message storage time (up to 7 days).";
"TUIKitErrorSVRMsgInvalidSyncOtherMachine" = "The type of the SyncOtherMachine field in the JSON request packet body is not Integer.";
"TUIkitErrorSVRMsgInvalidMsgLifeTime" = "The type of the MsgLifeTime field in the JSON request packet body is not Integer.";
"TUIKitErrorSVRMsgBodySizeLimit" = "The length of JSON data packet exceeds the limit. The message packet body shall not exceed 8 KB.";
"TUIKitErrorSVRmsgLongPollingCountLimit" = "Forced logout on the Web page during long polling (the number of online instances on the Web page exceeds the limit).";
"TUIKitErrorSVRGroupApiNameError" = "The API name in the request is incorrect.";
"TUIKitErrorSVRGroupAccountCountLimit" = "The number of accounts in the request packet body exceeds the limit.";
"TUIkitErrorSVRGroupFreqLimit" = "Call frequency is limited. Reduce the call frequency.";
"TUIKitErrorSVRGroupPermissionDeny" = "Insufficient operation permissions";
"TUIKitErrorSVRGroupInvalidReq" = "Invalid request";
"TUIKitErrorSVRGroupSuperNotAllowQuit" = "Group owner is not allowed to leave this group.";
"TUIKitErrorSVRGroupNotFound" = "The group does not exist.";
"TUIKitErrorSVRGroupJsonParseFailed" = "Failed to parse the JSON packet. Check whether the packet body conforms to the JSON format.";
"TUIKitErrorSVRGroupInvalidId" = "The identifier that is used to initiated the operation is invalid. Check whether the identifier of the user who initiated the operation is correct.";
"TUIKitErrorSVRGroupAllreadyMember" = "The invited user is a group member.";
"TUIKitErrorSVRGroupFullMemberCount" = "The number of group members has reached the limit. Unable to add the user in the request to the group.";
"TUIKitErrorSVRGroupInvalidGroupId" = "Invalid group ID. Check whether the group ID is correct.";
"TUIKitErrorSVRGroupRejectFromThirdParty" = "The app backend rejected this operation via a third-party callback.";
"TUIKitErrorSVRGroupShutDeny" = "This user is blocked from posting and thus cannot send messages. Check whether the sender is blocked from posting.";
"TUIKitErrorSVRGroupRspSizeLimit" = "The response packet length exceeds the limit.";
"TUIKitErrorSVRGroupAccountNotFound" = "Requested user account not found.";
"TUIKitErrorSVRGroupGroupIdInUse" = "The group ID has been used. Select another one.";
"TUIKitErrorSVRGroupSendMsgFreqLimit" = "The frequency of sending messages exceeds the limit. Extend the interval between sending messages.";
"TUIKitErrorSVRGroupReqAllreadyBeenProcessed" = "This invitation or request has been processed.";
"TUIKitErrorSVRGroupGroupIdUserdForSuper" = "The group ID has been used by the group owner. It can be used directly.";
"TUIKitErrorSVRGroupSDkAppidDeny" = "The command word used in the SDKAppID request has been disabled.";
"TUIKitErrorSVRGroupRevokeMsgNotFound" = "This message does not exist.";
"TUIKitErrorSVRGroupRevokeMsgTimeLimit" = "Timed out recalling the message (default is 2 min).";
"TUIKitErrorSVRGroupRevokeMsgDeny" = "Unable to recall this message.";
"TUIKitErrorSVRGroupNotAllowRevokeMsg" = "Unable to recall messages in groups of this type.";
"TUIKitErrorSVRGroupRemoveMsgDeny" = "Unable to delete messages of this type.";
"TUIKitErrorSVRGroupNotAllowRemoveMsg" = "Unable to delete messages in the voice/video chat room and the broadcast group of online members.";
"TUIKitErrorSVRGroupAvchatRoomCountLimit" = "The number of created voice/video chat rooms exceeds the limit.";
"TUIKitErrorSVRGroupCountLimit" = "The number of groups that a single user can create and join exceeds the limit.";
"TUIKitErrorSVRGroupMemberCountLimit" = "The number of group members exceeds the limit.";
"TUIKitErrorSVRNoSuccessResult" = "No success result returned for the batch operation.";
"TUIKitErrorSVRToUserInvalid" = "IM: Invalid recipient";
"TUIKitErrorSVRRequestTimeout" = "Request timeout";
"TUIKitErrorSVRInitCoreFail" = "INIT CORE module failed";
"TUIKitErrorExpiredSessionNode" = "SessionNode is null.";
"TUIKitErrorLoggedOutBeforeLoginFinished" = "Logged out before login (returned at login time)";
"TUIKitErrorTLSSDKNotInitialized" = "tlssdk is not initialized.";
"TUIKitErrorTLSSDKUserNotFound" = "The user information for TLSSDK was not found.";
"TUIKitErrorBindFaildRegTimeout" = "Registration timed out";
"TUIKitErrorBindFaildIsBinding" = "The bind operation in progress.";
"TUIKitErrorPacketFailUnknown" = "Unknown error occurred while sending packet";
"TUIKitErrorPacketFailReqNoNet" = "No network connection when sending request packet, which is converted to case ERR_REQ_NO_NET_ON_REQ:";
"TUIKitErrorPacketFailRespNoNet" = "No network connection when sending response packet, which is converted to case ERR_REQ_NO_NET_ON_RSP:";
"TUIKitErrorPacketFailReqNoAuth" = "No permission when sending request packet";
"TUIKitErrorPacketFailSSOErr" = "SSO error";
"TUIKitErrorPacketFailRespTimeout" = "Response timed out";
"TUIKitErrorFriendshipProxySyncing" = "proxy_manager failed to sync SVR data";
"TUIKitErrorFriendshipProxySyncedFail" = "proxy_manager sync failed";
"TUIKitErrorFriendshipProxyLocalCheckErr" = "proxy_manager request parameter is invalid in local check.";
"TUIKitErrorGroupInvalidField" = "group assistant request field contains non-preset fields.";
"TUIKitErrorGroupStoreageDisabled" = "Local storage of group assistant group data is disabled.";
"TUIKitErrorLoadGrpInfoFailed" = "Failed to load groupinfo from storage";
"TUIKitErrorReqNoNetOnReq" = "No network connection when sending request";
"TUIKitErrorReqNoNetOnResp" = "No network connection when sending response";
"TUIKitErrorServiceNotReady" = "QALSDK service is not ready.";
"TUIKitErrorLoginAuthFailed" = "Account verification failed (user info get failed)";
"TUIKitErrorNeverConnectAfterLaunch" = "Failed to connect network when the app is lunched.";
"TUIKitErrorReqFailed" = "QAL execution failed";
"TUIKitErrorReqInvaidReq" = "Invalid request. Invalid toMsgService.";
"TUIKitErrorReqOnverLoaded" = "Request queue is full.";
"TUIKitErrorReqKickOff" = "Forced logout on another device";
"TUIKitErrorReqServiceSuspend" = "Service suspended";
"TUIKitErrorReqInvalidSign" = "SSO signature error";
"TUIKitErrorReqInvalidCookie" = "Invalid SSO cookie";
"TUIKitErrorLoginTlsRspParseFailed" = "TSL response packet is verified at login time. Packet length error.";
"TUIKitErrorLoginOpenMsgTimeout" = "Timeout occurred when OPENSTATSVC attempted to report status to OPENMSG during login.";
"TUIKitErrorLoginOpenMsgRspParseFailed" = "Response parsing failed when OPENSTATSVC reports status to OPENMSG during login.";
"TUIKitErrorLoginTslDecryptFailed" = "TLS decryption failed at login time.";
"TUIKitErrorWifiNeedAuth" = "Verification is required for Wi-Fi connection.";
"TUIKitErrorUserCanceled" = "Canceled by user";
"TUIkitErrorRevokeTimeLimitExceed" = "Timed out recalling the message (default is 2 min).";
"TUIKitErrorLackUGExt" = "Missing UGC extension pack";
"TUIKitErrorAutoLoginNeedUserSig" = "Local ticket for auto login expired. userSig is required for manual login.";
"TUIKitErrorQALNoShortConneAvailable" = "No available SSO for short connections.";
"TUIKitErrorReqContentAttach" = "Message content is filtered due to security reasons.";
"TUIKitErrorLoginSigExpire" = "Returned at login time. Ticket expired.";
"TUIKitErrorSDKHadInit" = "SDK has been initialized. Do not initialize again.";
"TUIKitErrorOpenBDHBase" = "Openbdh error";
"TUIKitErrorRequestNoNetOnReq" = "No network connection when sending request. Try again once network connection is restored.";
"TUIKitErrorRequestNoNetOnRsp" = "No network connection when sending response. Try again once network connection is restored.";
"TUIKitErrorRequestOnverLoaded" = "Request queue is full.";
/***************************** 消息转发 & 消息搜索 *************************/
// 补充
"Multiple" = "Multiple";
"Forward" = "Forward";
"Delete" = "Delete";
"Copy" = "Copy";
"Revoke" = "Revoke";
"Resend" = "Resend";
"Search" = "Search";
"TUIKitCallMicCamAuthTips" = "Please granted the prillage to mic and camera";
"TUIKitCallMicAuthTips" = "Please granted the prillage to mic";
"TUIKitMessageTipsSureToResend" = "Sure to re-send message?";
// 消息转发
"TUIKitRelayNoMessageTips" = "Please select one message at least";
"TUIKitRelayRecentMessages" = "Recent messages";
"TUIKitRelayChatHistory" = "History";
"TUIKitRelaySepcialForbid" = "Audio messages and other special messages cannot be forwarded.";
"TUIKitRelayConfirmForward" = "Forward to?";
"TUIKitRelayOneByOneForward" = "One-by-one forward";
"TUIKitRelayCombineForwad" = "Combine and forward";
"TUIKitRelayGroupChatHistory" = "Chat history for group";
"TUIKitRelayChatHistoryForSomebodyFormat" = "Chat history for %@ and %@";
"TUIKitRelayErrorForwardFormat" = "@\"Forward error, code:%d, desc:%@\"";
"TUIKitRelayTargetCreateNewChat" = "Create new chat";
"TUIKitRelayTargetSelectFromContacts" = "Select from Contacts";
"TUIKitRelayTargetCrateGroupError" = "Create group error";
"TUIKitRelayTargetNoneTips" = "Contact or conversation cannot null";
"TUIKitRelayLayerLimitTips" = "Sorrythe message has over-limit layers";
"TUIKitRelayCompatibleText" = "Unsupported merged message, please upgrade to the latest version.";
"TUIKitRelayUnsupportForward" = "Messages that failed to be sent do not support forwarding";
"TUIKitRelayOneByOnyOverLimit" = "Too many forwarded messages, one by one forwarding is not currently supported";
// 消息搜索
"TUIKitSearchItemHeaderTitleContact" = "Contact";
"TUIKitSearchItemFooterTitleContact" = "More contacts";
"TUIKitSearchItemHeaderTitleGroup" = "Group";
"TUIKitSearchItemFooterTitleGroup" = "More Groups";
"TUIkitSearchItemHeaderTitleChatHistory" = "Chat history";
"TUIKitSearchItemFooterTitleChatHistory" = "More chat history";
"TUIKitSearchResultMatchFormat" = "Included:%@";
"TUIKitSearchResultMatchGroupIDFormat" = "Inclued group ID:%@";
"TUIKitSearchResultMatchGroupMember" = "Inclued group member:";
"TUIKitSearchResultDisplayChatHistoryCountFormat" = "%zd of chat history";
/***************************** 消息转发 & 消息搜索 *************************/
/***************************** 消息回复 & 换肤 *************************/
"Reply" = "Reply";
"TUIKitReplyMessageNotFoundOriginMessage" = "Unable to locate the original message";
"TUIKitClearAllChatHistory" = "Clear chat history";
"TUIKitClearAllChatHistoryTips" = "Sure to clear all chat history?";
"Discline" = "Discline";
"Copied" = "Copied";
"ConfirmDeleteMessage" = "Sure to delete selected messages";
"TUIKitAddFriend" = "Add friend";
"TUIKitAddGroup" = "Add Group";
"TUIKitSearchUserID" = "Search user ID";
"TUIKitSearchGroupID" = "Search group ID";
"TUIKitNoSelfSignature" = "What's Up not set";
"TUIKitSelfSignatureFormat" = "Signature:%@";
/***************************** 消息回复 & 换肤 *************************/
/***************************** 视频、图片加载 & 保存 *************************/
"TUIKitVideoTranscoding" = "video transcoding...";
"TUIKitVideoDownloading" = "video downloading...";
"TUIKitVideoSavedSuccess" = "video saved successfully";
"TUIKitVideoSavedFailed" = "video save failed";
"TUIKitPictureSavedSuccess" = "picture saved successfully";
"TUIKitPictureSavedFailed" = "picture saved failed";
/***************************** 视频、图片加载 & 保存 *************************/

View File

@@ -0,0 +1,564 @@
/*
Localizable.strings
Chinese Simplized
Created by harvy on 2020/10/9.
*/
"TUIKitTipsMostSelectTextFormat" = "最多选择%ld个";
"Confirm" = "确定";
"Cancel" = "取消";
"Send" = "发送";
"Save" = "保存";
"You" = "您";
"you" = "您";
"Male" = "男";
"Female" = "女";
"File" = "文件";
"Download" = "下载";
"Unsetted" = "未设置";
"Monday" = "星期一";
"Tuesday" = "星期二";
"Wednesday" = "星期三";
"Thursday" = "星期四";
"Friday" = "星期五";
"Saturday" = "星期六";
"Sunday" = "星期日";
"Yesterday" = "昨天";
"am" = "上午";
"pm" = "下午";
"YesterdayDateFormat" = "aHH:mm";
"Read" = "已读";
"Unread" = "未读";
"Copy" = "复制";
"Delete" = "删除";
"Revoke" = "撤回";
"Retry" = "重试";
"Re-send" = "重发";
"Make-a-call" = "发起呼叫";
"Done" = "完成";
"All" = "所有人";
"Living" = "正在直播";
"Live-finished" = "直播结束";
"Agreed" = "已同意";
"Disclined" = "已拒绝";
"Agree" = "同意";
"Have-been-sent" = "已发送";
"View-the-original" = "查看原图";
"TUIKitWelcome" = "欢迎加入腾讯·云通信大家庭!";
"TUIKitMicCamerAuthTips" = "请开启麦克风和摄像头权限";
"TUIKitMicAuth" = "请开启麦克风权限";
"TUIKitTipsConfirmResendMessage" = "确定重发此消息吗? ";
"TUIKitTipsSystemError" = "系统错误";
"TUIKitTipsEnterRoomErrorFormat" = "进房失败: %d";
"TUIKitWhosLiveFormat" = "%@的直播";
"TUIKitWhoRequestForJoinGroupFormat" = "%@申请加入群聊";
"TUIKitAgreedByAdministor" = "管理员同意申请";
"TUIkitDiscliedByAdministor" = "管理员拒绝申请";
"TUIKitDownloadProgressFormat" = "正在下载%d%%";
"TUIKitOpenWithOtherApp" = "用其他应用程序打开";
"TUIKitTipsContactListNil" = "联系人列表为空,请先添加好友";
"TUIKitInputHoldToTalk" = "按住 说话";
"TUIKitInputReleaseToSend" = "松开 结束";
"TUIKitInputReleaseToCancel" = "松开 取消";
"TUIKitInputNoMicTitle" = "无法访问麦克风";
"TUIKitInputNoMicTips" = "开启麦克风权限才能发送语音消息";
"TUIKitInputNoMicOperateLater" = "以后再说";
"TUIKitInputNoMicOperateEnable" = "去开启";
"TUIKitInputBlankMessageTitle" = "不能发送空白消息";
"TUIKitInputWillFinishRecordInSeconds" = "将在 %ld 秒后结束录制";
"TUIKitInputRecordSlideToCancel" = "手指上滑,取消发送";
"TUIKitInputRecordReleaseToCancel" = "松开手指,取消发送";
"TUIKitInputRecordTimeshort" = "说话时间太短";
"TUIKitInputRecordTimeLong" = "说话时间太长";
"TUIKitGroupProfileDetails" = "详细资料";
"TUIKitGroupProfileMember" = "群成员";
"TUIKitGroupProfileMemberCount" = "%d 人";
"TUIKitGroupProfileMemberCountlu" = "%lu人";
"TUIKitGroupProfileType" = "群类型";
"TUIKitGroupProfileJoinType" = "加群方式";
"TUIKitGroupProfileInviteJoin" = "邀请加入";
"TUIKitGroupProfileAutoApproval" = "自动审批";
"TUIKitGroupProfileAlias" = "我的群昵称";
"TUIKitGroupProfileMessageDoNotDisturb" = "消息免打扰";
"TUIKitGroupProfileStickyOnTop" = "置顶聊天";
"TUIKitGroupProfileDeleteAndExit" = "删除并退出";
"TUIKitGroupProfileDissolve" = "解散该群";
"TUIKitGroupProfileJoinDisable" = "禁止加群";
"TUIKitGroupProfileAdminApprove" = "管理员审批";
"TUIKitGroupProfileEditAlias" = "修改我的群昵称";
"TUIKitGroupProfileEditGroupName" = "修改群名称";
"TUIKitGroupProfileEditAnnouncement" = "修改群公告";
"TUIKitGroupProfileEditAvatar" = "修改群头像";
"TUIKitGroupProfileDeleteGroupTips" = "退出后不会再接收到此群聊消息";
"TUIKitGroupProfileGroupCountFormat" = "群成员(%ld人)";
"TUIKitGroupProfileManage" = "管理";
"TUIKitGroupProfileManageAdd" = "添加成员";
"TUIKitGroupProfileManageDelete" = "删除成员";
"TUIKitGroupApplicant" = "群申请";
"TUIKitGroupDismssTipsFormat" = "%@ 群已解散";
"TUIKitGroupRecycledTipsFormat" = "%@ 群已回收";
"TUIKitGroupKickOffTipsFormat" = "您已被踢出 %@ 群";
"TUIKitGroupDropoutTipsFormat" = "您已退出 %@ 群";
"TUIKitMessageTipsYouRecallMessage" = "您撤回了一条消息";
"TUIKitMessageTipsReEditMessage" = "重新编辑";
"TUIKitMessageTipsRecallMessageFormat" = "\"%@\"撤回了一条消息";
"TUIkitMessageTipsOthersRecallMessage" = "对方撤回了一条消息";
"TUIKitMessageTipsJoinGroupFormat" = "\"%@\"加入群组";
"TUIKitMessageTipsInviteJoinGroupFormat" = "\"%@\"邀请\"%@\"加入群组";
"TUIKitMessageTipsLeaveGroupFormat" = "\"%@\"退出了群聊";
"TUIKitMessageTipsKickoffGroupFormat" = "\"%@\"将\"%@\"踢出群组";
"TUIKitMessageTipsSettAdminFormat" = "\"%@\"被设置管理员";
"TUIKitMessageTipsCancelAdminFormat" = "\"%@\"被取消管理员";
"TUIkitMessageTipsEditGroupNameFormat" = "%@修改群名为\"%@\"、";
"TUIKitMessageTipsEditGroupIntroFormat" = "%@修改群简介为\"%@\"、";
"TUIKitMessageTipsEditGroupAnnounceFormat" = "%@修改群公告为\"%@\"、";
"TUIKitMessageTipsEditGroupAvatarFormat" = "%@修改群头像、";
"TUIKitMessageTipsEditGroupOwnerFormat" = "%@修改群主为\"%@\"、";
"TUIKitMessageTipsCreateGroupFormat" = "\"%@\"创建群组";
"TUIKitMessageTipsUnsupportCustomMessage" = "[自定义消息]";
"TUIKitMessageTipsMute" = "被禁言";
"TUIKitMessageTipsUnmute" = "被解除禁言";
"TUIKitSignalingFinishGroupChat" = "结束群聊";
"TUIKitSignalingFinishConversationAndTimeFormat" = "通话时长:%.2d:%.2d";
"TUIKitSignalingNewCall" = "发起通话";
"TUIKitSignalingNewGroupCallFormat" = "\"%@\" 发起群通话";
"TUIkitSignalingCancelCall" = "取消通话";
"TUIkitSignalingCancelGroupCallFormat" = "\"%@\" 取消群通话";
"TUIkitSignalingHangonCall" = "已接听";
"TUIKitSignalingHangonCallFormat" = "\"%@\" 已接听";
"TUIKitSignalingBusyFormat" = "\"%@\" 忙线";
"TUIKitSignalingDeclineFormat" = "\"%@\" 拒绝通话";
"TUIKitSignalingCallBusy" = "对方忙线";
"TUIkitSignalingDecline" = "拒绝通话";
"TUIKitSignalingNoResponse" = "无应答";
"TUIkitSignalingUnrecognlize" = "不能识别的通话指令";
"TUIkitMessageTypeImage" = "[图片]";
"TUIKitMessageTypeVoice" = "[语音]";
"TUIkitMessageTypeVideo" = "[视频]";
"TUIkitMessageTypeFile" = "[文件]";
"TUIKitMessageTypeAnimateEmoji" = "[动画表情]";
"TUIKitMessageTypeDraftFormat" = "[草稿]";
"TUIKitMoreCamera" = "拍照";
"TUIKitMorePhoto" = "图片";
"TUIKitMoreVideo" = "录像";
"TUIKitMoreVideoCaptureDurationTip" = "录制时间过短";
"TUIKitMoreFile" = "文件";
"TUIKitMoreVideoCall" = "视频通话";
"TUIKitMoreVoiceCall" = "语音通话";
"TUIKitMoreGroupLive" = "群直播";
"TUIKitMoreLink" = "自定义";
"TUIKitMoreLinkDetails" = "查看详情>>";
"TUIKitCallInviteYouVideoCall" = "邀请你视频通话";
"TUIKitCallTurningOnMute" = "开启静音";
"TUIKitCallTurningOffMute" = "关闭静音";
"TUIKitCallUsingSpeaker" = "使用扬声器";
"TUIKitCallUsingHeadphone" = "使用听筒";
"TUIKitCallCancelCallingFormat" = "%@ 取消了通话";
"TUIKitAtSelectMemberTitle" = "选择群成员";
"TUIKitConversationTipsAtMe" = "[有人@我]";
"TUIKitConversationTipsAtAll" = "[@所有人]";
"TUIKitConversationTipsAtMeAndAll" = "[有人@我][@所有人]";
"TUIKitPublicGroup" = "公开群";
"TUIKitWorkGroup" = "讨论组";
"TUIKitChatRoom" = "聊天室";
"TUIKitCommunity" = "社群";
"TUIKitContactsNewFriends" = "新的联系人";
"TUIKitContactsGroupChats" = "群聊";
"TUIKitContactsBlackList" = "黑名单";
"TUIKitAddFriendSourceFormat" = "来源: %@";
"TUIKitFriendApplicationApproved" = "已同意好友申请";
"TUIKitFirendRequestRejected" = "已拒绝好友申请";
"TUIKitOfflinePushCallTips" = "您有一个通话请求";
"TUIKitChatPendencyTitle" = "点击处理";
"TUIKitChatPendencyRequestToJoinGroupFormat" = "%@条入群请求";
"TUIKitSignalingLiveRequestForMic" = "直播间申请上麦";
"TUIKitSignalingLiveRequestForMicRejected" = "直播间申请上麦被拒绝";
"TUIKitSignalingAgreeMicRequest" = "直播间同意上麦";
"TUIKitSignalingCloseLinkMicRequest" = "直播间申请关闭连麦";
"TUIKitSignalingCloseLinkMic" = "直播间关闭连麦";
"TUIKitSignalingRequestForPK" = "直播间申请PK";
"TUIKitSignalingRequestForPKRejected" = "直播间申请PK被拒绝";
"TUIKitSignalingRequestForPKAgree" = "直播间同意PK";
"TUIKitSignalingPKExit" = "直播间退出PK";
"TUIKitAllowTypeAcceptOne" = "同意任何用户加好友";
"TUIKitAllowTypeNeedConfirm" = "需要验证";
"TUIKitAllowTypeDeclineAll" = "拒绝任何人加好友";
"TUIKitErrorInProcess" = "执行中";
"TUIKitErrorInvalidParameters" = "参数无效";
"TUIKitErrorIOOperateFaild" = "操作本地 IO 错误";
"TUIKitErrorInvalidJson" = "错误的 JSON 格式";
"TUIKitErrorOutOfMemory" = "内存不足";
"TUIKitErrorParseResponseFaild" = "PB 解析失败";
"TUIKitErrorSerializeReqFaild" = "PB 序列化失败";
"TUIKitErrorSDKNotInit" = "IM SDK 未初始化";
"TUIKitErrorLoadMsgFailed" = "加载本地数据库操作失败";
"TUIKitErrorDatabaseOperateFailed" = "本地数据库操作失败";
"TUIKitErrorCrossThread" = "跨线程错误";
"TUIKitErrorTinyIdEmpty" = "用户信息为空";
"TUIKitErrorInvalidIdentifier" = "Identifier 非法";
"TUIKitErrorFileNotFound" = "文件不存在";
"TUIKitErrorFileTooLarge" = "文件大小超出了限制";
"TUIKitErrorEmptyFile" = "空文件";
"TUIKitErrorFileOpenFailed" = "文件打开失败";
"TUIKitErrorNotLogin" = "IM SDK 未登陆";
"TUIKitErrorNoPreviousLogin" = "并没有登录过该用户";
"TUIKitErrorUserSigExpired" = "UserSig 过期";
"TUIKitErrorLoginKickedOffByOther" = "其他终端登录同一账号";
"TUIKitErrorTLSSDKInit" = "TLS SDK 初始化失败";
"TUIKitErrorTLSSDKUninit" = "TLS SDK 未初始化";
"TUIKitErrorTLSSDKTRANSPackageFormat" = "TLS SDK TRANS 包格式错误";
"TUIKitErrorTLSDecrypt" = "TLS SDK 解密失败";
"TUIKitErrorTLSSDKRequest" = "TLS SDK 请求失败";
"TUIKitErrorTLSSDKRequestTimeout" = "TLS SDK 请求超时";
"TUIKitErrorInvalidConveration" = "会话无效";
"TUIKitErrorFileTransAuthFailed" = "文件传输鉴权失败";
"TUIKitErrorFileTransNoServer" = "文件传输获取 Server 列表失败";
"TUIKitErrorFileTransUploadFailed" = "文件传输上传失败,请检查网络是否连接";
"TUIKitErrorFileTransUploadFailedNotImage" = "文件传输上传失败,请检查上传的图片是否能够正常打开";
"TUIKitErrorFileTransDownloadFailed" = "文件传输下载失败,请检查网络,或者文件、语音是否已经过期";
"TUIKitErrorHTTPRequestFailed" = "HTTP 请求失败";
"TUIKitErrorInvalidMsgElem" = "IM SDK 无效消息 elem";
"TUIKitErrorInvalidSDKObject" = "无效的对象";
"TUIKitSDKMsgBodySizeLimit" = "消息长度超出限制";
"TUIKitErrorSDKMsgKeyReqDifferRsp" = "消息 KEY 错误";
"TUIKitErrorSDKGroupInvalidID" = "群组 ID 非法,自定义群组 ID 必须为可打印 ASCII 字符0x20-0x7e最长48个字节且前缀不能为 @TGS#";
"TUIKitErrorSDKGroupInvalidName" = "群名称非法群名称最长30字节";
"TUIKitErrorSDKGroupInvalidIntroduction" = "群简介非法群简介最长240字节";
"TUIKitErrorSDKGroupInvalidNotification" = "群公告非法群公告最长300字节";
"TUIKitErrorSDKGroupInvalidFaceURL" = "群头像 URL 非法,群头像 URL 最长100字节";
"TUIKitErrorSDKGroupInvalidNameCard" = "群名片非法群名片最长50字节";
"TUIKitErrorSDKGroupMemberCountLimit" = "超过群组成员数的限制";
"TUIKitErrorSDKGroupJoinPrivateGroupDeny" = "不允许申请加入 Private 群组";
"TUIKitErrorSDKGroupInviteSuperDeny" = "不允许邀请角色为群主的成员";
"TUIKitErrorSDKGroupInviteNoMember" = "不允许邀请0个成员";
"TUIKitErrorSDKFriendShipInvalidProfileKey" = "资料字段非法";
"TUIKitErrorSDKFriendshipInvalidAddRemark" = "备注字段非法最大96字节";
"TUIKitErrorSDKFriendshipInvalidAddWording" = "请求添加好友的请求说明字段非法最大120字节";
"TUIKitErrorSDKFriendshipInvalidAddSource" = "请求添加好友的添加来源字段非法来源需要添加“AddSource_Type_”前缀。";
"TUIKitErrorSDKFriendshipFriendGroupEmpty" = "好友分组字段非法必须不为空每个分组的名称最长30字节";
"TUIKitErrorSDKNetEncodeFailed" = "网络链接加密失败";
"TUIKitErrorSDKNetDecodeFailed" = "网络链接解密失败";
"TUIKitErrorSDKNetAuthInvalid" = "网络链接未完成鉴权";
"TUIKitErrorSDKNetCompressFailed" = "数据包压缩失败";
"TUIKitErrorSDKNetUncompressFaile" = "数据包解压失败";
"TUIKitErrorSDKNetFreqLimit" = "调用频率限制,最大每秒发起 5 次请求";
"TUIKitErrorSDKnetReqCountLimit" = "请求队列満超过同时请求的数量限制最大同时发起1000个请求。";
"TUIKitErrorSDKNetDisconnect" = "网络已断开,未建立连接,或者建立 socket 连接时,检测到无网络。";
"TUIKitErrorSDKNetAllreadyConn" = "网络连接已建立,重复创建连接";
"TUIKitErrorSDKNetConnTimeout" = "建立网络连接超时,请等网络恢复后重试。";
"TUIKitErrorSDKNetConnRefuse" = "网络连接已被拒绝,请求过于频繁,服务端拒绝服务。";
"TUIKitErrorSDKNetNetUnreach" = "没有到达网络的可用路由,请等网络恢复后重试。";
"TUIKitErrorSDKNetSocketNoBuff" = "系统中没有足够的缓冲区空间资源可用来完成调用,系统过于繁忙,内部错误。";
"TUIKitERRORSDKNetResetByPeer" = "对端重置了连接";
"TUIKitErrorSDKNetSOcketInvalid" = "socket 套接字无效";
"TUIKitErrorSDKNetHostGetAddressFailed" = "IP 地址解析失败";
"TUIKitErrorSDKNetConnectReset" = "网络连接到中间节点或服务端重置";
"TUIKitErrorSDKNetWaitInQueueTimeout" = "请求包等待进入待发送队列超时";
"TUIKitErrorSDKNetWaitSendTimeout" = "请求包已进入待发送队列,等待进入系统的网络 buffer 超时";
"TUIKitErrorSDKNetWaitAckTimeut" = "请求包已进入系统的网络 buffer ,等待服务端回包超时";
"TUIKitErrorSDKSVRSSOConnectLimit" = "Server 的连接数量超出限制,服务端拒绝服务。";
"TUIKitErrorSDKSVRSSOVCode" = "验证码下发超时。";
"TUIKitErrorSVRSSOD2Expired" = "Key 过期。Key 是根据 UserSig 生成的内部票据Key 的有效期小于或等于 UserSig 的有效期。请重新调用 TIMManager.getInstance().login 登录接口生成新的 Key。";
"TUIKitErrorSVRA2UpInvalid" = "Ticket 过期。Ticket 是根据 UserSig 生成的内部票据Ticket 的有效期小于或等于 UserSig 的有效期。请重新调用 TIMManager.getInstance().login 登录接口生成新的 Ticket。";
"TUIKitErrorSVRA2DownInvalid" = "票据验证没通过或者被安全打击。请重新调用 TIMManager.getInstance().login 登录接口生成新的票据。";
"TUIKitErrorSVRSSOEmpeyKey" = "不允许空 Key。";
"TUIKitErrorSVRSSOUinInvalid" = "Key 中的帐号和请求包头的帐号不匹配。";
"TUIKitErrorSVRSSOVCodeTimeout" = "验证码下发超时。";
"TUIKitErrorSVRSSONoImeiAndA2" = "需要带上 Key 和 Ticket。";
"TUIKitErrorSVRSSOCookieInvalid" = "Cookie 检查不匹配。";
"TUIKitErrorSVRSSODownTips" = "下发提示语Key 过期。";
"TUIKitErrorSVRSSODisconnect" = "断链锁屏。";
"TUIKitErrorSVRSSOIdentifierInvalid" = "失效身份。";
"TUIKitErrorSVRSSOClientClose" = "终端自动退出。";
"TUIKitErrorSVRSSOMSFSDKQuit" = "MSFSDK 自动退出。";
"TUIKitErrorSVRSSOD2KeyWrong" = "解密失败次数超过阈值,通知终端需要重置,请重新调用 TIMManager.getInstance().login 登录接口生成新的 Key。";
"TUIKitErrorSVRSSOUnsupport" = "不支持聚合,给终端返回统一的错误码。终端在该 TCP 长连接上停止聚合。";
"TUIKitErrorSVRSSOPrepaidArrears" = "预付费欠费。";
"TUIKitErrorSVRSSOPacketWrong" = "请求包格式错误。";
"TUIKitErrorSVRSSOAppidBlackList" = "SDKAppID 黑名单。";
"TUIKitErrorSVRSSOCmdBlackList" = "SDKAppID 设置 service cmd 黑名单。";
"TUIKitErrorSVRSSOAppidWithoutUsing" = "SDKAppID 停用。";
"TUIKitErrorSVRSSOFreqLimit" = "频率限制(用户),频率限制是设置针对某一个协议的每秒请求数的限制。";
"TUIKitErrorSVRSSOOverload" = "过载丢包(系统),连接的服务端处理过多请求,处理不过来,拒绝服务。";
"TUIKitErrorSVRResNotFound" = "要发送的资源文件不存在。";
"TUIKitErrorSVRResAccessDeny" = "要发送的资源文件不允许访问。";
"TUIKitErrorSVRResSizeLimit"= "文件大小超过限制。";
"TUIKitErrorSVRResSendCancel" = "用户取消发送,如发送过程中登出等原因。";
"TUIKitErrorSVRResReadFailed" = "读取文件内容失败。";
"TUIKitErrorSVRResTransferTimeout" = "资源文件传输超时";
"TUIKitErrorSVRResInvalidParameters" = "参数非法。";
"TUIKitErrorSVRResInvalidFileMd5" = "文件 MD5 校验失败。";
"TUIKitErrorSVRResInvalidPartMd5" = "分片 MD5 校验失败。";
"TUIKitErrorSVRCommonInvalidHttpUrl" = "HTTP 解析错误 ,请检查 HTTP 请求 URL 格式。";
"TUIKitErrorSVRCommomReqJsonParseFailed" = "HTTP 请求 JSON 解析错误,请检查 JSON 格式。";
"TUIKitErrorSVRCommonInvalidAccount" = "请求 URI 或 JSON 包体中 Identifier 或 UserSig 错误。";
"TUIKitErrorSVRCommonInvalidSdkappid" = "SDKAppID 失效,请核对 SDKAppID 有效性。";
"TUIKitErrorSVRCommonRestFreqLimit" = "REST 接口调用频率超过限制,请降低请求频率。";
"TUIKitErrorSVRCommonRequestTimeout" = "服务请求超时或 HTTP 请求格式错误,请检查并重试。";
"TUIKitErrorSVRCommonInvalidRes" = "请求资源错误,请检查请求 URL。";
"TUIKitErrorSVRCommonIDNotAdmin" = "REST API 请求的 Identifier 字段请填写 App 管理员帐号。";
"TUIKitErrorSVRCommonSdkappidFreqLimit" = "SDKAppID 请求频率超限,请降低请求频率。";
"TUIKitErrorSVRCommonSdkappidMiss" = "REST 接口需要带 SDKAppID请检查请求 URL 中的 SDKAppID。";
"TUIKitErrorSVRCommonRspJsonParseFailed" = "HTTP 响应包 JSON 解析错误。";
"TUIKitErrorSVRCommonExchangeAccountTimeout" = "置换帐号超时。";
"TUIKitErrorSVRCommonInvalidIdFormat" = "请求包体 Identifier 类型错误,请确认 Identifier 为字符串格式。";
"TUIKitErrorSVRCommonSDkappidForbidden" = "SDKAppID 被禁用";
"TUIKitErrorSVRCommonReqForbidden" = "请求被禁用";
"TUIKitErrorSVRCommonReqFreqLimit" = "请求过于频繁,请稍后重试。";
"TUIKitErrorSVRCommonInvalidService" = "您的专业版套餐包已到期并停用,请登录 即时通信 IM 购买页面 重新购买套餐包。购买后将在5分钟后生效。";
"TUIKitErrorSVRCommonSensitiveText" = "文本安全打击,文本中可能包含敏感词汇。";
"TUIKitErrorSVRCommonBodySizeLimit" = "发消息包体过长目前支持最大8k消息包体长度请减少包体大小重试。";
"TUIKitErrorSVRAccountUserSigExpired" = "UserSig 已过期,请重新生成 UserSig";
"TUIKitErrorSVRAccountUserSigEmpty" = "UserSig 长度为0";
"TUIKitErrorSVRAccountUserSigCheckFailed" = "UserSig 校验失败";
"TUIKitErrorSVRAccountUserSigMismatchPublicKey" = "用公钥验证 UserSig 失败";
"TUIKitErrorSVRAccountUserSigMismatchId" = "请求的 Identifier 与生成 UserSig 的 Identifier 不匹配。";
"TUIKitErrorSVRAccountUserSigMismatchSdkAppid" = "请求的 SDKAppID 与生成 UserSig 的 SDKAppID 不匹配。";
"TUIKitErrorSVRAccountUserSigPublicKeyNotFound" = "验证 UserSig 时公钥不存在";
"TUIKitErrorSVRAccountUserSigSdkAppidNotFount" = "SDKAppID 未找到,请在云通信 IM 控制台确认应用信息。";
"TUIKitErrorSVRAccountInvalidUserSig" = "UserSig 已经失效,请重新生成,再次尝试。";
"TUIKitErrorSVRAccountNotFound" = "请求的用户帐号不存在。";
"TUIKitErrorSVRAccountSecRstr" = "安全原因被限制。";
"TUIKitErrorSVRAccountInternalTimeout" = "服务端内部超时,请重试。";
"TUIKitErrorSVRAccountInvalidCount" = "请求中批量数量不合法。";
"TUIkitErrorSVRAccountINvalidParameters" = "参数非法,请检查必填字段是否填充,或者字段的填充是否满足协议要求。";
"TUIKitErrorSVRAccountAdminRequired" = "请求需要 App 管理员权限。";
"TUIKitErrorSVRAccountFreqLimit" = "因失败且重试次数过多导致被限制,请检查 UserSig 是否正确,一分钟之后再试。";
"TUIKitErrorSVRAccountBlackList" = "帐号被拉入黑名单。";
"TUIKitErrorSVRAccountCountLimit" = "创建帐号数量超过免费体验版数量限制,请升级为专业版。";
"TUIKitErrorSVRAccountInternalError" = "服务端内部错误,请重试。";
"TUIKitErrorSVRProfileInvalidParameters" = "请求参数错误,请根据错误描述检查请求是否正确。";
"TUIKitErrorSVRProfileAccountMiss" = "请求参数错误,没有指定需要拉取资料的用户帐号。";
"TUIKitErrorSVRProfileAccountNotFound" = "请求的用户帐号不存在。";
"TUIKitErrorSVRProfileAdminRequired" = "请求需要 App 管理员权限。";
"TUIKitErrorSVRProfileSensitiveText" = "资料字段中包含敏感词。";
"TUIKitErrorSVRProfileInternalError" = "服务端内部错误,请稍后重试。";
"TUIKitErrorSVRProfileReadWritePermissionRequired" = "没有资料字段的读权限,详情可参见 资料字段。";
"TUIKitErrorSVRProfileTagNotFound" = "资料字段的 Tag 不存在。";
"TUIKitErrorSVRProfileSizeLimit" = "资料字段的 Value 长度超过500字节。";
"TUIKitErrorSVRProfileValueError" = "标配资料字段的 Value 错误,详情可参见 标配资料字段。";
"TUIKitErrorSVRProfileInvalidValueFormat" = "资料字段的 Value 类型不匹配,详情可参见 标配资料字段。";
"TUIKitErrorSVRFriendshipInvalidParameters" = "请求参数错误,请根据错误描述检查请求是否正确。";
"TUIKitErrorSVRFriendshipInvalidSdkAppid" = "SDKAppID 不匹配。";
"TUIKitErrorSVRFriendshipAccountNotFound" = "请求的用户帐号不存在。";
"TUIKitErrorSVRFriendshipAdminRequired" = "请求需要 App 管理员权限。";
"TUIKitErrorSVRFriendshipSensitiveText" = "关系链字段中包含敏感词。";
"TUIKitErrorSVRFriendshipNetTimeout" = "网络超时,请稍后重试。";
"TUIKitErrorSVRFriendshipWriteConflict" = "并发写导致写冲突,建议使用批量方式。";
"TUIKitErrorSVRFriendshipAddFriendDeny" = "后台禁止该用户发起加好友请求。";
"TUIkitErrorSVRFriendshipCountLimit" = "自己的好友数已达系统上限。";
"TUIKitErrorSVRFriendshipGroupCountLimit" = "分组已达系统上限。";
"TUIKitErrorSVRFriendshipPendencyLimit" = "未决数已达系统上限。";
"TUIKitErrorSVRFriendshipBlacklistLimit" = "黑名单数已达系统上限。";
"TUIKitErrorSVRFriendshipPeerFriendLimit" = "对方的好友数已达系统上限。";
"TUIKitErrorSVRFriendshipInSelfBlacklist" = "对方在自己的黑名单中,不允许加好友。";
"TUIKitErrorSVRFriendshipAllowTypeDenyAny" = "对方的加好友验证方式是不允许任何人添加自己为好友。";
"TUIKitErrorSVRFriendshipInPeerBlackList" = "自己在对方的黑名单中,不允许加好友。";
"TUIKitErrorSVRFriendshipAllowTypeNeedConfirm" = "请求已发送,等待对方同意";
"TUIKitErrorSVRFriendshipAddFriendSecRstr" = "添加好友请求被安全策略打击,请勿频繁发起添加好友请求。";
"TUIKitErrorSVRFriendshipPendencyNotFound" = "请求的未决不存在。";
"TUIKitErrorSVRFriendshipDelFriendSecRstr" = "删除好友请求被安全策略打击,请勿频繁发起删除好友请求。";
"TUIKirErrorSVRFriendAccountNotFoundEx" = "请求的用户帐号不存在。";
"TUIKitErrorSVRMsgPkgParseFailed" = "解析请求包失败。";
"TUIKitErrorSVRMsgInternalAuthFailed" = "内部鉴权失败。";
"TUIKitErrorSVRMsgInvalidId" = "Identifier 无效";
"TUIKitErrorSVRMsgNetError" = "网络异常,请重试。";
"TUIKitErrorSVRMsgPushDeny" = "触发发送单聊消息之前回调App 后台返回禁止下发该消息。";
"TUIKitErrorSVRMsgInPeerBlackList" = "发送单聊消息,被对方拉黑,禁止发送。";
"TUIKitErrorSVRMsgBothNotFriend" = "消息发送双方互相不是好友,禁止发送。";
"TUIKitErrorSVRMsgNotPeerFriend" = "发送单聊消息,自己不是对方的好友(单向关系),禁止发送。";
"TUIkitErrorSVRMsgNotSelfFriend" = "发送单聊消息,对方不是自己的好友(单向关系),禁止发送。";
"TUIKitErrorSVRMsgShutupDeny" = "因禁言,禁止发送消息。";
"TUIKitErrorSVRMsgRevokeTimeLimit" = "消息撤回超过了时间限制默认2分钟。";
"TUIKitErrorSVRMsgDelRambleInternalError" = "删除漫游内部错误。";
"TUIKitErrorSVRMsgJsonParseFailed" = "JSON 格式解析失败,请检查请求包是否符合 JSON 规范。";
"TUIKitErrorSVRMsgInvalidJsonBodyFormat" = "JSON 格式请求包中 MsgBody 不符合消息格式描述";
"TUIKitErrorSVRMsgInvalidToAccount" = "JSON 格式请求包体中缺少 To_Account 字段或者 To_Account 字段不是 Integer 类型";
"TUIKitErrorSVRMsgInvalidRand" = "JSON 格式请求包体中缺少 MsgRandom 字段或者 MsgRandom 字段不是 Integer 类型";
"TUIKitErrorSVRMsgInvalidTimestamp" = "JSON 格式请求包体中缺少 MsgTimeStamp 字段或者 MsgTimeStamp 字段不是 Integer 类型";
"TUIKitErrorSVRMsgBodyNotArray" = "JSON 格式请求包体中 MsgBody 类型不是 Array 类型";
"TUIKitErrorSVRMsgInvalidJsonFormat" = "JSON 格式请求包不符合消息格式描述";
"TUIKitErrorSVRMsgToAccountCountLimit" = "批量发消息目标帐号超过500";
"TUIKitErrorSVRMsgToAccountNotFound" = "To_Account 没有注册或不存在";
"TUIKitErrorSVRMsgTimeLimit" = "消息离线存储时间错误最多不能超过7天。";
"TUIKitErrorSVRMsgInvalidSyncOtherMachine" = "JSON 格式请求包体中 SyncOtherMachine 字段不是 Integer 类型";
"TUIkitErrorSVRMsgInvalidMsgLifeTime" = "JSON 格式请求包体中 MsgLifeTime 字段不是 Integer 类型";
"TUIKitErrorSVRMsgBodySizeLimit" = "JSON 数据包超长消息包体请不要超过8k。";
"TUIKitErrorSVRmsgLongPollingCountLimit" = "Web 端长轮询被踢Web 端同时在线实例个数超出限制)。";
"TUIKitErrorSVRGroupApiNameError" = "请求中的接口名称错误";
"TUIKitErrorSVRGroupAccountCountLimit" = "请求包体中携带的帐号数量过多。";
"TUIkitErrorSVRGroupFreqLimit" = "操作频率限制,请尝试降低调用的频率。";
"TUIKitErrorSVRGroupPermissionDeny" = "操作权限不足";
"TUIKitErrorSVRGroupInvalidReq" = "请求非法";
"TUIKitErrorSVRGroupSuperNotAllowQuit" = "该群不允许群主主动退出。";
"TUIKitErrorSVRGroupNotFound" = "群组不存在";
"TUIKitErrorSVRGroupJsonParseFailed" = "解析 JSON 包体失败,请检查包体的格式是否符合 JSON 格式。";
"TUIKitErrorSVRGroupInvalidId" = "发起操作的 Identifier 非法,请检查发起操作的用户 Identifier 是否填写正确。";
"TUIKitErrorSVRGroupAllreadyMember" = "被邀请加入的用户已经是群成员。";
"TUIKitErrorSVRGroupFullMemberCount" = "群已满员,无法将请求中的用户加入群组";
"TUIKitErrorSVRGroupInvalidGroupId" = "群组 ID 非法,请检查群组 ID 是否填写正确。";
"TUIKitErrorSVRGroupRejectFromThirdParty" = "App 后台通过第三方回调拒绝本次操作。";
"TUIKitErrorSVRGroupShutDeny" = "因被禁言而不能发送消息,请检查发送者是否被设置禁言。";
"TUIKitErrorSVRGroupRspSizeLimit" = "应答包长度超过最大包长";
"TUIKitErrorSVRGroupAccountNotFound" = "请求的用户帐号不存在。";
"TUIKitErrorSVRGroupGroupIdInUse" = "群组 ID 已被使用,请选择其他的群组 ID。";
"TUIKitErrorSVRGroupSendMsgFreqLimit" = "发消息的频率超限,请延长两次发消息时间的间隔。";
"TUIKitErrorSVRGroupReqAllreadyBeenProcessed" = "此邀请或者申请请求已经被处理。";
"TUIKitErrorSVRGroupGroupIdUserdForSuper" = "群组 ID 已被使用,并且操作者为群主,可以直接使用。";
"TUIKitErrorSVRGroupSDkAppidDeny" = "该 SDKAppID 请求的命令字已被禁用";
"TUIKitErrorSVRGroupRevokeMsgNotFound" = "请求撤回的消息不存在。";
"TUIKitErrorSVRGroupRevokeMsgTimeLimit" = "消息撤回超过了时间限制默认2分钟。";
"TUIKitErrorSVRGroupRevokeMsgDeny" = "请求撤回的消息不支持撤回操作。";
"TUIKitErrorSVRGroupNotAllowRevokeMsg" = "群组类型不支持消息撤回操作。";
"TUIKitErrorSVRGroupRemoveMsgDeny" = "该消息类型不支持删除操作。";
"TUIKitErrorSVRGroupNotAllowRemoveMsg" = "音视频聊天室和在线成员广播大群不支持删除消息。";
"TUIKitErrorSVRGroupAvchatRoomCountLimit" = "音视频聊天室创建数量超过了限制";
"TUIKitErrorSVRGroupCountLimit" = "单个用户可创建和加入的群组数量超过了限制”。";
"TUIKitErrorSVRGroupMemberCountLimit" = "群成员数量超过限制";
"TUIKitErrorSVRNoSuccessResult" = "批量操作无成功结果";
"TUIKitErrorSVRToUserInvalid" = "IM: 无效接收方";
"TUIKitErrorSVRRequestTimeout" = "请求超时";
"TUIKitErrorSVRInitCoreFail" = "INIT CORE模块失败";
"TUIKitErrorExpiredSessionNode" = "SessionNode为null";
"TUIKitErrorLoggedOutBeforeLoginFinished" = "在登录完成前进行了登出(在登录时返回)";
"TUIKitErrorTLSSDKNotInitialized" = "tlssdk未初始化";
"TUIKitErrorTLSSDKUserNotFound" = "TLSSDK没有找到相应的用户信息";
"TUIKitErrorBindFaildRegTimeout" = "注册超时";
"TUIKitErrorBindFaildIsBinding" = "正在bind操作中";
"TUIKitErrorPacketFailUnknown" = "发包未知错误";
"TUIKitErrorPacketFailReqNoNet" = "发送请求包时没有网络,处理时转换成case ERR_REQ_NO_NET_ON_REQ:";
"TUIKitErrorPacketFailRespNoNet" = "发送回复包时没有网络,处理时转换成case ERR_REQ_NO_NET_ON_RSP:";
"TUIKitErrorPacketFailReqNoAuth" = "发送请求包时没有权限";
"TUIKitErrorPacketFailSSOErr" = "SSO错误";
"TUIKitErrorPacketFailRespTimeout" = "回复超时";
"TUIKitErrorFriendshipProxySyncing" = "proxy_manager没有完成svr数据同步";
"TUIKitErrorFriendshipProxySyncedFail" = "proxy_manager同步失败";
"TUIKitErrorFriendshipProxyLocalCheckErr" = "proxy_manager请求参数在本地检查不合法";
"TUIKitErrorGroupInvalidField" = "group assistant请求字段中包含非预设字段";
"TUIKitErrorGroupStoreageDisabled" = "group assistant群资料本地存储没有开启";
"TUIKitErrorLoadGrpInfoFailed" = "无法从存储中加载groupinfo";
"TUIKitErrorReqNoNetOnReq" = "请求的时候没有网络";
"TUIKitErrorReqNoNetOnResp" = "响应的时候没有网络";
"TUIKitErrorServiceNotReady" = "QALSDK服务未就绪";
"TUIKitErrorLoginAuthFailed" = "账号认证失败(用户信息获取失败)";
"TUIKitErrorNeverConnectAfterLaunch" = "在应用启动后没有尝试联网";
"TUIKitErrorReqFailed" = "QAL执行失败";
"TUIKitErrorReqInvaidReq" = "请求非法toMsgService非法";
"TUIKitErrorReqOnverLoaded" = "请求队列满";
"TUIKitErrorReqKickOff" = "已经被其他终端踢了";
"TUIKitErrorReqServiceSuspend" = "服务被暂停";
"TUIKitErrorReqInvalidSign" = "SSO签名错误";
"TUIKitErrorReqInvalidCookie" = "SSO cookie无效";
"TUIKitErrorLoginTlsRspParseFailed" = "登录时TLS回包校验包体长度错误";
"TUIKitErrorLoginOpenMsgTimeout" = "登录时OPENSTATSVC向OPENMSG上报状态超时";
"TUIKitErrorLoginOpenMsgRspParseFailed" = "登录时OPENSTATSVC向OPENMSG上报状态时解析回包失败";
"TUIKitErrorLoginTslDecryptFailed" = "登录时TLS解密失败";
"TUIKitErrorWifiNeedAuth" = "wifi需要认证";
"TUIKitErrorUserCanceled" = "用户已取消";
"TUIkitErrorRevokeTimeLimitExceed" = "消息撤回超过了时间限制默认2分钟";
"TUIKitErrorLackUGExt" = "缺少UGC扩展包";
"TUIKitErrorAutoLoginNeedUserSig" = "自动登录本地票据过期需要userSig手动登录";
"TUIKitErrorQALNoShortConneAvailable" = "没有可用的短连接sso";
"TUIKitErrorReqContentAttach" = "消息内容安全打击";
"TUIKitErrorLoginSigExpire" = "登录返回,票据过期";
"TUIKitErrorSDKHadInit" = "SDK 已经初始化无需重复初始化";
"TUIKitErrorOpenBDHBase" = "openbdh 错误码";
"TUIKitErrorRequestNoNetOnReq" = "请求时没有网络,请等网络恢复后重试";
"TUIKitErrorRequestNoNetOnRsp" = "响应时没有网络,请等网络恢复后重试";
"TUIKitErrorRequestOnverLoaded" = "请求队列満";
/***************************** 消息转发 & 消息搜索 *************************/
// 补充
"Multiple" = "多选";
"Forward" = "转发";
"Delete" = "删除";
"Copy" = "复制";
"Revoke" = "撤回";
"Resend" = "重发";
"Search" = "搜索";
"TUIKitCallMicCamAuthTips" = "请开启麦克风和摄像头权限";
"TUIKitCallMicAuthTips" = "请开启麦克风权限";
"TUIKitMessageTipsSureToResend" = "确定重发消息?";
// 消息转发
"TUIKitRelayNoMessageTips" = "请选择消息";
"TUIKitRelayRecentMessages" = "最近聊天";
"TUIKitRelayChatHistory" = "聊天记录";
"TUIKitRelaySepcialForbid" = "选中的消息中,语音消息等其他消息不能被转发.";
"TUIKitRelayConfirmForward" = "确定转发?";
"TUIKitRelayOneByOneForward" = "逐条转发";
"TUIKitRelayCombineForwad" = "合并转发";
"TUIKitRelayGroupChatHistory" = "群聊的聊天记录";
"TUIKitRelayChatHistoryForSomebodyFormat" = "%@和%@的聊天记录";
"TUIKitRelayErrorForwardFormat" = "@\"转发失败, code:%d, desc:%@\"";
"TUIKitRelayTargetCreateNewChat" = "创建新聊天";
"TUIKitRelayTargetSelectFromContacts" = "从联系人中选择";
"TUIKitRelayTargetCrateGroupError" = "创建群失败";
"TUIKitRelayTargetNoneTips" = "请选择联系人或会话";
"TUIKitRelayLayerLimitTips" = "抱歉,当前嵌套层级超过了限制";
"TUIKitRelayCompatibleText" = "不支持合并转发消息,请升级到最新版本。";
"TUIKitRelayUnsupportForward" = "发送失败的消息不支持转发";
"TUIKitRelayOneByOnyOverLimit" = "转发消息过多,暂不支持逐条转发";
// 消息搜索
"TUIKitSearchItemHeaderTitleContact" = "联系人";
"TUIKitSearchItemFooterTitleContact" = "查看更多联系人";
"TUIKitSearchItemHeaderTitleGroup" = "群聊";
"TUIKitSearchItemFooterTitleGroup" = "查看更多群聊";
"TUIkitSearchItemHeaderTitleChatHistory" = "聊天记录";
"TUIKitSearchItemFooterTitleChatHistory" = "查看更多聊天记录";
"TUIKitSearchResultMatchFormat" = "包含:%@";
"TUIKitSearchResultMatchGroupIDFormat" = "包含群ID:%@";
"TUIKitSearchResultMatchGroupMember" = "包含群成员:";
"TUIKitSearchResultDisplayChatHistoryCountFormat" = "%zd条聊天记录";
/***************************** 消息转发 & 消息搜索 *************************/
/***************************** 消息回复 & 换肤 *************************/
"Reply" = "回复";
"TUIKitReplyMessageNotFoundOriginMessage" = "无法定位到原消息";
"TUIKitClearAllChatHistory" = "清除聊天记录";
"TUIKitClearAllChatHistoryTips" = "确定清空聊天记录?";
"Discline" = "拒绝";
"Copied" = "已复制";
"ConfirmDeleteMessage" = "确定删除已选消息";
"TUIKitAddFriend" = "添加好友";
"TUIKitAddGroup" = "添加群组";
"TUIKitSearchUserID" = "搜索用户ID";
"TUIKitSearchGroupID" = "搜索群ID";
"TUIKitNoSelfSignature" = "暂无个性签名";
"TUIKitSelfSignatureFormat" = "个性签名:%@";
/***************************** 消息回复 & 换肤 *************************/
/***************************** 视频、图片加载 & 保存 *************************/
"TUIKitVideoTranscoding" = "视频转码中...";
"TUIKitVideoDownloading" = "视频下载中...";
"TUIKitVideoSavedSuccess" = "视频保存成功";
"TUIKitVideoSavedFailed" = "视频保存失败";
"TUIKitPictureSavedSuccess" = "图片保存成功";
"TUIKitPictureSavedFailed" = "图片保存失败";
/***************************** 视频、图片加载 & 保存 *************************/

View File

@@ -0,0 +1,15 @@
// Copyright (c) 2020 Tencent. All rights reserved.
#ifndef TIM_IM_SDK_PLUS_H_
#define TIM_IM_SDK_PLUS_H_
#import "TIMErrorCode.h"
#import "V2TIMManager.h"
#import "V2TIMManager+APNS.h"
#import "V2TIMManager+Message.h"
#import "V2TIMManager+Conversation.h"
#import "V2TIMManager+Group.h"
#import "V2TIMManager+Friendship.h"
#import "V2TIMManager+Signaling.h"
#endif

View File

@@ -0,0 +1,415 @@
// Copyright (c) 2020 Tencent. All rights reserved.
#ifndef TIM_ERROR_CODE_H_
#define TIM_ERROR_CODE_H_
enum ERROR_CODE {
/////////////////////////////////////////////////////////////////////////////////
//
// IM SDK 的错误码
//
/////////////////////////////////////////////////////////////////////////////////
// 通用错误码
ERR_SUCC = 0, ///< 无错误。
ERR_IN_PROGESS = 6015, ///< 执行中,请做好接口调用控制,例如,第一次初始化操作在回调前,后续的初始化操作会返回该错误码。
ERR_INVALID_PARAMETERS = 6017, ///< 参数无效,请检查参数是否符合要求,具体可查看错误信息进一步定义哪个字段。
ERR_IO_OPERATION_FAILED = 6022, ///< 操作本地 IO 错误,检查是否有读写权限,磁盘是否已满。
ERR_INVALID_JSON = 6027, ///< 错误的 JSON 格式,请检查参数是否符合接口的要求,具体可查看错误信息进一步定义哪个字段。
ERR_OUT_OF_MEMORY = 6028, ///< 内存不足可能存在内存泄漏iOS 平台使用 Instrument 工具Android 平台使用 Profiler 工具,分析出什么地方的内存占用高。
ERR_PARSE_RESPONSE_FAILED = 6001, ///< PB 解析失败,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SERIALIZE_REQ_FAILED = 6002, ///< PB 序列化失败,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_NOT_INITIALIZED = 6013, ///< IM SDK 未初始化,初始化成功回调之后重试。
ERR_LOADMSG_FAILED = 6005, ///< 加载本地数据库操作失败,可能存储文件有损坏,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 联系客服定位具体问题。
ERR_DATABASE_OPERATE_FAILED = 6019, ///< 本地数据库操作失败,可能是部分目录无权限或者数据库文件已损坏。
ERR_SDK_COMM_CROSS_THREAD = 7001, ///< 跨线程错误,不能在跨越不同线程中执行,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_COMM_TINYID_EMPTY = 7002, ///< TinyId 为空,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_COMM_INVALID_IDENTIFIER = 7003, ///< Identifier 非法,必须不为空,要求可打印 ASCII 字符0x20-0x7e长度不超过32字节。
ERR_SDK_COMM_FILE_NOT_FOUND = 7004, ///< 文件不存在,请检查文件路径是否正确。
ERR_SDK_COMM_FILE_TOO_LARGE = 7005, ///< 文件大小超出了限制图片、语音最大限制是28MB视频、文件最大限制是100MB
ERR_SDK_COMM_FILE_SIZE_EMPTY = 7006, ///< 空文件要求文件大小不是0字节如果上传图片、语音、视频或文件请检查文件是否正确生成。
ERR_SDK_COMM_FILE_OPEN_FAILED = 7007, ///< 文件打开失败,请检查文件是否存在,或者已被独占打开,引起 SDK 打开失败。
ERR_SDK_COMM_API_CALL_FREQUENCY_LIMIT = 7008, ///< API 调用超频
ERR_SDK_INTERFACE_NOT_SUPPORT = 7013, ///< 套餐包不支持该接口的使用,请升级到旗舰版套餐
ERR_SDK_INVALID_OPERATION = 7014, ///< 非法请求
// 帐号错误码
ERR_SDK_NOT_LOGGED_IN = 6014, ///< IM SDK 未登录,请先登录,成功回调之后重试,或者已被踢下线,可使用 TIMManager getLoginUser 检查当前是否在线。
ERR_NO_PREVIOUS_LOGIN = 6026, ///< 自动登录时,并没有登录过该用户,这时候请调用 login 接口重新登录。
ERR_USER_SIG_EXPIRED = 6206, ///< UserSig 过期,请重新获取有效的 UserSig 后再重新登录。
ERR_LOGIN_KICKED_OFF_BY_OTHER = 6208, ///< 其他终端登录同一个帐号,引起已登录的帐号被踢,需重新登录。
ERR_SDK_ACCOUNT_LOGIN_IN_PROCESS = 7501, ///< 登录正在执行中,例如,第一次 login 或 autoLogin 操作在回调前,后续的 login 或 autoLogin 操作会返回该错误码。
ERR_SDK_ACCOUNT_LOGOUT_IN_PROCESS = 7502, ///< 登出正在执行中,例如,第一次 logout 操作在回调前,后续的 logout 操作会返回该错误码。
ERR_SDK_ACCOUNT_TLS_INIT_FAILED = 7503, ///< TLS SDK 初始化失败,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_ACCOUNT_TLS_NOT_INITIALIZED = 7504, ///< TLS SDK 未初始化,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_ACCOUNT_TLS_TRANSPKG_ERROR = 7505, ///< TLS SDK TRANS 包格式错误,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_ACCOUNT_TLS_DECRYPT_FAILED = 7506, ///< TLS SDK 解密失败,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_ACCOUNT_TLS_REQUEST_FAILED = 7507, ///< TLS SDK 请求失败,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_SDK_ACCOUNT_TLS_REQUEST_TIMEOUT = 7508, ///< TLS SDK 请求超时,内部错误,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
// 消息错误码
ERR_INVALID_CONVERSATION = 6004, ///< 会话无效getConversation 时检查是否已经登录,如未登录获取会话,会有此错误码返回。
ERR_FILE_TRANS_AUTH_FAILED = 6006, ///< 文件传输鉴权失败,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_FILE_TRANS_NO_SERVER = 6007, ///< 文件传输获取 Server 列表失败,可 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 提供使用接口、错误码、错误信息给客服解决。
ERR_FILE_TRANS_UPLOAD_FAILED = 6008, ///< 文件传输上传失败,请检查网络是否连接
ERR_IMAGE_UPLOAD_FAILED_NOTIMAGE = 6031, ///< 文件传输上传失败,请检查上传的图片是否能够正常打开。
ERR_FILE_TRANS_DOWNLOAD_FAILED = 6009, ///< 文件传输下载失败请检查网络或者文件、语音是否已经过期目前资源文件存储7天。
ERR_HTTP_REQ_FAILED = 6010, ///< HTTP 请求失败,请检查 URL 地址是否合法,可在网页浏览器尝试访问该 URL 地址。
ERR_INVALID_MSG_ELEM = 6016, ///< IM SDK 无效消息 elem具体可查看错误信息进一步定义哪个字段。
ERR_INVALID_SDK_OBJECT = 6021, ///< 无效的对象,例如用户自己生成 TIMImage 对象,或内部赋值错误导致对象无效。
ERR_SDK_MSG_BODY_SIZE_LIMIT = 8001, ///< 消息长度超出限制消息长度不要超过8k消息长度是各个 elem 长度的总和elem 长度是所有 elem 字段的长度总和。
ERR_SDK_MSG_KEY_REQ_DIFFER_RSP = 8002, ///< 消息 KEY 错误,内部错误,网络请求包的 KEY 和 回复包的不一致。
ERR_SDK_IMAGE_CONVERT_ERROR = 8003, ///< 万象优图 HTTP 请求失败。
ERR_MERGER_MSG_LAYERS_OVER_LIMIT = 8005, ///< 合并消息嵌套层数超过上限(上限 100 层)。
ERR_SDK_SIGNALING_INVALID_INVITE_ID = 8010, ///< 信令请求 ID 无效或已经被处理过。
ERR_SDK_SIGNALING_NO_PERMISSION = 8011, ///< 信令请求无权限,比如取消非自己发起的邀请。
ERR_SDK_SIGNALING_ALREADY_EXISTS = 8012, ///< 信令邀请已存在。
// 群组错误码
ERR_SDK_GROUP_INVALID_ID = 8501, ///< 群组 ID 非法,自定义群组 ID 必须为可打印 ASCII 字符0x20-0x7e最长48个字节且前缀不能为 @TGS#(避免与服务端默认分配的群组 ID 混淆)。
ERR_SDK_GROUP_INVALID_NAME = 8502, ///< 群名称非法群名称最长30字节字符编码必须是 UTF-8 ,如果包含中文,可能用多个字节表示一个中文字符,请注意检查字符串的字节长度。
ERR_SDK_GROUP_INVALID_INTRODUCTION = 8503, ///< 群简介非法群简介最长240字节字符编码必须是 UTF-8 ,如果包含中文,可能用多个字节表示一个中文字符,请注意检查字符串的字节长度。
ERR_SDK_GROUP_INVALID_NOTIFICATION = 8504, ///< 群公告非法群公告最长300字节字符编码必须是 UTF-8 ,如果包含中文,可能用多个字节表示一个中文字符,请注意检查字符串的字节长度。
ERR_SDK_GROUP_INVALID_FACE_URL = 8505, ///< 群头像 URL 非法,群头像 URL 最长100字节可在网页浏览器尝试访问该 URL 地址。
ERR_SDK_GROUP_INVALID_NAME_CARD = 8506, ///< 群名片非法群名片最长50字节字符编码必须是 UTF-8 ,如果包含中文,可能用多个字节表示一个中文字符,请注意检查字符串的字节长度。
ERR_SDK_GROUP_MEMBER_COUNT_LIMIT = 8507, ///< 超过群组成员数的限制在创建群和邀请成员时指定的成员数超出限制最大群成员数量私有群是200人公开群是2000人聊天室是10000人音视频聊天室和在线成员广播大群无限制。
ERR_SDK_GROUP_JOIN_PRIVATE_GROUP_DENY = 8508, ///< 不允许申请加入 Private 群组,任意群成员可邀请入群,且无需被邀请人同意。
ERR_SDK_GROUP_INVITE_SUPER_DENY = 8509, ///< 不允许邀请角色为群主的成员,请检查角色字段是否填写正确。
ERR_SDK_GROUP_INVITE_NO_MEMBER = 8510, ///< 不允许邀请0个成员请检查成员字段是否填写正确。
ERR_SDK_GROUP_ATTR_FREQUENCY_LIMIT = 8511, ///< 群属性接口操作限制增删改接口后台限制1秒5次查接口 SDK 限制5秒20次。
// 关系链错误码
ERR_SDK_FRIENDSHIP_INVALID_PROFILE_KEY = 9001, ///< 资料字段非法资料支持标配字段及自定义字段其中自定义字段的关键字必须是英文字母且长度不得超过8字节自定义字段的值最长不能超过500字节。
ERR_SDK_FRIENDSHIP_INVALID_ADD_REMARK = 9002, ///< 备注字段非法最大96字节字符编码必须是 UTF-8 ,如果包含中文,可能用多个字节表示一个中文字符,请注意检查字符串的字节长度。
ERR_SDK_FRIENDSHIP_INVALID_ADD_WORDING = 9003, ///< 请求添加好友的请求说明字段非法最大120字节字符编码必须是 UTF-8 ,如果包含中文,可能用多个字节表示一个中文字符,请注意检查字符串的字节长度。
ERR_SDK_FRIENDSHIP_INVALID_ADD_SOURCE = 9004, ///< 请求添加好友的添加来源字段非法来源需要添加“AddSource_Type_”前缀。
ERR_SDK_FRIENDSHIP_FRIEND_GROUP_EMPTY = 9005, ///< 好友分组字段非法必须不为空每个分组的名称最长30字节字符编码必须是 UTF-8 ,如果包含中文,可能用多个字节表示一个中文字符,请注意检查字符串的字节长度。
// 网络错误码
ERR_SDK_NET_ENCODE_FAILED = 9501, ///< 网络加密失败,内部错误。
ERR_SDK_NET_DECODE_FAILED = 9502, ///< 网络数据解密失败,内部错误。
ERR_SDK_NET_AUTH_INVALID = 9503, ///< 未完成鉴权,可能登录未完成,请在登录完成后再操作。
ERR_SDK_NET_COMPRESS_FAILED = 9504, ///< 数据包压缩失败,内部错误。
ERR_SDK_NET_UNCOMPRESS_FAILED = 9505, ///< 数据包解压失败,内部错误。
ERR_SDK_NET_FREQ_LIMIT = 9506, ///< 调用频率限制,最大每秒发起 5 次请求。
ERR_SDK_NET_REQ_COUNT_LIMIT = 9507, ///< 请求队列満超过同时请求的数量限制最大同时发起1000个请求。
ERR_SDK_NET_DISCONNECT = 9508, ///< 网络已断开,未建立连接,或者建立 socket 连接时,检测到无网络。
ERR_SDK_NET_ALLREADY_CONN = 9509, ///< 网络连接已建立,重复创建连接,内部错误。
ERR_SDK_NET_CONN_TIMEOUT = 9510, ///< 建立网络连接超时,请等网络恢复后重试。
ERR_SDK_NET_CONN_REFUSE = 9511, ///< 网络连接已被拒绝,请求过于频繁,服务端拒绝服务。
ERR_SDK_NET_NET_UNREACH = 9512, ///< 没有到达网络的可用路由,请等网络恢复后重试。
ERR_SDK_NET_SOCKET_NO_BUFF = 9513, ///< 系统中没有足够的缓冲区空间资源可用来完成调用,系统过于繁忙,内部错误。
ERR_SDK_NET_RESET_BY_PEER = 9514, ///< 对端重置了连接可能服务端过载SDK 内部会自动重连,请等网络连接成功 onConnSucc iOS 或 onConnected Android 回调后重试。
ERR_SDK_NET_SOCKET_INVALID = 9515, ///< socket 套接字无效,内部错误。
ERR_SDK_NET_HOST_GETADDRINFO_FAILED = 9516, ///< IP 地址解析失败,内部错误,可能是本地 imsdk_config 配置文件被损坏,读取到到 IP 地址非法。
ERR_SDK_NET_CONNECT_RESET = 9517, ///< 网络连接到中间节点或服务端重置引起连接失效内部错误SDK 内部会自动重连,请等网络连接成功 onConnSucc iOS 或 onConnected Android 回调后重试。
ERR_SDK_NET_WAIT_INQUEUE_TIMEOUT = 9518, ///< 请求包等待进入待发送队列超时,发送时网络连接建立比较慢 或 频繁断网重连时,会出现该错误,请检查网络连接是否正常。
ERR_SDK_NET_WAIT_SEND_TIMEOUT = 9519, ///< 请求包已进入 IM SDK 待发送队列,等待进入操作系统的网络层时超时。一般可能原因是本地网络受限/不通或本地网络与 IM SDK 后台连接不通。建议用不同的网络环境分别运行 IM SDK 来确认是否因当前网络环境问题引起。
ERR_SDK_NET_WAIT_ACK_TIMEOUT = 9520, ///< 请求包已由 IM SDK 待发送队列进入操作系统网络层,等待服务端回包超时。一般可能原因是本地网络受限/不通或本地网络与 IM SDK 后台连接不通。建议用不同的网络环境分别运行 IM SDK 来确认是否因当前网络环境问题引起。
ERR_SDK_NET_WAIT_SEND_REMAINING_TIMEOUT = 9521, ///< 请求包已进入待发送队列,部分数据已发送,等待发送剩余部分出现超时,可能上行带宽不足,请检查网络是否畅通,在回调错误时检测有联网,内部错误。
ERR_SDK_NET_PKG_SIZE_LIMIT = 9522, ///< 请求包长度大于限制,最大支持 1MB 。
ERR_SDK_NET_WAIT_SEND_TIMEOUT_NO_NETWORK = 9523, ///< 请求包已进入待发送队列,等待进入系统的网络 buffer 超时,数据包较多 或 发送线程处理不过来,在回调错误码时检测到没有联网。
ERR_SDK_NET_WAIT_ACK_TIMEOUT_NO_NETWORK = 9524, ///< 请求包已进入系统的网络 buffer ,等待服务端回包超时,可能请求包没离开终端设备、中间路由丢弃、服务端意外丢包或回包被系统网络层丢弃,在回调错误码时检测到没有联网。
ERR_SDK_NET_SEND_REMAINING_TIMEOUT_NO_NETWORK = 9525, ///< 请求包已进入待发送队列,部分数据已发送,等待发送剩余部分出现超时,可能上行带宽不足,请检查网络是否畅通,在回调错误码时检测到没有联网。
/////////////////////////////////////////////////////////////////////////////////
//
// (二)服务端的错误码
//
/////////////////////////////////////////////////////////////////////////////////
// SSO 接入层的错误码
ERR_SVR_SSO_CONNECT_LIMIT = -302 , ///< SSO 的连接数量超出限制,服务端拒绝服务。
ERR_SVR_SSO_VCODE = -10000, ///< 下发验证码标志错误。
ERR_SVR_SSO_D2_EXPIRED = -10001, ///< D2 过期。
ERR_SVR_SSO_A2_UP_INVALID = -10003, ///< A2 校验失败等场景使用。
ERR_SVR_SSO_A2_DOWN_INVALID = -10004, ///< 处理下行包时发现 A2 验证没通过或者被安全打击。
ERR_SVR_SSO_EMPTY_KEY = -10005, ///< 不允许空 D2Key 加密。
ERR_SVR_SSO_UIN_INVALID = -10006, ///< D2 中的 uin 和 SSO 包头的 uin 不匹配。
ERR_SVR_SSO_VCODE_TIMEOUT = -10007, ///< 验证码下发超时。
ERR_SVR_SSO_NO_IMEI_AND_A2 = -10008, ///< 需要带上 IMEI 和 A2 。
ERR_SVR_SSO_COOKIE_INVALID = -10009, ///< Cookie 非法。
ERR_SVR_SSO_DOWN_TIP = -10101, ///< 下发提示语D2 过期。
ERR_SVR_SSO_DISCONNECT = -10102, ///< 断链锁屏。
ERR_SVR_SSO_IDENTIFIER_INVALID = -10103, ///< 失效身份。
ERR_SVR_SSO_CLIENT_CLOSE = -10104, ///< 终端自动退出。
ERR_SVR_SSO_MSFSDK_QUIT = -10105, ///< MSFSDK 自动退出。
ERR_SVR_SSO_D2KEY_WRONG = -10106, ///< SSO D2key 解密失败次数太多,通知终端需要重置,重新刷新 D2 。
ERR_SVR_SSO_UNSURPPORT = -10107, ///< 不支持聚合,给终端返回统一的错误码。终端在该 TCP 长连接上停止聚合。
ERR_SVR_SSO_PREPAID_ARREARS = -10108, ///< 预付费欠费。
ERR_SVR_SSO_PACKET_WRONG = -10109, ///< 请求包格式错误。
ERR_SVR_SSO_APPID_BLACK_LIST = -10110, ///< SDKAppID 黑名单。
ERR_SVR_SSO_CMD_BLACK_LIST = -10111, ///< SDKAppID 设置 service cmd 黑名单。
ERR_SVR_SSO_APPID_WITHOUT_USING = -10112, ///< SDKAppID 停用。
ERR_SVR_SSO_FREQ_LIMIT = -10113, ///< 频率限制(用户),频率限制是设置针对某一个协议的每秒请求数的限制。
ERR_SVR_SSO_OVERLOAD = -10114, ///< 过载丢包(系统),连接的服务端处理过多请求,处理不过来,拒绝服务。
// 资源文件错误码
ERR_SVR_RES_NOT_FOUND = 114000, ///< 要发送的资源文件不存在。
ERR_SVR_RES_ACCESS_DENY = 114001, ///< 要发送的资源文件不允许访问。
ERR_SVR_RES_SIZE_LIMIT = 114002, ///< 文件大小超过限制。
ERR_SVR_RES_SEND_CANCEL = 114003, ///< 用户取消发送,如发送过程中登出等原因。
ERR_SVR_RES_READ_FAILED = 114004, ///< 读取文件内容失败。
ERR_SVR_RES_TRANSFER_TIMEOUT = 114005, ///< 资源文件(如图片、文件、语音、视频)传输超时,一般是网络问题导致。
ERR_SVR_RES_INVALID_PARAMETERS = 114011, ///< 参数非法。
ERR_SVR_RES_INVALID_FILE_MD5 = 115066, ///< 文件 MD5 校验失败。
ERR_SVR_RES_INVALID_PART_MD5 = 115068, ///< 分片 MD5 校验失败。
// 后台公共错误码
ERR_SVR_COMM_INVALID_HTTP_URL = 60002, ///< HTTP 解析错误 ,请检查 HTTP 请求 URL 格式。
ERR_SVR_COMM_REQ_JSON_PARSE_FAILED = 60003, ///< HTTP 请求 JSON 解析错误,请检查 JSON 格式。
ERR_SVR_COMM_INVALID_ACCOUNT = 60004, ///< 请求 URI 或 JSON 包体中 Identifier 或 UserSig 错误。
ERR_SVR_COMM_INVALID_ACCOUNT_EX = 60005, ///< 请求 URI 或 JSON 包体中 Identifier 或 UserSig 错误。
ERR_SVR_COMM_INVALID_SDKAPPID = 60006, ///< SDKAppID 失效,请核对 SDKAppID 有效性。
ERR_SVR_COMM_REST_FREQ_LIMIT = 60007, ///< REST 接口调用频率超过限制,请降低请求频率。
ERR_SVR_COMM_REQUEST_TIMEOUT = 60008, ///< 服务请求超时或 HTTP 请求格式错误,请检查并重试。
ERR_SVR_COMM_INVALID_RES = 60009, ///< 请求资源错误,请检查请求 URL。
ERR_SVR_COMM_ID_NOT_ADMIN = 60010, ///< REST API 请求的 Identifier 字段请填写 App 管理员帐号。
ERR_SVR_COMM_SDKAPPID_FREQ_LIMIT = 60011, ///< SDKAppID 请求频率超限,请降低请求频率。
ERR_SVR_COMM_SDKAPPID_MISS = 60012, ///< REST 接口需要带 SDKAppID请检查请求 URL 中的 SDKAppID。
ERR_SVR_COMM_RSP_JSON_PARSE_FAILED = 60013, ///< HTTP 响应包 JSON 解析错误。
ERR_SVR_COMM_EXCHANGE_ACCOUNT_TIMEUT = 60014, ///< 置换帐号超时。
ERR_SVR_COMM_INVALID_ID_FORMAT = 60015, ///< 请求包体 Identifier 类型错误,请确认 Identifier 为字符串格式。
ERR_SVR_COMM_SDKAPPID_FORBIDDEN = 60016, ///< SDKAppID 被禁用,请 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 联系客服确认。
ERR_SVR_COMM_REQ_FORBIDDEN = 60017, ///< 请求被禁用,请 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 联系客服确认。
ERR_SVR_COMM_REQ_FREQ_LIMIT = 60018, ///< 请求过于频繁,请稍后重试。
ERR_SVR_COMM_REQ_FREQ_LIMIT_EX = 60019, ///< 请求过于频繁,请稍后重试。
ERR_SVR_COMM_INVALID_SERVICE = 60020, ///< 未购买套餐包或购买的套餐包正在配置中暂未生效,请五分钟后再次尝试。
ERR_SVR_COMM_SENSITIVE_TEXT = 80001, ///< 文本安全打击,文本中可能包含敏感词汇。
ERR_SVR_COMM_BODY_SIZE_LIMIT = 80002, ///< 发消息包体过长目前支持最大8k消息包体长度请减少包体大小重试。
// 帐号错误码
ERR_SVR_ACCOUNT_USERSIG_EXPIRED = 70001, ///< UserSig 已过期,请重新生成 UserSig建议 UserSig 有效期不小于24小时。
ERR_SVR_ACCOUNT_USERSIG_EMPTY = 70002, ///< UserSig 长度为0请检查传入的 UserSig 是否正确。
ERR_SVR_ACCOUNT_USERSIG_CHECK_FAILED = 70003, ///< UserSig 校验失败,请确认下 UserSig 内容是否被截断,如缓冲区长度不够导致的内容截断。
ERR_SVR_ACCOUNT_USERSIG_CHECK_FAILED_EX = 70005, ///< UserSig 校验失败,可用工具自行验证生成的 UserSig 是否正确。
ERR_SVR_ACCOUNT_USERSIG_MISMATCH_PUBLICKEY = 70009, ///< 用公钥验证 UserSig 失败,请确认生成的 UserSig 使用的私钥和 SDKAppID 是否对应。
ERR_SVR_ACCOUNT_USERSIG_MISMATCH_ID = 70013, ///< 请求的 Identifier 与生成 UserSig 的 Identifier 不匹配。
ERR_SVR_ACCOUNT_USERSIG_MISMATCH_SDKAPPID = 70014, ///< 请求的 SDKAppID 与生成 UserSig 的 SDKAppID 不匹配。
ERR_SVR_ACCOUNT_USERSIG_PUBLICKEY_NOT_FOUND = 70016, ///< 验证 UserSig 时公钥不存在。请先登录控制台下载私钥,下载私钥的具体方法可参考 [下载签名用的私钥](https://cloud.tencent.com/document/product/269/32688#.E4.B8.8B.E8.BD.BD.E7.AD.BE.E5.90.8D.E7.94.A8.E7.9A.84.E7.A7.81.E9.92.A5) 。
ERR_SVR_ACCOUNT_SDKAPPID_NOT_FOUND = 70020, ///< SDKAppID 未找到,请在云通信 IM 控制台确认应用信息。
ERR_SVR_ACCOUNT_INVALID_USERSIG = 70052, ///< UserSig 已经失效,请重新生成,再次尝试。
ERR_SVR_ACCOUNT_NOT_FOUND = 70107, ///< 请求的用户帐号不存在。
ERR_SVR_ACCOUNT_SEC_RSTR = 70114, ///< 安全原因被限制。
ERR_SVR_ACCOUNT_INTERNAL_TIMEOUT = 70169, ///< 服务端内部超时,请重试。
ERR_SVR_ACCOUNT_INVALID_COUNT = 70206, ///< 请求中批量数量不合法。
ERR_SVR_ACCOUNT_INVALID_PARAMETERS = 70402, ///< 参数非法,请检查必填字段是否填充,或者字段的填充是否满足协议要求。
ERR_SVR_ACCOUNT_ADMIN_REQUIRED = 70403, ///< 请求需要 App 管理员权限。
ERR_SVR_ACCOUNT_FREQ_LIMIT = 70050, ///< 因失败且重试次数过多导致被限制,请检查 UserSig 是否正确,一分钟之后再试。
ERR_SVR_ACCOUNT_BLACKLIST = 70051, ///< 帐号被拉入黑名单。
ERR_SVR_ACCOUNT_COUNT_LIMIT = 70398, ///< 创建帐号数量超过免费体验版数量限制,请升级为专业版。
ERR_SVR_ACCOUNT_INTERNAL_ERROR = 70500, ///< 服务端内部错误,请重试。
// 资料错误码
ERR_SVR_PROFILE_INVALID_PARAMETERS = 40001, ///< 请求参数错误,请根据错误描述检查请求是否正确。
ERR_SVR_PROFILE_ACCOUNT_MISS = 40002, ///< 请求参数错误,没有指定需要拉取资料的用户帐号。
ERR_SVR_PROFILE_ACCOUNT_NOT_FOUND = 40003, ///< 请求的用户帐号不存在。
ERR_SVR_PROFILE_ADMIN_REQUIRED = 40004, ///< 请求需要 App 管理员权限。
ERR_SVR_PROFILE_SENSITIVE_TEXT = 40005, ///< 资料字段中包含敏感词。
ERR_SVR_PROFILE_INTERNAL_ERROR = 40006, ///< 服务端内部错误,请稍后重试。
ERR_SVR_PROFILE_READ_PERMISSION_REQUIRED = 40007, ///< 没有资料字段的读权限,详情可参见 [资料字段](https://cloud.tencent.com/document/product/269/1500#.E8.B5.84.E6.96.99.E5.AD.97.E6.AE.B5) 。
ERR_SVR_PROFILE_WRITE_PERMISSION_REQUIRED = 40008, ///< 没有资料字段的写权限,详情可参见 [资料字段](https://cloud.tencent.com/document/product/269/1500#.E8.B5.84.E6.96.99.E5.AD.97.E6.AE.B5) 。
ERR_SVR_PROFILE_TAG_NOT_FOUND = 40009, ///< 资料字段的 Tag 不存在。
ERR_SVR_PROFILE_SIZE_LIMIT = 40601, ///< 资料字段的 Value 长度超过500字节。
ERR_SVR_PROFILE_VALUE_ERROR = 40605, ///< 标配资料字段的 Value 错误,详情可参见 [标配资料字段](https://cloud.tencent.com/doc/product/269/1500#.E6.A0.87.E9.85.8D.E8.B5.84.E6.96.99.E5.AD.97.E6.AE.B5) 。
ERR_SVR_PROFILE_INVALID_VALUE_FORMAT = 40610, ///< 资料字段的 Value 类型不匹配,详情可参见 [标配资料字段](https://cloud.tencent.com/doc/product/269/1500#.E6.A0.87.E9.85.8D.E8.B5.84.E6.96.99.E5.AD.97.E6.AE.B5) 。
// 关系链错误码
ERR_SVR_FRIENDSHIP_INVALID_PARAMETERS = 30001, ///< 请求参数错误,请根据错误描述检查请求是否正确。
ERR_SVR_FRIENDSHIP_INVALID_SDKAPPID = 30002, ///< SDKAppID 不匹配。
ERR_SVR_FRIENDSHIP_ACCOUNT_NOT_FOUND = 30003, ///< 请求的用户帐号不存在。
ERR_SVR_FRIENDSHIP_ADMIN_REQUIRED = 30004, ///< 请求需要 App 管理员权限。
ERR_SVR_FRIENDSHIP_SENSITIVE_TEXT = 30005, ///< 关系链字段中包含敏感词。
ERR_SVR_FRIENDSHIP_INTERNAL_ERROR = 30006, ///< 服务端内部错误,请重试。
ERR_SVR_FRIENDSHIP_NET_TIMEOUT = 30007, ///< 网络超时,请稍后重试。
ERR_SVR_FRIENDSHIP_WRITE_CONFLICT = 30008, ///< 并发写导致写冲突,建议使用批量方式。
ERR_SVR_FRIENDSHIP_ADD_FRIEND_DENY = 30009, ///< 后台禁止该用户发起加好友请求。
ERR_SVR_FRIENDSHIP_COUNT_LIMIT = 30010, ///< 自己的好友数已达系统上限。
ERR_SVR_FRIENDSHIP_GROUP_COUNT_LIMIT = 30011, ///< 分组已达系统上限。
ERR_SVR_FRIENDSHIP_PENDENCY_LIMIT = 30012, ///< 未决数已达系统上限。
ERR_SVR_FRIENDSHIP_BLACKLIST_LIMIT = 30013, ///< 黑名单数已达系统上限。
ERR_SVR_FRIENDSHIP_PEER_FRIEND_LIMIT = 30014, ///< 对方的好友数已达系统上限。
ERR_SVR_FRIENDSHIP_IN_SELF_BLACKLIST = 30515, ///< 请求添加好友时,对方在自己的黑名单中,不允许加好友。
ERR_SVR_FRIENDSHIP_ALLOW_TYPE_DENY_ANY = 30516, ///< 请求添加好友时,对方的加好友验证方式是不允许任何人添加自己为好友。
ERR_SVR_FRIENDSHIP_IN_PEER_BLACKLIST = 30525, ///< 请求添加好友时,自己在对方的黑名单中,不允许加好友。
ERR_SVR_FRIENDSHIP_ALLOW_TYPE_NEED_CONFIRM = 30539, ///< A 请求加 B 为好友B 的加好友验证方式被设置为“AllowType_Type_NeedConfirm”这时 A 与 B 之间只能形成未决关系,该返回码用于标识加未决成功,以便与加好友成功的返回码区分开,调用方可以捕捉该错误给用户一个合理的提示。
ERR_SVR_FRIENDSHIP_ADD_FRIEND_SEC_RSTR = 30540, ///< 添加好友请求被安全策略打击,请勿频繁发起添加好友请求。
ERR_SVR_FRIENDSHIP_PENDENCY_NOT_FOUND = 30614, ///< 请求的未决不存在。
ERR_SVR_FRIENDSHIP_DEL_NONFRIEND = 31704, ///< 与请求删除的帐号之间不存在好友关系。
ERR_SVR_FRIENDSHIP_DEL_FRIEND_SEC_RSTR = 31707, ///< 删除好友请求被安全策略打击,请勿频繁发起删除好友请求。
ERR_SVR_FRIENDSHIP_ACCOUNT_NOT_FOUND_EX = 31804, ///< 请求的用户帐号不存在。
// 最近联系人错误码
ERR_SVR_CONV_ACCOUNT_NOT_FOUND = 50001, ///< 请求的用户帐号不存在。
ERR_SVR_CONV_INVALID_PARAMETERS = 50002, ///< 请求参数错误,请根据错误描述检查请求是否正确。
ERR_SVR_CONV_ADMIN_REQUIRED = 50003, ///< 请求需要 App 管理员权限。
ERR_SVR_CONV_INTERNAL_ERROR = 50004, ///< 服务端内部错误,请重试。
ERR_SVR_CONV_NET_TIMEOUT = 50005, ///< 网络超时,请稍后重试。
// 消息错误码
ERR_SVR_MSG_PKG_PARSE_FAILED = 20001, ///< 请求包非法,请检查发送方和接收方帐号是否存在。
ERR_SVR_MSG_INTERNAL_AUTH_FAILED = 20002, ///< 内部鉴权失败。
ERR_SVR_MSG_INVALID_ID = 20003, ///< Identifier 无效或者 Identifier 未导入云通信 IM。
ERR_SVR_MSG_NET_ERROR = 20004, ///< 网络异常,请重试。
ERR_SVR_MSG_INTERNAL_ERROR1 = 20005, ///< 服务端内部错误,请重试。
ERR_SVR_MSG_PUSH_DENY = 20006, ///< 触发发送单聊消息之前回调App 后台返回禁止下发该消息。
ERR_SVR_MSG_IN_PEER_BLACKLIST = 20007, ///< 发送单聊消息,被对方拉黑,禁止发送。
ERR_SVR_MSG_BOTH_NOT_FRIEND = 20009, ///< 消息发送双方互相不是好友,禁止发送(配置单聊消息校验好友关系才会出现)。
ERR_SVR_MSG_NOT_PEER_FRIEND = 20010, ///< 发送单聊消息,自己不是对方的好友(单向关系),禁止发送。
ERR_SVR_MSG_NOT_SELF_FRIEND = 20011, ///< 发送单聊消息,对方不是自己的好友(单向关系),禁止发送。
ERR_SVR_MSG_SHUTUP_DENY = 20012, ///< 因禁言,禁止发送消息。
ERR_SVR_MSG_REVOKE_TIME_LIMIT = 20016, ///< 消息撤回超过了时间限制默认2分钟
ERR_SVR_MSG_DEL_RAMBLE_INTERNAL_ERROR = 20018, ///< 删除漫游内部错误。
ERR_SVR_MSG_JSON_PARSE_FAILED = 90001, ///< JSON 格式解析失败,请检查请求包是否符合 JSON 规范。
ERR_SVR_MSG_INVALID_JSON_BODY_FORMAT = 90002, ///< JSON 格式请求包中 MsgBody 不符合消息格式描述,或者 MsgBody 不是 Array 类型,请参考 [TIMMsgElement 对象](https://cloud.tencent.com/document/product/269/2720#.E6.B6.88.E6.81.AF.E5.85.83.E7.B4.A0timmsgelement) 的定义。
ERR_SVR_MSG_INVALID_TO_ACCOUNT = 90003, ///< JSON 格式请求包体中缺少 To_Account 字段或者 To_Account 字段不是 Integer 类型
ERR_SVR_MSG_INVALID_RAND = 90005, ///< JSON 格式请求包体中缺少 MsgRandom 字段或者 MsgRandom 字段不是 Integer 类型
ERR_SVR_MSG_INVALID_TIMESTAMP = 90006, ///< JSON 格式请求包体中缺少 MsgTimeStamp 字段或者 MsgTimeStamp 字段不是 Integer 类型
ERR_SVR_MSG_BODY_NOT_ARRAY = 90007, ///< JSON 格式请求包体中 MsgBody 类型不是 Array 类型,请将其修改为 Array 类型
ERR_SVR_MSG_ADMIN_REQUIRED = 90009, ///< 请求需要 App 管理员权限。
ERR_SVR_MSG_INVALID_JSON_FORMAT = 90010, ///< JSON 格式请求包不符合消息格式描述,请参考 [TIMMsgElement 对象](https://cloud.tencent.com/document/product/269/2720#.E6.B6.88.E6.81.AF.E5.85.83.E7.B4.A0timmsgelement) 的定义。
ERR_SVR_MSG_TO_ACCOUNT_COUNT_LIMIT = 90011, ///< 批量发消息目标帐号超过500请减少 To_Account 中目标帐号数量。
ERR_SVR_MSG_TO_ACCOUNT_NOT_FOUND = 90012, ///< To_Account 没有注册或不存在,请确认 To_Account 是否导入云通信 IM 或者是否拼写错误。
ERR_SVR_MSG_TIME_LIMIT = 90026, ///< 消息离线存储时间错误最多不能超过7天
ERR_SVR_MSG_INVALID_SYNCOTHERMACHINE = 90031, ///< JSON 格式请求包体中 SyncOtherMachine 字段不是 Integer 类型
ERR_SVR_MSG_INVALID_MSGLIFETIME = 90044, ///< JSON 格式请求包体中 MsgLifeTime 字段不是 Integer 类型
ERR_SVR_MSG_ACCOUNT_NOT_FOUND = 90048, ///< 请求的用户帐号不存在。
ERR_SVR_MSG_INTERNAL_ERROR2 = 90994, ///< 服务内部错误,请重试。
ERR_SVR_MSG_INTERNAL_ERROR3 = 90995, ///< 服务内部错误,请重试。
ERR_SVR_MSG_INTERNAL_ERROR4 = 91000, ///< 服务内部错误,请重试。
ERR_SVR_MSG_INTERNAL_ERROR5 = 90992, ///< 服务内部错误,请重试;如果所有请求都返回该错误码,且 App 配置了第三方回调,请检查 App 服务端是否正常向云通信 IM 后台服务端返回回调结果。
ERR_SVR_MSG_BODY_SIZE_LIMIT = 93000, ///< JSON 数据包超长消息包体请不要超过8k。
ERR_SVR_MSG_LONGPOLLING_COUNT_LIMIT = 91101, ///< Web 端长轮询被踢Web 端同时在线实例个数超出限制)。
// 120001 - 130000, ///< 单聊第三方回调返回的自定义错误码。
// 群组错误码
ERR_SVR_GROUP_INTERNAL_ERROR = 10002, ///< 服务端内部错误,请重试。
ERR_SVR_GROUP_API_NAME_ERROR = 10003, ///< 请求中的接口名称错误,请核对接口名称并重试。
ERR_SVR_GROUP_INVALID_PARAMETERS = 10004, ///< 参数非法,请根据错误描述检查请求是否正确。
ERR_SVR_GROUP_ACOUNT_COUNT_LIMIT = 10005, ///< 请求包体中携带的帐号数量过多。
ERR_SVR_GROUP_FREQ_LIMIT = 10006, ///< 操作频率限制,请尝试降低调用的频率。
ERR_SVR_GROUP_PERMISSION_DENY = 10007, ///< 操作权限不足,比如 Public 群组中普通成员尝试执行踢人操作,但只有 App 管理员才有权限。
ERR_SVR_GROUP_INVALID_REQ = 10008, ///< 请求非法,可能是请求中携带的签名信息验证不正确,请再次尝试或 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 联系技术客服。
ERR_SVR_GROUP_SUPER_NOT_ALLOW_QUIT = 10009, ///< 该群不允许群主主动退出。
ERR_SVR_GROUP_NOT_FOUND = 10010, ///< 群组不存在,或者曾经存在过,但是目前已经被解散。
ERR_SVR_GROUP_JSON_PARSE_FAILED = 10011, ///< 解析 JSON 包体失败,请检查包体的格式是否符合 JSON 格式。
ERR_SVR_GROUP_INVALID_ID = 10012, ///< 发起操作的 Identifier 非法,请检查发起操作的用户 Identifier 是否填写正确。
ERR_SVR_GROUP_ALLREADY_MEMBER = 10013, ///< 被邀请加入的用户已经是群成员。
ERR_SVR_GROUP_FULL_MEMBER_COUNT = 10014, ///< 群已满员,无法将请求中的用户加入群组,如果是批量加人,可以尝试减少加入用户的数量。
ERR_SVR_GROUP_INVALID_GROUPID = 10015, ///< 群组 ID 非法,请检查群组 ID 是否填写正确。
ERR_SVR_GROUP_REJECT_FROM_THIRDPARTY = 10016, ///< App 后台通过第三方回调拒绝本次操作。
ERR_SVR_GROUP_SHUTUP_DENY = 10017, ///< 因被禁言而不能发送消息,请检查发送者是否被设置禁言。
ERR_SVR_GROUP_RSP_SIZE_LIMIT = 10018, ///< 应答包长度超过最大包长1MB请求的内容过多请尝试减少单次请求的数据量。
ERR_SVR_GROUP_ACCOUNT_NOT_FOUND = 10019, ///< 请求的用户帐号不存在。
ERR_SVR_GROUP_GROUPID_IN_USED = 10021, ///< 群组 ID 已被使用,请选择其他的群组 ID。
ERR_SVR_GROUP_SEND_MSG_FREQ_LIMIT = 10023, ///< 发消息的频率超限,请延长两次发消息时间的间隔。
ERR_SVR_GROUP_REQ_ALLREADY_BEEN_PROCESSED = 10024, ///< 此邀请或者申请请求已经被处理。
ERR_SVR_GROUP_GROUPID_IN_USED_FOR_SUPER = 10025, ///< 群组 ID 已被使用,并且操作者为群主,可以直接使用。
ERR_SVR_GROUP_SDKAPPID_DENY = 10026, ///< 该 SDKAppID 请求的命令字已被禁用,请 [提交工单](https://console.cloud.tencent.com/workorder/category?level1_id=29&level2_id=40&source=0&data_title=%E4%BA%91%E9%80%9A%E4%BF%A1%20%20IM&step=1) 联系客服。
ERR_SVR_GROUP_REVOKE_MSG_NOT_FOUND = 10030, ///< 请求撤回的消息不存在。
ERR_SVR_GROUP_REVOKE_MSG_TIME_LIMIT = 10031, ///< 消息撤回超过了时间限制默认2分钟
ERR_SVR_GROUP_REVOKE_MSG_DENY = 10032, ///< 请求撤回的消息不支持撤回操作。
ERR_SVR_GROUP_NOT_ALLOW_REVOKE_MSG = 10033, ///< 群组类型不支持消息撤回操作。
ERR_SVR_GROUP_REMOVE_MSG_DENY = 10034, ///< 该消息类型不支持删除操作。
ERR_SVR_GROUP_NOT_ALLOW_REMOVE_MSG = 10035, ///< 音视频聊天室和在线成员广播大群不支持删除消息。
ERR_SVR_GROUP_AVCHATROOM_COUNT_LIMIT = 10036, ///< 音视频聊天室创建数量超过了限制,请参考 [价格说明](https://cloud.tencent.com/document/product/269/11673) 购买预付费套餐“IM音视频聊天室”。
ERR_SVR_GROUP_COUNT_LIMIT = 10037, ///< 单个用户可创建和加入的群组数量超过了限制,请参考 [价格说明](https://cloud.tencent.com/document/product/269/11673) 购买或升级预付费套餐“单人可创建与加入群组数”。
ERR_SVR_GROUP_MEMBER_COUNT_LIMIT = 10038, ///< 群成员数量超过限制,请参考 [价格说明](https://cloud.tencent.com/document/product/269/11673) 购买或升级预付费套餐“扩展群人数上限”。
ERR_SVR_GROUP_ATTRIBUTE_WRITE_CONFILCT = 10056, ///< 群属性写冲突请先拉取最新的群属性后再尝试写操作IMSDK 5.6 及其以上版本支持。
/////////////////////////////////////////////////////////////////////////////////
//
// IM SDK V3 版本的错误码
//
/////////////////////////////////////////////////////////////////////////////////
ERR_NO_SUCC_RESULT = 6003, ///< 批量操作无成功结果。
ERR_TO_USER_INVALID = 6011, ///< 无效接收方。
ERR_REQUEST_TIMEOUT = 6012, ///< 请求超时。
ERR_INIT_CORE_FAIL = 6018, ///< INIT CORE 模块失败。
ERR_EXPIRED_SESSION_NODE = 6020, ///< SessionNode 为 null 。
ERR_LOGGED_OUT_BEFORE_LOGIN_FINISHED = 6023, ///< 在登录完成前进行了登出(在登录时返回)。
ERR_TLSSDK_NOT_INITIALIZED = 6024, ///< TLS SDK 未初始化。
ERR_TLSSDK_USER_NOT_FOUND = 6025, ///< TLS SDK 没有找到相应的用户信息。
ERR_BIND_FAIL_UNKNOWN = 6100, ///< QALSDK 未知原因BIND失败。
ERR_BIND_FAIL_NO_SSOTICKET = 6101, ///< 缺少 SSO 票据。
ERR_BIND_FAIL_REPEATD_BIND = 6102, ///< 重复 BIND。
ERR_BIND_FAIL_TINYID_NULL = 6103, ///< TinyId 为空。
ERR_BIND_FAIL_GUID_NULL = 6104, ///< GUID 为空。
ERR_BIND_FAIL_UNPACK_REGPACK_FAILED = 6105, ///< 解注册包失败。
ERR_BIND_FAIL_REG_TIMEOUT = 6106, ///< 注册超时。
ERR_BIND_FAIL_ISBINDING = 6107, ///< 正在 BIND 操作中。
ERR_PACKET_FAIL_UNKNOWN = 6120, ///< 发包未知错误。
ERR_PACKET_FAIL_REQ_NO_NET = 6121, ///< 发送请求包时没有网络。
ERR_PACKET_FAIL_RESP_NO_NET = 6122, ///< 发送回复包时没有网络。
ERR_PACKET_FAIL_REQ_NO_AUTH = 6123, ///< 发送请求包时没有权限。
ERR_PACKET_FAIL_SSO_ERR = 6124, ///< SSO 错误。
ERR_PACKET_FAIL_REQ_TIMEOUT = 6125, ///< 请求超时。
ERR_PACKET_FAIL_RESP_TIMEOUT = 6126, ///< 回复超时。
ERR_PACKET_FAIL_REQ_ON_RESEND = 6127, ///< 重发失败。
ERR_PACKET_FAIL_RESP_NO_RESEND = 6128, ///< 重发时没有真正发送。
ERR_PACKET_FAIL_FLOW_SAVE_FILTERED = 6129, ///< 保存被过滤。
ERR_PACKET_FAIL_REQ_OVER_LOAD = 6130, ///< 发送过载。
ERR_PACKET_FAIL_LOGIC_ERR = 6131, ///< 数据逻辑错误。
ERR_FRIENDSHIP_PROXY_NOT_SYNCED = 6150, ///< proxy_manager 没有完成服务端数据同步。
ERR_FRIENDSHIP_PROXY_SYNCING = 6151, ///< proxy_manager 正在进行服务端数据同步。
ERR_FRIENDSHIP_PROXY_SYNCED_FAIL = 6152, ///< proxy_manager 同步失败。
ERR_FRIENDSHIP_PROXY_LOCAL_CHECK_ERR = 6153, ///< proxy_manager 请求参数,在本地检查不合法。
ERR_GROUP_INVALID_FIELD = 6160, ///< Group assistant 请求字段中包含非预设字段。
ERR_GROUP_STORAGE_DISABLED = 6161, ///< Group assistant 群资料本地存储没有开启。
ERR_LOADGRPINFO_FAILED = 6162, ///< 加载群资料失败。
ERR_REQ_NO_NET_ON_REQ = 6200, ///< 请求的时候没有网络。
ERR_REQ_NO_NET_ON_RSP = 6201, ///< 响应的时候没有网络。
ERR_SERIVCE_NOT_READY = 6205, ///< QALSDK 服务未就绪。
ERR_LOGIN_AUTH_FAILED = 6207, ///< 账号认证失败( TinyId 转换失败)。
ERR_NEVER_CONNECT_AFTER_LAUNCH = 6209, ///< 在应用启动后没有尝试联网。
ERR_REQ_FAILED = 6210, ///< QALSDK 执行失败。
ERR_REQ_INVALID_REQ = 6211, ///< 请求非法toMsgService 非法。
ERR_REQ_OVERLOADED = 6212, ///< 请求队列满。
ERR_REQ_KICK_OFF = 6213, ///< 已经被其他终端踢了。
ERR_REQ_SERVICE_SUSPEND = 6214, ///< 服务被暂停。
ERR_REQ_INVALID_SIGN = 6215, ///< SSO 签名错误。
ERR_REQ_INVALID_COOKIE = 6216, ///< SSO cookie 无效。
ERR_LOGIN_TLS_RSP_PARSE_FAILED = 6217, ///< 登录时 TLS SDK 回包校验,包体长度错误。
ERR_LOGIN_OPENMSG_TIMEOUT = 6218, ///< 登录时 OPENSTATSVC 向 OPENMSG 上报状态超时。
ERR_LOGIN_OPENMSG_RSP_PARSE_FAILED = 6219, ///< 登录时 OPENSTATSVC 向 OPENMSG 上报状态时解析回包失败。
ERR_LOGIN_TLS_DECRYPT_FAILED = 6220, ///< 登录时 TLS SDK 解密失败。
ERR_WIFI_NEED_AUTH = 6221, ///< WIFI 需要认证。
ERR_USER_CANCELED = 6222, ///< 用户已取消。
ERR_REVOKE_TIME_LIMIT_EXCEED = 6223, ///< 消息撤回超过了时间限制默认2分钟
ERR_LACK_UGC_EXT = 6224, ///< 缺少 UGC 扩展包。
ERR_AUTOLOGIN_NEED_USERSIG = 6226, ///< 自动登录,本地票据过期,需要 UserSig 手动登录。
ERR_QAL_NO_SHORT_CONN_AVAILABLE = 6300, ///< 没有可用的短连接 SSO 。
ERR_REQ_CONTENT_ATTACK = 80101, ///< 消息内容安全打击。
ERR_LOGIN_SIG_EXPIRE = 70101, ///< 登录返回,票据过期。
ERR_SDK_HAD_INITIALIZED = 90101, ///< IM SDK 已经初始化无需重复初始化。
ERR_OPENBDH_BASE = 115000, ///< OpenBDH 错误码基。
ERR_REQUEST_NO_NET_ONREQ = 6250, ///< 请求时没有网络,请等网络恢复后重试。
ERR_REQUEST_NO_NET_ONRSP = 6251, ///< 响应时没有网络,请等网络恢复后重试。
ERR_REQUEST_FAILED = 6252, ///< QALSDK 执行失败。
ERR_REQUEST_INVALID_REQ = 6253, ///< 请求非法toMsgService 非法。
ERR_REQUEST_OVERLOADED = 6254, ///< 请求队列満。
ERR_REQUEST_KICK_OFF = 6255, ///< 已经被其他终端踢了。
ERR_REQUEST_SERVICE_SUSPEND = 6256, ///< 服务被暂停。
ERR_REQUEST_INVALID_SIGN = 6257, ///< SSO 签名错误。
ERR_REQUEST_INVALID_COOKIE = 6258, ///< SSO cookie 无效。
};
#endif

View File

@@ -0,0 +1,110 @@
/////////////////////////////////////////////////////////////////////
//
// 腾讯云通信服务 IMSDK
//
// 模块名称V2TIMManager+APNS
//
// 消息推送接口,里面包含了消息的推送的开启逻辑
//
/////////////////////////////////////////////////////////////////////
#import "V2TIMManager.h"
@class V2TIMAPNSConfig;
@protocol V2TIMAPNSListener;
@interface V2TIMManager (APNS)
/////////////////////////////////////////////////////////////////////////////////
//
// 设置 APNS 推送
//
/////////////////////////////////////////////////////////////////////////////////
/**
* 1.1 设置 APNS 监听
*/
- (void)setAPNSListener:(id<V2TIMAPNSListener>)apnsListener;
/**
* 1.2 设置 APNS 推送
*
* config -> token苹果后台对客户端的唯一标识需要主动调用系统 API 获取,获取方法如下:
*
* <pre>
* //获取 token 代码示例
* if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
* [[UIApplication sharedApplication] registerUserNotificationSettings:
* [UIUserNotificationSettings settingsForTypes:
* (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
* [[UIApplication sharedApplication] registerForRemoteNotifications];
* }
* else{
* [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
* (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
* }
*
* //收到 token 代码示例
* -(void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
* //回调的 deviceToken 就是需要的 token 信息
* }
* </pre>
*
* config -> busiId推送证书 ID上传推送证书p.12)到 IM 控制台后生成。
* 具体步骤请参考 [离线推送](https://cloud.tencent.com/document/product/269/9154)。
*
* @note
* - 接口成功设置后会开启离线推送功能,如果您需要自定义推送的格式信息,请参考 V2TIMManager+Message.h 里面的 sendMessage 接口。
* - 如果成功开启了离线推送APP 进后台后如果收到消息会弹系统推送通知APP 进前台后,如果收到消息,则不会弹系统推送通知。
* - APP 进后台后应用图标展示的未读数默认为所有会话未读数之和,如果您需要自定义 APP 的未读数,请监听 V2TIMAPNSListener 回调设置。
* - 如果您想关闭离线推送,请把 config 设置为 nil。
*/
- (void)setAPNS:(V2TIMAPNSConfig*)config succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// APNS 监听器
//
/////////////////////////////////////////////////////////////////////////////////
@protocol V2TIMAPNSListener <NSObject>
@optional
/** 程序进后台后,自定义 APP 的未读数如果不处理APP 未读数默认为所有会话未读数之和
* <pre>
*
* - (uint32_t)onSetAPPUnreadCount {
* return 100; // 自定义未读数
* }
*
* </pre>
*/
- (uint32_t)onSetAPPUnreadCount;
@end
/////////////////////////////////////////////////////////////////////////////////
// APNS 配置
/////////////////////////////////////////////////////////////////////////////////
@interface V2TIMAPNSConfig : NSObject
/**
* APNS token 或者 TPNS token
* @note token 使用注意事项
* - 当接入推送 TPNS 通道时,需要设置 isTPNSToken 为 YES上报注册 TPNS 获取的 token
* - 当接入推送 APNS 通道时,需要设置 isTPNSToken 为 NO上报注册 APNS 获取的 token。
*/
@property(nonatomic,strong) NSData *token;
/**
* IM 控制台证书 ID接入 TPNS 时不需要填写
*/
@property(nonatomic,assign) int businessID;
/**
* 是否接入配置 TPNS, token 是否是从 TPNS 获取
*/
@property(nonatomic,assign) BOOL isTPNSToken;
@end

View File

@@ -0,0 +1,246 @@
/////////////////////////////////////////////////////////////////////
//
// 腾讯云通信服务 IMSDK
//
// 模块名称V2TIMManager+Conversation
//
// 会话接口,里面包含了会话的获取,删除,更新的逻辑
//
/////////////////////////////////////////////////////////////////////
#import "V2TIMManager.h"
#import "V2TIMManager+Group.h"
#import "V2TIMManager+Message.h"
@protocol V2TIMConversationListener;
@class V2TIMConversation;
@class V2TIMGroupAtInfo;
/////////////////////////////////////////////////////////////////////////////////
//
// 消息会话相关接口
//
/////////////////////////////////////////////////////////////////////////////////
@interface V2TIMManager (Conversation)
/// 获取会话列表成功的回调nextSeq下一次分页拉取的游标 isFinished会话列表是否已经拉取完毕
typedef void(^V2TIMConversationResultSucc)(NSArray<V2TIMConversation *>*list, uint64_t nextSeq, BOOL isFinished);
/// 获取单个会话成功回调
typedef void(^V2TIMConversationSucc)(V2TIMConversation *conv);
/// 搜索会话列表成功回调
typedef void(^V2TIMConversationListSucc)(NSArray<V2TIMConversation *>*list);
/// 获取会话总未读数回调
typedef void(^V2TIMTotalUnreadMessageCountSucc)(UInt64 totalCount);
/// 会话类型
typedef NS_ENUM(NSInteger, V2TIMConversationType) {
V2TIM_C2C = 1, ///< 单聊
V2TIM_GROUP = 2, ///< 群聊
};
/// @ 类型
typedef NS_ENUM(NSInteger, V2TIMGroupAtType) {
V2TIM_AT_ME = 1, ///< @ 我
V2TIM_AT_ALL = 2, ///< @ 群里所有人
V2TIM_AT_ALL_AT_ME = 3, ///< @ 群里所有人并且单独 @ 我
};
/**
* 1.1 添加会话监听器
*/
- (void)addConversationListener:(id<V2TIMConversationListener>)listener NS_SWIFT_NAME(addConversationListener(listener:));
/**
* 1.2 移除会话监听器
*/
- (void)removeConversationListener:(id<V2TIMConversationListener>)listener NS_SWIFT_NAME(removeConversationListener(listener:));
/**
* 1.3 获取会话列表
*
* - 一个会话对应一个聊天窗口,比如跟一个好友的 1v1 聊天,或者一个聊天群,都是一个会话。
* - 由于历史的会话数量可能很多,所以该接口希望您采用分页查询的方式进行调用,每次分页拉取的个数建议为 100 个。
* - 该接口拉取的是本地缓存的会话如果服务器会话有更新SDK 内部会自动同步,然后在 @ref V2TIMConversationListener 回调告知客户。
* - 如果会话全部拉取完毕,成功回调里面 V2TIMConversationResult 中的 isFinished 获取字段值为 YES。
*
* @note 会话排序规则
* - 5.5.892 及以后版本, 该接口获取的会话列表默认已经按照会话 orderKey 做了排序orderKey 值越大,代表该会话排序越靠前。
* - 5.5.892 以前版本,该接口获取的会话列表默认已经按照会话 lastMessage -> timestamp 做了排序timestamp 越大,会话越靠前。
*
* @param nextSeq 分页拉取的游标,第一次默认取传 0后续分页拉传上一次分页拉取成功回调里的 nextSeq
* @param count 分页拉取的个数,一次分页拉取不宜太多,会影响拉取的速度,建议每次拉取 100 个会话
*/
- (void)getConversationList:(uint64_t)nextSeq count:(int)count succ:(V2TIMConversationResultSucc)succ fail:(V2TIMFail)fail;
/**
* 1.4 获取单个会话
*
* @param conversationID 会话唯一 ID, C2C 单聊组成方式:[NSString stringWithFormat:@"c2c_%@",userID];群聊组成方式为 [NSString stringWithFormat:@"group_%@",groupID]
*/
- (void)getConversation:(NSString *)conversationID succ:(V2TIMConversationSucc)succ fail:(V2TIMFail)fail;
/**
* 1.5 获取指定会话列表
*
* @param conversationIDList 会话唯一 ID 列表C2C 单聊组成方式:[NSString stringWithFormat:@"c2c_%@",userID];群聊组成方式为 [NSString stringWithFormat:@"group_%@",groupID]
*/
- (void)getConversationList:(NSArray<NSString *> *)conversationIDList succ:(V2TIMConversationListSucc)succ fail:(V2TIMFail)fail;
/**
* 1.6 删除会话以及该会话中的历史消息
*
* @param conversationID 会话唯一 IDC2C 单聊组成方式:[NSString stringWithFormat:@"c2c_%@",userID];群聊组成方式为 [NSString stringWithFormat:@"group_%@",groupID]
*
* @note 请注意:
* - 该会话以及会话中的历史消息,会被 SDK 从本地和服务端一同删除掉,并且不可恢复。
*/
- (void)deleteConversation:(NSString *)conversationID succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 1.7 设置会话草稿
*
* @param conversationID 会话唯一 IDC2C 单聊组成方式:[NSString stringWithFormat:@"c2c_%@",userID];群聊组成方式为 [NSString stringWithFormat:@"group_%@",groupID]
*
* 只在本地保存,不会存储 Server不能多端同步程序卸载重装会失效。
*/
- (void)setConversationDraft:(NSString *)conversationID draftText:(NSString *)draftText succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 1.8 设置会话置顶5.3.425 及以上版本支持)
*
* @param conversationID 会话唯一 IDC2C 单聊组成方式:[NSString stringWithFormat:@"c2c_%@",userID];群聊组成方式为 [NSString stringWithFormat:@"group_%@",groupID]
* @param isPinned 是否置顶
*/
- (void)pinConversation:(NSString *)conversationID isPinned:(BOOL)isPinned succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 1.9 获取所有会话的未读消息总数5.3.425 及以上版本支持)
* @note
* - 未读总数会减去设置为免打扰的会话的未读数,即消息接收选项设置为 V2TIMMessage.V2TIM_NOT_RECEIVE_MESSAGE 或 V2TIMMessage.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE 的会话。
*/
- (void)getTotalUnreadMessageCount:(V2TIMTotalUnreadMessageCountSucc)succ fail:(V2TIMFail)fail;
/**
* 设置会话监听器(待废弃接口,请使用 addConversationListener 和 removeConversationListener 接口)
*/
- (void)setConversationListener:(id<V2TIMConversationListener>)listener __attribute__((deprecated("use addConversationListener: instead")));
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 会话变更监听器
//
/////////////////////////////////////////////////////////////////////////////////
@protocol V2TIMConversationListener <NSObject>
@optional
/**
* 同步服务器会话开始SDK 会在登录成功或者断网重连后自动同步服务器会话,您可以监听这个事件做一些 UI 进度展示操作。
*/
- (void)onSyncServerStart;
/**
* 同步服务器会话完成,如果会话有变更,会通过 onNewConversation | onConversationChanged 回调告知客户
*/
- (void)onSyncServerFinish;
/**
* 同步服务器会话失败
*/
- (void)onSyncServerFailed;
/**
* 有新的会话(比如收到一个新同事发来的单聊消息、或者被拉入了一个新的群组中),可以根据会话的 lastMessage -> timestamp 重新对会话列表做排序。
*/
- (void)onNewConversation:(NSArray<V2TIMConversation*> *) conversationList;
/**
* 某些会话的关键信息发生变化(未读计数发生变化、最后一条消息被更新等等),可以根据会话的 lastMessage -> timestamp 重新对会话列表做排序。
*/
- (void)onConversationChanged:(NSArray<V2TIMConversation*> *) conversationList;
/**
* 会话未读总数变更通知5.3.425 及以上版本支持)
* @note
* - 未读总数会减去设置为免打扰的会话的未读数,即消息接收选项设置为 V2TIMMessage.V2TIM_NOT_RECEIVE_MESSAGE 或 V2TIMMessage.V2TIM_RECEIVE_NOT_NOTIFY_MESSAGE 的会话。
*/
- (void)onTotalUnreadMessageCountChanged:(UInt64) totalUnreadCount;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 会话对象 V2TIMConversation
//
/////////////////////////////////////////////////////////////////////////////////
/// 会话对象
@interface V2TIMConversation : NSObject
/// 会话类型
@property(nonatomic,assign,readonly) V2TIMConversationType type;
/// 会话唯一 ID如果是 C2C 单聊,组成方式为 c2c_userID如果是群聊组成方式为 group_groupID
@property(nonatomic,strong,readonly) NSString *conversationID;
/// 如果会话类型为 C2C 单聊userID 会存储对方的用户ID否则为 nil
@property(nonatomic,strong,readonly) NSString *userID;
/// 如果会话类型为群聊groupID 会存储当前群的群 ID否则为 nil
@property(nonatomic,strong,readonly) NSString *groupID;
/// 如果会话类型为群聊groupType 为当前群类型,否则为 nil
@property(nonatomic,strong,readonly) NSString *groupType;
/// 会话展示名称(群组:群名称 >> 群 IDC2C对方好友备注 >> 对方昵称 >> 对方的 userID
@property(nonatomic,strong,readonly) NSString *showName;
/// 会话展示头像群组群头像C2C对方头像
@property(nonatomic,strong,readonly) NSString *faceUrl;
/// 会话未读消息数量,直播群AVChatRoom不支持未读计数默认为 0
@property(nonatomic,assign,readonly) int unreadCount;
/// 消息接收选项(接收 | 接收但不提醒 | 不接收)
@property(nonatomic,assign,readonly) V2TIMReceiveMessageOpt recvOpt;
/**
* 会话最后一条消息
* @note 5.5.892 以前版本,请您使用 lastMessage -> timestamp 对会话做排序timestamp 越大,会话越靠前
*/
@property(nonatomic,strong,readonly) V2TIMMessage *lastMessage;
/// 群会话 @ 信息列表,用于展示 “有人@我” 或 “@所有人” 这两种提醒状态
@property(nonatomic,strong,readonly) NSArray<V2TIMGroupAtInfo *> *groupAtInfolist;
/// 草稿信息,设置草稿信息请调用 setConversationDraft() 接口
@property(nonatomic,strong,readonly) NSString *draftText;
/// 草稿编辑时间,草稿设置的时候自动生成
@property(nonatomic,strong,readonly) NSDate *draftTimestamp;
/// 是否置顶
@property(nonatomic,assign,readonly) BOOL isPinned;
/**
* 排序字段5.5.892 及以后版本支持)
* @note
* - 排序字段 orderKey 是按照会话的激活时间线性递增的一个数字(注意:不是时间戳,因为同一时刻可能会有多个会话被同时激活)
* - 5.5.892 及其以后版本推荐您使用该字段对所有会话进行排序orderKey 值越大,代表该会话排序越靠前
* - 当您 “清空会话所有消息” 或者 “逐个删除会话的所有消息” 之后,会话的 lastMessage 变为空,但会话的 orderKey 不会改变;如果想保持会话的排序位置不变,可以使用该字段对所有会话进行排序
*/
@property(nonatomic,assign,readonly) NSUInteger orderKey;
@end
/// @ 信息
@interface V2TIMGroupAtInfo : NSObject
/// @ 消息序列号,即带有 “@我” 或者 “@所有人” 标记的消息的序列号
@property(nonatomic,assign,readonly) uint64_t seq;
/// @ 提醒类型,分成 “@我” 、“@所有人” 以及 “@我并@所有人” 三类
@property(nonatomic,assign,readonly) V2TIMGroupAtType atType;
@end

View File

@@ -0,0 +1,518 @@
/////////////////////////////////////////////////////////////////////
//
// 腾讯云通信服务 IMSDK
//
// 模块名称V2TIMManager+Friendship
//
// 关系链接口,里面包含了好友的添加、删除,黑名单的添加、删除等逻辑
//
/////////////////////////////////////////////////////////////////////
#import "V2TIMManager.h"
@protocol V2TIMFriendshipListener;
@class V2TIMFriendOperationResult;
@class V2TIMFriendInfoResult;
@class V2TIMFriendInfo;
@class V2TIMFriendCheckResult;
@class V2TIMFriendApplicationResult;
@class V2TIMFriendAddApplication;
@class V2TIMFriendApplication;
@class V2TIMFriendGroup;
@class V2TIMFriendSearchParam;
@interface V2TIMManager (Friendship)
/// 获取好友列表成功回调
typedef void (^V2TIMFriendInfoListSucc)(NSArray<V2TIMFriendInfo *> *infoList);
/// 获取指定好友信息成功回调
typedef void (^V2TIMFriendInfoResultListSucc)(NSArray<V2TIMFriendInfoResult *> *resultList);
/// 好友操作成功回调
typedef void (^V2TIMFriendOperationResultSucc)(V2TIMFriendOperationResult *result);
/// 好友列表操作成功回调
typedef void (^V2TIMFriendOperationResultListSucc)(NSArray<V2TIMFriendOperationResult *> *resultList);
/// 好友检查成功回调
typedef void (^V2TIMFriendCheckResultListSucc)(NSArray<V2TIMFriendCheckResult *> *resultList);
/// 获取群分组列表成功回调
typedef void (^V2TIMFriendGroupListSucc)(NSArray<V2TIMFriendGroup *> * groups);
/// 获取好友申请列表成功回调
typedef void (^V2TIMFriendApplicationResultSucc)(V2TIMFriendApplicationResult *result);
/// 好友申请类型
typedef NS_ENUM(NSInteger, V2TIMFriendApplicationType) {
V2TIM_FRIEND_APPLICATION_COME_IN = 1, ///< 别人发给我的
V2TIM_FRIEND_APPLICATION_SEND_OUT = 2, ///< 我发给别人的
V2TIM_FRIEND_APPLICATION_BOTH = 3, ///< 别人发给我的 和 我发给别人的。仅拉取时有效
};
/// 好友类型
typedef NS_ENUM(NSInteger, V2TIMFriendType) {
V2TIM_FRIEND_TYPE_SINGLE = 1, ///< 单向好友
V2TIM_FRIEND_TYPE_BOTH = 2, ///< 双向好友
};
/// 好友关系类型
typedef NS_ENUM(NSInteger, V2TIMFriendRelationType) {
V2TIM_FRIEND_RELATION_TYPE_NONE = 0x0, ///< 不是好友
V2TIM_FRIEND_RELATION_TYPE_IN_MY_FRIEND_LIST = 0x1, ///< 对方在我的好友列表中
V2TIM_FRIEND_RELATION_TYPE_IN_OTHER_FRIEND_LIST = 0x2, ///< 我在对方的好友列表中
V2TIM_FRIEND_RELATION_TYPE_BOTH_WAY = 0x3, ///< 互为好友
};
/// 好友申请接受类型
typedef NS_ENUM(NSInteger, V2TIMFriendAcceptType) {
V2TIM_FRIEND_ACCEPT_AGREE = 0, ///< 接受加好友(建立单向好友)
V2TIM_FRIEND_ACCEPT_AGREE_AND_ADD = 1, ///< 接受加好友并加对方为好友(建立双向好友)
};
/////////////////////////////////////////////////////////////////////////////////
//
// 关系链和用户资料监听器
//
/////////////////////////////////////////////////////////////////////////////////
/**
* 1.1 添加关系链监听器
*/
- (void)addFriendListener:(id<V2TIMFriendshipListener>)listener NS_SWIFT_NAME(addFriendListener(listener:));
/**
* 1.2 移除关系链监听器
*/
- (void)removeFriendListener:(id<V2TIMFriendshipListener>)listener NS_SWIFT_NAME(removeFriendListener(listener:));
/**
* 设置关系链监听器(待废弃接口,请使用 addFriendListener 和 removeFriendListener 接口)
*/
- (void)setFriendListener:(id<V2TIMFriendshipListener>)listener __attribute__((deprecated("use addFriendListener: instead")));
/////////////////////////////////////////////////////////////////////////////////
//
// 好友添加、删除、列表获取、资料设置相关接口
//
/////////////////////////////////////////////////////////////////////////////////
/**
* 2.1 获取好友列表
*/
- (void)getFriendList:(V2TIMFriendInfoListSucc)succ fail:(V2TIMFail)fail;
/**
* 2.2 获取指定好友资料
* @param userIDList 好友 userID 列表
* - ID 建议一次最大 100 个,因为数量过多可能会导致数据包太大被后台拒绝,后台限制数据包最大为 1M。
*/
- (void)getFriendsInfo:(NSArray<NSString *> *)userIDList succ:(V2TIMFriendInfoResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 2.3 设置指定好友资料
*/
- (void)setFriendInfo:(V2TIMFriendInfo *)info succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 2.4 搜索好友5.4.666 及以上版本支持,需要您购买旗舰版套餐)
* @note 接口返回本地存储的用户资料,可以根据 V2TIMFriendInfoResult 中的 getRelation 来判断是否为好友。
*/
- (void)searchFriends:(V2TIMFriendSearchParam *)searchParam succ:(V2TIMFriendInfoResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 2.5 添加好友
*/
- (void)addFriend:(V2TIMFriendAddApplication *)application succ:(V2TIMFriendOperationResultSucc)succ fail:(V2TIMFail)fail;
/**
* 2.6 删除好友
* @param userIDList 要删除的好友 userID 列表
* - ID 建议一次最大 100 个,因为数量过多可能会导致数据包太大被后台拒绝,后台限制数据包最大为 1M。
* @param deleteType 删除类型(单向好友、双向好友)
*/
- (void)deleteFromFriendList:(NSArray *)userIDList deleteType:(V2TIMFriendType)deleteType succ:(V2TIMFriendOperationResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 2.7 检查指定用户的好友关系
* @param userIDList 要检查的 userID 列表
* @param checkType 检查类型 (单向好友检查、双向好友检查)
* @param succ 成功后的回调
* @param fail 失败后的回调
*
* @note checkType 的使用需要注意:
* - checkType 如果传入 V2TIM_FRIEND_TYPE_SINGLE结果返回V2TIM_FRIEND_RELATION_TYPE_NONE、V2TIM_FRIEND_RELATION_TYPE_IN_MY_FRIEND_LIST 两种情况
* - checkType 如果传入 V2TIM_FRIEND_TYPE_BOTH结果返回V2TIM_FRIEND_RELATION_TYPE_NONE、V2TIM_FRIEND_RELATION_TYPE_IN_MY_FRIEND_LIST、
* V2TIM_FRIEND_RELATION_TYPE_IN_OTHER_FRIEND_LIST、V2TIM_FRIEND_RELATION_TYPE_BOTH_WAY 四种情况
*/
- (void)checkFriend:(NSArray<NSString *> *)userIDList checkType:(V2TIMFriendType)checkType succ:(V2TIMFriendCheckResultListSucc)succ fail:(V2TIMFail)fail;
/////////////////////////////////////////////////////////////////////////////////
//
// 好友申请、删除相关逻辑
//
/////////////////////////////////////////////////////////////////////////////////
/**
* 3.1 获取好友申请列表
*
* @note 好友申请列表包括发起的好友申请和收到的好友申请。
*/
- (void)getFriendApplicationList:(V2TIMFriendApplicationResultSucc)succ fail:(V2TIMFail)fail;
/**
* 3.2 同意好友申请
*
* @param application 好友申请信息getFriendApplicationList 成功后会返回
* @param acceptType 建立单向/双向好友关系
*/
- (void)acceptFriendApplication:(V2TIMFriendApplication *)application type:(V2TIMFriendAcceptType)acceptType succ:(V2TIMFriendOperationResultSucc)succ fail:(V2TIMFail)fail;
/**
* 3.3 拒绝好友申请
*
* @param application 好友申请信息getFriendApplicationList 成功后会返回
*/
- (void)refuseFriendApplication:(V2TIMFriendApplication *)application succ:(V2TIMFriendOperationResultSucc)succ fail:(V2TIMFail)fail;
/**
* 3.4 删除好友申请
*
* @param application 好友申请信息getFriendApplicationList 成功后会返回
*/
- (void)deleteFriendApplication:(V2TIMFriendApplication *)application succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 3.5 设置好友申请已读
*/
- (void)setFriendApplicationRead:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/////////////////////////////////////////////////////////////////////////////////
//
// 黑名单
//
/////////////////////////////////////////////////////////////////////////////////
/**
* 4.1 添加用户到黑名单
*/
- (void)addToBlackList:(NSArray *)userIDList succ:(V2TIMFriendOperationResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 4.2 把用户从黑名单中删除
*/
- (void)deleteFromBlackList:(NSArray *)userIDList succ:(V2TIMFriendOperationResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 4.3 获取黑名单列表
*/
- (void)getBlackList:(V2TIMFriendInfoListSucc)succ fail:(V2TIMFail)fail;
/////////////////////////////////////////////////////////////////////////////////
//
// 好友分组
//
/////////////////////////////////////////////////////////////////////////////////
/**
* 5.1 新建好友分组
*
* @param groupName 分组名称
* @param userIDList 要添加到分组中的好友
*/
- (void)createFriendGroup:(NSString *)groupName userIDList:(NSArray *)userIDList succ:(V2TIMFriendOperationResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 5.2 获取分组信息
*
* @param groupNameList 要获取信息的好友分组名称列表,传入 nil 获得所有分组信息
*/
- (void)getFriendGroupList:(NSArray *)groupNameList succ:(V2TIMFriendGroupListSucc)succ fail:(V2TIMFail)fail;
/**
* 5.3 删除好友分组
*/
- (void)deleteFriendGroup:(NSArray *)groupNameList succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 5.4 修改好友分组的名称
*/
- (void)renameFriendGroup:(NSString*)oldName newName:(NSString*)newName succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 5.5 添加好友到一个好友分组
*/
- (void)addFriendsToFriendGroup:(NSString *)groupName userIDList:(NSArray *)userIDList succ:(V2TIMFriendOperationResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 5.6 从好友分组中删除好友
*/
- (void)deleteFriendsFromFriendGroup:(NSString *)groupName userIDList:(NSArray *)userIDList succ:(V2TIMFriendOperationResultListSucc)succ fail:(V2TIMFail)fail;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 资料关系链回调
//
/////////////////////////////////////////////////////////////////////////////////
/// 资料关系链回调
@protocol V2TIMFriendshipListener <NSObject>
@optional
/**
* 好友申请新增通知,两种情况会收到这个回调:
* 1. 自己申请加别人好友
* 2. 别人申请加自己好友
*/
- (void)onFriendApplicationListAdded:(NSArray<V2TIMFriendApplication *> *)applicationList;
/**
* 好友申请删除通知,四种情况会收到这个回调:
* 1. 调用 deleteFriendApplication 主动删除好友申请
* 2. 调用 refuseFriendApplication 拒绝好友申请
* 3. 调用 acceptFriendApplication 同意好友申请
* 4. 申请加别人好友被拒绝
*/
- (void)onFriendApplicationListDeleted:(NSArray *)userIDList;
/**
* 好友申请已读通知,如果调用 setFriendApplicationRead 设置好友申请列表已读,会收到这个回调(主要用于多端同步)
*/
- (void)onFriendApplicationListRead;
/**
* 好友新增通知
*/
- (void)onFriendListAdded:(NSArray<V2TIMFriendInfo *>*)infoList;
/**
* 好友删除通知,两种情况会收到这个回调:
* 1. 自己删除好友(单向和双向删除都会收到回调)
* 2. 好友把自己删除(双向删除会收到)
*/
- (void)onFriendListDeleted:(NSArray*)userIDList;
/**
* 黑名单新增通知
*/
- (void)onBlackListAdded:(NSArray<V2TIMFriendInfo *>*)infoList;
/**
* 黑名单删除通知
*/
- (void)onBlackListDeleted:(NSArray*)userIDList;
/**
* 好友资料变更通知
*/
- (void)onFriendProfileChanged:(NSArray<V2TIMFriendInfo *> *)infoList;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 好友资料获取结果
//
/////////////////////////////////////////////////////////////////////////////////
/// 好友资料获取结果
@interface V2TIMFriendInfoResult : NSObject
/// 返回码
@property(nonatomic,assign) int resultCode;
/// 返结果表述
@property(nonatomic,strong) NSString *resultInfo;
/// 好友类型
@property(nonatomic,assign) V2TIMFriendRelationType relation;
/// 好友个人资料,如果不是好友,除了 userID 字段,其他字段都为空
@property(nonatomic,strong) V2TIMFriendInfo *friendInfo;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 好友资料
//
/////////////////////////////////////////////////////////////////////////////////
/// 好友资料
@interface V2TIMFriendInfo : NSObject
/// 好友 ID
@property(nonatomic,strong) NSString *userID;
/**
* 好友备注
*
* @note
* - 备注长度最长不得超过 96 个字节;
* - 字段描述详见 [控制台](https://cloud.tencent.com/document/product/269/1501#.E6.A0.87.E9.85.8D.E5.A5.BD.E5.8F.8B.E5.AD.97.E6.AE.B5)。
*/
@property(nonatomic,strong) NSString *friendRemark;
/// 好友自定义字段
/// 首先要在 [控制台](https://console.cloud.tencent.com/im) (功能配置 -> 好友自定义字段) 配置好友自定义字段然后再调用该接口进行设置key 值不需要加 Tag_SNS_Custom_ 前缀。
@property(nonatomic,strong) NSDictionary<NSString *,NSData *> *friendCustomInfo;
/**
* 好友所在分组列表
*
* @note
* - 最多支持 32 个分组;
* - 不允许分组名为空;
* - 分组名长度不得超过 30 个字节;
* - 同一个好友可以有多个不同的分组。
* - 字段描述详见 [控制台](https://cloud.tencent.com/document/product/269/1501#.E6.A0.87.E9.85.8D.E5.A5.BD.E5.8F.8B.E5.AD.97.E6.AE.B5)。
*/
@property(nonatomic,strong,readonly) NSArray *friendGroups;
/// 好友个人资料
@property(nonatomic,strong,readonly) V2TIMUserFullInfo *userFullInfo;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 好友申请相关对象
//
/////////////////////////////////////////////////////////////////////////////////
/// 加好友
@interface V2TIMFriendAddApplication : NSObject
/// 用户 userID必填
@property (nonatomic,strong) NSString* userID;
/// 备注备注最大96字节
@property (nonatomic,strong) NSString* friendRemark;
/// 预分组名最大96字节
@property (nonatomic,strong) NSString* friendGroup;
/// 请求说明最大120字节
@property (nonatomic,strong) NSString* addWording;
/// 添加来源
@property (nonatomic,strong) NSString* addSource;
/// 加好友方式
@property (nonatomic,assign) V2TIMFriendType addType;
@end
/// 好友申请列表
@interface V2TIMFriendApplicationResult : NSObject
/// 好友申请未读数量
@property(nonatomic,assign) uint64_t unreadCount;
/// 好友申请列表
@property(nonatomic,strong) NSMutableArray<V2TIMFriendApplication *> * applicationList;
@end
/// 好友申请
@interface V2TIMFriendApplication : NSObject
/// 用户标识
@property(nonatomic,strong,readonly) NSString* userID;
/// 用户昵称
@property(nonatomic,strong,readonly) NSString* nickName;
/// 用户头像
@property(nonatomic,strong,readonly) NSString* faceUrl;
/// 添加时间
@property(nonatomic,assign,readonly) uint64_t addTime;
/// 来源
@property(nonatomic,strong,readonly) NSString* addSource;
/// 加好友附言
@property(nonatomic,strong,readonly) NSString* addWording;
/// 好友申请类型
@property(nonatomic,assign,readonly) V2TIMFriendApplicationType type;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 好友关系链检查结果
//
/////////////////////////////////////////////////////////////////////////////////
/// 好友关系链检查结果
@interface V2TIMFriendCheckResult : NSObject
/// 用户id
@property(nonatomic,strong) NSString* userID;
/// 返回码
@property(nonatomic,assign) NSInteger resultCode;
/// 返回信息
@property(nonatomic,strong) NSString *resultInfo;
/// 检查结果
@property(nonatomic,assign) V2TIMFriendRelationType relationType;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 好友操作结果(添加、删除、加黑名单、添加分组等)
//
/////////////////////////////////////////////////////////////////////////////////
/// 好友操作结果(添加、删除、加黑名单、添加分组等)
@interface V2TIMFriendOperationResult : NSObject
/// 用户Id
@property(nonatomic,strong) NSString* userID;
/// 返回码
@property(nonatomic,assign) NSInteger resultCode;
/// 返回信息
@property(nonatomic,strong) NSString *resultInfo;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 好友分组
//
/////////////////////////////////////////////////////////////////////////////////
/// 好友分组
@interface V2TIMFriendGroup : NSObject
/// 好友分组名称
@property(nonatomic,strong) NSString* groupName;
/// 分组成员数量
@property(nonatomic,assign) uint64_t userCount;
/// 分组成员列表
@property(nonatomic,strong) NSMutableArray* friendList;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 好友搜索
//
/////////////////////////////////////////////////////////////////////////////////
@interface V2TIMFriendSearchParam : NSObject
/// 搜索的关键字列表,关键字列表最多支持 5 个
@property(nonatomic, strong) NSArray<NSString *> *keywordList;
/// 设置是否搜索 userID
@property(nonatomic, assign) BOOL isSearchUserID;
/// 是否设置搜索昵称
@property(nonatomic, assign) BOOL isSearchNickName;
/// 是否设置搜索备注
@property(nonatomic, assign) BOOL isSearchRemark;;
@end

View File

@@ -0,0 +1,537 @@
/////////////////////////////////////////////////////////////////////
//
// 腾讯云通信服务 IMSDK
//
// 模块名称V2TIMManager+Group
//
// 群组高级接口,里面包含了群组的高级功能,比如群成员邀请、非群成员申请进群等操作接口。
//
/////////////////////////////////////////////////////////////////////
#import "V2TIMManager.h"
#import "V2TIMManager+Message.h"
@class V2TIMGroupMemberOperationResult;
@class V2TIMGroupApplicationResult;
@class V2TIMCreateGroupMemberInfo;
@class V2TIMGroupInfo;
@class V2TIMGroupInfoResult;
@class V2TIMGroupApplication;
@class V2TIMGroupSearchParam;
@class V2TIMGroupMemberSearchParam;
/////////////////////////////////////////////////////////////////////////////////
//
// 群相关的高级接口
//
/////////////////////////////////////////////////////////////////////////////////
@interface V2TIMManager (Group)
/// 获取已加入群列表成功回调
typedef void (^V2TIMGroupInfoListSucc)(NSArray<V2TIMGroupInfo *> *groupList);
/// 获取指定群列表成功回调
typedef void (^V2TIMGroupInfoResultListSucc)(NSArray<V2TIMGroupInfoResult *> *groupResultList);
/// 获取群属性列表成功回调
typedef void (^V2TIMGroupAttributeListSucc)(NSMutableDictionary<NSString *,NSString *> *groupAttributeList);
/// 获取群成员列表成功回调
typedef void (^V2TIMGroupMemberInfoListSucc)(NSArray<V2TIMGroupMemberFullInfo *> *memberList);
/// 获取指定群成员列表成功回调
typedef void (^V2TIMGroupMemberInfoResultSucc)(uint64_t nextSeq, NSArray<V2TIMGroupMemberFullInfo *> * memberList);
/// 搜索群成员列表成功回调
typedef void (^V2TIMGroupMemberInfoListSearchSucc)(NSDictionary<NSString *, NSArray<V2TIMGroupMemberFullInfo *> *> *memberList);
/// 群成员操作成功回调
typedef void (^V2TIMGroupMemberOperationResultListSucc)(NSArray<V2TIMGroupMemberOperationResult*> * resultList);
/// 获取好友申请列表成功回调
typedef void (^V2TIMGroupApplicationResultSucc)(V2TIMGroupApplicationResult *result);
/// 获取群在线人数成功回调
typedef void (^V2TIMGroupOnlineMemberCountSucc)(NSInteger count);
/// 加群选项
typedef NS_ENUM(NSInteger, V2TIMGroupAddOpt) {
V2TIM_GROUP_ADD_FORBID = 0, ///< 禁止加群
V2TIM_GROUP_ADD_AUTH = 1, ///< 需要管理员审批
V2TIM_GROUP_ADD_ANY = 2, ///< 任何人可以加入
};
/// 群组操作结果
typedef NS_ENUM(NSInteger, V2TIMGroupMemberResult) {
V2TIM_GROUP_MEMBER_RESULT_FAIL = 0, ///< 操作失败
V2TIM_GROUP_MEMBER_RESULT_SUCC = 1, ///< 操作成功
V2TIM_GROUP_MEMBER_RESULT_INVALID = 2, ///< 无效操作,加群时已经是群成员,移除群组时不在群内
V2TIM_GROUP_MEMBER_RESULT_PENDING = 3, ///< 等待处理,邀请入群时等待对方处理
V2TIM_GROUP_MEMBER_RESULT_OVERLIMIT = 4, ///< 操作失败,创建群指定初始群成员列表或邀请入群时,被邀请者加入的群总数超限
};
/// 群成员角色过滤方式
typedef NS_ENUM(NSInteger, V2TIMGroupMemberFilter) {
V2TIM_GROUP_MEMBER_FILTER_ALL = 0x00, ///< 全部成员
V2TIM_GROUP_MEMBER_FILTER_OWNER = 0x01, ///< 群主
V2TIM_GROUP_MEMBER_FILTER_ADMIN = 0x02, ///< 管理员
V2TIM_GROUP_MEMBER_FILTER_COMMON = 0x04, ///< 普通成员
};
/// 群组未决请求类型
typedef NS_ENUM(NSInteger, V2TIMGroupApplicationGetType) {
V2TIM_GROUP_APPLICATION_GET_TYPE_JOIN = 0x0, ///< 申请入群
V2TIM_GROUP_APPLICATION_GET_TYPE_INVITE = 0x1, ///< 邀请入群
};
/// 群组已决标志
typedef NS_ENUM(NSInteger, V2TIMGroupApplicationHandleStatus) {
V2TIM_GROUP_APPLICATION_HANDLE_STATUS_UNHANDLED = 0, ///< 未处理
V2TIM_GROUP_APPLICATION_HANDLE_STATUS_HANDLED_BY_OTHER = 1, ///< 被他人处理
V2TIM_GROUP_APPLICATION_HANDLE_STATUS_HANDLED_BY_SELF = 2, ///< 自己已处理
};
/// 群组已决结果
typedef NS_ENUM(NSInteger, V2TIMGroupApplicationHandleResult) {
V2TIM_GROUP_APPLICATION_HANDLE_RESULT_REFUSE = 0, ///< 拒绝申请
V2TIM_GROUP_APPLICATION_HANDLE_RESULT_AGREE = 1, ///< 同意申请
};
/////////////////////////////////////////////////////////////////////////////////
// 群管理
/////////////////////////////////////////////////////////////////////////////////
/**
* 1.1 创建自定义群组(高级版本:可以指定初始的群成员)
*
* @param info 自定义群组信息,可以设置 groupID | groupType | groupName | notification | introduction | faceURL 字段
* @param memberList 指定初始的群成员(直播群 AVChatRoom 不支持指定初始群成员memberList 请传 nil
*
* @note 其他限制请参考 V2TIMManager.h -> createGroup 注释
*/
- (void)createGroup:(V2TIMGroupInfo*)info memberList:(NSArray<V2TIMCreateGroupMemberInfo *>*) memberList succ:(V2TIMCreateGroupSucc)succ fail:(V2TIMFail)fail;
/**
* 1.2 获取当前用户已经加入的群列表
*
* @note
* - 直播群AVChatRoom不支持该 API
* - 该接口有频限检测SDK 限制调用频率为 1 秒 10 次,超过限制后会报 ERR_SDK_COMM_API_CALL_FREQUENCY_LIMIT 7008错误
*/
- (void)getJoinedGroupList:(V2TIMGroupInfoListSucc)succ fail:(V2TIMFail)fail;
/////////////////////////////////////////////////////////////////////////////////
// 群资料管理
/////////////////////////////////////////////////////////////////////////////////
/**
* 2.1 拉取群资料
*
* @param groupIDList 群组 ID 列表
*/
- (void)getGroupsInfo:(NSArray<NSString *> *)groupIDList succ:(V2TIMGroupInfoResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 2.2 搜索群列表5.4.666 及以上版本支持,需要您购买旗舰版套餐)
*
* SDK 会搜索群名称包含于关键字列表 keywordList 的所有群并返回群信息列表。关键字列表最多支持5个。
*/
- (void)searchGroups:(V2TIMGroupSearchParam *)searchParam succ:(V2TIMGroupInfoListSucc)succ fail:(V2TIMFail)fail;
/**
* 2.3 修改群资料
*/
- (void)setGroupInfo:(V2TIMGroupInfo *)info succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 2.4 初始化群属性,会清空原有的群属性列表
*
* @note
* attributes 的使用限制如下:
* - 目前只支持 AVChatRoom
* - key 最多支持 16 个,长度限制为 32 字节;
* - value 长度限制为 4k
* - 总的 attributes包括 key 和 value限制为 16k
* - initGroupAttributes、setGroupAttributes、deleteGroupAttributes 接口合并计算, SDK 限制为 5 秒 10 次,超过后回调 8511 错误码;后台限制 1 秒 5 次,超过后返回 10049 错误码;
* - getGroupAttributes 接口 SDK 限制 5 秒 20 次;
* - 从 5.6 版本开始当每次APP启动后初次修改群属性时请您先调用 getGroupAttributes 拉取到最新的群属性之后,再发起修改操作;
* - 从 5.6 版本开始,当多个用户同时修改同一个群属性时,只有第一个用户可以执行成功,其它用户会收到 10056 错误码;收到这个错误码之后,请您调用 getGroupAttributes 把本地保存的群属性更新到最新之后,再发起修改操作。
*/
- (void)initGroupAttributes:(NSString*)groupID attributes:(NSDictionary<NSString *,NSString *> *)attributes succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 2.5 设置群属性,已有该群属性则更新其 value 值,没有该群属性则添加该群属性。
* @note
* - 目前只支持 AVChatRoom
*/
- (void)setGroupAttributes:(NSString*)groupID attributes:(NSDictionary<NSString *,NSString *> *)attributes succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 2.6 删除群指定属性keys 传 nil 则清空所有群属性。
* @note
* - 目前只支持 AVChatRoom
*/
- (void)deleteGroupAttributes:(NSString*)groupID keys:(NSArray<NSString *> *)keys succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 2.7 获取群指定属性keys 传 nil 则获取所有群属性。
* @note
* - 目前只支持 AVChatRoom
*/
- (void)getGroupAttributes:(NSString*)groupID keys:(NSArray<NSString *> *)keys succ:(V2TIMGroupAttributeListSucc)succ fail:(V2TIMFail)fail;
/**
* 2.8 获取指定群在线人数
*
* @param groupID 群id
* @param succ 成功回调
* @param fail 失败回调
*
* @note 请注意
* - 目前只支持:直播群( AVChatRoom
* - 该接口有频限检测SDK 限制调用频率为60秒1次。
*/
- (void)getGroupOnlineMemberCount:(NSString*)groupID succ:(V2TIMGroupOnlineMemberCountSucc)succ fail:(V2TIMFail)fail;
/////////////////////////////////////////////////////////////////////////////////
// 群成员管理
/////////////////////////////////////////////////////////////////////////////////
/**
* 3.1 获取群成员列表
*
* @param filter 指定群成员类型V2TIMGroupMemberFilter
* @param nextSeq 分页拉取标志第一次拉取填0回调成功如果 nextSeq 不为零,需要分页,传入再次拉取,直至为 0。
*
* @note 直播群AVChatRoom的特殊限制
* - 不支持管理员角色的拉取,群成员个数最大只支持 31 个(新进来的成员会排前面),用户每次登录后,都需要重新加入群组,否则拉取群成员会报 10007 错误码。
* - 群成员资料信息仅支持 userID | nickName | faceURL | role 字段。
* - role 字段不支持管理员角色,如果您的业务逻辑依赖于管理员角色,可以使用群自定义字段 groupAttributes 管理该角色。
*/
- (void)getGroupMemberList:(NSString*)groupID filter:(uint32_t)filter nextSeq:(uint64_t)nextSeq succ:(V2TIMGroupMemberInfoResultSucc)succ fail:(V2TIMFail)fail;
/**
* 3.2 指定的群成员资料
*/
- (void)getGroupMembersInfo:(NSString*)groupID memberList:(NSArray<NSString*>*)memberList succ:(V2TIMGroupMemberInfoListSucc)succ fail:(V2TIMFail)fail;
/**
* 3.3 搜索指定的群成员资料5.4.666 及以上版本支持,需要您购买旗舰版套餐)
*
* SDK 会在本地搜索指定群 ID 列表中群成员信息名片、好友备注、昵称、userID包含于关键字列表 keywordList 的所有群成员并返回群 ID 和群成员列表的 map关键字列表最多支持5个。
*
* @param searchParam 搜索参数
*/
- (void)searchGroupMembers:(V2TIMGroupMemberSearchParam *)searchParam
succ:(V2TIMGroupMemberInfoListSearchSucc)succ
fail:(V2TIMFail)fail;
/**
* 3.4 修改指定的群成员资料
*/
- (void)setGroupMemberInfo:(NSString*)groupID info:(V2TIMGroupMemberFullInfo *)info succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 3.5 禁言(只有管理员或群主能够调用)
*/
- (void)muteGroupMember:(NSString*)groupID member:(NSString*)userID muteTime:(uint32_t)seconds succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 3.6 邀请他人入群
*
* @note 请注意不同类型的群有如下限制:
* - 工作群Work群里的任何人都可以邀请其他人进群。
* - 会议群Meeting和公开群Public只有通过rest api 使用 App 管理员身份才可以邀请其他人进群。
* - 直播群AVChatRoom不支持此功能。
*/
- (void)inviteUserToGroup:(NSString*)groupID userList:(NSArray<NSString *>*)userList succ:(V2TIMGroupMemberOperationResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 3.7 踢人
*
* @note 请注意不同类型的群有如下限制:
* - 工作群Work只有群主或 APP 管理员可以踢人。
* - 公开群Public、会议群Meeting群主、管理员和 APP 管理员可以踢人
* - 直播群AVChatRoom只支持禁言muteGroupMember不支持踢人。
*/
- (void)kickGroupMember:(NSString*)groupID memberList:(NSArray<NSString *>*)memberList reason:(NSString*)reason succ:(V2TIMGroupMemberOperationResultListSucc)succ fail:(V2TIMFail)fail;
/**
* 3.8 切换群成员的角色
*
* @note 请注意不同类型的群有如下限制:
* - 公开群Public和会议群Meeting只有群主才能对群成员进行普通成员和管理员之间的角色切换。
* - 其他群不支持设置群成员角色。
* - 转让群组请调用 @ref transferGroupOwner 接口。
* - 会议群Meeting切换群成员角色之后不会有 onGrantAdministrator 和 onRevokeAdministrator 通知回调
* - 切换的角色支持普通群成员( V2TIM_GROUP_MEMBER_ROLE_MEMBER 和管理员V2TIM_GROUP_MEMBER_ROLE_ADMIN
*/
- (void)setGroupMemberRole:(NSString*)groupID member:(NSString *)userID newRole:(uint32_t)role succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 3.9 转让群主
*
* @note 请注意不同类型的群有如下限制:
* - 普通类型的群Work、Public、Meeting只有群主才有权限进行群转让操作。
* - 直播群AVChatRoom不支持转让群主。
*/
- (void)transferGroupOwner:(NSString*)groupID member:(NSString*)userID succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/////////////////////////////////////////////////////////////////////////////////
// 加群申请
/////////////////////////////////////////////////////////////////////////////////
/**
* 4.1 获取加群申请列表
*/
- (void)getGroupApplicationList:(V2TIMGroupApplicationResultSucc)succ fail:(V2TIMFail)fail;
/**
* 4.2 同意某一条加群申请
*/
- (void)acceptGroupApplication:(V2TIMGroupApplication *)application reason:(NSString*)reason succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 4.3 拒绝某一条加群申请
*/
- (void)refuseGroupApplication:(V2TIMGroupApplication *)application reason:(NSString*)reason succ:(V2TIMSucc)succ fail:(V2TIMFail)fail;
/**
* 4.4 标记申请列表为已读
*/
- (void)setGroupApplicationRead:(V2TIMSucc)succ fail:(V2TIMFail)fail;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 群基本资料(可以通过 getGroupInfo 获取,不支持由客户自行创建)
//
/////////////////////////////////////////////////////////////////////////////////
/// 群资料
@interface V2TIMGroupInfo : NSObject
/**
* 群组 ID
*
* @note 自定义群组 ID 必须为可打印 ASCII 字符0x20-0x7e最长48个字节且前缀不能为 @TGS#(避免与默认分配的群组 ID 混淆)
*/
@property(nonatomic,strong) NSString* groupID;
/// 群类型
@property(nonatomic,strong) NSString* groupType;
/**
* 群名称
*
* @note 群名称最长30字节
*/
@property(nonatomic,strong) NSString* groupName;
/**
* 群公告
*
* @note 群公告最长300字节
*/
@property(nonatomic,strong) NSString* notification;
/**
* 群简介
*
* @note 群简介最长240字节
*/
@property(nonatomic,strong) NSString* introduction;
/**
* 群头像
*
* @note 群头像 URL 最长100字节
*/
@property(nonatomic,strong) NSString* faceURL;
/// 是否全员禁言
@property(nonatomic,assign) BOOL allMuted;
///设置群自定义字段需要两个步骤:
///1.在 [控制台](https://console.cloud.tencent.com/im) (功能配置 -> 群自定义字段) 配置群自定义字段的 key 值Key 为 String 类型,长度不超过 16 字节。
///2.调用 setGroupInfo 接口设置该字段value 为 NSData 数据,长度不超过 512 字节。
///@note 该字段主要用于 V1 和 V2 版本的兼容,如果您直接使用的是 V2 版本的 API ,建议使用 initGroupAttributes 接口设置群属性,其设置更灵活(无需控制台配置),支持的存储也更大(最大支持 16K
@property(nonatomic,strong) NSDictionary<NSString *,NSData *>* customInfo;
/// 群创建人/管理员
@property(nonatomic,strong,readonly) NSString *owner;
/// 群创建时间
@property(nonatomic,assign,readonly) uint32_t createTime;
/// 加群是否需要管理员审批工作群Work不能主动加入不支持此设置项
@property(nonatomic,assign) V2TIMGroupAddOpt groupAddOpt;
/// 群最近一次群资料修改时间
@property(nonatomic,assign,readonly) uint32_t lastInfoTime;
/// 群最近一次发消息时间
@property(nonatomic,assign,readonly) uint32_t lastMessageTime;
/// 已加入的群成员数量
@property(nonatomic,assign,readonly) uint32_t memberCount;
/// 在线的群成员数量
@property(nonatomic,assign,readonly) uint32_t onlineCount;
/// 最多允许加入的群成员数量
/// @note 各类群成员人数限制详见: https://cloud.tencent.com/document/product/269/1502#.E7.BE.A4.E7.BB.84.E9.99.90.E5.88.B6.E5.B7.AE.E5.BC.82
@property(nonatomic,assign,readonly) uint32_t memberMaxCount;
/// 当前用户在此群组中的角色V2TIMGroupMemberRole切换角色请调用 setGroupMemberRole 接口
@property(nonatomic,assign,readonly) uint32_t role;
/// 当前用户在此群组中的消息接收选项,修改群消息接收选项请调用 setGroupReceiveMessageOpt 接口
@property(nonatomic,assign,readonly) V2TIMReceiveMessageOpt recvOpt;
/// 当前用户在此群中的加入时间,不支持设置,系统自动生成
@property(nonatomic,assign,readonly) uint32_t joinTime;
@end
/// 获取群组资料结果
@interface V2TIMGroupInfoResult : NSObject
/// 结果 0成功非0失败
@property(nonatomic,assign) int resultCode;
/// 如果获取失败,会返回错误信息
@property(nonatomic,strong) NSString *resultMsg;
/// 如果获取成功,会返回对应的 info
@property(nonatomic,strong) V2TIMGroupInfo *info;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 群申请信息(可以通过 getGroupApplicationList 获取,不支持由客户自行创建)
//
/////////////////////////////////////////////////////////////////////////////////
/// 群申请信息
@interface V2TIMGroupApplication : NSObject
/// 群组 ID
@property(nonatomic,strong,readonly) NSString* groupID;
/// 请求者 userID
@property(nonatomic,strong,readonly) NSString* fromUser;
/// 请求者昵称
@property(nonatomic,strong,readonly) NSString* fromUserNickName;
/// 请求者头像
@property(nonatomic,strong,readonly) NSString* fromUserFaceUrl;
/// 判决者id有人请求加群:0邀请其他人加群:被邀请人用户 ID
@property(nonatomic,strong,readonly) NSString* toUser;
/// 申请时间
@property(nonatomic,assign,readonly) uint64_t addTime;
/// 申请或邀请附加信息
@property(nonatomic,strong,readonly) NSString* requestMsg;
/// 审批信息:同意或拒绝信息
@property(nonatomic,strong,readonly) NSString* handledMsg;
/// 请求类型
@property(nonatomic,assign,readonly) V2TIMGroupApplicationGetType getType;
/// 处理标志
@property(nonatomic,assign,readonly) V2TIMGroupApplicationHandleStatus handleStatus;
/// 处理结果
@property(nonatomic,assign,readonly) V2TIMGroupApplicationHandleResult handleResult;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 邀请其他人入群的操作结果
//
/////////////////////////////////////////////////////////////////////////////////
/// 邀请其他人入群的操作结果
@interface V2TIMGroupMemberOperationResult : NSObject
/// 被操作成员
@property(nonatomic,strong) NSString* userID;
/// 返回状态
@property(nonatomic,assign) V2TIMGroupMemberResult result;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 创建群时指定群成员
//
/////////////////////////////////////////////////////////////////////////////////
/// 创建群时指定群成员
@interface V2TIMCreateGroupMemberInfo : NSObject
/// 被操作成员
@property(nonatomic,strong) NSString* userID;
/** 群成员类型,需要注意一下事项:
* 1. role 不设置或则设置为 V2TIM_GROUP_MEMBER_UNDEFINED进群后默认为群成员。
* 2. 工作群Work不支持设置 role 为管理员。
* 3. 所有的群都不支持设置 role 为群主。
*/
@property(nonatomic,assign) uint32_t role;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 加群申请列表(包含已处理和待处理的)
//
/////////////////////////////////////////////////////////////////////////////////
/// 加群申请列表
@interface V2TIMGroupApplicationResult : NSObject
/// 未读的申请数量
@property(nonatomic,assign) uint64_t unreadCount;
/// 加群申请的列表
@property(nonatomic,strong) NSMutableArray<V2TIMGroupApplication *> * applicationList;
@end
/////////////////////////////////////////////////////////////////////////////////
//
// 群搜索
//
/////////////////////////////////////////////////////////////////////////////////
@interface V2TIMGroupSearchParam : NSObject
/// 搜索关键字列表最多支持5个。
@property(nonatomic, strong) NSArray<NSString *> *keywordList;
/// 设置是否搜索群 ID。
@property(nonatomic, assign) BOOL isSearchGroupID;
/// 设置是否搜索群名称
@property(nonatomic, assign) BOOL isSearchGroupName;
@end
@interface V2TIMGroupMemberSearchParam : NSObject
/// 指定群 ID 列表,若为 null 则搜索全部群中的群成员
@property(nonatomic, strong) NSArray<NSString *> *groupIDList;
/// 搜索关键字列表最多支持5个
@property(nonatomic, strong) NSArray<NSString *> *keywordList;
/// 设置是否搜索群成员 userID
@property(nonatomic, assign) BOOL isSearchMemberUserID;
/// 设置是否搜索群成员昵称
@property(nonatomic, assign) BOOL isSearchMemberNickName;
/// 设置是否搜索群成员备注
@property(nonatomic, assign) BOOL isSearchMemberRemark;
/// 设置是否搜索群成员名片
@property(nonatomic, assign) BOOL isSearchMemberNameCard;
@end

Some files were not shown because too many files have changed in this diff Show More