diff --git a/App.vue b/App.vue
index 424dcbb..eb5fe74 100644
--- a/App.vue
+++ b/App.vue
@@ -344,6 +344,8 @@ export default {
this.$store.dispatch("user/getSelfInfo");
this.$store.dispatch("conversation/getConversationList");
this.$store.dispatch("conversation/getUnReadCount");
+ this.$store.dispatch("contact/getFriendList");
+ this.$store.dispatch("contact/getGrouplist");
this.$store.dispatch("contact/getBlacklist");
this.$store.dispatch("contact/getRecvFriendApplications");
this.$store.dispatch("contact/getSentFriendApplications");
diff --git a/components/MyAvatar/index.vue b/components/MyAvatar/index.vue
index 486a94f..9e0a9a9 100644
--- a/components/MyAvatar/index.vue
+++ b/components/MyAvatar/index.vue
@@ -49,7 +49,7 @@ export default {
computed: {
getAvatarUrl() {
if (this.src) {
- return this.src;
+ return this.getFixedSourceUrl(this.src);
}
if (this.isGroup) {
return defaultGroupIcon;
@@ -65,6 +65,13 @@ export default {
},
},
methods: {
+ getFixedSourceUrl(url) {
+ // 如果 url 以 http://47.117.71.33/api/object/ 开头,则替换为带端口的
+ if (typeof url === 'string' && url.startsWith('http://47.117.71.33/api/object/')) {
+ return url.replace('http://47.117.71.33/api/object/', 'http://47.117.71.33:15219/api/object/');
+ }
+ return url;
+ },
errorHandle() {
this.avatarText = this.desc ? this.desc.slice(0, 1) : "未知";
},
diff --git a/manifest.json b/manifest.json
index 81e6c7b..f28ed37 100644
--- a/manifest.json
+++ b/manifest.json
@@ -2,8 +2,8 @@
"name" : "德讯",
"appid" : "__UNI__D705A34",
"description" : "",
- "versionName" : "toc_base_open 3.3.4",
- "versionCode" : 334,
+ "versionName" : "fad-im 3.4.5",
+ "versionCode" : 345,
"transformPx" : false,
"app-plus" : {
"bounce" : "none",
@@ -11,9 +11,9 @@
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
- "alwaysShowBeforeRender" : false,
+ "alwaysShowBeforeRender" : true,
"waiting" : true,
- "autoclose" : false,
+ "autoclose" : true,
"delay" : 0
},
"modules" : {
@@ -21,8 +21,7 @@
"Camera" : {},
"Record" : {},
"Geolocation" : {},
- "Maps" : {},
- "Push" : {}
+ "Maps" : {}
},
"distribute" : {
"android" : {
diff --git a/pages/contact/friendList/index.vue b/pages/contact/friendList/index.vue
index a04efe8..ab76164 100644
--- a/pages/contact/friendList/index.vue
+++ b/pages/contact/friendList/index.vue
@@ -41,6 +41,7 @@ export default {
computed: {
...mapGetters(["storeFriendList"]),
getIndexData() {
+
return formatChooseData(this.storeFriendList);
},
},
diff --git a/pages/conversation/chating/components/ChatingFooter/index.vue b/pages/conversation/chating/components/ChatingFooter/index.vue
index 16806d7..f876380 100644
--- a/pages/conversation/chating/components/ChatingFooter/index.vue
+++ b/pages/conversation/chating/components/ChatingFooter/index.vue
@@ -94,13 +94,80 @@
:closeOnClickOverlay="true" :closeOnClickAction="true" :show="showActionSheet"
@close="showActionSheet = false">
-
+
+
+
+
+
+
+
+
+ 聊天文件
+
+
+ 系统文件
+
+
+
+
+
+ 暂无聊天文件
+
+
+
+
+
+ {{ getFileName(file) }}
+ {{ getFileSize(file) }}
+
+
+
+
+
+
+
+
+ 文档
+
+
+
+ 图片
+
+
+
+ 视频
+
+
+
+ 音频
+
+
+
+
+
+
@@ -169,6 +236,9 @@ export default {
recordingTime: 0,
recordingTimer: null,
showEmojiPicker: false,
+ showFileSelectModal: false,
+ currentFileTab: 'chat',
+ chatFiles: [],
recorderManager: null,
recordFilePath: '',
recordFileDuration: 0,
@@ -188,12 +258,21 @@ export default {
footerOutsideFlag(newVal) {
this.onClickActionBarOutside();
},
+ showFileSelectModal(newVal) {
+ if (newVal) {
+ // 当弹窗显示时,获取聊天文件列表
+ this.getChatFiles();
+ }
+ },
},
mounted() {
this.setKeyboardListener();
- document.addEventListener('plusready', function() {
- // plus 相关代码
- });
+ // 只在浏览器环境下添加事件监听
+ if (typeof document !== 'undefined') {
+ document.addEventListener('plusready', function() {
+ // plus 相关代码
+ });
+ }
},
beforeDestroy() {
this.disposeKeyboardListener();
@@ -344,38 +423,275 @@ export default {
}
},
async chooseFileAndSend() {
- if (!uni.chooseMessageFile) {
- return;
+ // 显示文件选择弹窗,类似微信的文件选择
+ this.showFileSelectModal = true;
+ },
+
+ // 获取聊天文件列表
+ getChatFiles() {
+ // 从store中获取当前会话的消息列表,筛选出文件消息
+ const messages = this.$store.getters.storeHistoryMessageList || [];
+ this.chatFiles = messages.filter(msg => {
+ return msg.contentType === 105; // 文件消息类型
+ }).slice(-20); // 只显示最近20个文件
+ },
+
+ // 选择聊天文件
+ selectChatFile(file) {
+ // 直接转发这个文件消息
+ this.forwardFileMessage(file);
+ this.showFileSelectModal = false;
+ },
+
+ // 转发文件消息
+ async forwardFileMessage(file) {
+ try {
+ const uuid = IMSDK.uuid();
+ const fileElem = file.fileElem;
+
+ // 创建新的文件消息
+ const message = await IMSDK.asyncApi('createFileMessageByURL', IMSDK.uuid(), {
+ filePath: fileElem.filePath || '',
+ fileName: fileElem.fileName,
+ uuid: uuid,
+ sourceUrl: fileElem.sourceUrl,
+ fileSize: fileElem.fileSize,
+ fileType: fileElem.fileType,
+ });
+
+ // 发送消息
+ this.sendMessage(message);
+ } catch (e) {
+ console.log('转发文件失败:', e);
+ uni.showToast({
+ title: '转发文件失败',
+ icon: 'none'
+ });
}
- uni.chooseMessageFile({
- count: 1,
- type: 'file',
- success: async (res) => {
- const file = res.tempFiles[0];
- try {
- const nameIdx = file.name.lastIndexOf("/") + 1;
- const fileName = file.name.slice(nameIdx);
- const typeIdx = file.name.lastIndexOf(".") + 1;
- const fileType = file.name.slice(typeIdx);
- const { data: { url } } = await IMSDK.asyncApi(IMMethods.UploadFile, IMSDK.uuid(), {
- filepath: file.path,
- name: fileName,
- contentType: fileType,
- uuid: IMSDK.uuid(),
- });
- // 创建文件消息
- const message = await IMSDK.asyncApi(IMMethods.CreateFileMessage, IMSDK.uuid(), {
- fileName: fileName,
- fileSize: file.size,
- sourceUrl: url,
- });
- this.sendMessage(message);
- } catch (e) {
+ },
+
+ // 获取文件图标
+ getFileIcon(file) {
+ const fileName = file.fileElem?.fileName?.toLowerCase() || '';
+ if (fileName.endsWith('.pdf')) {
+ return '/static/images/file_message/file_pdf.png';
+ } else if (fileName.endsWith('.doc') || fileName.endsWith('.docx')) {
+ return '/static/images/file_message/file_word.png';
+ } else if (fileName.endsWith('.xls') || fileName.endsWith('.xlsx')) {
+ return '/static/images/file_message/file_excel.png';
+ } else if (fileName.endsWith('.ppt') || fileName.endsWith('.pptx')) {
+ return '/static/images/file_message/file_ppt.png';
+ } else if (fileName.endsWith('.zip') || fileName.endsWith('.rar') || fileName.endsWith('.7z')) {
+ return '/static/images/file_message/file_zip.png';
+ } else if (fileName.endsWith('.jpg') || fileName.endsWith('.jpeg') || fileName.endsWith('.png') || fileName.endsWith('.gif')) {
+ return '/static/images/file_message/file_image.png';
+ } else {
+ return '/static/images/file_message/file_unknown.png';
+ }
+ },
+
+ // 获取文件名
+ getFileName(file) {
+ return file.fileElem?.fileName || '未知文件';
+ },
+
+ // 获取文件大小
+ getFileSize(file) {
+ const size = file.fileElem?.fileSize;
+ if (!size) return '';
+ if (size < 1024) {
+ return size + ' B';
+ } else if (size < 1024 * 1024) {
+ return (size / 1024).toFixed(1) + ' KB';
+ } else {
+ return (size / (1024 * 1024)).toFixed(1) + ' MB';
+ }
+ },
+
+ // 选择系统文件
+ chooseSystemFile(type) {
+ switch (type) {
+ case 'document':
+ // 选择文档
+ uni.chooseMessageFile({
+ count: 1,
+ type: 'file',
+ success: async (res) => {
+ const file = res.tempFiles[0];
+ await this.processFileAndSend(file);
+ },
+ fail: () => {
+ uni.showToast({
+ title: '请从聊天记录中选择文档',
+ icon: 'none'
+ });
+ }
+ });
+ break;
+ case 'image':
+ // 选择图片
+ uni.chooseImage({
+ count: 1,
+ sourceType: ['album'],
+ success: async (res) => {
+ const file = {
+ name: 'image.jpg',
+ size: 0,
+ path: res.tempFilePaths[0],
+ type: 'image'
+ };
+ await this.processFileAndSend(file);
+ }
+ });
+ break;
+ case 'video':
+ // 选择视频
+ uni.chooseVideo({
+ sourceType: ['album'],
+ success: async (res) => {
+ const file = {
+ name: 'video.mp4',
+ size: res.size || 0,
+ path: res.tempFilePath,
+ type: 'video'
+ };
+ await this.processFileAndSend(file);
+ }
+ });
+ break;
+ case 'audio':
+ // 选择音频
+ uni.chooseMessageFile({
+ count: 1,
+ type: 'file',
+ success: async (res) => {
+ const file = res.tempFiles[0];
+ await this.processFileAndSend(file);
+ },
+ fail: () => {
+ uni.showToast({
+ title: '请从聊天记录中选择音频文件',
+ icon: 'none'
+ });
+ }
+ });
+ break;
+ }
+ this.showFileSelectModal = false;
+ },
+
+
+
+
+
+ async processFileAndSend(file) {
+ try {
+ // 处理文件名
+ let fileName = file.name;
+ if (!fileName) {
+ const pathParts = file.path.split('/');
+ fileName = pathParts[pathParts.length - 1] || 'unknown';
+ }
+
+ // 处理文件类型
+ let fileType = file.type;
+ if (!fileType) {
+ const nameIdx = fileName.lastIndexOf(".") + 1;
+ fileType = fileName.slice(nameIdx) || 'unknown';
+ }
+
+ const uuid = IMSDK.uuid();
+
+ // 如果是图片类型,直接创建图片消息
+ if (fileType.toLowerCase().includes('image') || fileType.toLowerCase().includes('jpg') || fileType.toLowerCase().includes('jpeg') || fileType.toLowerCase().includes('png') || fileType.toLowerCase().includes('gif')) {
+ // 创建图片消息
+ const message = await IMSDK.asyncApi(
+ IMMethods.CreateImageMessageFromFullPath,
+ IMSDK.uuid(),
+ file.path
+ );
+ this.sendMessage(message);
+ return;
+ }
+
+ // 先保存到本地
+ uni.saveFile({
+ tempFilePath: file.path,
+ success: (saveRes) => {
+ let savedFilePath = saveRes.savedFilePath;
+ // 用 plus.io 转换为原生绝对路径
+ if (typeof plus !== 'undefined') {
+ plus.io.resolveLocalFileSystemURL(savedFilePath, (entry) => {
+ IMSDK.asyncApi(IMMethods.UploadFile, uuid, {
+ name: fileName,
+ contentType: fileType,
+ uuid: uuid,
+ filepath: entry.fullPath
+ })
+ .then(({ data }) => {
+ let sourceUrl = data.url;
+ IMSDK.asyncApi('createFileMessageByURL', IMSDK.uuid(), {
+ filePath: entry.fullPath,
+ fileName: fileName,
+ uuid: uuid,
+ sourceUrl: sourceUrl,
+ fileSize: file.size || 0,
+ fileType: fileType,
+ })
+ .then((message) => {
+ IMSDK.asyncApi('sendMessageNotOss', IMSDK.uuid(), {
+ recvID: this.storeCurrentConversation.userID,
+ groupID: this.storeCurrentConversation.groupID,
+ message: message,
+ offlinePushInfo: {
+ title: '你有新消息',
+ desc: '新消息',
+ ex: '',
+ iOSPushSound: '+1',
+ iOSBadgeCount: true,
+ }
+ })
+ .then(({ data }) => {
+ // 1. 本地新增消息
+ this.pushNewMessage(message);
+ // 2. 更新消息状态
+ this.updateOneMessage({
+ message: data,
+ isSuccess: true,
+ });
+ this.$emit("scrollToBottom");
+ })
+ .catch(({ errCode, errMsg }) => {
+ // 发送失败时也要更新消息状态为失败
+ this.updateOneMessage({
+ message: message,
+ type: UpdateMessageTypes.KeyWords,
+ keyWords: [
+ { key: "status", value: MessageStatus.Failed },
+ { key: "errCode", value: errCode },
+ ],
+ });
+ });
+ })
+ .catch(() => {
+ // 忽略错误提示
+ });
+ })
+ .catch(() => {
+ // 忽略错误提示
+ });
+ }, () => {
+ // 忽略路径转换失败
+ });
+ }
+ },
+ fail: () => {
+ // 忽略保存失败
}
- },
- fail: function (err) {
- },
- });
+ });
+ } catch (e) {
+ console.log('处理文件失败:', e);
+ }
},
// from comp
@@ -648,4 +964,177 @@ export default {
position: relative;
z-index: 999;
}
+
+.file-select-mask {
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100vw;
+ height: 100vh;
+ background: rgba(0, 0, 0, 0.6);
+ z-index: 998;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ backdrop-filter: blur(4px);
+}
+
+.file-select-container {
+ background: #fff;
+ border-radius: 16px;
+ width: 90%;
+ max-width: 500px;
+ max-height: 80vh;
+ overflow: hidden;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
+}
+
+.file-select-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20px 24px;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.file-select-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+}
+
+.file-select-close {
+ font-size: 24px;
+ color: #999;
+ cursor: pointer;
+ padding: 4px;
+}
+
+.file-select-tabs {
+ display: flex;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.tab-item {
+ flex: 1;
+ text-align: center;
+ padding: 16px;
+ font-size: 16px;
+ color: #666;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ border-bottom: 2px solid transparent;
+}
+
+.tab-item.active {
+ color: #4a9cfc;
+ border-bottom-color: #4a9cfc;
+ background: rgba(74, 156, 252, 0.05);
+}
+
+.file-select-content {
+ max-height: 400px;
+ overflow-y: auto;
+}
+
+.chat-files {
+ padding: 16px;
+}
+
+.empty-state {
+ text-align: center;
+ padding: 40px 20px;
+}
+
+.empty-text {
+ color: #999;
+ font-size: 14px;
+}
+
+.file-list {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.file-item {
+ display: flex;
+ align-items: center;
+ padding: 12px;
+ border-radius: 8px;
+ background: #f8f9fa;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.file-item:hover {
+ background: #e9ecef;
+}
+
+.file-icon {
+ width: 40px;
+ height: 40px;
+ margin-right: 12px;
+}
+
+.file-info {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+}
+
+.file-name {
+ font-size: 14px;
+ color: #333;
+ font-weight: 500;
+ margin-bottom: 4px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.file-size {
+ font-size: 12px;
+ color: #999;
+}
+
+.system-files {
+ padding: 24px;
+}
+
+.file-options {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 16px;
+}
+
+.option-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 20px;
+ border-radius: 12px;
+ background: #f8f9fa;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.option-item:hover {
+ background: #e9ecef;
+ transform: translateY(-2px);
+}
+
+.option-icon {
+ width: 48px;
+ height: 48px;
+ margin-bottom: 8px;
+}
+
+.option-text {
+ font-size: 14px;
+ color: #333;
+ font-weight: 500;
+}
+
+
\ No newline at end of file
diff --git a/pages/conversation/chating/components/MessageItem/FileMessageRender.vue b/pages/conversation/chating/components/MessageItem/FileMessageRender.vue
new file mode 100644
index 0000000..749da8b
--- /dev/null
+++ b/pages/conversation/chating/components/MessageItem/FileMessageRender.vue
@@ -0,0 +1,194 @@
+
+
+
+
+ {{ fileName }}
+ {{ fileSizeText }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/conversation/chating/components/MessageItem/MediaMessageRender.vue b/pages/conversation/chating/components/MessageItem/MediaMessageRender.vue
index 1e6d638..e8249a9 100644
--- a/pages/conversation/chating/components/MessageItem/MediaMessageRender.vue
+++ b/pages/conversation/chating/components/MessageItem/MediaMessageRender.vue
@@ -10,7 +10,16 @@
@click="clickMediaItem"
>
-
+
+
+
+
+
+
+
+ 加载中...
+
+
@@ -28,13 +37,22 @@ export default {
};
},
computed: {
- getImgUrl() {
+
+
+ getImgUrl() {
+ if (!this.message || !this.message.pictureElem) {
+ return '';
+ }
return (
- this.message.pictureElem.snapshotPicture?.url ??
- this.message.pictureElem.sourcePath
- );
+ this.message.pictureElem.snapshotPicture && this.message.pictureElem.snapshotPicture.url ?
+ this.getFixedSourceUrl(this.message.pictureElem.snapshotPicture.url) :
+ this.getFixedSourceUrl(this.message.pictureElem.sourcePicture.url)
+ );
},
maxHeight() {
+ if (!this.message || !this.message.pictureElem || !this.message.pictureElem.sourcePicture) {
+ return 120;
+ }
const imageHeight = this.message.pictureElem.sourcePicture.height;
const imageWidth = this.message.pictureElem.sourcePicture.width;
const aspectRatio = imageHeight / imageWidth;
@@ -42,10 +60,20 @@ export default {
},
},
methods: {
+ getFixedSourceUrl(url) {
+ if (typeof url === 'string' && url.startsWith('http://47.117.71.33/api/object/')) {
+ return url.replace('http://47.117.71.33/api/object/', 'http://47.117.71.33:15219/api/object/');
+ }
+ return url;
+ },
+
clickMediaItem() {
+ if (!this.message || !this.message.pictureElem || !this.message.pictureElem.sourcePicture) {
+ return;
+ }
uni.previewImage({
current: 0,
- urls: [this.message.pictureElem.sourcePicture.url],
+ urls: [this.getFixedSourceUrl(this.message.pictureElem.sourcePicture.url)],
indicator: "none",
});
},
@@ -61,6 +89,7 @@ export default {
position: relative;
border-radius: 16rpx;
overflow: hidden;
+ display: inline-block;
.play_icon {
width: 48px;
@@ -78,4 +107,71 @@ export default {
color: #fff;
}
}
+
+.custom-loading {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(255, 255, 255, 0.9);
+ backdrop-filter: blur(4px);
+ border-radius: 16rpx;
+ box-sizing: border-box;
+}
+
+.loading-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+.loading-spinner {
+ position: relative;
+ width: 40px;
+ height: 40px;
+ margin-bottom: 8px;
+}
+
+.spinner-ring {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ border: 3px solid transparent;
+ border-top: 3px solid #4a9cfc;
+ border-radius: 50%;
+ animation: spin 1.2s linear infinite;
+
+ &:nth-child(2) {
+ width: 80%;
+ height: 80%;
+ top: 10%;
+ left: 10%;
+ border-top-color: #6bb6ff;
+ animation-delay: -0.4s;
+ }
+
+ &:nth-child(3) {
+ width: 60%;
+ height: 60%;
+ top: 20%;
+ left: 20%;
+ border-top-color: #8cc8ff;
+ animation-delay: -0.8s;
+ }
+}
+
+.loading-text {
+ font-size: 12px;
+ color: #666;
+ font-weight: 500;
+}
+
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/pages/conversation/chating/components/MessageItem/TextMessageRender.vue b/pages/conversation/chating/components/MessageItem/TextMessageRender.vue
index 8ecaeda..fe57b50 100644
--- a/pages/conversation/chating/components/MessageItem/TextMessageRender.vue
+++ b/pages/conversation/chating/components/MessageItem/TextMessageRender.vue
@@ -20,8 +20,8 @@ export default {
},
computed: {
getContent() {
- console.log(this.message);
- return parseBr(this.message.textElem.content);
+ return this.message && this.message.textElem && this.message.textElem.content ?
+ parseBr(this.message.textElem.content) : '';
},
},
data() {
diff --git a/pages/conversation/chating/components/MessageItem/VoiceMessageRender.vue b/pages/conversation/chating/components/MessageItem/VoiceMessageRender.vue
index e6be4a1..1767a5d 100644
--- a/pages/conversation/chating/components/MessageItem/VoiceMessageRender.vue
+++ b/pages/conversation/chating/components/MessageItem/VoiceMessageRender.vue
@@ -2,7 +2,7 @@
{{ durationText }}
@@ -15,11 +15,15 @@ export default {
source: {
type: Object,
required: true
+ },
+ isSender: {
+ type: Boolean,
+ default: false
}
},
computed: {
durationText() {
- const d = this.source.soundElem && this.source.soundElem.duration;
+ const d = this.source && this.source.soundElem && this.source.soundElem.duration;
return d ? `${d}''` : '';
}
},
@@ -46,7 +50,7 @@ export default {
this.innerAudioContext = null;
}
this.innerAudioContext = uni.createInnerAudioContext();
- const rawUrl = this.source.soundElem && this.source.soundElem.sourceUrl || '';
+ const rawUrl = this.source && this.source.soundElem && this.source.soundElem.sourceUrl || '';
this.innerAudioContext.src = this.getFixedSourceUrl(rawUrl);
this.isPlaying = true;
this.innerAudioContext.play();
diff --git a/pages/conversation/chating/components/MessageItem/index.vue b/pages/conversation/chating/components/MessageItem/index.vue
index 19aaabb..2d05631 100644
--- a/pages/conversation/chating/components/MessageItem/index.vue
+++ b/pages/conversation/chating/components/MessageItem/index.vue
@@ -41,16 +41,16 @@
-
+
-
+
[暂未实现] 视频消息
- [暂未实现] 文件消息
+
[暂未实现] @消息
@@ -93,6 +93,7 @@ import TextMessageRender from "./TextMessageRender.vue";
import MediaMessageRender from "./MediaMessageRender.vue";
import ErrorMessageRender from "./ErrorMessageRender.vue";
import VoiceMessageRender from './VoiceMessageRender.vue'
+import FileMessageRender from './FileMessageRender.vue'
import { noticeMessageTypes } from "@/constant";
import { tipMessaggeFormat, formatMessageTime } from "@/util/imCommon";
@@ -106,7 +107,8 @@ export default {
TextMessageRender,
MediaMessageRender,
ErrorMessageRender,
- VoiceMessageRender
+ VoiceMessageRender,
+ FileMessageRender
},
props: {
source: Object,
@@ -131,15 +133,18 @@ export default {
);
},
formattedMessageTime() {
- return formatMessageTime(this.source.sendTime);
+ return this.source && this.source.sendTime ? formatMessageTime(this.source.sendTime) : '';
},
showTextRender() {
- return textRenderTypes.includes(this.source.contentType);
+ return this.source && this.source.contentType ? textRenderTypes.includes(this.source.contentType) : false;
},
showMediaRender() {
- return mediaRenderTypes.includes(this.source.contentType);
+ return this.source && this.source.contentType ? mediaRenderTypes.includes(this.source.contentType) : false;
},
getNoticeContent() {
+ if (!this.source || !this.source.contentType) {
+ return "";
+ }
const isNoticeMessage = noticeMessageTypes.includes(
this.source.contentType
);
@@ -151,13 +156,13 @@ export default {
);
},
isSuccessMessage() {
- return this.source.status === MessageStatus.Succeed;
+ return this.source && this.source.status === MessageStatus.Succeed;
},
isFailedMessage() {
- return this.source.status === MessageStatus.Failed;
+ return this.source && this.source.status === MessageStatus.Failed;
},
showSending() {
- return this.source.status === MessageStatus.Sending && !this.sendingDelay;
+ return this.source && this.source.status === MessageStatus.Sending && !this.sendingDelay;
},
},
mounted() {
@@ -166,7 +171,7 @@ export default {
},
methods: {
setSendingDelay() {
- if (this.source.status === MessageStatus.Sending) {
+ if (this.source && this.source.status === MessageStatus.Sending) {
setTimeout(() => {
this.sendingDelay = false;
}, 2000);
diff --git a/pages/conversation/conversationList/components/ConversationItem.vue b/pages/conversation/conversationList/components/ConversationItem.vue
index 79e7caa..8a0bfb2 100644
--- a/pages/conversation/conversationList/components/ConversationItem.vue
+++ b/pages/conversation/conversationList/components/ConversationItem.vue
@@ -53,7 +53,6 @@ export default {
let parsedMessage;
try {
parsedMessage = JSON.parse(this.source.latestMsg);
- console.log(parsedMessage);
} catch (e) {}
if (!parsedMessage) return "";
diff --git a/pages/login/index.vue b/pages/login/index.vue
index a64d15a..300da83 100644
--- a/pages/login/index.vue
+++ b/pages/login/index.vue
@@ -2,8 +2,8 @@
-
- 欢迎使用福安德内部平台
+
+ 欢迎使用德迅,福安德信息科技有限公司内部交流平台
{
+ // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
+ // #ifdef MP-WEIXIN
+ uni.chooseMedia({
+ count,
+ sizeType,
+ sourceType,
+ mediaType: ['image'],
+ extension,
+ success(res) {
+ res.tempFiles.forEach(item => {
+ item.path = item.tempFilePath;
+ })
+ resolve(normalizeChooseAndUploadFileRes(res, 'image'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
+ });
+ },
+ })
+ // #endif
+ // #ifndef MP-WEIXIN
+ uni.chooseImage({
+ count,
+ sizeType,
+ sourceType,
+ extension,
+ success(res) {
+ resolve(normalizeChooseAndUploadFileRes(res, 'image'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ // #endif
+
+ });
+}
+
+function chooseVideo(opts) {
+ const {
+ count,
+ camera,
+ compressed,
+ maxDuration,
+ sourceType,
+ extension
+ } = opts;
+ return new Promise((resolve, reject) => {
+ // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口
+ // #ifdef MP-WEIXIN
+ uni.chooseMedia({
+ count,
+ compressed,
+ maxDuration,
+ sourceType,
+ extension,
+ mediaType: ['video'],
+ success(res) {
+ const {
+ tempFiles,
+ } = res;
+ resolve(normalizeChooseAndUploadFileRes({
+ errMsg: 'chooseVideo:ok',
+ tempFiles: tempFiles.map(item => {
+ return {
+ name: item.name || '',
+ path: item.tempFilePath,
+ thumbTempFilePath: item.thumbTempFilePath,
+ size:item.size,
+ type: (res.tempFile && res.tempFile.type) || '',
+ width:item.width,
+ height:item.height,
+ duration:item.duration,
+ fileType: 'video',
+ cloudPath: '',
+ }
+ }),
+ }, 'video'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
+ });
+ },
+ })
+ // #endif
+ // #ifndef MP-WEIXIN
+ uni.chooseVideo({
+ camera,
+ compressed,
+ maxDuration,
+ sourceType,
+ extension,
+ success(res) {
+ const {
+ tempFilePath,
+ duration,
+ size,
+ height,
+ width
+ } = res;
+ resolve(normalizeChooseAndUploadFileRes({
+ errMsg: 'chooseVideo:ok',
+ tempFilePaths: [tempFilePath],
+ tempFiles: [{
+ name: (res.tempFile && res.tempFile.name) || '',
+ path: tempFilePath,
+ size,
+ type: (res.tempFile && res.tempFile.type) || '',
+ width,
+ height,
+ duration,
+ fileType: 'video',
+ cloudPath: '',
+ }, ],
+ }, 'video'));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ // #endif
+ });
+}
+
+function chooseAll(opts) {
+ const {
+ count,
+ extension
+ } = opts;
+ return new Promise((resolve, reject) => {
+ let chooseFile = uni.chooseFile;
+ if (typeof wx !== 'undefined' &&
+ typeof wx.chooseMessageFile === 'function') {
+ chooseFile = wx.chooseMessageFile;
+ }
+ if (typeof chooseFile !== 'function') {
+ return reject({
+ errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
+ });
+ }
+ chooseFile({
+ type: 'all',
+ count,
+ extension,
+ success(res) {
+ resolve(normalizeChooseAndUploadFileRes(res));
+ },
+ fail(res) {
+ reject({
+ errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
+ });
+ },
+ });
+ });
+}
+
+function normalizeChooseAndUploadFileRes(res, fileType) {
+ res.tempFiles.forEach((item, index) => {
+ if (!item.name) {
+ item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
+ }
+ if (fileType) {
+ item.fileType = fileType;
+ }
+ item.cloudPath =
+ Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
+ });
+ if (!res.tempFilePaths) {
+ res.tempFilePaths = res.tempFiles.map((file) => file.path);
+ }
+ return res;
+}
+
+function uploadCloudFiles(files, max = 5, onUploadProgress) {
+ files = JSON.parse(JSON.stringify(files))
+ const len = files.length
+ let count = 0
+ let self = this
+ return new Promise(resolve => {
+ while (count < max) {
+ next()
+ }
+
+ function next() {
+ let cur = count++
+ if (cur >= len) {
+ !files.find(item => !item.url && !item.errMsg) && resolve(files)
+ return
+ }
+ const fileItem = files[cur]
+ const index = self.files.findIndex(v => v.uuid === fileItem.uuid)
+ fileItem.url = ''
+ delete fileItem.errMsg
+
+ uniCloud
+ .uploadFile({
+ filePath: fileItem.path,
+ cloudPath: fileItem.cloudPath,
+ fileType: fileItem.fileType,
+ onUploadProgress: res => {
+ res.index = index
+ onUploadProgress && onUploadProgress(res)
+ }
+ })
+ .then(res => {
+ fileItem.url = res.fileID
+ fileItem.index = index
+ if (cur < len) {
+ next()
+ }
+ })
+ .catch(res => {
+ fileItem.errMsg = res.errMsg || res.message
+ fileItem.index = index
+ if (cur < len) {
+ next()
+ }
+ })
+ }
+ })
+}
+
+
+
+
+
+function uploadFiles(choosePromise, {
+ onChooseFile,
+ onUploadProgress
+}) {
+ return choosePromise
+ .then((res) => {
+ if (onChooseFile) {
+ const customChooseRes = onChooseFile(res);
+ if (typeof customChooseRes !== 'undefined') {
+ return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ?
+ res : chooseRes);
+ }
+ }
+ return res;
+ })
+ .then((res) => {
+ if (res === false) {
+ return {
+ errMsg: ERR_MSG_OK,
+ tempFilePaths: [],
+ tempFiles: [],
+ };
+ }
+ return res
+ })
+}
+
+function chooseAndUploadFile(opts = {
+ type: 'all'
+}) {
+ if (opts.type === 'image') {
+ return uploadFiles(chooseImage(opts), opts);
+ } else if (opts.type === 'video') {
+ return uploadFiles(chooseVideo(opts), opts);
+ }
+ return uploadFiles(chooseAll(opts), opts);
+}
+
+export {
+ chooseAndUploadFile,
+ uploadCloudFiles
+};
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
new file mode 100644
index 0000000..872cf74
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
@@ -0,0 +1,658 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
new file mode 100644
index 0000000..625d92e
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
@@ -0,0 +1,325 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue
new file mode 100644
index 0000000..ff48466
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue
@@ -0,0 +1,282 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 点击重试
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/utils.js b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js
new file mode 100644
index 0000000..1bc9259
--- /dev/null
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js
@@ -0,0 +1,110 @@
+/**
+ * 获取文件名和后缀
+ * @param {String} name
+ */
+export const get_file_ext = (name) => {
+ const last_len = name.lastIndexOf('.')
+ const len = name.length
+ return {
+ name: name.substring(0, last_len),
+ ext: name.substring(last_len + 1, len)
+ }
+}
+
+/**
+ * 获取扩展名
+ * @param {Array} fileExtname
+ */
+export const get_extname = (fileExtname) => {
+ if (!Array.isArray(fileExtname)) {
+ let extname = fileExtname.replace(/(\[|\])/g, '')
+ return extname.split(',')
+ } else {
+ return fileExtname
+ }
+ return []
+}
+
+/**
+ * 获取文件和检测是否可选
+ */
+export const get_files_and_is_max = (res, _extname) => {
+ let filePaths = []
+ let files = []
+ if(!_extname || _extname.length === 0){
+ return {
+ filePaths,
+ files
+ }
+ }
+ res.tempFiles.forEach(v => {
+ let fileFullName = get_file_ext(v.name)
+ const extname = fileFullName.ext.toLowerCase()
+ if (_extname.indexOf(extname) !== -1) {
+ files.push(v)
+ filePaths.push(v.path)
+ }
+ })
+ if (files.length !== res.tempFiles.length) {
+ uni.showToast({
+ title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`,
+ icon: 'none',
+ duration: 5000
+ })
+ }
+
+ return {
+ filePaths,
+ files
+ }
+}
+
+
+/**
+ * 获取图片信息
+ * @param {Object} filepath
+ */
+export const get_file_info = (filepath) => {
+ return new Promise((resolve, reject) => {
+ uni.getImageInfo({
+ src: filepath,
+ success(res) {
+ resolve(res)
+ },
+ fail(err) {
+ reject(err)
+ }
+ })
+ })
+}
+/**
+ * 获取封装数据
+ */
+export const get_file_data = async (files, type = 'image') => {
+ // 最终需要上传数据库的数据
+ let fileFullName = get_file_ext(files.name)
+ const extname = fileFullName.ext.toLowerCase()
+ let filedata = {
+ name: files.name,
+ uuid: files.uuid,
+ extname: extname || '',
+ cloudPath: files.cloudPath,
+ fileType: files.fileType,
+ thumbTempFilePath: files.thumbTempFilePath,
+ url: files.path || files.path,
+ size: files.size, //单位是字节
+ image: {},
+ path: files.path,
+ video: {}
+ }
+ if (type === 'image') {
+ const imageinfo = await get_file_info(files.path)
+ delete filedata.video
+ filedata.image.width = imageinfo.width
+ filedata.image.height = imageinfo.height
+ filedata.image.location = imageinfo.path
+ } else {
+ delete filedata.image
+ }
+ return filedata
+}
diff --git a/uni_modules/uni-file-picker/package.json b/uni_modules/uni-file-picker/package.json
new file mode 100644
index 0000000..830bb7e
--- /dev/null
+++ b/uni_modules/uni-file-picker/package.json
@@ -0,0 +1,86 @@
+{
+ "id": "uni-file-picker",
+ "displayName": "uni-file-picker 文件选择上传",
+ "version": "1.0.12",
+ "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
+ "keywords": [
+ "uni-ui",
+ "uniui",
+ "图片上传",
+ "文件上传"
+],
+ "repository": "https://github.com/dcloudio/uni-ui",
+ "engines": {
+ "HBuilderX": ""
+ },
+ "directories": {
+ "example": "../../temps/example_temps"
+ },
+"dcloudext": {
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "无",
+ "permissions": "无"
+ },
+ "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+ "type": "component-vue"
+ },
+ "uni_modules": {
+ "dependencies": ["uni-scss"],
+ "encrypt": [],
+ "platforms": {
+ "cloud": {
+ "tcb": "y",
+ "aliyun": "y",
+ "alipay": "n"
+ },
+ "client": {
+ "App": {
+ "app-vue": "y",
+ "app-nvue": "n",
+ "app-harmony": "u",
+ "app-uvue": "u"
+ },
+ "H5-mobile": {
+ "Safari": "y",
+ "Android Browser": "y",
+ "微信浏览器(Android)": "y",
+ "QQ浏览器(Android)": "y"
+ },
+ "H5-pc": {
+ "Chrome": "y",
+ "IE": "y",
+ "Edge": "y",
+ "Firefox": "y",
+ "Safari": "y"
+ },
+ "小程序": {
+ "微信": "y",
+ "阿里": "y",
+ "百度": "y",
+ "字节跳动": "y",
+ "QQ": "y"
+ },
+ "快应用": {
+ "华为": "u",
+ "联盟": "u"
+ },
+ "Vue": {
+ "vue2": "y",
+ "vue3": "y"
+ }
+ }
+ }
+ }
+}
diff --git a/uni_modules/uni-file-picker/readme.md b/uni_modules/uni-file-picker/readme.md
new file mode 100644
index 0000000..c8399a5
--- /dev/null
+++ b/uni_modules/uni-file-picker/readme.md
@@ -0,0 +1,11 @@
+
+## FilePicker 文件选择上传
+
+> **组件名:uni-file-picker**
+> 代码块: `uFilePicker`
+
+
+文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file