2025-05-04 18:45:03 +08:00
|
|
|
<script setup lang="ts">
|
|
|
|
import type {
|
|
|
|
AttachmentsProps,
|
|
|
|
BubbleListProps,
|
|
|
|
ConversationsProps,
|
|
|
|
PromptsProps,
|
|
|
|
} from 'ant-design-x-vue';
|
2025-05-02 22:08:36 +08:00
|
|
|
|
2025-05-04 18:45:03 +08:00
|
|
|
import type { VNode } from 'vue';
|
2025-05-02 22:08:36 +08:00
|
|
|
|
2025-05-04 18:45:03 +08:00
|
|
|
import { computed, h, onMounted, ref, watch } from 'vue';
|
2025-05-02 22:08:36 +08:00
|
|
|
|
2025-05-04 18:45:03 +08:00
|
|
|
import {
|
|
|
|
CloudUploadOutlined,
|
|
|
|
CommentOutlined,
|
|
|
|
CopyOutlined,
|
|
|
|
DeleteOutlined,
|
|
|
|
EllipsisOutlined,
|
|
|
|
FireOutlined,
|
|
|
|
HeartOutlined,
|
|
|
|
PaperClipOutlined,
|
|
|
|
PlusOutlined,
|
|
|
|
ReadOutlined,
|
|
|
|
ShareAltOutlined,
|
|
|
|
SmileOutlined,
|
|
|
|
SyncOutlined,
|
|
|
|
} from '@ant-design/icons-vue';
|
|
|
|
import VueOfficePptx from '@vue-office/pptx';
|
|
|
|
import {
|
|
|
|
Badge,
|
|
|
|
Button,
|
|
|
|
Flex,
|
|
|
|
message,
|
|
|
|
Space,
|
|
|
|
theme,
|
|
|
|
Typography,
|
|
|
|
} from 'ant-design-vue';
|
|
|
|
import {
|
|
|
|
Attachments,
|
|
|
|
Bubble,
|
|
|
|
Conversations,
|
|
|
|
Prompts,
|
|
|
|
Sender,
|
|
|
|
useXAgent,
|
|
|
|
useXChat,
|
|
|
|
Welcome,
|
|
|
|
} from 'ant-design-x-vue';
|
|
|
|
|
|
|
|
import { getChatList, sendWorkflow } from '#/api';
|
|
|
|
|
|
|
|
defineOptions({ name: 'PlaygroundIndependentSetup' });
|
|
|
|
|
|
|
|
const { token } = theme.useToken();
|
|
|
|
|
|
|
|
const styles = computed(() => {
|
|
|
|
return {
|
|
|
|
layout: {
|
|
|
|
width: '100%',
|
|
|
|
'min-width': '1000px',
|
|
|
|
height: '722px',
|
|
|
|
'border-radius': `${token.value.borderRadius}px`,
|
|
|
|
display: 'flex',
|
|
|
|
background: `${token.value.colorBgContainer}`,
|
|
|
|
'font-family': `AlibabaPuHuiTi, ${token.value.fontFamily}, sans-serif`,
|
|
|
|
},
|
|
|
|
menu: {
|
|
|
|
background: `${token.value.colorBgLayout}80`,
|
|
|
|
width: '280px',
|
|
|
|
height: '100%',
|
|
|
|
display: 'flex',
|
|
|
|
'flex-direction': 'column',
|
|
|
|
},
|
|
|
|
conversations: {
|
|
|
|
padding: '0 12px',
|
|
|
|
flex: 1,
|
|
|
|
'overflow-y': 'auto',
|
|
|
|
},
|
|
|
|
chat: {
|
|
|
|
height: '100%',
|
|
|
|
width: '100%',
|
|
|
|
'max-width': '700px',
|
|
|
|
margin: '0 auto',
|
|
|
|
'box-sizing': 'border-box',
|
|
|
|
display: 'flex',
|
|
|
|
'flex-direction': 'column',
|
|
|
|
padding: `${token.value.paddingLG}px`,
|
|
|
|
gap: '16px',
|
|
|
|
},
|
|
|
|
messages: {
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
placeholder: {
|
|
|
|
'padding-top': '32px',
|
|
|
|
'text-align': 'left',
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
sender: {
|
|
|
|
'box-shadow': token.value.boxShadow,
|
|
|
|
},
|
|
|
|
logo: {
|
|
|
|
display: 'flex',
|
|
|
|
height: '72px',
|
|
|
|
'align-items': 'center',
|
|
|
|
'justify-content': 'start',
|
|
|
|
padding: '0 24px',
|
|
|
|
'box-sizing': 'border-box',
|
|
|
|
},
|
|
|
|
'logo-img': {
|
|
|
|
width: '24px',
|
|
|
|
height: '24px',
|
|
|
|
display: 'inline-block',
|
|
|
|
},
|
|
|
|
'logo-span': {
|
|
|
|
display: 'inline-block',
|
|
|
|
margin: '0 8px',
|
|
|
|
'font-weight': 'bold',
|
|
|
|
color: token.value.colorText,
|
|
|
|
'font-size': '16px',
|
|
|
|
},
|
|
|
|
addBtn: {
|
|
|
|
background: '#1677ff0f',
|
|
|
|
border: '1px solid #1677ff34',
|
|
|
|
width: 'calc(100% - 24px)',
|
|
|
|
margin: '0 12px 24px 12px',
|
|
|
|
},
|
|
|
|
} as const;
|
|
|
|
});
|
|
|
|
|
|
|
|
const pptx = ref<any>('/static/43b7da46a6ca47e5a9d7710d8dcf499c.pptx');
|
|
|
|
|
|
|
|
const [messageApi, contextHolder] = message.useMessage();
|
|
|
|
|
|
|
|
const menuConfig: ConversationsProps['menu'] = (conversation) => ({
|
|
|
|
items: [
|
|
|
|
{
|
|
|
|
label: '删除此对话',
|
|
|
|
key: 'operation3',
|
|
|
|
icon: h(DeleteOutlined),
|
|
|
|
danger: true,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
onClick: (menuInfo) => {
|
|
|
|
messageApi.info(`Click ${conversation.key} - ${menuInfo.key}`);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const acticeModeKey = ref('1');
|
|
|
|
|
|
|
|
// 定义模板数据
|
|
|
|
const templates = ref([
|
|
|
|
{ label: '模板1', key: '1' },
|
|
|
|
{ label: '模板2', key: '2' },
|
|
|
|
{ label: '模板3', key: '3' },
|
|
|
|
{ label: '模板34', key: '4' },
|
|
|
|
{ label: '模板35', key: '5' },
|
|
|
|
{ label: '模板36', key: '7' },
|
|
|
|
{ label: '模板37', key: '8' },
|
|
|
|
{ label: '模板38', key: '9' },
|
|
|
|
]);
|
|
|
|
|
|
|
|
// const sleep = () => new Promise(resolve => setTimeout(resolve, 500))
|
|
|
|
|
|
|
|
function renderTitle(icon: VNode, title: string) {
|
|
|
|
return h(Space, { align: 'start' }, [icon, h('span', title)]);
|
|
|
|
}
|
|
|
|
|
|
|
|
const defaultConversationsItems = [
|
|
|
|
{
|
|
|
|
key: '0',
|
|
|
|
label: 'What is Ant Design X?',
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
const placeholderPromptsItems: PromptsProps['items'] = [
|
|
|
|
{
|
|
|
|
key: '1',
|
|
|
|
label: renderTitle(
|
|
|
|
h(FireOutlined, { style: { color: '#FF4D4F' } }),
|
|
|
|
'Hot Topics',
|
|
|
|
),
|
|
|
|
description: 'What are you interested in?',
|
|
|
|
children: [
|
|
|
|
{
|
|
|
|
key: '1-1',
|
|
|
|
description: `What's new in X?`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: '1-2',
|
|
|
|
description: `What's AGI?`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: '1-3',
|
|
|
|
description: `Where is the doc?`,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
2025-05-02 22:08:36 +08:00
|
|
|
{
|
2025-05-04 18:45:03 +08:00
|
|
|
key: '2',
|
|
|
|
label: renderTitle(
|
|
|
|
h(ReadOutlined, { style: { color: '#1890FF' } }),
|
|
|
|
'Design Guide',
|
|
|
|
),
|
|
|
|
description: 'How to design a good product?',
|
|
|
|
children: [
|
|
|
|
{
|
|
|
|
key: '2-1',
|
|
|
|
icon: h(HeartOutlined),
|
|
|
|
description: `Know the well`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: '2-2',
|
|
|
|
icon: h(SmileOutlined),
|
|
|
|
description: `Set the AI role`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: '2-3',
|
|
|
|
icon: h(CommentOutlined),
|
|
|
|
description: `Express the feeling`,
|
|
|
|
},
|
|
|
|
],
|
2025-05-02 22:08:36 +08:00
|
|
|
},
|
2025-05-04 18:45:03 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
const senderPromptsItems: PromptsProps['items'] = [
|
2025-05-02 22:08:36 +08:00
|
|
|
{
|
2025-05-04 18:45:03 +08:00
|
|
|
key: '1',
|
|
|
|
description: 'Hot Topics',
|
|
|
|
icon: h(FireOutlined, { style: { color: '#FF4D4F' } }),
|
2025-05-02 22:08:36 +08:00
|
|
|
},
|
|
|
|
{
|
2025-05-04 18:45:03 +08:00
|
|
|
key: '2',
|
|
|
|
description: 'Design Guide',
|
|
|
|
icon: h(ReadOutlined, { style: { color: '#1890FF' } }),
|
2025-05-02 22:08:36 +08:00
|
|
|
},
|
|
|
|
];
|
|
|
|
|
2025-05-04 18:45:03 +08:00
|
|
|
const roles: BubbleListProps['roles'] = {
|
|
|
|
ai: {
|
|
|
|
placement: 'start',
|
|
|
|
typing: { step: 5, interval: 20 },
|
|
|
|
styles: {
|
|
|
|
content: {
|
|
|
|
borderRadius: '16px',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
local: {
|
|
|
|
placement: 'end',
|
|
|
|
variant: 'shadow',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// ==================== State ====================
|
|
|
|
const headerOpen = ref(false);
|
|
|
|
const content = ref('');
|
|
|
|
const conversationsItems = ref(defaultConversationsItems);
|
|
|
|
const activeKey = ref(defaultConversationsItems[0]?.key);
|
|
|
|
const attachedFiles = ref<AttachmentsProps['items']>([]);
|
|
|
|
const agentRequestLoading = ref(false);
|
|
|
|
|
|
|
|
// ==================== Runtime ====================
|
|
|
|
const [agent] = useXAgent({
|
|
|
|
request: async ({ message }, { onSuccess }) => {
|
|
|
|
agentRequestLoading.value = true;
|
|
|
|
const res = await sendWorkflow(
|
|
|
|
{
|
|
|
|
appid: 'baca08c1-e92b-4dc9-a445-3584803f54d4',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
userId: '1562',
|
|
|
|
conversationId: '',
|
|
|
|
files: [],
|
|
|
|
inputs: {
|
|
|
|
declarationDoc: message,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
agentRequestLoading.value = false;
|
|
|
|
if (res.data.data.outputs.result) {
|
|
|
|
onSuccess(`下载链接:${res.data.data.outputs.result}`);
|
|
|
|
const url = new URL(res.data.data.outputs.result);
|
|
|
|
pptx.value = url.pathname;
|
|
|
|
} else {
|
|
|
|
onSuccess('发生异常,可以输入更多信息再让我来回答或重试。');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const { onRequest, messages, setMessages } = useXChat({
|
|
|
|
agent: agent?.value,
|
|
|
|
});
|
|
|
|
|
|
|
|
watch(
|
|
|
|
activeKey,
|
|
|
|
() => {
|
|
|
|
if (activeKey.value !== undefined) {
|
|
|
|
setMessages([]);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{ immediate: true },
|
|
|
|
);
|
|
|
|
|
|
|
|
// ==================== Event ====================
|
|
|
|
function onSubmit(nextContent: string) {
|
|
|
|
if (!nextContent) return;
|
|
|
|
onRequest(nextContent);
|
|
|
|
// sendMessage(nextContent)
|
|
|
|
content.value = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
const onPromptsItemClick: PromptsProps['onItemClick'] = (info) => {
|
|
|
|
onRequest(info.data.description as string);
|
|
|
|
};
|
|
|
|
|
|
|
|
function onAddConversation() {
|
|
|
|
conversationsItems.value = [
|
|
|
|
...conversationsItems.value,
|
|
|
|
{
|
|
|
|
key: `${conversationsItems.value.length}`,
|
|
|
|
label: `New Conversation ${conversationsItems.value.length}`,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
activeKey.value = `${conversationsItems.value.length}`;
|
2025-05-02 22:08:36 +08:00
|
|
|
}
|
2025-05-04 18:45:03 +08:00
|
|
|
|
|
|
|
const onConversationClick: ConversationsProps['onActiveChange'] = (key) => {
|
|
|
|
activeKey.value = key;
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleFileChange: AttachmentsProps['onChange'] = (info) =>
|
|
|
|
(attachedFiles.value = info.fileList);
|
|
|
|
|
|
|
|
// ==================== Nodes ====================
|
|
|
|
const placeholderNode = computed(() =>
|
|
|
|
h(
|
|
|
|
Space,
|
|
|
|
{ direction: 'vertical', size: 16, style: styles.value.placeholder },
|
|
|
|
[
|
|
|
|
h(Welcome, {
|
|
|
|
variant: 'borderless',
|
|
|
|
icon: 'https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp',
|
|
|
|
title: "Hello, I'm Ant Design X",
|
|
|
|
description:
|
|
|
|
'Base on Ant Design, AGI product interface solution, create a better intelligent vision~',
|
|
|
|
extra: h(Space, {}, [
|
|
|
|
h(Button, { icon: h(ShareAltOutlined) }),
|
|
|
|
h(Button, { icon: h(EllipsisOutlined) }),
|
|
|
|
]),
|
|
|
|
}),
|
|
|
|
h(Prompts, {
|
|
|
|
title: 'Do you want?',
|
|
|
|
items: placeholderPromptsItems,
|
|
|
|
styles: {
|
|
|
|
list: {
|
|
|
|
width: '100%',
|
|
|
|
},
|
|
|
|
item: {
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
onItemClick: onPromptsItemClick,
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
const items = computed<BubbleListProps['items']>(() => {
|
|
|
|
if (messages.value.length === 0) {
|
|
|
|
return [{ content: placeholderNode, variant: 'borderless' }];
|
|
|
|
}
|
|
|
|
return messages.value.map(({ id, message, status }) => ({
|
|
|
|
key: id,
|
|
|
|
loading: status === 'loading',
|
|
|
|
role: status === 'local' ? 'local' : 'ai',
|
|
|
|
content: message,
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
|
|
|
|
// 自定义代码
|
|
|
|
|
|
|
|
// 获取会话记录
|
|
|
|
const getConversationList = async () => {
|
|
|
|
const res = await getChatList(
|
|
|
|
{
|
|
|
|
appid: '363b9580-ae60-4a40-ae7d-ec434e86e326',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
userId: '1562',
|
|
|
|
lastId: '4dfa17e1-364a-4c98-af5d-1109c8f28212',
|
|
|
|
sortBy: '',
|
|
|
|
limit: '5',
|
|
|
|
},
|
|
|
|
);
|
|
|
|
if (res.status === 200) {
|
|
|
|
conversationsItems.value = res.data.data.map((item: any) => {
|
|
|
|
return {
|
|
|
|
key: item.id,
|
|
|
|
label: item.name,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
activeKey.value = res.data.data[0].id;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const showQuoteButton = ref(false);
|
|
|
|
const selectedText = ref('');
|
|
|
|
const quoteButtonStyle = ref({
|
|
|
|
position: 'absolute',
|
|
|
|
top: '0',
|
|
|
|
left: '0',
|
|
|
|
display: 'none',
|
|
|
|
});
|
|
|
|
|
|
|
|
const handleTextSelection = (event: any) => {
|
|
|
|
const selection = window.getSelection();
|
|
|
|
if (selection && selection.toString().trim() !== '') {
|
|
|
|
selectedText.value = selection.toString();
|
|
|
|
|
|
|
|
// 获取鼠标位置
|
|
|
|
const mouseX = event.pageX;
|
|
|
|
const mouseY = event.pageY;
|
|
|
|
|
|
|
|
// 设置按钮位置
|
|
|
|
quoteButtonStyle.value = {
|
|
|
|
position: 'fixed',
|
|
|
|
top: `${mouseY}px`,
|
|
|
|
left: `${mouseX}px`,
|
|
|
|
display: 'block',
|
|
|
|
};
|
|
|
|
|
|
|
|
showQuoteButton.value = true;
|
|
|
|
} else {
|
|
|
|
showQuoteButton.value = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleQuoteClick = () => {
|
|
|
|
// 处理引用逻辑,比如将选中的文本添加到引用框中
|
|
|
|
content.value = selectedText.value;
|
|
|
|
showQuoteButton.value = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
// 定义 pptx 的样式
|
|
|
|
const pptStyle = ref({
|
|
|
|
height: 'calc(100vh - 150px)',
|
|
|
|
width: '40%',
|
|
|
|
margin: '30px 20px',
|
|
|
|
});
|
|
|
|
|
|
|
|
// 监听窗口大小变化
|
|
|
|
const handleResize = () => {
|
|
|
|
// 动态调整宽度和高度
|
|
|
|
pptStyle.value = {
|
|
|
|
height: 'calc(100vh - 150px)', // 保持高度不变
|
|
|
|
width: '40%', // 宽度为窗口宽度的 40%
|
|
|
|
margin: '30px 20px',
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
// 监听模板选择事件
|
|
|
|
const onModeClick: ConversationsProps['onActiveChange'] = (key) => {
|
|
|
|
acticeModeKey.value = key;
|
|
|
|
};
|
|
|
|
|
|
|
|
const renderedHandler = () => {
|
|
|
|
console.warn('渲染完成');
|
|
|
|
};
|
|
|
|
const errorHandler = () => {
|
|
|
|
console.error('渲染失败');
|
|
|
|
};
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
getConversationList();
|
|
|
|
window.addEventListener('resize', handleResize);
|
|
|
|
});
|
2025-05-02 22:08:36 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2025-05-04 18:45:03 +08:00
|
|
|
<contextHolder />
|
|
|
|
<div :style="styles.layout" style="height: calc(100vh - 70px)">
|
|
|
|
<div :style="styles.menu">
|
|
|
|
<!-- 🌟 Logo -->
|
|
|
|
<div :style="styles.logo">
|
|
|
|
<img
|
|
|
|
src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
|
|
|
|
draggable="false"
|
|
|
|
alt="logo"
|
|
|
|
:style="styles['logo-img']"
|
|
|
|
/>
|
|
|
|
<span :style="styles['logo-span']">PPT模板生成</span>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- 🌟 添加会话 -->
|
|
|
|
<Button type="link" :style="styles.addBtn" @click="onAddConversation">
|
|
|
|
<PlusOutlined />
|
|
|
|
新建会话
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
<!-- 🌟 会话管理 -->
|
|
|
|
<Conversations
|
|
|
|
:items="conversationsItems"
|
|
|
|
:style="styles.conversations"
|
|
|
|
:active-key="activeKey"
|
|
|
|
:menu="menuConfig"
|
|
|
|
@active-change="onConversationClick"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<!-- 🌟 会话管理 -->
|
|
|
|
<Typography.Title :level="5" style="margin: 0 0 8px">
|
|
|
|
选择模板
|
|
|
|
</Typography.Title>
|
|
|
|
<Conversations
|
|
|
|
:items="templates"
|
|
|
|
:style="styles.conversations"
|
|
|
|
:active-key="acticeModeKey"
|
|
|
|
:menu="menuConfig"
|
|
|
|
@active-change="onModeClick"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div :style="styles.chat" style="margin-left: 20px">
|
|
|
|
<!-- 🌟 消息列表 -->
|
|
|
|
<Bubble.List
|
|
|
|
:items="items"
|
|
|
|
:roles="roles"
|
|
|
|
:style="styles.messages"
|
|
|
|
@mouseup="handleTextSelection"
|
|
|
|
>
|
|
|
|
<template #footer>
|
|
|
|
<Space :size="token.paddingXXS">
|
|
|
|
<Button type="text" size="small" :icon="h(SyncOutlined)" />
|
|
|
|
<Button type="text" size="small" :icon="h(CopyOutlined)" />
|
|
|
|
</Space>
|
|
|
|
</template>
|
|
|
|
</Bubble.List>
|
|
|
|
|
|
|
|
<a-button
|
|
|
|
v-if="showQuoteButton"
|
|
|
|
:style="quoteButtonStyle"
|
|
|
|
@click="handleQuoteClick"
|
|
|
|
>
|
|
|
|
引用
|
|
|
|
</a-button>
|
|
|
|
|
|
|
|
<!-- 🌟 提示词 -->
|
|
|
|
<Prompts :items="senderPromptsItems" @item-click="onPromptsItemClick" />
|
|
|
|
|
|
|
|
<!-- 🌟 输入框 -->
|
|
|
|
<Sender
|
|
|
|
:value="content"
|
|
|
|
:style="styles.sender"
|
|
|
|
:loading="agentRequestLoading"
|
|
|
|
@submit="onSubmit"
|
|
|
|
@change="(value) => (content = value)"
|
|
|
|
>
|
|
|
|
<template #prefix>
|
|
|
|
<Badge :dot="attachedFiles.length > 0 && !headerOpen">
|
|
|
|
<Button type="text" @click="() => (headerOpen = !headerOpen)">
|
|
|
|
<template #icon>
|
|
|
|
<PaperClipOutlined />
|
|
|
|
</template>
|
|
|
|
</Button>
|
|
|
|
</Badge>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<template #header>
|
|
|
|
<Sender.Header
|
|
|
|
title="Attachments"
|
|
|
|
:open="headerOpen"
|
|
|
|
:styles="{ content: { padding: 0 } }"
|
|
|
|
@open-change="(open) => (headerOpen = open)"
|
|
|
|
>
|
|
|
|
<Attachments
|
|
|
|
:before-upload="() => false"
|
|
|
|
:items="attachedFiles"
|
|
|
|
@change="handleFileChange"
|
|
|
|
>
|
|
|
|
<template #placeholder="type">
|
|
|
|
<Flex
|
|
|
|
v-if="type && type.type === 'inline'"
|
|
|
|
align="center"
|
|
|
|
justify="center"
|
|
|
|
vertical
|
|
|
|
gap="2"
|
|
|
|
>
|
|
|
|
<Typography.Text style="font-size: 30px; line-height: 1">
|
|
|
|
<CloudUploadOutlined />
|
|
|
|
</Typography.Text>
|
|
|
|
<Typography.Title
|
|
|
|
:level="5"
|
|
|
|
style="margin: 0; font-size: 14px; line-height: 1.5"
|
|
|
|
>
|
|
|
|
Upload files
|
|
|
|
</Typography.Title>
|
|
|
|
<Typography.Text type="secondary">
|
|
|
|
Click or drag files to this area to upload
|
|
|
|
</Typography.Text>
|
|
|
|
</Flex>
|
|
|
|
<Typography.Text v-if="type && type.type === 'drop'">
|
|
|
|
Drop file here
|
|
|
|
</Typography.Text>
|
|
|
|
</template>
|
|
|
|
</Attachments>
|
|
|
|
</Sender.Header>
|
|
|
|
</template>
|
|
|
|
</Sender>
|
|
|
|
</div>
|
|
|
|
<VueOfficePptx
|
|
|
|
:src="pptx"
|
|
|
|
:style="pptStyle"
|
|
|
|
@rendered="renderedHandler"
|
|
|
|
@error="errorHandler"
|
|
|
|
/>
|
2025-05-02 22:08:36 +08:00
|
|
|
</div>
|
|
|
|
</template>
|