数通互联化工云平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

798 lines
25 KiB

<!--
@ 作者: han2015
@ 时间: 2025-05-12 15:39:13
@ 备注: 文档管理组件
-->
<script lang="ts" setup>
import { getExpirTime, getFileIcon, readableSize} from "./tools"
import sharePermission from './sharePermission.vue';
import { useUserStore } from "@/store/modules/user";
import { getMatterList,postCreateDir,postDelMatter,postCreateShare,postMatterRename,postDelMatBatch,getMySpaces,doCreateSpace} from "@/api/doc/index"
import { matterPage,matterInfo,respCreateShare,matterTree, doFileUpload} from "@/api/doc/type"
import { h } from 'vue'
import {
Delete,
View,
Download,
Share,
Search,
Edit,
Promotion,
Folder,
Avatar,
Plus
} from '@element-plus/icons-vue'
import {ElSelect,ElOption, ElText,ElInput,TableInstance,ElMessage,UploadFile,UploadFiles,ElPagination,ElTree,TreeNode} from "element-plus";
import preview from './preview.vue';
import space from './space.vue';
//TODO: add file icons done!
//TODO: click on table-item, 1)preview on file .....................
// 2) go into dir-item done!
// 3)search file done!
//TODO: rename matters done!
//TODO: get share list done!
//TODO: visit share link done!
//TODO: select on table items for batch opts 1)delete done!
// 2)share done!
//TODO: test on Pagination done!
const userStore = useUserStore();
const uid=btoa("p0"+userStore.userInfoCont.userId);
const siteHost=document.location.origin;
const apiURL=import.meta.env.VITE_APP_BASE_API+"/hxpan/api"
const matterList = ref<matterInfo[]>([])
const searchname=ref("")
const newdir=ref("") //创建新目录时的目录名
const currentHoverRow=ref("") //table 行的按钮控制
const selectedValue = ref("sixhour") //分享弹窗的世间变量
const tabSelected=ref<matterInfo[]>([]) //table组件多选数据维护
//to support tree mode refactor
const treeData=ref<matterTree[]>([])//{name:'个人空间',uuid:'root',children:[]}
const treeRef = ref();
const currentNode=ref<matterTree>({}) //打开的路径层次
const officeHost=import.meta.env.VITE_OFFICE_HOST
const dynamicVNode = ref<VNode | null>(null) //permission 组件的父组件
const multipleTableRef = ref<TableInstance>()
const paginInfo = ref({ page: 0, total: 0 })
const PRIVATESPACE = ref(true) //是空间状态的控制 2种:私有云盘和共享空间
const SpaceID= ref<{name:string,uuid:string,userUuid:string}>({}) //当前space的id
const SpaceList=ref<{name:string,uuid:string,userUuid:string}[]>([])
const spaceEleRef = ref() //space组件的引用,它与spaceTreeRef没有父子关系,反而是为了处理spaceTree的操作而创建的该变量
const spaceTreeData=ref<matterTree[]>([])//{name:'个人空间',uuid:'root',children:[]}
const spaceTreeRef = ref(); //space的树树组件的引用
let spaceNodeUid="" //用来判断树组件的展开和关闭,如何只是展开和关闭的点击事件不在刷新,通currentNode的作用
const Departs = computed(() => {
return `${userStore.userInfoCont.company},${userStore.userInfoCont.department},${userStore.userInfoCont.organization}`
})
const uploadFormData = computed(() => {
return {
userUuid: uid, // 用户的uuid
puuid: currentNode.value.uuid, // 父目录的uuid,基目录为root
}
});
const fileList=ref([])//upload files
//--------------单文件分享-------------
function onShareMatter(row?:matterInfo){
const showSharePermission=ref(false)
let permited =""
let infos=""
let _len=0
ElMessageBox({
title: row?.name+' 请选择分享有效时间',
message: () => h('div',{style:{ width:'660px'}},[
h(ElSelect,
{
defaultFirstOption:true,
modelValue: selectedValue.value,
'onUpdate:modelValue': (value) => {
selectedValue.value = value
},
valueKey: "value",
fallbackPlacements:['bottom-start'],
style: { width:'360px' }
},() => [
h(ElOption, { label: '六小时',key: 'sixhour', value: 'sixhour' }),
h(ElOption, { label: '一 天', key: 'oneday', value: 'oneday' }),
h(ElOption, { label: '三 天', key: 'threeday', value: 'threeday' }),
h(ElOption, { label: '一 周', key: 'oneweek', value: 'oneweek' }),
h(ElOption, { label: '一 月', key: 'onemonth', value: 'onemonth' }),
h(ElOption, { label: '三 月', key: 'threemonth', value: 'threemonth' }),
h(ElOption, { label: '永 久', key: 'permanent', value: 'permanent' }),
]),
h(ElButton, {
style: "width:30px;margin:0 10px;",
icon: Avatar,
onClick: () => {
showSharePermission.value = true
}
}),
h(sharePermission, {
uid: uid,
uuid: row?.uuid ?? "",
modelValue: showSharePermission.value,
confirmFunc: (_list: string[],_infos:string[]) => {
// 组织权限数据
_len=_list.length
permited = btoa(_list.join("|"))
infos=_infos.join("|"),
showSharePermission.value = false
},
closeFunc: () => {
showSharePermission.value = false
}
})
]
),
showCancelButton: true
}).then(() => {
let param;
if (row){
param={matterUuids:row.uuid,expireInfinity:false,expireTime:"",
permitList:permited,len:_len,permitInfos:infos}
}else if (tabSelected.value.length>1){
param={matterUuids:tabSelected.value.map((item:matterInfo)=>item.uuid).join(","),expireInfinity:false,expireTime:"",
permitList:permited,len:_len,permitInfos:infos}
}
if(param){
if(selectedValue.value==='permanent'){
param.expireInfinity=true
}else{
param.expireTime=getExpirTime(selectedValue.value)
}
postCreateShare(uid,param).then((resp)=>{
showShareMessage(resp.data)
})
onLoadMatterList()
selectedValue.value="sixhour"
}
}).catch(() => {
selectedValue.value='sixhour'
return
})
}
function showShareMessage(row:respCreateShare){
let _shareURL=`${siteHost}/#/doc/share/?uuid=${row.uuid}&code=${row.code}`
ElMessageBox({
title: '分享详情',
customStyle: { '--el-messagebox-width':'800px',padding:'40px'},
message: () => h('div',{style:{display:'flex','flex-direction':'column','line-height':'34px', width:'600px'}},[
h(ElText,{style:{'align-self':'flex-start'}},()=>row.name),
h(ElText,{style:{'align-self':'flex-start'}},()=>"失效时间:"+row.expireTime),
h(ElText,{style:{'align-self':'flex-start'}},()=>"链接:"+_shareURL)
]),
confirmButtonText: '复制分享链接',
showCancelButton: true
}).then(()=>{
navigator.clipboard.writeText(_shareURL)
}).catch(() => {});
}
//----------------------------------------
//删除
function onDelMatter(row:matterInfo){
if (row.uuid){
ElMessageBox.confirm(`确认删除( ${row.name}) ?删除后不可恢复!取消则放弃删除操作。`, "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(()=>{
postDelMatter(uid,{
"uuid":row.uuid
}).then(()=>{
if (row.dir) {
currentNode.value.uuid = row.puuid ?? ""
currentNode.value.name = row.path ? row.path.replace(`/${row.name}`,'').match(/[^/]+$/g)?.pop() :"上级目录"
treeRef.value.remove(row.uuid)
}
onLoadMatterList()
})
})
}
}
function onDelMatBatch(){
ElMessageBox.confirm("确认删除选择的内容?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(()=>{
postDelMatBatch(uid,{
"uuids":tabSelected.value.map((item:matterInfo)=>item.uuid).join(",")
}).then(()=>onLoadMatterList())
})
}
function onDownload(row:matterInfo){
ElMessageBox.confirm("确认下载此数据项?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(()=>{
if (row.uuid){
let _url= apiURL+`/alien/download/${row.uuid}/${row.name}`
window.open(_url)
}
})
}
function onMatterRename(row:matterInfo){
const newname=ref(row.name)
ElMessageBox({
title:"请输入新的文件名",
confirmButtonText: "确定",
cancelButtonText: "取消",
message: () => h(ElInput, {
style: { width:'360px' },
modelValue: newname.value,
'onUpdate:modelValue': (val) => {
newname.value = val
},
}),
}).then(() => {
postMatterRename(uid,{
uuid:row.uuid,
name:newname.value,
}).then(()=>onLoadMatterList())
})
}
//加载文件列表
function onSearchFile(name?:string){
let _page: matterPage = {
page: 0,
pageSize: 50,
orderCreateTime: "DESC",
orderDir: "DESC",
name:name
};
getMatterList(uid,_page).then((resp)=>{
//page+1 是由于分页的起始index是1,而后端api的分页index起始是0
paginInfo.value={total:resp.data.totalPages,page:resp.data.page}
matterList.value=resp.data.data.filter((item)=>{
return !item.dir
})
})
}
//加载目录文件列表
function onLoadMatterList(){
let _page: matterPage = {
page: paginInfo.value.page,
pageSize: 50,
orderCreateTime: "DESC",
orderDir: "DESC",
puuid:currentNode.value.uuid,
deleted:false
};
getMatterList(uid,_page).then((resp)=>{
//page+1 是由于分页的起始index是1,而后端api的分页index起始是0
paginInfo.value={total:resp.data.totalPages,page:resp.data.page}
matterList.value=resp.data.data
//2025-08-07: 保持space一样,文件夹一并显示
// .filter((item)=>{
// return !item.dir
// })
})
}
//----------for dir-----------
function createDir(){
matterList.value?.unshift({
name:"",
userUuid:uid,
puuid:"",
uuid:"",
dir:true,
size:0,
deleted:false,
})
}
function onCreateDir(){
postCreateDir(uid,{
userUuid:uid,
puuid:currentNode.value.uuid,
name:newdir.value,
}).then((resp)=> {
newdir.value=""
//调用tree的append方法
treeRef.value.append(
{uuid:resp.data.uuid,dir:false,name:resp.data.name,puuid:resp.data.puuid},
currentNode.value.uuid
)
//onLoadMatterList()
})
.catch((e)=>{
ElMessage.error(e.msg)
})
}
//树节点展开
function onNodeExpand(node: TreeNode, resolve: (data: matterTree[]) => void, reject: () => void) {
if ((node.data as matterTree).uuid) {
const cuuid = (node.data as matterTree).uuid
currentNode.value = node.data
let _page: matterPage = {
page: 0,
pageSize: 50,
orderCreateTime: "DESC",
orderDir: "DESC",
puuid: cuuid,
deleted: false
};
getMatterList(uid, _page).then((resp) => {
paginInfo.value = { total: resp.data.totalPages, page: resp.data.page }
matterList.value = resp.data.data
// .filter((item)=>{
// return !item.dir
// })
let node_data = resp.data.data.filter((item) => {
return item.dir
}).map((val) => {
const copy = structuredClone(val)
copy.dir = !copy.dir
return copy
})
resolve(node_data)
}).catch(() => reject())
}
}
//树节点单击
function onNodeClick(data:matterTree,node:TreeNode,self:any,env:any){
if(!PRIVATESPACE.value) {
PRIVATESPACE.value=true
}
if (currentNode.value.uuid === data.uuid) return;
const cuuid = data.uuid
currentNode.value = data
onLoadMatterList()
return
let _page: matterPage = {
page: 0,
pageSize: 50,
orderCreateTime: "DESC",
orderDir: "DESC",
puuid: cuuid,
deleted: false
};
getMatterList(uid, _page).then((resp) => {
paginInfo.value = { total: resp.data.totalPages, page: resp.data.page }
matterList.value = resp.data.data.filter((item)=>{
return !item.dir
})
//展开的时候暂时不做目录更新,看以后的使用情况
let node_data = resp.data.data.filter((item) => {
return item.dir
}).map((item) => {
item.dir = !item.dir
return item
})
if (node) {
if(data.children && data.children.length!==node_data.length){
treeRef.value.updateKeyChildren(data.uuid,node_data)
}
} else if(data.children.length!==node_data.length){
data.children = node_data
}
})
}
//文件预览
function onPrivateView(row:matterInfo){
if(row.dir){
alert("目录不支持预览")
return
}
let a = `${row.uuid}${row.name}`
let _token=document.cookie.match(/hxpan=([\w-]*)/)
if (_token&&_token.length>1){
_token=_token[1]
}
let _url=`${siteHost}${apiURL}/alien/download/${row.uuid}/${row.name}?access_token=${_token}&fullfilename=${a}`
dynamicVNode.value=h(preview,{
url:`${officeHost}/kkpreview/onlinePreview?url=`+window.btoa(unescape(encodeURIComponent(_url))),
closeFunc:()=>dynamicVNode.value=null
})
}
//--------------UPGRADE: multy file upload section----------------
//自定义上传,目的是支持多文件上传, 使用html原生组件,是为了解决并发问题
async function onCustomUpload(e:Event){
const files = e.target!.files??[]
for(let ff of files){
await handleSingleFile(ff)
}
onLoadMatterList() //刷新
}
async function handleSingleFile(ff:File){
const fields=new FormData()
fields.append("userUuid",uploadFormData.value.userUuid)
fields.append("puuid",uploadFormData.value.puuid)
fields.append("file",ff)
const res = await doFileUpload(fields,'/hxpan/api/matter/upload')
if(res.code!=200){
console.log(ff.name+"上传失败! ")
alert(ff.name+"上传失败! ")
}
}
//文件夹上传,原理:自定义的input组件,一次拿到所有需要上传的文件列表,然后依次上传
//能减少并发问题
async function uploadFolder(e:Event){
const files = e.target!.files??[]
for(let f of files){
await handleFolderFile(f)
}
onLoadMatterList() //刷新
}
async function handleFolderFile(option:File){
//根据路径,来判断需不需要重建目录
const _path = option.webkitRelativePath
const _dir=_path.replace(/\/[^/]+\w+$/,"") //只保留文件夹目录,[^/]就是用来限制,只能是最后一个目录
const node = matterList.value.filter((item)=>{
return item.dir && item.path?.endsWith(_dir)
})
let puuid=""
//说明是新的目录,需要新建;如果存在,直接上传文件即可
if(node.length==0){
const subs= await doCreateMultyDir(_dir,currentNode.value.uuid)
matterList.value.push(...subs) //这里如果子文件夹多的时候,可能会造成第一级路径多次创建,只是造成资源浪费,问题不大
const newnodes=matterList.value.filter((item)=>{
return item.dir && item.path?.endsWith(_dir)
})
if(newnodes.length>0){
puuid=newnodes[0].uuid
}else{
console.log(_path+"上传失败! ")
alert(_path +" 上传失败! ")
return
}
}else{
puuid=node[0].uuid
}
const fields = new FormData()
fields.append('file', option)
fields.append("space",uploadFormData.value.space)
fields.append("puuid",puuid)
const res = await doFileUpload(fields,'/hxpan/api/matter/upload')
if(res.code!=200){
console.log(_path+"上传失败! ")
alert(_path +" 上传失败! ")
}
}
//创建多级目录,并返回matterinfos数组
async function doCreateMultyDir(path:string,uuid:string){
const list=[];
const dirs=path.split("/")
for(let i=0;i<dirs.length;i++){
await postCreateDir(uid,{
userUuid:uid,
puuid:uuid,
name:dirs[i],
}).then((resp)=> {
uuid=resp.data.uuid //第一级别的uuid, 是第二级的puuid
list.push(resp.data)
})
}
return list
}
function handleMouseEnter(row:any){
currentHoverRow.value=row.name
}
//上传成功
function handleSingleUpload(response:any){
fileList.value=[]
onLoadMatterList()
}
interface uploadError{
msg:string
}
//上传失败
function handleSigLoadErr(error: Error, uploadFile: UploadFile, uploadFiles:UploadFiles){
ElMessage.error(JSON.parse(error.message).msg)
}
//-----------------------------------------------------------
//-------------------space feature---------------------
function onNewSpace(){
const newname=ref("")
ElMessageBox({
title:"请输入空间名称",
customStyle: { bottom:'200px'},
confirmButtonText: "确定",
cancelButtonText: "取消",
message: () => h(ElInput, {
style: { width:'360px' },
modelValue: newname.value,
'onUpdate:modelValue': (val) => {
newname.value = val
},
}),
}).then(() => {
if(newname.value!==""){
doCreateSpace(uid,newname.value).then((resp)=>{
SpaceList.value.push({name:resp.data.name,uuid:resp.data.uuid,userUuid:"p0"+userStore.userInfoCont.userId})
})
}
})
}
function onSpaceNodeClick(data:matterTree,node:TreeNode,self:any,env:any){
if(PRIVATESPACE.value) { //如果打开了个人空间,突然点击共享空间,要及时切换状态
PRIVATESPACE.value=false
}
//如果在单个组件上重复点击,不在刷新请求
if(spaceNodeUid==data.uuid) return;
spaceNodeUid=data.uuid
if(data.uuid.startsWith("s0") && data.uuid!=SpaceID.value.uuid){ //切换空间
SpaceID.value={
name: data.name ?? "",
uuid: data.uuid ?? "",
userUuid: data.userUuid ?? ""
};
PRIVATESPACE.value=false;
}else{
let matter= {
uuid:data.uuid==SpaceID.value.uuid?"root":data.uuid,
puuid: data.puuid,
name:data.name,
agent:data.agent,
dir:true
}
//打开具体的节点
spaceEleRef.value.handleDoubleClick(matter)
}
}
function flushSpaceTree(uuid:string,data:matterTree[]){
if(uuid==="root") uuid=SpaceID.value.uuid
spaceTreeRef.value.updateKeyChildren(uuid,data)
}
//------------------------------------------------------
//http://172.20.2.87:6010/api/alien/preview/5a10aaf6-396e-4d9a-7e87-3c5c8029d4db/123.png?ir=fill_100_100
//渲染完页面再执行
onMounted(() => {
treeRef.value.append(
{name:'个人空间',uuid:'root',dir:false},
currentNode.value.uuid
)
//加载我的空间列表
getMySpaces(uid,{roles:Departs}).then((resp)=>{
//SpaceList.value=resp.data
resp.data.forEach((item)=>{
spaceTreeRef.value.append({name:item.name,uuid:item.uuid,dir:false,userUuid:item.userUuid})
})
})
});
const handleSelectionChange = (val:matterInfo[]) => {
tabSelected.value = val
}
</script>
<template>
<div style="display:grid;grid-template-columns:1fr 4fr; width: 100%;height: 100%;">
<div class="menus_tree">
<el-tree
ref="treeRef"
style="max-width: 600px"
:data="treeData"
node-key="uuid"
highlight-current
lazy
:props="{label: 'name',children:'children',isLeaf:'dir'}"
:load="onNodeExpand"
:default-expanded-keys="['root']"
@node-click="onNodeClick"
/>
<el-button style="margin: 10px 0;" :icon="Plus" @click="onNewSpace"> 共享空间</el-button>
<el-tree
ref="spaceTreeRef"
style="max-width: 600px"
:data="spaceTreeData"
node-key="uuid"
accordion
highlight-current
lazy
:props="{label: 'name',children:'children',isLeaf:'dir'}"
@node-click="onSpaceNodeClick"
/>
<ul style="background-color: white;max-width: 600px;">
<li class="spaceitem" v-for="sp in SpaceList" @click="()=>{SpaceID=sp; PRIVATESPACE=false;}">{{ sp.name }}</li>
</ul>
</div>
<div v-if="PRIVATESPACE" class="app_container">
<el-row :gutter="24" style="margin: 12px 0px;">
<el-link v-if="currentNode.name!=='root'" @click="onNodeClick(treeData[0], null as unknown as TreeNode, null, null)">
<span style="font-weight: bold;margin-right: 5px;">根目录</span>/
</el-link>
<span style="font-weight: bold;margin:0 5px;align-content:center;">{{ currentNode.name }}</span>
<el-col :span="6" class="search">
<el-input placeholder="搜索文件" v-model="searchname" @blur="searchname===''?onLoadMatterList():''"/>
<el-button :icon="Search" @click="onSearchFile(searchname)"></el-button>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="14">
<div class="el-button el-button--default" style="position: relative;">
<input type="file" style="position: absolute;opacity: 0;width: 50px;"
@change="onCustomUpload" multiple />
文件上传
</div>
<div class="el-button el-button--default" style="position: relative;">
<input type="file" style="position: absolute;opacity: 0;width: 50px;"
@change="uploadFolder"
webkitdirectory
multiple
/>
文件夹上传
</div>
<el-button @click="createDir">新建目录</el-button>
<span v-if="tabSelected.length>1" style="margin:12px">
<el-button @click="onShareMatter()">分享</el-button>
<el-button @click="onDelMatBatch">删除</el-button>
</span>
<el-button type="danger" plain @click="onShareMatter({uuid:currentNode.uuid,name:currentNode.name})">分享目录</el-button>
<el-button type="danger" plain @click="onDelMatter({uuid:currentNode.uuid,name:currentNode.name,dir:true,
puuid:currentNode.puuid,path:currentNode.path})">删除目录</el-button>
</el-col>
</el-row>
<el-row :gutter="24" style="height: 84%;overflow-y: auto;">
<el-table
stripe
:data="matterList"
ref="multipleTableRef"
:header-cell-style="{ background: '#f5f8fd' }"
style="width: 100%"
row-key="uuid"
:row-style ="() => ({ lineHeight: '36px' })"
@selection-change="handleSelectionChange"
@cell-mouse-enter="handleMouseEnter">
<el-table-column type="selection" width="50" />
<el-table-column width="450" property="name" label="文件名">
<template #default="scope">
<input type="text" autofocus placeholder="文件夹名" style="border:groove;height:30px;" v-model="newdir" @change="onCreateDir" v-if="scope.row.name===''" />
<div v-if="scope.row.name" style="display: flex; align-items: center;">
<el-icon :size="26">
<component v-if="scope.row.dir" :is="Folder" />
<component v-else :is="getFileIcon(scope.row.name)" />
</el-icon>
<span style="margin-left: 10px">{{ scope.row.name }}</span>
</div>
</template>
</el-table-column>
<el-table-column width="250" align="center">
<template #default="scope">
<div v-show="currentHoverRow === scope.row.name">
<!-- <el-button size="small" :icon="Promotion" circle ></el-button> -->
<el-button size="small" :icon="View" circle @click="onPrivateView(scope.row)"></el-button>
<el-button size="small" :icon="Share" circle @click="onShareMatter(scope.row)"></el-button>
<el-button size="small" :icon="Download" circle @click="onDownload(scope.row)"></el-button>
<!-- <el-button size="small" :icon="Edit" circle @click="onMatterRename(scope.row)"></el-button> -->
<el-button size="small" :icon="Delete" circle @click="onDelMatter(scope.row)"></el-button>
</div>
</template>
</el-table-column>
<el-table-column prop="size" width="100" :formatter="readableSize" label="大小" />
<el-table-column prop="updateTime" label="修改日期">
<template #default="scope">
<span v-if="scope.row.updateTime">{{ scope.row.updateTime.slice(0,16) }}</span>
</template>
</el-table-column>
</el-table>
</el-row>
<el-row v-if="paginInfo.total>1" style="justify-content: center;">
<el-pagination size="small" background layout="prev, pager, next" :current-page="paginInfo.page+1" @current-change="(value:number)=>{paginInfo.page=value-1;onLoadMatterList();}" :page-count="paginInfo.total" class="mt-4"/>
</el-row>
</div>
<div v-else class="app_container">
<space ref="spaceEleRef" :uid="uid" :tree="spaceTreeRef"
:spaceid="SpaceID.uuid" :roles="Departs" :spacename="SpaceID.name" :owner="SpaceID.userUuid"
:officeHost="officeHost" :site-host="siteHost" :api-u-r-l="apiURL"
:flushSpaceTree="flushSpaceTree"></space>
</div>
<div v-if="dynamicVNode">
<component :is="dynamicVNode" />
</div>
</div>
</template>
<style lang="scss" scoped>
.menus_tree{
padding: 20px 0px 0px 15px;
height: 100%;
overflow-y: auto;
.el-tree{
--el-color-primary-light-9:#6eb3f8;
--el-tree-node-hover-bg-color:#a1c7ee;
--el-tree-node-content-height:43px;
--el-tree-expand-icon-color:#4c4c4e;
}
}
.app_container {
padding: 10px 30px 0px 30px;
height: calc(100% - 10px);
overflow: hidden;
overflow-y: auto;
position: relative;
}
.search{
margin-left: auto;
margin-right: 20px;
display:inherit;
}
.shareDialog{
--el-messagebox-width:'800px';
padding:40px;
.el-text{
align-self: flex-start;
}
}
.spaceitem{
height: 50px;
align-content: center;
padding: 14px;
color: #606266;
font-weight:bold;
}
.dynamic-width-message-box-byme .el-message-box__message{
width: 100%;
}
.el-overlay-message-box{
top: 200x;
bottom: auto;
}
</style>