Merge branch 'cool-team-official:5.x' into 5.x

This commit is contained in:
tttclz 2022-06-17 19:40:35 +08:00 committed by GitHub
commit 77c53c78fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 3038 additions and 428 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"
},
"dependencies": {
"@cool-vue/crud": "^5.0.10",
"@cool-vue/crud": "^5.0.13",
"@element-plus/icons-vue": "^1.1.3",
"@vueuse/core": "^8.2.5",
"axios": "^0.27.2",
"codemirror": "^5.62.0",
"core-js": "^3.6.5",
"echarts": "^5.0.2",
"element-plus": "^2.2.0",
"element-plus": "^2.2.5",
"file-saver": "^2.0.5",
"js-beautify": "^1.13.5",
"lodash": "^4.17.21",
@ -25,6 +25,7 @@
"nprogress": "^0.2.0",
"pinia": "^2.0.12",
"quill": "^1.3.7",
"socket.io-client": "^4.5.1",
"store": "^2.0.12",
"unocss": "^0.31.0",
"vue": "^3.2.32",

View File

@ -3,4 +3,4 @@ export * from "./bootstrap";
export * from "./hook";
export * from "./router";
export * from "./config";
export { storage } from "./utils";
export { storage, module } from "./utils";

View File

@ -86,6 +86,7 @@ export function useEps(service: Service) {
})
.catch((err) => {
console.error("[Eps] 获取失败!", err.message);
createDts([]);
});
}
}

View File

