模块 chat 添加图片,视频上传

This commit is contained in:
icssoa 2021-03-22 21:54:10 +08:00
parent 9edba6ebed
commit 58907611f6
12 changed files with 224 additions and 61 deletions

View File

@ -1,6 +1,6 @@
{
"name": "cool-admin-vue",
"version": "3.1.3",
"version": "3.1.4",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",

View File

@ -13,7 +13,7 @@ export const host = "https://show.cool-admin.com";
// Socket
export const socketUrl = (isDev ? `${host}` : "") + "/socket";
// 请求地址
// 请求地址,本地会使用代理请求
export const baseUrl = (function() {
let proxy = getUrlParam("proxy");

View File

@ -75,6 +75,7 @@ export default {
data() {
return {
modes: ["text", "image", "emoji", "voice", "video"], //
visible: false,
socket: null
};
@ -95,7 +96,7 @@ export default {
},
created() {
// this.socket = io(`${socketUrl}/?isAdmin=true&token=${token}`);
// this.socket = io(`${socketUrl}?isAdmin=true&token=${token}`);
// this.socket.on("connect", () => {
// console.log("socket connect");
// });
@ -149,7 +150,7 @@ export default {
});
//
eventBus.$emit("message-append", {
this.$store.commit("APPEND_MESSAGE_LIST", {
contentType,
content: JSON.parse(content),
type: 1
@ -177,7 +178,7 @@ export default {
});
} else {
//
eventBus.$emit("session-refresh");
eventBus.$emit("session.refresh");
}
} catch (e) {
console.error("消息格式异常", e);

View File

@ -8,13 +8,27 @@
<emoji @select="onEmojiSelect" />
</li>
<!-- 图片上传 -->
<li hidden>
<cl-upload accept="image/*" list-type :on-success="onImageSelect">
<li>
<cl-upload
accept="image/*"
list-type
:before-upload="
f => {
onBeforeUpload(f, 'image');
}
"
:on-progress="onUploadProgress"
:on-success="
(r, f) => {
onUploadSuccess(r, f, 'image');
}
"
>
<img src="../static/images/image.png" alt="" />
</cl-upload>
</li>
<!-- 视频上传 -->
<li hidden>
<li>
<cl-upload
accept="video/*"
list-type
@ -57,7 +71,6 @@
<script>
import { mapGetters } from "vuex";
import Emoji from "./emoji";
import eventBus from "../utils/event-bus";
export default {
components: {
@ -76,29 +89,48 @@ export default {
},
computed: {
...mapGetters(["session"])
...mapGetters(["session", "messageList"])
},
methods: {
//
//
onBeforeUpload(file, key) {
const data = {
content: {
[`${key}Url`]: ""
},
type: 0,
contentType: MODES.indexOf(key),
uid: file.uid,
loading: true,
progress: "0%"
const next = (options = {}) => {
const data = {
content: {
[`${key}Url`]: ""
},
type: 0,
uid: file.uid,
loading: true,
progress: "0%",
contentType: this.chat.modes.indexOf(key),
...options
};
this.append(data);
};
this.append(data);
if (key == "image") {
const fileReader = new FileReader();
fileReader.onload = e => {
next({
content: {
imageUrl: e.target.result
}
});
};
fileReader.readAsDataURL(file);
} else {
next();
}
},
//
onUploadProgress(e, file) {
const item = this.message.list.find(e => e.uid == file.uid);
const item = this.messageList.find(e => e.uid == file.uid);
if (item) {
item.progress = e.percent + "%";
@ -107,7 +139,7 @@ export default {
//
onUploadSuccess(res, file, key) {
const item = this.message.list.find(e => e.uid == file.uid);
const item = this.messageList.find(e => e.uid == file.uid);
if (item) {
item.loading = false;
@ -204,7 +236,7 @@ export default {
//
append(data) {
eventBus.$emit("message-append", data);
this.$store.commit("APPEND_MESSAGE_LIST", data);
}
}
};

View File

@ -1,5 +1,5 @@
<template>
<div class="cl-chat-message" v-loading="loading" element-loading-text="消息加载中">
<div class="cl-chat-message" v-loading="!visible && loading" element-loading-text="消息加载中">
<div
class="cl-chat-message__scroller scroller1"
ref="scroller"
@ -8,7 +8,7 @@
}"
>
<!-- 加载更多 -->
<div class="cl-chat-message__more" v-if="list.length > 0">
<div class="cl-chat-message__more" v-show="list.length > 0">
<el-button round size="mini" :loading="loading" @click="onLoadmore"
>加载更多</el-button
>
@ -18,17 +18,19 @@
<div class="cl-chat-message__list">
<div
class="cl-chat-message__item"
v-for="item in messageList"
v-for="item in list"
:key="item.id || item.uid"
:class="[item.type == 0 ? `is-right` : `is-left`, `is-${item.mode}`]"
>
<!-- 日期 -->
<div class="date" v-if="item._date">
<span>{{ item._date }}</span>
</div>
<!-- 内容 -->
<div class="main">
<!-- 头像 -->
<div class="avatar" @tap="toUserDetail(item)">
<div class="avatar">
<img :src="item.avatarUrl" />
</div>
@ -53,7 +55,17 @@
:key="item.uid"
:src="item.content.imageUrl"
:preview-src-list="[item.content.imageUrl]"
></el-image>
:z-index="3000"
:style="item.style"
>
<template #placeholder>
<img
:src="item.content.imageUrl"
:style="item.style"
alt=""
/>
</template>
</el-image>
</template>
<!-- 表情 -->
@ -90,7 +102,7 @@
</div>
</div>
<!-- voice -->
<!-- 音频 -->
<div class="voice">
<audio style="display: none" ref="voice" :src="voice.url" controls></audio>
</div>
@ -106,19 +118,17 @@ import { isString } from "cl-admin/utils";
import eventBus from "../utils/event-bus";
import IconVoice from "./icon-voice";
//
const ModeList = ["text", "image", "emoji", "voice", "video"];
export default {
components: {
IconVoice
},
inject: ["chat"],
data() {
return {
loading: false,
visible: false,
list: [],
pagination: {
page: 1,
size: 20,
@ -140,12 +150,12 @@ export default {
},
computed: {
...mapGetters(["userInfo", "session"]),
...mapGetters(["userInfo", "session", "messageList"]),
messageList() {
list() {
let date = "";
return this.list.map(e => {
return this.messageList.map(e => {
//
e._date = date
? dayjs(e.createTime).isBefore(dayjs(date).add(1, "minute"))
@ -178,15 +188,18 @@ export default {
...e,
avatarUrl,
nickName,
mode: ModeList[e.contentType]
mode: this.chat.modes[e.contentType]
};
});
}
},
created() {
eventBus.$on("message-refresh", this.refresh);
eventBus.$on("message-append", this.append);
//
eventBus.$on("message.refresh", this.refresh);
//
eventBus.$on("message.scrollToBottom", this.scrollToBottom);
if (this.session) {
this.refresh();
@ -196,7 +209,7 @@ export default {
destroyed() {
clearTimeout(this.voice.timer);
this.list.map(e => {
this.messageList.map(e => {
e.isPlay = false;
});
},
@ -206,7 +219,7 @@ export default {
onTap(item) {
//
if (item.mode == "voice") {
this.list.map(e => {
this.messageList.map(e => {
this.$set(e, "isPlay", e.id == item.id ? e.isPlay : false);
});
@ -245,11 +258,13 @@ export default {
sort: "desc"
};
//
this.loading = true;
//
if (data.page === 1) {
this.loading = true;
this.visible = false;
this.list = [];
this.$store.commit("CLEAR_MESSAGE_LIST");
}
//
@ -269,7 +284,7 @@ export default {
//
this.pagination = res.pagination;
//
this.prepend.apply(this, res.list);
this.$store.commit("PREPEND_MESSAGE_LIST", res.list);
if (data.page === 1) {
this.scrollToBottom();
@ -301,17 +316,6 @@ export default {
});
}
});
},
//
prepend(...data) {
this.list.unshift(...data.reverse());
},
//
append(...data) {
this.list.push(...data);
this.scrollToBottom();
}
}
};
@ -349,7 +353,7 @@ export default {
font-size: 12px;
color: #fff;
border-radius: 3px;
padding: 2px 5px;
padding: 3px 5px 2px 5px;
letter-spacing: 1px;
}
}
@ -474,8 +478,10 @@ export default {
&.is-video {
.item {
video {
display: block;
max-width: 300px;
max-height: 300px;
border-radius: 10px;
}
}
}

View File

@ -91,7 +91,7 @@ export default {
created() {
//
eventBus.$on("session-refresh", this.refresh);
eventBus.$on("session.refresh", this.refresh);
// PC
this.refresh().then(res => {

View File

@ -1,5 +1,7 @@
import session from "./session";
import message from "./message";
export default {
session
session,
message
};

View File

@ -0,0 +1,67 @@
import { isArray } from "cl-admin/utils";
import eventBus from "../utils/event-bus";
export default {
state: {
list: []
},
getters: {
messageList: state => state.list
},
mutations: {
// 设置列表
SET_MESSAGE_LIST(state, data) {
state.list = data;
},
// 追加数据
APPEND_MESSAGE_LIST(state, data) {
const next = options => {
state.list.push({
...data,
...options
});
eventBus.$emit("message.scrollToBottom");
};
// 图片预览、大小处理
if (data.contentType === 1) {
const image = new Image();
image.onload = () => {
let height = 0;
let width = 0;
if (image.width > 200) {
width = 200;
height = (image.height * 200) / image.width;
}
next({
style: {
height: height + "px",
width: width + "px"
}
});
};
image.src = data.content.imageUrl;
} else {
next();
}
},
// 追加数据到头部
PREPEND_MESSAGE_LIST(state, data) {
const list = isArray(data) ? data : [data];
state.list.unshift(...list.reverse());
},
// 清空列表
CLEAR_MESSAGE_LIST(state) {
state.list = [];
}
}
};

View File

@ -22,7 +22,7 @@ export default {
SET_SESSION(state, data) {
state.current = data;
state.current.serviceUnreadCount = 0;
eventBus.$emit("message-refresh", { page: 1 });
eventBus.$emit("message.refresh", { page: 1 });
},
// 清空会话信息

View File

@ -0,0 +1,6 @@
import { video_poster, image_resize } from "./oss";
export default {
video_poster,
image_resize
};

View File

@ -0,0 +1,48 @@
import { isArray, isObject } from "cl-admin/utils";
function parse(rules, { url, size }) {
if (!url) {
return "";
}
if (url.indexOf("http") !== 0) {
return url;
}
let h = 0;
let w = 0;
if (isArray(size)) {
h = size[0];
w = size[1];
} else if (isObject(size)) {
h = size.h;
w = size.w;
if (size.m) {
rules.push(size.m);
}
} else {
h = w = size;
}
url += url.includes("?") ? "&" : "?";
if (h) {
rules.push(`h_${h}`);
}
if (w) {
rules.push(`w_${w}`);
}
return `${url}${rules.join(",")}`;
}
export function video_poster(url, size) {
return parse(["x-oss-process=video/snapshot,t_1000,f_jpg"], { url, size });
}
export function image_resize(url, size) {
return parse(["x-oss-process=image/resize"], { url, size });
}

View File

@ -1,4 +1,5 @@
import service from "./service";
import components from "./components";
import filters from "./filters";
export default { components, service };
export default { components, service, filters };