添加聊天模块

This commit is contained in:
icssoa 2022-06-14 16:07:47 +08:00
parent f70f4b5d73
commit 68858f794c
17 changed files with 1713 additions and 98 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -9,14 +9,14 @@
"lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix" "lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix"
}, },
"dependencies": { "dependencies": {
"@cool-vue/crud": "^5.0.11", "@cool-vue/crud": "^5.0.13",
"@element-plus/icons-vue": "^1.1.3", "@element-plus/icons-vue": "^1.1.3",
"@vueuse/core": "^8.2.5", "@vueuse/core": "^8.2.5",
"axios": "^0.27.2", "axios": "^0.27.2",
"codemirror": "^5.62.0", "codemirror": "^5.62.0",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"echarts": "^5.0.2", "echarts": "^5.0.2",
"element-plus": "^2.2.0", "element-plus": "^2.2.5",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"js-beautify": "^1.13.5", "js-beautify": "^1.13.5",
"lodash": "^4.17.21", "lodash": "^4.17.21",

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="cl-chat__wrap"> <div class="cl-chat__wrap">
<div class="cl-chat__icon" @click="open"> <div class="cl-chat__icon" @click="open">
<el-badge :value="19"> <el-badge :value="unCount">
<el-icon><BellFilled /></el-icon> <el-icon><BellFilled /></el-icon>
</el-badge> </el-badge>
</div> </div>
@ -15,6 +15,7 @@
keep-alive keep-alive
custom-class="cl-chat__dialog" custom-class="cl-chat__dialog"
:close-on-click-modal="false" :close-on-click-modal="false"
:close-on-press-escape="false"
append-to-body append-to-body
:controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']" :controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']"
> >
@ -50,12 +51,9 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, reactive } from "vue"; export default {
import { useStore } from "../store";
export default defineComponent({
name: "cl-chat" name: "cl-chat"
}); };
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
@ -69,6 +67,9 @@ import io from "socket.io-client";
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
import ChatMessage from "./message.vue"; import ChatMessage from "./message.vue";
import ChatSession from "./session.vue"; import ChatSession from "./session.vue";
import { Chat } from "../types";
import { useStore } from "../store";
import dayjs from "dayjs";
const { mitt } = useCool(); const { mitt } = useCool();
@ -79,7 +80,7 @@ const { session, message } = useStore();
const { app, user } = useBase(); const { app, user } = useBase();
// //
const { options } = module.get("upload"); const { options } = module.get("chat");
// //
const visible = ref(false); const visible = ref(false);
@ -87,6 +88,9 @@ const visible = ref(false);
// //
const isExpand = ref(true); const isExpand = ref(true);
//
const unCount = ref(parseInt(Math.random() * 100));
// Socket // Socket
let socket: Socket; let socket: Socket;
@ -95,7 +99,7 @@ function connect() {
return refresh(); return refresh();
if (!socket) { if (!socket) {
socket = io(config.host + `/chat`, { socket = io(config.host + options.path, {
auth: { auth: {
token: user.token token: user.token
} }
@ -130,6 +134,29 @@ function close() {
visible.value = false; visible.value = false;
} }
//
function send(data: Chat.Message, isAppend?: boolean) {
// socket.emit("message", {});
if (isAppend) {
append(data);
}
}
//
function append(data: Chat.Message) {
message.list.push({
fromId: user.info?.id,
toId: session.value?.userId,
avatar: user.info?.headImg,
nickName: user.info?.nickName,
createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
...data
});
scrollToBottom();
}
// //
const scrollToBottom = debounce(() => { const scrollToBottom = debounce(() => {
nextTick(() => { nextTick(() => {
@ -150,6 +177,7 @@ async function refresh() {
provide("chat", { provide("chat", {
socket, socket,
send,
scrollToBottom scrollToBottom
}); });

View File

@ -21,20 +21,38 @@
<div <div
class="item" class="item"
:class="{ :class="{
'is-right': item.type == 1 'is-right': item.isMy
}" }"
> >
<div class="avatar"> <div class="avatar">
<el-avatar :size="36" shape="square" :src="item.avatar"></el-avatar> <el-avatar :size="36" shape="square" :src="item.avatar"></el-avatar>
</div> </div>
<div class="det"> <div
class="det"
@contextmenu="
(e) => {
onContextMenu(e, item);
}
"
>
<div class="h"> <div class="h">
<span class="name">{{ item.nickName }}</span> <span class="name">{{ item.nickName }}</span>
</div> </div>
<div class="content"> <div class="content">
<div class="is-text"> <!-- 文本 -->
<span>{{ item.text }}</span> <div class="is-text" v-if="item.contentType == 0">
<span>{{ item.content.text }}</span>
</div>
<!-- 图片 -->
<div class="is-image" v-else-if="item.contentType == 1">
<el-image
:src="item.content.imageUrl"
:preview-src-list="previewUrls"
:initial-index="item._index"
scroll-container=".chat-message .list"
/>
</div> </div>
</div> </div>
</div> </div>
@ -47,7 +65,11 @@
<div class="footer"> <div class="footer">
<div class="tools"> <div class="tools">
<ul> <ul>
<li></li> <li>
<cl-upload @success="onImageSend" :show-file-list="false">
<el-icon><Picture /></el-icon>
</cl-upload>
</li>
</ul> </ul>
</div> </div>
@ -63,7 +85,7 @@
}" }"
placeholder="输入内容" placeholder="输入内容"
></el-input> ></el-input>
<el-button size="small" type="success" @click="send" :disabled="!value" <el-button size="small" type="success" @click="onTextSend" :disabled="!value"
>发送</el-button >发送</el-button
> >
</div> </div>
@ -75,17 +97,93 @@
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import { useChat } from "../hooks"; import { useChat } from "../hooks";
import { useStore } from "../store"; import { useStore } from "../store";
import { Picture } from "@element-plus/icons-vue";
import { useBase } from "/$/base";
import { ContextMenu } from "@cool-vue/crud";
import { useClipboard } from "@vueuse/core";
import { Chat } from "../types";
const { user } = useBase();
const { chat } = useChat(); const { chat } = useChat();
const { message, session } = useStore(); const { message, session } = useStore();
const { copy } = useClipboard();
const value = ref(""); const value = ref("");
// //
const list = computed(() => message.list); const list = computed(() => {
let n = 0;
function send() { return message.list.map((e) => {
chat?.scrollToBottom(); if (e.contentType == 1) {
e._index = n++;
}
//
e.isMy = e.fromId == user.info?.id;
return e;
});
});
//
const previewUrls = computed(() =>
message.list
.filter((e) => e.contentType == 1)
.map((e) => e.content?.imageUrl)
.filter(Boolean)
);
//
function onTextSend() {
chat?.send(
{
contentType: 0,
content: {
text: value.value
}
},
true
);
value.value = "";
}
//
function onImageSend(res: any) {
chat?.send(
{
contentType: 1,
content: {
imageUrl: res.url
}
},
true
);
value.value = "";
}
//
function onContextMenu(e: Event, item: Chat.Message) {
ContextMenu.open(e, {
hover: {
target: "content"
},
list: [
{
label: "复制",
callback(done) {
copy(item.content.text || "");
done();
}
},
{
label: "转发"
},
{
label: "删除"
}
]
});
} }
</script> </script>
@ -122,6 +220,8 @@ function send() {
ul { ul {
& > li { & > li {
list-style: none;
.date { .date {
display: flex; display: flex;
align-items: center; align-items: center;
@ -161,9 +261,13 @@ function send() {
font-size: 14px; font-size: 14px;
} }
.is-img { .is-image {
background-color: #fff;
.el-image { .el-image {
max-width: 300px; display: block;
min-height: 100px;
max-width: 200px;
border-radius: 3px; border-radius: 3px;
} }
} }
@ -204,12 +308,20 @@ function send() {
ul { ul {
li { li {
height: 25px; height: 26px;
width: 25px; width: 26px;
border-radius: 3px; border-radius: 3px;
background-color: #eee;
margin-right: 10px; margin-right: 10px;
list-style: none; list-style: none;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-size: 18px;
&:hover {
background-color: #f7f7f7;
}
} }
} }
} }

View File

@ -10,32 +10,33 @@
</ul> </ul>
</div> </div>
<div class="list scroller1" v-loading="session?.loading"> <div class="list" v-loading="session?.loading">
<div <div class="scroller1">
class="item" <div
v-for="(item, index) in list" class="item"
:key="index" v-for="(item, index) in list"
:class="{ :key="index"
'is-active': item.id == session?.value?.id :class="{
}" 'is-active': item.id == session?.value?.id
@click="toDetail(item)" }"
> @click="toDetail(item)"
<div class="avatar"> >
<el-badge :value="item.num" :hidden="item.num == 0"> <div class="avatar">
<el-avatar shape="square" :src="item.avatar"></el-avatar> <el-badge :value="item.num" :hidden="item.num == 0">
</el-badge> <el-avatar shape="square" :src="item.avatar"></el-avatar>
</div> </el-badge>
</div>
<div class="det"> <div class="det">
<p class="name">{{ item.nickName }}</p> <p class="name">{{ item.nickName }}</p>
<p class="message"> <p class="message">
{{ item.text }} {{ item.text }}
</p> </p>
</div> </div>
<div class="status"> <div class="status">
<p class="date">{{ item.createTime }}</p> <p class="date">{{ item.createTime }}</p>
<!-- <el-tag size="small">厦门</el-tag> --> </div>
</div> </div>
</div> </div>
@ -49,19 +50,22 @@ import { computed, ref } from "vue";
import { useChat } from "../hooks"; import { useChat } from "../hooks";
import { useStore } from "../store"; import { useStore } from "../store";
import { Refresh } from "@element-plus/icons-vue"; import { Refresh } from "@element-plus/icons-vue";
import { Chat } from "../types";
const { chat } = useChat(); const { chat } = useChat();
const { session } = useStore(); const { session, message } = useStore();
// //
const keyWord = ref(""); const keyWord = ref("");
// //
const list = computed(() => session?.list.filter((e) => e.nickName.includes(keyWord.value)) || []); const list = computed(() => session?.list.filter((e) => e.nickName?.includes(keyWord.value)) || []);
// //
function toDetail(item: any) { async function toDetail(item: Chat.Session) {
chat?.setSession(item); session.set(item);
await message.get({ page: 1 });
chat?.scrollToBottom();
} }
</script> </script>
@ -105,6 +109,12 @@ function toDetail(item: any) {
.list { .list {
height: calc(100% - 51px); height: calc(100% - 51px);
overflow: hidden;
.scroller1 {
height: 100%;
}
.item { .item {
display: flex; display: flex;
padding: 15px 10px; padding: 15px 10px;

View File

@ -0,0 +1,4 @@
export default {
// socket.io 连接地址
path: "/chat"
};

View File

@ -2,7 +2,7 @@ import { inject } from "vue";
import { Chat } from "../types"; import { Chat } from "../types";
export function useChat() { export function useChat() {
const chat = inject<Chat>("chat"); const chat = inject<Chat.Provide>("chat");
return { return {
chat chat

View File

@ -12,11 +12,8 @@ class ChatMessage extends BaseService {
nickName: "@name", nickName: "@name",
createTime: "@datetime(HH:mm:ss)", createTime: "@datetime(HH:mm:ss)",
text: "@cparagraph(5)", text: "@cparagraph(5)",
content() { "contentType|0-1": 0,
return JSON.stringify({ text: this.text }); "userId|1-2": 1,
},
"contentType|0-3": 0,
"type|0-1": 0,
avatar() { avatar() {
return Mock.Random.image( return Mock.Random.image(
"40x40", "40x40",
@ -25,6 +22,18 @@ class ChatMessage extends BaseService {
"png", "png",
this.nickName[0] this.nickName[0]
); );
},
content() {
return JSON.stringify({
text: this.text,
imageUrl: Mock.Random.image(
"100x100",
Mock.Random.color(),
"#FFF",
"png",
this.nickName
)
});
} }
} }
] ]

View File

@ -12,15 +12,27 @@ export const useMessageStore = defineStore("chat-message", () => {
const list = ref<any[]>([]); const list = ref<any[]>([]);
// 分页 // 分页
const pagination = ref(); const pagination = ref({
page: 1,
total: 0,
size: 20
});
// 获取列表 // 获取列表
async function get(params?: any) { async function get(params?: any) {
loading.value = true; loading.value = true;
// 清空
if (params?.page == 1) {
list.value = [];
}
// 发送请求 // 发送请求
await service.chat.message.page(params).then((res) => { await service.chat.message.page(params).then((res) => {
list.value = res.list; list.value = res.list.map((e) => {
e.content = JSON.parse(e.content);
return e;
});
pagination.value = res.pagination; pagination.value = res.pagination;
}); });

View File

@ -34,8 +34,6 @@ export const useSessionStore = defineStore("chat-session", () => {
// 设置值 // 设置值
function set(data: any) { function set(data: any) {
// 清空消息列表
list.value = [];
// 设置值 // 设置值
value.value = data; value.value = data;
} }

View File

@ -1,31 +1,35 @@
import { Socket } from "socket.io-client"; import { Socket } from "socket.io-client";
export declare interface Item { export namespace Chat {
id: string; enum ContentType {
avatar: string; "text" = 0,
nickName: string; "image" = 1,
[key: string]: any; "video" = 2
} }
export declare interface Chat { interface Message {
socket?: Socket; fromId?: string;
inputValue: string; toId?: string;
session: { content: {
loading: boolean; text?: string;
value?: Item; imageUrl?: string;
list: Item[]; [key: string]: any;
};
message: {
loading: boolean;
list: Item[];
pagination: {
page: number;
total: number;
size: number;
}; };
}; contentType: ContentType;
scrollToBottom(): void; [key: string]: any;
getSession(params?: any): void; }
setSession(data: any): void;
getMessage(params?: any): void; interface Session {
id: string;
avatar: string;
nickName: string;
[key: string]: any;
}
interface Provide {
socket?: Socket;
send(data: Message, isAppend?: boolean): void;
append(data: Message): void;
scrollToBottom(): void;
}
} }

View File

@ -1,6 +1,14 @@
<template> <template>
<div class="cl-upload__wrap"> <div class="cl-upload__wrap">
<div class="cl-upload" :class="[`cl-upload--${type}`]"> <div
class="cl-upload"
:class="[
`cl-upload--${type}`,
{
'is-slot': $slots.default
}
]"
>
<!-- 列表 --> <!-- 列表 -->
<draggable <draggable
v-model="list" v-model="list"
@ -610,5 +618,15 @@ defineExpose({
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
&.is-slot {
.cl-upload__list {
margin: 0;
}
.un-drag {
display: flex;
}
}
} }
</style> </style>

View File

@ -26,7 +26,7 @@
<div class="cl-upload-space__header scroller1"> <div class="cl-upload-space__header scroller1">
<el-button @click="refresh({ page: 1 })">刷新</el-button> <el-button @click="refresh({ page: 1 })">刷新</el-button>
<div :style="{ marginLeft: '10px' }"> <div :style="{ margin: '0px 10px' }">
<cl-upload <cl-upload
ref="Upload" ref="Upload"
type="file" type="file"

View File

@ -17,6 +17,7 @@
<li <li
v-for="(item, index) in flist" v-for="(item, index) in flist"
:key="index" :key="index"
class="item"
:class="{ :class="{
'is-active': item.id == space.category.id 'is-active': item.id == space.category.id
}" }"
@ -141,6 +142,9 @@ function onContextMenu(e: any, { id, name }: any) {
} }
ContextMenu.open(e, { ContextMenu.open(e, {
hover: {
target: "item"
},
list: [ list: [
{ {
label: "刷新", label: "刷新",
@ -238,7 +242,7 @@ onMounted(() => {
ul { ul {
height: 100%; height: 100%;
li { .item {
list-style: none; list-style: none;
font-size: 14px; font-size: 14px;
height: 40px; height: 40px;
@ -251,7 +255,7 @@ onMounted(() => {
color: var(--color-primary); color: var(--color-primary);
} }
&:hover { &:not(.cl-context-menu__target):hover {
background-color: #f7f7f7; background-color: #f7f7f7;
} }
} }

View File

@ -984,10 +984,10 @@
"@babel/helper-validator-identifier" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@cool-vue/crud@^5.0.11": "@cool-vue/crud@^5.0.13":
version "5.0.11" version "5.0.13"
resolved "https://registry.npmjs.org/@cool-vue/crud/-/crud-5.0.11.tgz#fbca5084c4d1e9e82fba00f17bbbb984bd2ee38e" resolved "https://registry.npmjs.org/@cool-vue/crud/-/crud-5.0.13.tgz#6fe3dc2b0660ea5ccfa8a7420af97972de3887ec"
integrity sha512-0N1w5RCZqDKz5DLmhwXNLxZIbJPt/lkW8DuFzXB/cpeZTYYLc+5VubbD+KTah1YyA6C2js+Wt1MlKhC0gY6ROA== integrity sha512-yzzYWAlUKnOiJKX7+OQZgD39xXCyQCcuOWdp8foMWIWdUaWyHTxK3aFDd+V4EuK+T8lWbG+HggE784fKTxZJRQ==
dependencies: dependencies:
array.prototype.flat "^1.2.4" array.prototype.flat "^1.2.4"
core-js "^3.21.1" core-js "^3.21.1"
@ -1006,6 +1006,11 @@
resolved "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz#5d2788ea356f1458068e6d400e724ca5f3d29aca" resolved "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-1.1.4.tgz#5d2788ea356f1458068e6d400e724ca5f3d29aca"
integrity sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ== integrity sha512-Iz/nHqdp1sFPmdzRwHkEQQA3lKvoObk8azgABZ81QUOpW9s/lUyQVUSh0tNtEPZXQlKwlSh7SPgoVxzrE0uuVQ==
"@element-plus/icons-vue@^2.0.5":
version "2.0.5"
resolved "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.0.5.tgz#8eb4143a7b5e4d8468d2e72af99eefee446f5ea0"
integrity sha512-jvNWyKcdvPvMDLTWjghrPY+bYHKqh7hbAFIPe+HWR073zilzt33csREzmKx3VwhdlJUW5u0nCqN+0rwI8jlH+w==
"@eslint/eslintrc@^0.4.3": "@eslint/eslintrc@^0.4.3":
version "0.4.3" version "0.4.3"
resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@ -1026,6 +1031,11 @@
resolved "https://registry.npmjs.org/@floating-ui/core/-/core-0.6.2.tgz#f2813f0e5f3d5ed7af5029e1a082203dadf02b7d" resolved "https://registry.npmjs.org/@floating-ui/core/-/core-0.6.2.tgz#f2813f0e5f3d5ed7af5029e1a082203dadf02b7d"
integrity sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg== integrity sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg==
"@floating-ui/core@^0.7.3":
version "0.7.3"
resolved "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz#d274116678ffae87f6b60e90f88cc4083eefab86"
integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==
"@floating-ui/dom@^0.4.5": "@floating-ui/dom@^0.4.5":
version "0.4.5" version "0.4.5"
resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.4.5.tgz#2e88d16646119cc67d44683f75ee99840475bbfa" resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.4.5.tgz#2e88d16646119cc67d44683f75ee99840475bbfa"
@ -1033,6 +1043,13 @@
dependencies: dependencies:
"@floating-ui/core" "^0.6.2" "@floating-ui/core" "^0.6.2"
"@floating-ui/dom@^0.5.2":
version "0.5.3"
resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.3.tgz#ade192cf9a911fc3e95fb614fe281658b654043c"
integrity sha512-vpjWB1uC7rajvgA58uzlJZgtWqrdDQLw+XVA3w63ZTmsWwRmVd0Gl5Dy9VMAViI9cP7hBWaJt23Jy3AVgVYnoQ==
dependencies:
"@floating-ui/core" "^0.7.3"
"@hapi/hoek@^9.0.0": "@hapi/hoek@^9.0.0":
version "9.2.1" version "9.2.1"
resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17"
@ -1127,7 +1144,7 @@
resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.6": "@popperjs/core@npm:@sxzz/popperjs-es@^2.11.6", "@popperjs/core@npm:@sxzz/popperjs-es@^2.11.7":
version "2.11.7" version "2.11.7"
resolved "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671" resolved "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ== integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
@ -1812,6 +1829,15 @@
"@vueuse/shared" "8.4.2" "@vueuse/shared" "8.4.2"
vue-demi "*" vue-demi "*"
"@vueuse/core@^8.6.0":
version "8.6.0"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-8.6.0.tgz#a8f80363cc63d17382423f16beae57696f376e67"
integrity sha512-VirzExCm/N+QdrEWT7J4uSrvJ5hquKIAU9alQ37kUvIJk9XxCLxmfRnmekYc1kz2+6BnoyuKYXVmrMV351CB4w==
dependencies:
"@vueuse/metadata" "8.6.0"
"@vueuse/shared" "8.6.0"
vue-demi "*"
"@vueuse/metadata@8.2.5": "@vueuse/metadata@8.2.5":
version "8.2.5" version "8.2.5"
resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.2.5.tgz#51c7d95e04284ea378a5242a2e88b77494e2c117" resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.2.5.tgz#51c7d95e04284ea378a5242a2e88b77494e2c117"
@ -1822,6 +1848,11 @@
resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.4.2.tgz#b33e6b7bd5ca69e3f24ea41b149267118bcd566f" resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.4.2.tgz#b33e6b7bd5ca69e3f24ea41b149267118bcd566f"
integrity sha512-2BIj++7P0/I5dfMsEe8q7Kw0HqVAjVcyNOd9+G22/ILUC9TVLTeYOuJ1kwa1Gpr+0LWKHc6GqHiLWNL33+exoQ== integrity sha512-2BIj++7P0/I5dfMsEe8q7Kw0HqVAjVcyNOd9+G22/ILUC9TVLTeYOuJ1kwa1Gpr+0LWKHc6GqHiLWNL33+exoQ==
"@vueuse/metadata@8.6.0":
version "8.6.0"
resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.6.0.tgz#34771443a72ee891ae001a70aa05dd9a1d799372"
integrity sha512-F+CKPvaExsm7QgRr8y+ZNJFwXasn89rs5wth/HeX9lJ1q8XEt+HJ16Q5Sxh4rfG5YSKXrStveVge8TKvPjMjFA==
"@vueuse/shared@8.2.5": "@vueuse/shared@8.2.5":
version "8.2.5" version "8.2.5"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-8.2.5.tgz#1ae200a240c4b8d42d41723b64d8f917aa57ff16" resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-8.2.5.tgz#1ae200a240c4b8d42d41723b64d8f917aa57ff16"
@ -1836,6 +1867,13 @@
dependencies: dependencies:
vue-demi "*" vue-demi "*"
"@vueuse/shared@8.6.0":
version "8.6.0"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-8.6.0.tgz#63dad9fc4b73a7fccbe5d6b97adeacf73d4fec41"
integrity sha512-Y/IVywZo7IfEoSSEtCYpkVEmPV7pU35mEIxV7PbD/D3ly18B3mEsBaPbtDkNM/QP3zAZ5mn4nEkOfddX4uwuIA==
dependencies:
vue-demi "*"
"@webassemblyjs/ast@1.11.1": "@webassemblyjs/ast@1.11.1":
version "1.11.1" version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@ -2129,6 +2167,11 @@ async-validator@^4.0.7:
resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe" resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe"
integrity sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ== integrity sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ==
async-validator@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.1.1.tgz#3cd1437faa2de64743f7d56649dd904c946a18fe"
integrity sha512-p4DO/JXwjs8klJyJL8Q2oM4ks5fUTze/h5k10oPPKMiLe1fj3G1QMzPHNmN1Py4ycOk7WlO2DcGXv1qiESJCZA==
asynckit@^0.4.0: asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -2748,6 +2791,11 @@ dayjs@^1.11.1:
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5" resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5"
integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw== integrity sha512-F4LXf1OeU9hrSYRPTTj/6FbO4HTjPKXvEIC1P2kcnFurViINCVk3ZV0xAS3XVx9MkMsXbbqlK6hjseaYbgKEHw==
dayjs@^1.11.3:
version "1.11.3"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz#4754eb694a624057b9ad2224b67b15d552589258"
integrity sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==
debug@2.6.9, debug@^2.2.0, debug@^2.3.3: debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
version "2.6.9" version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -2989,6 +3037,27 @@ element-plus@^2.2.0:
memoize-one "^6.0.0" memoize-one "^6.0.0"
normalize-wheel-es "^1.1.2" normalize-wheel-es "^1.1.2"
element-plus@^2.2.5:
version "2.2.5"
resolved "https://registry.npmjs.org/element-plus/-/element-plus-2.2.5.tgz#2bb889660c9bcb9bb71e18619915b35e0f48d569"
integrity sha512-Kl0yn/PQca5YQo3M3NPBP4Xl71NQuMtDx5zNXZGVyl5FjdMujXiFB9SXKYGDUCgFU3d/Rl14vB4Fpmcl2Iz+Hw==
dependencies:
"@ctrl/tinycolor" "^3.4.1"
"@element-plus/icons-vue" "^2.0.5"
"@floating-ui/dom" "^0.5.2"
"@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.7"
"@types/lodash" "^4.14.182"
"@types/lodash-es" "^4.17.6"
"@vueuse/core" "^8.6.0"
async-validator "^4.1.1"
dayjs "^1.11.3"
escape-html "^1.0.3"
lodash "^4.17.21"
lodash-es "^4.17.21"
lodash-unified "^1.0.2"
memoize-one "^6.0.0"
normalize-wheel-es "^1.1.2"
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"