@ -19,6 +19,10 @@
<!-- 工具栏 -->
<ul class="app-topbar__tools">
<li>
<cl-chat />
</li>
<li>
<cl-theme />
</li>
@ -115,6 +119,7 @@ function onCommand(name: string) {
width: 45px;
border-radius: 3px;
cursor: pointer;
margin-left: 10px;
&:hover {
background-color: rgba(0, 0, 0, 0.1);

View File

@ -0,0 +1,265 @@
<template>
<div class="cl-chat__wrap">
<div class="cl-chat__icon" @click="open">
<el-badge :value="unCount">
<el-icon><BellFilled /></el-icon>
</el-badge>
</div>
<!-- 弹框 -->
<cl-dialog
v-model="visible"
title="聊天窗口"
height="630px"
width="1200px"
keep-alive
custom-class="cl-chat__dialog"
:close-on-click-modal="false"
:close-on-press-escape="false"
append-to-body
:controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']"
>
<div
class="cl-chat"
:class="{
'is-mini': app.browser.isMini,
'is-expand': isExpand
}"
>
<div class="cl-chat__session">
<chat-session />
</div>
<div class="cl-chat__right">
<chat-message />
</div>
</div>
<!-- 展开按钮 -->
<template #slot-expand>
<button class="cl-dialog__controls-icon">
<el-icon @click="isExpand = true" v-if="!isExpand">
<notebook />
</el-icon>
<el-icon @click="isExpand = false" v-else>
<arrow-left />
</el-icon>
</button>
</template>
</cl-dialog>
</div>
</template>
<script lang="ts">
export default {
name: "cl-chat"
};
</script>
<script lang="ts" setup>
import { nextTick, provide, ref, watch } from "vue";
import { module } from "/@/cool/utils";
import { useCool, config } from "/@/cool";
import { useBase } from "/$/base";
import { Notebook, ArrowLeft, BellFilled } from "@element-plus/icons-vue";
import { debounce } from "lodash";
import io from "socket.io-client";
import { Socket } from "socket.io-client";
import ChatMessage from "./message.vue";
import ChatSession from "./session.vue";
import { Chat } from "../types";
import { useStore } from "../store";
import dayjs from "dayjs";
const { mitt } = useCool();
//
const { session, message } = useStore();
//
const { app, user } = useBase();
//
const { options } = module.get("chat");
//
const visible = ref(false);
//
const isExpand = ref(true);
//
const unCount = ref(parseInt(Math.random() * 100));
// Socket
let socket: Socket;
//
function connect() {
return refresh();
if (!socket) {
socket = io(config.host + options.path, {
auth: {
token: user.token
}
});
socket.on("connect", () => {
console.log(`connect ${user.info?.nickName}`);
//
socket.on("message", (msg) => {
console.log(msg);
mitt("chat-message", msg);
});
refresh();
});
socket.on("disconnect", (err) => {
console.error(err);
});
}
}
//
function open() {
visible.value = true;
connect();
}
//
function close() {
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(() => {
nextTick(() => {
const box = document.querySelector(".cl-chat .chat-message .list");
box?.scroll({
top: 100000 + Math.random(),
behavior: "smooth"
});
});
}, 300);
//
async function refresh() {
await session.get();
await message.get();
scrollToBottom();
}
provide("chat", {
socket,
send,
scrollToBottom
});
//
watch(
() => app.browser.isMini,
(val) => {
isExpand.value = val ? false : true;
},
{
immediate: true
}
);
defineExpose({
open,
close
});
</script>
<style lang="scss">
.cl-chat {
display: flex;
justify-content: flex-end;
background-color: #eee;
height: 100%;
padding: 5px;
box-sizing: border-box;
position: relative;
&__icon {
padding: 5px;
.el-badge__content {
transform: translateY(-50%) translateX(100%) scale(0.8) !important;
}
}
&__dialog {
.el-dialog__body {
padding: 0;
}
}
&__footer {
padding: 9px 0;
}
&__session {
height: calc(100% - 10px);
width: 345px;
position: absolute;
left: 5px;
top: 5px;
}
&__right {
position: relative;
z-index: 99;
transition: width 0.3s;
width: 100%;
}
&.is-mini {
&.is-expand {
.cl-chat__session {
z-index: 100;
}
}
.cl-chat__session {
width: calc(100% - 10px);
}
.cl-chat__right {
width: 100% !important;
}
}
&.is-expand {
.cl-chat__right {
width: calc(100% - 350px);
}
}
}
</style>

View File

@ -0,0 +1,342 @@
<template>
<div class="chat-message" v-loading="message?.loading" element-loading-text="消息列表加载中">
<!-- 头部 -->
<div class="head">
<template v-if="session?.value">
<div class="avatar">
<el-avatar :size="30" shape="square" :src="session?.value.avatar"></el-avatar>
</div>
<span class="name">{{ session?.value.nickName }}聊天中</span>
<ul class="tools">
<li></li>
</ul>
</template>
</div>
<!-- 消息列表 -->
<div class="list scroller1">
<ul>
<li v-for="(item, index) in list" :key="index">
<div
class="item"
:class="{
'is-right': item.isMy
}"
>
<div class="avatar">
<el-avatar :size="36" shape="square" :src="item.avatar"></el-avatar>
</div>
<div
class="det"
@contextmenu="
(e) => {
onContextMenu(e, item);
}
"
>
<div class="h">
<span class="name">{{ item.nickName }}</span>
</div>
<div class="content">
<!-- 文本 -->
<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>
</li>
</ul>
</div>
<!-- 底部 -->
<div class="footer">
<div class="tools">
<ul>
<li>
<cl-upload @success="onImageSend" :show-file-list="false">
<el-icon><Picture /></el-icon>
</cl-upload>
</li>
</ul>
</div>
<div class="input">
<el-input
v-model="value"
type="textarea"
:rows="4"
resize="none"
:autosize="{
minRows: 4,
maxRows: 10
}"
placeholder="输入内容"
></el-input>
<el-button size="small" type="success" @click="onTextSend" :disabled="!value"
>发送</el-button
>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from "vue";
import { useChat } from "../hooks";
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 { message, session } = useStore();
const { copy } = useClipboard();
const value = ref("");
//
const list = computed(() => {
let n = 0;
return message.list.map((e) => {
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>
<style lang="scss" scoped>
.chat-message {
display: flex;
flex-direction: column;
background-color: #fff;
border-radius: 5px;
height: 100%;
box-sizing: border-box;
.head {
display: flex;
align-items: center;
height: 50px;
padding: 0 10px;
.name {
margin-left: 10px;
font-size: 14px;
}
ul {
li {
list-style: none;
}
}
}
.list {
flex: 1;
background-color: #f7f7f7;
ul {
& > li {
list-style: none;
.date {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
font-size: 12px;
}
.item {
display: flex;
padding: 10px;
.avatar {
margin-right: 10px;
}
.det {
.h {
display: flex;
align-items: center;
.name {
font-size: 12px;
color: #666;
}
}
.content {
display: flex;
flex-direction: column;
margin-top: 5px;
.is-text {
background-color: #fff;
padding: 8px;
border-radius: 0 5px 5px 5px;
max-width: 400px;
font-size: 14px;
}
.is-image {
background-color: #fff;
.el-image {
display: block;
min-height: 100px;
max-width: 200px;
border-radius: 3px;
}
}
}
}
&.is-right {
flex-direction: row-reverse;
.avatar {
margin-left: 10px;
margin-right: 0;
}
.det {
.h {
justify-content: flex-end;
}
.content {
.is-text {
border-radius: 5px 0 5px 5px;
}
}
}
}
}
}
}
}
.footer {
padding: 10px;
.tools {
display: flex;
margin-bottom: 10px;
ul {
li {
height: 26px;
width: 26px;
border-radius: 3px;
margin-right: 10px;
list-style: none;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
font-size: 18px;
&:hover {
background-color: #f7f7f7;
}
}
}
}
.input {
display: flex;
position: relative;
.el-button {
margin-left: 10px;
position: absolute;
right: 10px;
bottom: 10px;
}
}
}
}
</style>

View File

@ -0,0 +1,176 @@
<template>
<div class="chat-session">
<div class="head">
<el-input v-model="keyWord" placeholder="关键字搜索" clearable></el-input>
<ul class="tools">
<li @click="session.get()">
<el-icon :size="16"><Refresh /></el-icon>
</li>
</ul>
</div>
<div class="list" v-loading="session?.loading">
<div class="scroller1">
<div
class="item"
v-for="(item, index) in list"
:key="index"
:class="{
'is-active': item.id == session?.value?.id
}"
@click="toDetail(item)"
>
<div class="avatar">
<el-badge :value="item.num" :hidden="item.num == 0">
<el-avatar shape="square" :src="item.avatar"></el-avatar>
</el-badge>
</div>
<div class="det">
<p class="name">{{ item.nickName }}</p>
<p class="message">
{{ item.text }}
</p>
</div>
<div class="status">
<p class="date">{{ item.createTime }}</p>
</div>
</div>
</div>
<el-empty v-if="list.length == 0" image-size="100" description="暂无会话"></el-empty>
</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from "vue";
import { useChat } from "../hooks";
import { useStore } from "../store";
import { Refresh } from "@element-plus/icons-vue";
import { Chat } from "../types";
const { chat } = useChat();
const { session, message } = useStore();
//
const keyWord = ref("");
//
const list = computed(() => session?.list.filter((e) => e.nickName?.includes(keyWord.value)) || []);
//
async function toDetail(item: Chat.Session) {
session.set(item);
await message.get({ page: 1 });
chat?.scrollToBottom();
}
</script>
<style lang="scss" scoped>
.chat-session {
height: 100%;
width: 100%;
background-color: #fff;
border-radius: 5px;
.head {
display: flex;
border-bottom: 1px solid #f7f7f7;
padding: 10px;
.el-input {
height: 30px;
background-color: #eee !important;
}
.tools {
display: inline-flex;
align-items: center;
li {
height: 30px;
width: 30px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin-left: 10px;
border-radius: 3px;
&:hover {
background-color: #eee;
}
}
}
}
.list {
height: calc(100% - 51px);
overflow: hidden;
.scroller1 {
height: 100%;
}
.item {
display: flex;
padding: 15px 10px;
cursor: pointer;
.avatar {
margin-right: 15px;
:deep(.el-badge__content) {
transform: translateY(-50%) translateX(100%) scale(0.8) !important;
}
}
.det {
flex: 1;
.name,
.message {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.name {
font-size: 14px;
margin-bottom: 4px;
}
.message {
font-size: 12px;
color: #666;
}
}
.status {
display: flex;
flex-direction: column;
align-items: flex-end;
font-size: 12px;
.date {
margin-bottom: 5px;
color: #999;
}
}
&.is-active {
background-color: #eee;
}
&:not(.is-active):hover {
background-color: #f7f7f7;
}
}
}
}
</style>

View File

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

View File

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

View File

@ -0,0 +1,56 @@
import { BaseService, Service } from "/@/cool";
import Mock from "mockjs";
@Service("chat/message")
class ChatMessage extends BaseService {
page() {
return new Promise((resolve) => {
const data = Mock.mock({
"list|20": [
{
id: "@id",
nickName: "@name",
createTime: "@datetime(HH:mm:ss)",
text: "@cparagraph(5)",
"contentType|0-1": 0,
"userId|1-2": 1,
avatar() {
return Mock.Random.image(
"40x40",
Mock.Random.color(),
"#FFF",
"png",
this.nickName[0]
);
},
content() {
return JSON.stringify({
text: this.text,
imageUrl: Mock.Random.image(
"100x100",
Mock.Random.color(),
"#FFF",
"png",
this.nickName
)
});
}
}
]
});
setTimeout(() => {
resolve({
list: data.list,
pagination: {
total: 20,
page: 1,
size: 20
}
});
}, 1000);
});
}
}
export default ChatMessage;

View File

@ -0,0 +1,43 @@
import { BaseService, Service } from "/@/cool";
import Mock from "mockjs";
@Service("chat/session")
class ChatSession extends BaseService {
page() {
return new Promise((resolve) => {
const data = Mock.mock({
"list|20": [
{
id: "@id",
nickName: "@name",
createTime: "@datetime(HH:mm:ss)",
text: "@cparagraph(5)",
"num|0-99": 0,
avatar() {
return Mock.Random.image(
"40x40",
Mock.Random.color(),
"#FFF",
"png",
this.nickName[0]
);
}
}
]
});
setTimeout(() => {
resolve({
list: data.list,
pagination: {
total: 20,
page: 1,
size: 20
}
});
}, 1000);
});
}
}
export default ChatSession;

View File

@ -0,0 +1,12 @@
import { useMessageStore } from "./message";
import { useSessionStore } from "./session";
export function useStore() {
const session = useSessionStore();
const message = useMessageStore();
return {
session,
message
};
}

View File

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

View File

@ -0,0 +1,48 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { useCool } from "/@/cool";
export const useSessionStore = defineStore("chat-session", () => {
const { service } = useCool();
// 加载状态
const loading = ref(false);
// 列表
const list = ref<any[]>([]);
// 选中
const value = ref<any>();
// 获取列表
async function get(params?: any) {
loading.value = true;
// 发送请求
await service.chat.session.page(params).then((res) => {
// 默认加载第一个会话的消息
if (!value.value) {
set(res.list[0]);
}
// 设置列表
list.value = res.list;
});
loading.value = false;
}
// 设置值
function set(data: any) {
// 设置值
value.value = data;
}
return {
loading,
list,
value,
get,
set
};
});

35
src/modules/chat/types/index.d.ts vendored Normal file
View File

@ -0,0 +1,35 @@
import { Socket } from "socket.io-client";
export namespace Chat {
enum ContentType {
"text" = 0,
"image" = 1,
"video" = 2
}
interface Message {
fromId?: string;
toId?: string;
content: {
text?: string;
imageUrl?: string;
[key: string]: any;
};
contentType: ContentType;
[key: string]: any;
}
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>
<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
v-model="list"
@ -610,5 +618,15 @@ defineExpose({
width: 100%;
box-sizing: border-box;
}
&.is-slot {
.cl-upload__list {
margin: 0;
}
.un-drag {
display: flex;
}
}
}
</style>

View File

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

View File

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

130
yarn.lock
View File

@ -984,10 +984,10 @@
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@cool-vue/crud@^5.0.10":
version "5.0.10"
resolved "https://registry.npmjs.org/@cool-vue/crud/-/crud-5.0.10.tgz#c2d70504fccdf89c907e1d32e62a93dd777fba9c"
integrity sha512-a3jZPS+Y/+7IJTA3iYjD7PK83rwtIDrnE0tcf5LfenZ7JnnlXs+QFMRybGypJfoeswsG97JmWFeSY6o/JyALDw==
"@cool-vue/crud@^5.0.13":
version "5.0.13"
resolved "https://registry.npmjs.org/@cool-vue/crud/-/crud-5.0.13.tgz#6fe3dc2b0660ea5ccfa8a7420af97972de3887ec"
integrity sha512-yzzYWAlUKnOiJKX7+OQZgD39xXCyQCcuOWdp8foMWIWdUaWyHTxK3aFDd+V4EuK+T8lWbG+HggE784fKTxZJRQ==
dependencies:
array.prototype.flat "^1.2.4"
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"
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":
version "0.4.3"
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"
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":
version "0.4.5"
resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.4.5.tgz#2e88d16646119cc67d44683f75ee99840475bbfa"
@ -1033,6 +1043,13 @@
dependencies:
"@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":
version "9.2.1"
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"
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"
resolved "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz#a7f69e3665d3da9b115f9e71671dae1b97e13671"
integrity sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==
@ -1178,6 +1195,11 @@
resolved "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
"@socket.io/component-emitter@~3.1.0":
version "3.1.0"
resolved "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
"@trysound/sax@0.2.0":
version "0.2.0"
resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
@ -1807,6 +1829,15 @@
"@vueuse/shared" "8.4.2"
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":
version "8.2.5"
resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.2.5.tgz#51c7d95e04284ea378a5242a2e88b77494e2c117"
@ -1817,6 +1848,11 @@
resolved "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.4.2.tgz#b33e6b7bd5ca69e3f24ea41b149267118bcd566f"
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":
version "8.2.5"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-8.2.5.tgz#1ae200a240c4b8d42d41723b64d8f917aa57ff16"
@ -1831,6 +1867,13 @@
dependencies:
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":
version "1.11.1"
resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@ -2124,6 +2167,11 @@ async-validator@^4.0.7:
resolved "https://registry.npmjs.org/async-validator/-/async-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe"
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:
version "0.4.0"
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -2743,6 +2791,11 @@ dayjs@^1.11.1:
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.2.tgz#fa0f5223ef0d6724b3d8327134890cfe3d72fbe5"
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:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -2750,7 +2803,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
dependencies:
ms "2.0.0"
debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4:
debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -2984,6 +3037,27 @@ element-plus@^2.2.0:
memoize-one "^6.0.0"
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:
version "8.0.0"
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@ -3006,6 +3080,22 @@ end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
engine.io-client@~6.2.1:
version "6.2.2"
resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz#c6c5243167f5943dcd9c4abee1bfc634aa2cbdd0"
integrity sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
engine.io-parser "~5.0.3"
ws "~8.2.3"
xmlhttprequest-ssl "~2.0.0"
engine.io-parser@~5.0.3:
version "5.0.4"
resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0"
integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==
enhanced-resolve@^5.0.0, enhanced-resolve@^5.9.2:
version "5.9.2"
resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9"
@ -5746,6 +5836,24 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
socket.io-client@^4.5.1:
version "4.5.1"
resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz#cab8da71976a300d3090414e28c2203a47884d84"
integrity sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.2"
engine.io-client "~6.2.1"
socket.io-parser "~4.2.0"
socket.io-parser@~4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.0.tgz#3f01e5bc525d94aa52a97ed5cbc12e229bbc4d6b"
integrity sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==
dependencies:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
sortablejs@1.14.0:
version "1.14.0"
resolved "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
@ -6616,6 +6724,11 @@ wrappy@1:
resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@~8.2.3:
version "8.2.3"
resolved "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba"
integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==
xlsx@^0.16.9:
version "0.16.9"
resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.16.9.tgz#dacd5bb46bda6dd3743940c9c3dc1e2171826256"
@ -6632,6 +6745,11 @@ xlsx@^0.16.9:
wmf "~1.0.1"
word "~0.3.0"
xmlhttprequest-ssl@~2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67"
integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==
yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"