im页面完成
This commit is contained in:
parent
4dfbb67c65
commit
8c4c26f554
@ -13,8 +13,8 @@ TypeScript cannot handle type information for `.vue` imports by default, so we r
|
||||
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||
|
||||
1. Disable the built-in TypeScript Extension
|
||||
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
## Customize configuration
|
||||
@ -44,5 +44,3 @@ npm run build
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
||||
|
||||
zmj 分支
|
||||
|
22
src/api/talk.ts
Normal file
22
src/api/talk.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import request from "@/utils/request/indexs";
|
||||
|
||||
/**
|
||||
* 绑定scoket
|
||||
*/
|
||||
export const bindScoket = (data: any) =>
|
||||
request.post({ url: "/common/im/doBindUid", data });
|
||||
// 发送消息
|
||||
export const sendMsgApi = (data: any) =>
|
||||
request.post({ url: "/common/im/sendTextMsg", data });
|
||||
// 发送文件
|
||||
export const sendFileApi = (data: any) =>
|
||||
request.post({ url: "/common/im/sendFileMsg", data });
|
||||
// 消息列表
|
||||
export const getMsgListApi = (data: any) =>
|
||||
request.post({ url: "/common/im/msgList", data });
|
||||
// 片区经理id
|
||||
export const getAreaManagerApi = (data: any) =>
|
||||
request.post({ url: "/common/im/getAreaManager", data });
|
||||
// 联系人列表
|
||||
export const getContactListApi = (data: any) =>
|
||||
request.post({ url: "/common/im/contactList", data });
|
BIN
src/assets/images/SP.png
Normal file
BIN
src/assets/images/SP.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
src/assets/images/XC.png
Normal file
BIN
src/assets/images/XC.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
@ -2,11 +2,19 @@ const config = {
|
||||
terminal: 1, //终端
|
||||
title: "后台管理系统", //网站默认标题
|
||||
version: "1.6.0", //版本号
|
||||
baseUrl: `${
|
||||
import.meta.env.VITE_APP_BASE_URL
|
||||
}/`, //请求接口域名
|
||||
baseUrl: `${import.meta.env.VITE_APP_BASE_URL}/`, //请求接口域名
|
||||
urlPrefix: "adminapi", //请求默认前缀
|
||||
timeout: 20 * 1000, //请求超时时长
|
||||
};
|
||||
|
||||
export default config;
|
||||
// const config = {
|
||||
// terminal: 1, //终端
|
||||
// title: "后台管理系统", //网站默认标题
|
||||
// version: "1.6.0", //版本号
|
||||
// baseUrl: `https://worker-task.lihaink.cn`, //请求接口域名
|
||||
// urlPrefix: "adminapi", //请求默认前缀
|
||||
// timeout: 20 * 1000, //请求超时时长
|
||||
// };
|
||||
|
||||
// export default config;
|
||||
|
131
src/utils/request/indexs.ts
Normal file
131
src/utils/request/indexs.ts
Normal file
@ -0,0 +1,131 @@
|
||||
import { merge } from "lodash";
|
||||
import configs from "@/config";
|
||||
import { Axios } from "./axios";
|
||||
import {
|
||||
ContentTypeEnum,
|
||||
RequestCodeEnum,
|
||||
RequestMethodsEnum,
|
||||
} from "@/enums/requestEnums";
|
||||
import type { AxiosHooks } from "./type";
|
||||
import { clearAuthInfo, getToken } from "../auth";
|
||||
import feedback from "../feedback";
|
||||
import NProgress from "nprogress";
|
||||
import { AxiosError, type AxiosRequestConfig } from "axios";
|
||||
import router from "@/router";
|
||||
import { PageEnum } from "@/enums/pageEnum";
|
||||
|
||||
// 处理axios的钩子函数
|
||||
const axiosHooks: AxiosHooks = {
|
||||
requestInterceptorsHook(config) {
|
||||
NProgress.start();
|
||||
const { withToken, isParamsToData } = config.requestOptions;
|
||||
const params = config.params || {};
|
||||
const headers = config.headers || {};
|
||||
|
||||
// 添加token
|
||||
if (withToken) {
|
||||
const token = getToken();
|
||||
headers.token = token;
|
||||
}
|
||||
// POST请求下如果无data,则将params视为data
|
||||
if (
|
||||
isParamsToData &&
|
||||
!Reflect.has(config, "data") &&
|
||||
config.method?.toUpperCase() === RequestMethodsEnum.POST
|
||||
) {
|
||||
config.data = params;
|
||||
config.params = {};
|
||||
}
|
||||
config.headers = headers;
|
||||
return config;
|
||||
},
|
||||
requestInterceptorsCatchHook(err) {
|
||||
NProgress.done();
|
||||
return err;
|
||||
},
|
||||
async responseInterceptorsHook(response) {
|
||||
NProgress.done();
|
||||
const { isTransformResponse, isReturnDefaultResponse } =
|
||||
response.config.requestOptions;
|
||||
|
||||
//返回默认响应,当需要获取响应头及其他数据时可使用
|
||||
if (isReturnDefaultResponse) {
|
||||
return response;
|
||||
}
|
||||
// 是否需要对数据进行处理
|
||||
if (!isTransformResponse) {
|
||||
return response.data;
|
||||
}
|
||||
const { code, data, show, msg } = response.data;
|
||||
switch (code) {
|
||||
case RequestCodeEnum.SUCCESS:
|
||||
if (show) {
|
||||
msg && feedback.msgSuccess(msg);
|
||||
}
|
||||
return data;
|
||||
case RequestCodeEnum.FAIL:
|
||||
if (show) {
|
||||
msg && feedback.msgError(msg);
|
||||
}
|
||||
return Promise.reject(data);
|
||||
case RequestCodeEnum.LOGIN_FAILURE:
|
||||
clearAuthInfo();
|
||||
router.push(PageEnum.LOGIN);
|
||||
return Promise.reject();
|
||||
case RequestCodeEnum.OPEN_NEW_PAGE:
|
||||
window.location.href = data.url;
|
||||
return data;
|
||||
default:
|
||||
return data;
|
||||
}
|
||||
},
|
||||
responseInterceptorsCatchHook(error) {
|
||||
NProgress.done();
|
||||
if (error.code !== AxiosError.ERR_CANCELED) {
|
||||
error.message && feedback.msgError(error.message);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
},
|
||||
};
|
||||
|
||||
const defaultOptions: AxiosRequestConfig = {
|
||||
//接口超时时间
|
||||
timeout: configs.timeout,
|
||||
// 基础接口地
|
||||
baseURL: configs.baseUrl,
|
||||
|
||||
// baseURL: "http://192.168.1.11:8081/",
|
||||
|
||||
//请求头
|
||||
headers: { "Content-Type": ContentTypeEnum.JSON, version: configs.version },
|
||||
// 处理 axios的钩子函数
|
||||
axiosHooks: axiosHooks,
|
||||
// 每个接口可以单独配置
|
||||
requestOptions: {
|
||||
// 是否将params视为data参数,仅限post请求
|
||||
isParamsToData: true,
|
||||
//是否返回默认的响应
|
||||
isReturnDefaultResponse: false,
|
||||
// 需要对返回数据进行处理
|
||||
isTransformResponse: true,
|
||||
// 接口拼接地址
|
||||
urlPrefix: "",
|
||||
// 忽略重复请求
|
||||
ignoreCancelToken: false,
|
||||
// 是否携带token
|
||||
withToken: true,
|
||||
// 开启请求超时重新发起请求请求机制
|
||||
isOpenRetry: true,
|
||||
// 重新请求次数
|
||||
retryCount: 2,
|
||||
},
|
||||
};
|
||||
|
||||
function createAxios(opt?: Partial<AxiosRequestConfig>) {
|
||||
return new Axios(
|
||||
// 深度合并
|
||||
merge(defaultOptions, opt || {})
|
||||
);
|
||||
}
|
||||
const request = createAxios();
|
||||
export default request;
|
686
src/views/business/index.vue
Normal file
686
src/views/business/index.vue
Normal file
@ -0,0 +1,686 @@
|
||||
<template>
|
||||
<div class="box">
|
||||
<div class="talk-list">
|
||||
<div class="mt-4 serch">
|
||||
<el-input v-model="queryUserName" placeholder="搜索联系人" class="input-with-select">
|
||||
<template #append>
|
||||
<el-button :icon="Search" @click="serchUserFn" />
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div style="height: 5vh;"></div>
|
||||
|
||||
<div class="contacts" v-for="(item, index) in userList" :key="index" @click="choseTalkFn(item, index)">
|
||||
<div class="l">
|
||||
<div style="position: relative;">
|
||||
<el-image style="width: 40px; height: 40px" :src="item.avatar" />
|
||||
<div class="brage" v-if="item.no_read_num">{{ item.no_read_num }}</div>
|
||||
</div>
|
||||
<div class="tit-a">
|
||||
<div>{{ item.name }}</div>
|
||||
<div v-if="item.last_msg_type == 'text'" class="value">{{ item.last_msg_content }}</div>
|
||||
<div v-if="item.last_msg_type == 'image'" class="value">[图片]</div>
|
||||
<div v-if="item.last_msg_type == 'video'" class="value">[视频]</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="r">
|
||||
{{ timeFn(item.last_msg_time) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="talk-detail" id="content">
|
||||
<div class="top">
|
||||
{{ talkDetail.name }}
|
||||
</div>
|
||||
<div style="height: 4vh"></div>
|
||||
<div class="center" id="center" @scroll="handleScroll">
|
||||
<div class="talk" v-for="(item, index) in talkDetail.talkList" :key="index">
|
||||
|
||||
<div style="text-align: center;" v-show="index % 5 == 0">{{ timeFn(item.create_time) }}</div>
|
||||
<!-- 我的消息 -->
|
||||
<div class="my_task" v-if="item.from_user_id == user_id">
|
||||
<div class="content">
|
||||
<!-- 文本 -->
|
||||
<div v-if="item.type == 'text'">
|
||||
<a :href="item.content" v-if="isLink(item.content)" target="_blank"
|
||||
style="color: #576B95;">{{
|
||||
item.content }}
|
||||
</a>
|
||||
<div v-else> {{ item.content }}</div>
|
||||
</div>
|
||||
<!-- 图片 -->
|
||||
<div v-if="item.type == 'image'">
|
||||
<el-image style="width: 100px;height: auto;" :src="item.content" :preview-src-list="srcList"
|
||||
@click="PreviewImgFn(item)"></el-image>
|
||||
</div>
|
||||
<!-- 视频 -->
|
||||
<div v-if="item.type == 'video'">
|
||||
<video controls :src="item.content"></video>
|
||||
</div>
|
||||
</div>
|
||||
<el-image style="width: 40px; height: 40px" :src="userStore.userInfo.avatar" />
|
||||
</div>
|
||||
<!-- 对方消息 -->
|
||||
<div class="to_task" v-else>
|
||||
<el-image style="width: 40px; height: 40px;margin-right: 5px;" :src="item.from_user_avatar" />
|
||||
<div class="content">
|
||||
<!-- 文本 -->
|
||||
<div v-if="item.type == 'text'">
|
||||
<a :href="item.content" target="_blank" v-if="isLink(item.content)"
|
||||
style="color: #576B95;">{{
|
||||
item.content }}
|
||||
</a>
|
||||
<div v-else> {{ item.content }}</div>
|
||||
</div>
|
||||
<!-- 图片 -->
|
||||
<div v-if="item.type == 'image'">
|
||||
<el-image style="width: 100px;height: auto;" :src="item.content" :preview-src-list="srcList"
|
||||
@click="PreviewImgFn(item)"></el-image>
|
||||
</div>
|
||||
<!-- 视频 -->
|
||||
<div v-if="item.type == 'video'">
|
||||
<video controls :src="item.content"></video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- 本地 -->
|
||||
<div v-show="item.status" class="my_task" v-for="item, index in local">
|
||||
<!-- <div></div> -->
|
||||
<!-- <div >上传中</div> -->
|
||||
<div class="content" v-loading="true">
|
||||
<div style="width: 120px;margin-right: 10px;">
|
||||
<video controls :src="item.localSrc" v-if="item.type == 'video'"></video>
|
||||
<img controls :src="item.localSrc" v-else />
|
||||
</div>
|
||||
<!-- <el-progress :text-inside="true" :stroke-width="14" :percentage="item.percentage" /> -->
|
||||
</div>
|
||||
<el-image style="width: 40px; height: 40px;margin-right: 10px;" :src="url" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div style="display: flex;">
|
||||
<el-upload :action="base_url + '/common/im/sendFileMsg'" :data="{
|
||||
from_user_id: user_id,
|
||||
to_user_id: talkDetail.to_user_id,
|
||||
scene: 1,
|
||||
type: 'image',
|
||||
msg_id: msg_id
|
||||
|
||||
}" multiple :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="changeFile">
|
||||
<img class="img_cls" src="@/assets/images/XC.png" style="width: 50px;height: 50px;" />
|
||||
</el-upload>
|
||||
<el-upload :action="base_url + '/common/im/sendFileMsg'" :data="{
|
||||
from_user_id: user_id,
|
||||
to_user_id: talkDetail.to_user_id,
|
||||
scene: 1,
|
||||
type: 'video',
|
||||
msg_id: msg_id
|
||||
}" multiple :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="changeFile1">
|
||||
|
||||
<img style="width: 50px; height: 50px" src="@/assets/images/SP.png" />
|
||||
</el-upload>
|
||||
</div>
|
||||
<el-input v-model="textarea" style="border: none;outline: none;" placeholder="请输入..."
|
||||
@keydown="keyup_submit(event)" />
|
||||
<div class="send-btn" @click="sendMsgFn">发送</div>
|
||||
</div>
|
||||
<!-- <div style="height: 30vh;"></div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" scoped setup>
|
||||
import { reactive, ref, onBeforeUnmount } from 'vue';
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import feedback from '@/utils/feedback'
|
||||
import {
|
||||
sendMsgApi, getMsgListApi, bindScoket, sendFileApi, getContactListApi
|
||||
} from "@/api/talk"
|
||||
import { ElMessage } from 'element-plus'
|
||||
import useUserStore from "@/stores/modules/user";
|
||||
import { inject } from "vue";
|
||||
const base_url: any = inject("base_url").replace('adminapi', '');
|
||||
const userStore = useUserStore();
|
||||
const user_id = userStore.userInfo.id
|
||||
let page_no = 1
|
||||
let to_id: any = null
|
||||
// 图片预览
|
||||
const srcList: any = reactive(
|
||||
[]
|
||||
)
|
||||
const PreviewImgFn = (item: any) => {
|
||||
srcList[0] = item.content
|
||||
}
|
||||
// 上拉加载
|
||||
const handleScroll = (e) => {
|
||||
let top = e.target.scrollTop
|
||||
if (top <= 0) {
|
||||
page_no++
|
||||
getMsgListApi({
|
||||
from_user_id: user_id,
|
||||
to_user_id: to_id,
|
||||
scene: 1,
|
||||
page_no: page_no,
|
||||
page_size: 10
|
||||
}).then(res2 => {
|
||||
if (res2.length <= 0) return
|
||||
talkDetail.talkList = res2.reverse().concat(talkDetail.talkList)
|
||||
e.target.scrollTop = 100
|
||||
})
|
||||
}
|
||||
}
|
||||
let bind = false
|
||||
// 获取用户列表
|
||||
const userList = reactive([])
|
||||
let queryList = reactive([])
|
||||
const talkDetail = reactive({
|
||||
name: "",
|
||||
to_user_id: "",
|
||||
talkList: [],
|
||||
index: 0,
|
||||
})
|
||||
getContactListApi({ user_id: user_id }).then(res => {
|
||||
res.forEach((element: any) => {
|
||||
userList.push(element)
|
||||
queryList.push(element)
|
||||
});
|
||||
// queryList = userList
|
||||
console.log(queryList, 6666)
|
||||
talkDetail.name = userList[0].name
|
||||
talkDetail.to_user_id = userList[0].id
|
||||
to_id = userList[0].id
|
||||
getMsgListApi({
|
||||
from_user_id: user_id,
|
||||
to_user_id: userList[0].id,
|
||||
scene: 1,
|
||||
page_no: 1,
|
||||
page_size: 10
|
||||
}).then(res2 => {
|
||||
talkDetail.talkList = res2.reverse()
|
||||
// console.log(talkDetail)
|
||||
})
|
||||
})
|
||||
const url = 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg'
|
||||
// 用户搜索
|
||||
const queryUserName = ref('')
|
||||
const serchUserFn = () => {
|
||||
getContactListApi({ user_id: user_id, keywords: queryUserName.value }).then(res => {
|
||||
userList.splice(0, userList.length);
|
||||
res.forEach((element: any) => {
|
||||
// @ts-ignore
|
||||
userList.push(element)
|
||||
// queryList.push(element)
|
||||
});
|
||||
})
|
||||
}
|
||||
// 发送文本消息
|
||||
const isLink = (text: string) => {
|
||||
var pattern = /^(https?:\/\/|www\.|.*\.com).*$/i;
|
||||
return pattern.test(text);
|
||||
}
|
||||
const textarea = ref("")
|
||||
const sendMsgFn = () => {
|
||||
if (!textarea.value) return
|
||||
sendMsgApi({
|
||||
from_user_id: user_id,
|
||||
to_user_id: talkDetail.to_user_id,
|
||||
type: "text",
|
||||
content: textarea.value,
|
||||
scene: 1,
|
||||
msg_id: msg_id.value
|
||||
}).then(res => {
|
||||
talkDetail.talkList.push(res)
|
||||
userList[talkDetail.index].last_msg_content = textarea.value
|
||||
userList[talkDetail.index].last_msg_time = res.create_time
|
||||
userList[talkDetail.index].last_msg_type = 'text'
|
||||
// userList[talkDetail.index].last_msg_content = textarea.value
|
||||
scrollFn()
|
||||
textarea.value = ""
|
||||
generateRandId()
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
const keyup_submit = (evt: any) => {
|
||||
var evt = window.event || evt;
|
||||
if (evt.keyCode == 13) {
|
||||
sendMsgFn()
|
||||
}
|
||||
}
|
||||
// 发送媒体消息
|
||||
let msg_id: any = ref('')
|
||||
const generateRandId = () => {
|
||||
var d = new Date().getTime();
|
||||
var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
||||
var r = (d + Math.random() * 16) % 16 | 0;
|
||||
d = Math.floor(d / 16);
|
||||
return (c == "x" ? r : r & 0x3 | 0x8).toString(16);
|
||||
});
|
||||
// return uuid;
|
||||
msg_id.value = uuid
|
||||
}
|
||||
generateRandId()
|
||||
const local = reactive([])
|
||||
let localData = () => {
|
||||
return {
|
||||
status: false,
|
||||
localType: null,
|
||||
localSrc: null,
|
||||
type: "",
|
||||
percentage: 0,
|
||||
msg_id: msg_id.value
|
||||
}
|
||||
}
|
||||
const changeFile = (res) => {
|
||||
console.log(res.type)
|
||||
|
||||
if (!res.type.includes('image')) {
|
||||
ElMessage.error('请选择正确的图片格式!!')
|
||||
return false
|
||||
}
|
||||
local.push(localData())
|
||||
let type = 'image'
|
||||
var localIndex = local.findIndex(function (element) {
|
||||
return element.msg_id === msg_id.value;
|
||||
});
|
||||
// userList[talkDetail.index].last_msg_type = type
|
||||
let file = res
|
||||
local[localIndex].type = type
|
||||
const blob = file;
|
||||
var reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
//监听文件读取结束后事件
|
||||
reader.onloadend = function (e) {
|
||||
local[localIndex].status = true
|
||||
local[localIndex].localSrc = e.target?.result
|
||||
scrollFn()
|
||||
generateRandId()
|
||||
};
|
||||
}
|
||||
const changeFile1 = (res) => {
|
||||
if (!res.type.includes('video')) {
|
||||
ElMessage.error('请选择正确的视频格式!!')
|
||||
return false
|
||||
}
|
||||
local.push(localData())
|
||||
let type = 'video'
|
||||
var localIndex = local.findIndex(function (element) {
|
||||
return element.msg_id === msg_id.value;
|
||||
});
|
||||
// userList[talkDetail.index].last_msg_type = type
|
||||
let file = res
|
||||
local[localIndex].type = type
|
||||
const blob = file;
|
||||
var reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
//监听文件读取结束后事件
|
||||
reader.onloadend = function (e) {
|
||||
local[localIndex].status = true
|
||||
local[localIndex].localSrc = e.target?.result
|
||||
scrollFn()
|
||||
generateRandId()
|
||||
};
|
||||
}
|
||||
const handleAvatarSuccess: any = (
|
||||
res: any
|
||||
) => {
|
||||
if (res.show == 0) {
|
||||
talkDetail.talkList.push(res.data)
|
||||
}
|
||||
else {
|
||||
feedback.msgError(res.msg)
|
||||
}
|
||||
var localIndex = local.findIndex(function (element) {
|
||||
return element.msg_id === res.data.msg_id;
|
||||
});
|
||||
local[localIndex].status = false
|
||||
userList[talkDetail.index].last_msg_type = res.data.type
|
||||
console.log(res.data)
|
||||
|
||||
}
|
||||
// 选择聊天
|
||||
const choseTalkFn = (item: any, index: number) => {
|
||||
userList[index].no_read_num = 0
|
||||
talkDetail.name = item.name
|
||||
talkDetail.to_user_id = item.id
|
||||
talkDetail.index = index
|
||||
to_id = item.id
|
||||
getMsgListApi({
|
||||
from_user_id: user_id,
|
||||
to_user_id: item.id,
|
||||
scene: 1,
|
||||
page_no: 1,
|
||||
page_size: 10
|
||||
}).then(res2 => {
|
||||
talkDetail.talkList = res2.reverse()
|
||||
scrollFn()
|
||||
|
||||
})
|
||||
}
|
||||
// 滚动底部
|
||||
let scrollTop: any = null
|
||||
onMounted(() => {
|
||||
scrollTop = document.getElementById('center')
|
||||
|
||||
})
|
||||
const scrollFn = () => {
|
||||
setTimeout(() => {
|
||||
scrollTop.scrollTop = 9999999
|
||||
}, 100)
|
||||
}
|
||||
// 时间处理
|
||||
const timeFn = (time) => {
|
||||
const currentDate = new Date(); // 当前日期对象
|
||||
const targetDate = new Date(time * 1000);
|
||||
if (isSameDay(currentDate, targetDate)) {
|
||||
const hours = targetDate.getHours(); // 小时
|
||||
const minutes = targetDate.getMinutes(); // 分钟
|
||||
return hours + ':' + (minutes < 10 ? '0' + minutes : minutes);
|
||||
|
||||
} else if (isYesterday(currentDate, targetDate)) {
|
||||
return '昨天';
|
||||
}
|
||||
const month = targetDate.getMonth() + 1; // 月份(注意月份从0开始,需要加1)
|
||||
const day = targetDate.getDate(); // 日期
|
||||
return month + '月' + day + '日';
|
||||
|
||||
|
||||
}
|
||||
const isSameDay = (date1, date2) => {
|
||||
return (
|
||||
date1.getFullYear() === date2.getFullYear() &&
|
||||
date1.getMonth() === date2.getMonth() &&
|
||||
date1.getDate() === date2.getDate()
|
||||
);
|
||||
}
|
||||
const isYesterday = (currentDate, targetDate) => {
|
||||
const yesterday = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate() - 1);
|
||||
return isSameDay(yesterday, targetDate);
|
||||
}
|
||||
// scoket
|
||||
const socket = new WebSocket('wss://worker-task.lihaink.cn/wss');
|
||||
const onSocketOpen = (event: any) => {
|
||||
console.log('WebSocket连接已打开');
|
||||
}
|
||||
const onSocketMessage = (event: any) => {
|
||||
let data = JSON.parse(event.data)
|
||||
if (!bind) {
|
||||
let client_id = (JSON.parse(event.data).client_id)
|
||||
bindScoket({
|
||||
client_id: client_id,
|
||||
user_id: user_id,
|
||||
scene: 1,
|
||||
}).then(res => {
|
||||
bind = true
|
||||
console.log('绑定成功')
|
||||
})
|
||||
}
|
||||
else if (data.id) {
|
||||
var index = userList.findIndex(function (element) {
|
||||
return element.id == data.from_user_id;
|
||||
});
|
||||
// talkDetail.talkList.push(data)
|
||||
if (data.from_user_id == talkDetail.to_user_id) {
|
||||
console.log(data, "收到scoket消息")
|
||||
talkDetail.talkList.push(data)
|
||||
userList[index].last_msg_content = data.content
|
||||
userList[index].last_msg_time = data.create_time
|
||||
userList[index].last_msg_type = data.type
|
||||
|
||||
scrollFn()
|
||||
} else {
|
||||
userList[index].no_read_num++
|
||||
userList[index].last_msg_content = data.content
|
||||
userList[index].last_msg_time = data.create_time
|
||||
userList[index].last_msg_type = data.type
|
||||
|
||||
// userList.forEach
|
||||
}
|
||||
}
|
||||
console.log(data)
|
||||
}
|
||||
const onSocketClose = (event: any) => {
|
||||
console.log('WebSocket连接已关闭');
|
||||
}
|
||||
const onSocketError = (event: any) => {
|
||||
console.error('WebSocket连接发生错误');
|
||||
}
|
||||
socket.addEventListener('open', onSocketOpen);
|
||||
socket.addEventListener('message', onSocketMessage);
|
||||
socket.addEventListener('close', onSocketClose);
|
||||
socket.addEventListener('error', onSocketError);
|
||||
onBeforeUnmount(() => {
|
||||
socket.close()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-input__wrapper) {
|
||||
box-shadow: none !important;
|
||||
// border-bottom: 1px solid black;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: flex;
|
||||
|
||||
.serch {
|
||||
background-color: #F6F6F6;
|
||||
position: fixed;
|
||||
top: 9vh;
|
||||
width: 17vw;
|
||||
z-index: 99;
|
||||
padding-left: 10px;
|
||||
padding-top: 10px;
|
||||
|
||||
}
|
||||
|
||||
.talk-list {
|
||||
width: 20vw;
|
||||
overflow: hidden;
|
||||
height: 85vh;
|
||||
position: relative;
|
||||
// background-color: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
.contacts {
|
||||
// margin-bottom: 10px;
|
||||
// background-color: red;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.l {
|
||||
display: flex;
|
||||
|
||||
.tit-a {
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
|
||||
.value {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 8vw;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.contacts:active {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.contacts:hover {
|
||||
background-color: #fff;
|
||||
|
||||
}
|
||||
|
||||
.talk-list::-webkit-scrollbar {
|
||||
width: 2px;
|
||||
/* 滚动条宽度 */
|
||||
}
|
||||
|
||||
.talk-list::-webkit-scrollbar-thumb {
|
||||
background-color: #888;
|
||||
/* 滚动条颜色 */
|
||||
border-radius: 1px;
|
||||
/* 滚动条圆角 */
|
||||
}
|
||||
|
||||
.img_cls {
|
||||
|
||||
margin-right: 10PX;
|
||||
margin-bottom: 10PX;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.talk-list:hover {
|
||||
// background-color: #888;
|
||||
overflow: scroll;
|
||||
|
||||
}
|
||||
|
||||
.talk-detail {
|
||||
width: 80vw;
|
||||
height: 85vh;
|
||||
|
||||
.top {
|
||||
position: fixed;
|
||||
height: 4vh;
|
||||
width: 70vw;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
z-index: 9;
|
||||
border-bottom: 1px solid #EAE8E7;
|
||||
}
|
||||
|
||||
.center {
|
||||
height: 65vh;
|
||||
|
||||
overflow-y: scroll;
|
||||
background-color: #fff;
|
||||
|
||||
}
|
||||
|
||||
.bottom {
|
||||
position: fixed;
|
||||
background-color: white;
|
||||
height: 20vh;
|
||||
border-top: 1px solid #EAE8E7;
|
||||
width: 70vw;
|
||||
box-sizing: border-box;
|
||||
// padding-top: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
// overflow: scroll;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.center::-webkit-scrollbar {
|
||||
width: 2px;
|
||||
/* 滚动条宽度 */
|
||||
}
|
||||
|
||||
.center::-webkit-scrollbar-thumb {
|
||||
background-color: #888;
|
||||
/* 滚动条颜色 */
|
||||
border-radius: 5px;
|
||||
/* 滚动条圆角 */
|
||||
}
|
||||
|
||||
.talk {
|
||||
// height: 4vh;
|
||||
// background-color: #fff;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
width: 50px;
|
||||
height: 30px;
|
||||
background-color: green;
|
||||
color: white;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
|
||||
.send-btn:active {
|
||||
background-color: yellowgreen;
|
||||
}
|
||||
|
||||
.my_task {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.content {
|
||||
background-color: #95EC69;
|
||||
border-radius: 5px;
|
||||
// height: 30px;
|
||||
padding: 5px;
|
||||
// height: 40px;
|
||||
// min-height: 40px;
|
||||
margin-right: 5px;
|
||||
line-height: 30px;
|
||||
max-width: 20vw;
|
||||
// overflow: hidden;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.to_task {
|
||||
display: flex;
|
||||
// justify-content: flex-end;
|
||||
|
||||
.content {
|
||||
background-color: #95EC69;
|
||||
border-radius: 5px;
|
||||
// height: 30px;
|
||||
padding: 5px 10px;
|
||||
// height: 40px;
|
||||
// min-height: 40px;
|
||||
margin-right: 5px;
|
||||
line-height: 30px;
|
||||
max-width: 20vw;
|
||||
word-break: break-all;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.brage {
|
||||
background-color: red;
|
||||
color: white;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
line-height: 16px;
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
top: -8px;
|
||||
right: -5px;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user