mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2024-11-01 14:10:27 +08:00
添加聊天模块
This commit is contained in:
parent
f70f4b5d73
commit
68858f794c
File diff suppressed because one or more lines are too long
1347
build/cool/temp/service.d.ts
vendored
1347
build/cool/temp/service.d.ts
vendored
File diff suppressed because it is too large
Load Diff
@ -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",
|
||||||
|
@ -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
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="list scroller1" v-loading="session?.loading">
|
<div class="list" v-loading="session?.loading">
|
||||||
|
<div class="scroller1">
|
||||||
<div
|
<div
|
||||||
class="item"
|
class="item"
|
||||||
v-for="(item, index) in list"
|
v-for="(item, index) in list"
|
||||||
@ -35,7 +36,7 @@
|
|||||||
|
|
||||||
<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;
|
||||||
|
4
src/modules/chat/config.ts
Normal file
4
src/modules/chat/config.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
// socket.io 连接地址
|
||||||
|
path: "/chat"
|
||||||
|
};
|
@ -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
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
46
src/modules/chat/types/index.d.ts
vendored
46
src/modules/chat/types/index.d.ts
vendored
@ -1,31 +1,35 @@
|
|||||||
import { Socket } from "socket.io-client";
|
import { Socket } from "socket.io-client";
|
||||||
|
|
||||||
export declare interface Item {
|
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;
|
id: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
nickName: string;
|
nickName: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare interface Chat {
|
interface Provide {
|
||||||
socket?: Socket;
|
socket?: Socket;
|
||||||
inputValue: string;
|
send(data: Message, isAppend?: boolean): void;
|
||||||
session: {
|
append(data: Message): void;
|
||||||
loading: boolean;
|
|
||||||
value?: Item;
|
|
||||||
list: Item[];
|
|
||||||
};
|
|
||||||
message: {
|
|
||||||
loading: boolean;
|
|
||||||
list: Item[];
|
|
||||||
pagination: {
|
|
||||||
page: number;
|
|
||||||
total: number;
|
|
||||||
size: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
scrollToBottom(): void;
|
scrollToBottom(): void;
|
||||||
getSession(params?: any): void;
|
}
|
||||||
setSession(data: any): void;
|
|
||||||
getMessage(params?: any): void;
|
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
79
yarn.lock
79
yarn.lock
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user