mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2024-11-01 06:02:38 +08:00
模块 chat 添加图片,视频上传
This commit is contained in:
parent
9edba6ebed
commit
58907611f6
@ -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",
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ export default {
|
||||
|
||||
created() {
|
||||
// 监听列表刷新
|
||||
eventBus.$on("session-refresh", this.refresh);
|
||||
eventBus.$on("session.refresh", this.refresh);
|
||||
|
||||
// PC 端下首次请求读取第一个消息
|
||||
this.refresh().then(res => {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import session from "./session";
|
||||
import message from "./message";
|
||||
|
||||
export default {
|
||||
session
|
||||
session,
|
||||
message
|
||||
};
|
||||
|
67
src/cool/modules/chat/store/message.js
Normal file
67
src/cool/modules/chat/store/message.js
Normal 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 = [];
|
||||
}
|
||||
}
|
||||
};
|
@ -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 });
|
||||
},
|
||||
|
||||
// 清空会话信息
|
||||
|
6
src/cool/modules/upload/filters/index.js
Normal file
6
src/cool/modules/upload/filters/index.js
Normal file
@ -0,0 +1,6 @@
|
||||
import { video_poster, image_resize } from "./oss";
|
||||
|
||||
export default {
|
||||
video_poster,
|
||||
image_resize
|
||||
};
|
48
src/cool/modules/upload/filters/oss.js
Normal file
48
src/cool/modules/upload/filters/oss.js
Normal 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 });
|
||||
}
|
@ -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 };
|
||||
|
Loading…
Reference in New Issue
Block a user