u
This commit is contained in:
1 parent
3e172a1d53
commit
401a6719f6
12 files changed
+487
-277
No files matched your search
-1
@@ -12,7 +12,6 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
Directory: typeof import('./src/components/wang-editor/modules/directory.vue')['default']
|
||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
|
||||
@@ -349,7 +349,11 @@ async function uploadLocalFiles(files) {
|
||||
const tempUrl = URL.createObjectURL(blob);
|
||||
|
||||
if (file.size > 512000) {
|
||||
const { url, size, blob: compressedBlob } = await compressImage(tempUrl);
|
||||
const {
|
||||
url,
|
||||
size,
|
||||
blob: compressedBlob,
|
||||
} = await compressImage(tempUrl);
|
||||
|
||||
fileInfo.mx_mapfilename = url;
|
||||
fileInfo.mx_filesize = size;
|
||||
@@ -494,7 +498,9 @@ async function handleDownloadFile(file) {
|
||||
function handleShowPreview(file) {
|
||||
console.log(file);
|
||||
if (isImage(file.mx_fileext)) {
|
||||
const index = previewImageList.value.findIndex((item) => item === file.mx_mapfilename);
|
||||
const index = previewImageList.value.findIndex(
|
||||
(item) => item === file.mx_mapfilename,
|
||||
);
|
||||
|
||||
if (index !== -1) {
|
||||
preViewImageIndex.value = index;
|
||||
@@ -507,7 +513,10 @@ function handleShowPreview(file) {
|
||||
|
||||
if (isExcel(file.mx_fileext)) {
|
||||
// https://view.officeapps.live.com/op/view.aspx?src=
|
||||
window.open(`https://view.officeapps.live.com/op/view.aspx?src=${fileUrl}`, "_blank");
|
||||
window.open(
|
||||
`https://view.officeapps.live.com/op/view.aspx?src=${fileUrl}`,
|
||||
"_blank",
|
||||
);
|
||||
} else {
|
||||
window.open(fileUrl, "_blank");
|
||||
}
|
||||
@@ -517,7 +526,9 @@ function handleShowPreview(file) {
|
||||
function handleDownloadPreviewImage(index) {
|
||||
const previewFileUrl = previewImageList.value[index];
|
||||
|
||||
const previewFile = fileList.value.find((item) => item.mx_mapfilename === previewFileUrl);
|
||||
const previewFile = fileList.value.find(
|
||||
(item) => item.mx_mapfilename === previewFileUrl,
|
||||
);
|
||||
|
||||
if (previewFile) {
|
||||
handleDownloadFile(previewFile);
|
||||
@@ -558,7 +569,7 @@ async function deleteFiles(files) {
|
||||
try {
|
||||
for (const item of files) {
|
||||
if (item.subid) {
|
||||
await deleteFileApi("bf_file", item.subid);
|
||||
await deleteFileApi(item.subid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,12 +598,12 @@ async function handleSave() {
|
||||
loading.value = true;
|
||||
loadingTip.value = "正在保存中 . . .";
|
||||
|
||||
const { insertdata, updatedata, deletedata, hasChanges } = compareAndClassifyData(
|
||||
fileList.value,
|
||||
oldFileList.value,
|
||||
"subid",
|
||||
["_content", "_status", "checked"],
|
||||
);
|
||||
const { insertdata, updatedata, deletedata, hasChanges } =
|
||||
compareAndClassifyData(fileList.value, oldFileList.value, "subid", [
|
||||
"_content",
|
||||
"_status",
|
||||
"checked",
|
||||
]);
|
||||
|
||||
// 处理新增的文件
|
||||
for (const item of insertdata) {
|
||||
@@ -679,7 +690,9 @@ function handleTreeNodeClick(data) {
|
||||
<div class="g3-title">
|
||||
附件管理({{ fileList.length }})
|
||||
|
||||
<template v-if="!props.readonly"> 未上传 ({{ pendingFileList.length }}) </template>
|
||||
<template v-if="!props.readonly">
|
||||
未上传 ({{ pendingFileList.length }})
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<input
|
||||
@@ -719,6 +732,9 @@ function handleTreeNodeClick(data) {
|
||||
style="margin-left: 8px"
|
||||
@click="handleDownloadZip"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:download" />
|
||||
</el-icon>
|
||||
打包下载
|
||||
</el-button>
|
||||
|
||||
@@ -729,6 +745,9 @@ function handleTreeNodeClick(data) {
|
||||
:disabled="checkedFiles.length === 0 || loading"
|
||||
@click="handleBatchDelete()"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -738,7 +757,7 @@ function handleTreeNodeClick(data) {
|
||||
<span class="g3-mode">
|
||||
模式:{{ displayMode === 0 ? "卡片视图" : "列表视图" }}
|
||||
<el-icon class="el-icon--right">
|
||||
<ArrowDown />
|
||||
<G3Icon icon="lucide:chevron-down" />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
@@ -767,13 +786,17 @@ function handleTreeNodeClick(data) {
|
||||
>
|
||||
<div v-if="fileList.length === 0" class="g3-tip">
|
||||
<el-icon size="64">
|
||||
<UploadFilled />
|
||||
<G3Icon icon="lucide:cloud-upload" />
|
||||
</el-icon>
|
||||
<div>支持 拖拽文件、粘贴文件、多文件上传</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="displayMode === 0" class="g3-files">
|
||||
<div v-for="(file, index) in fileList" :key="index" class="g3-file-item">
|
||||
<div
|
||||
v-for="(file, index) in fileList"
|
||||
:key="index"
|
||||
class="g3-file-item"
|
||||
>
|
||||
<div class="g3-file-checkbox">
|
||||
<el-checkbox v-model="file._checked" size="large" />
|
||||
</div>
|
||||
@@ -785,9 +808,15 @@ function handleTreeNodeClick(data) {
|
||||
<span v-if="file._status === 'pending'">未上传</span>
|
||||
<span v-if="file._status === 'failed'">上传失败</span>
|
||||
</div>
|
||||
<div class="g3-file-preview" @click.stop="handleShowPreview(file)">
|
||||
<div
|
||||
class="g3-file-preview"
|
||||
@click.stop="handleShowPreview(file)"
|
||||
>
|
||||
<template v-if="getFileIcon(file.mx_fileext) === 'image'">
|
||||
<el-image class="g3-file-preview-img" :src="file.mx_mapfilename" />
|
||||
<el-image
|
||||
class="g3-file-preview-img"
|
||||
:src="file.mx_mapfilename"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<G3Icon :icon="getFileIcon(file.mx_fileext)" size="88" />
|
||||
@@ -803,8 +832,15 @@ function handleTreeNodeClick(data) {
|
||||
<div>{{ formatFileSize(file.mx_filesize) }}</div>
|
||||
<div>
|
||||
{{ file.mx_updateuser_id || file.mx_inputuser_id }}
|
||||
<template v-if="file.mx_inputdatetime || file.mx_updatedatetime">
|
||||
| {{ formatTime(file.mx_updatedatetime || file.mx_inputdatetime) }}
|
||||
<template
|
||||
v-if="file.mx_inputdatetime || file.mx_updatedatetime"
|
||||
>
|
||||
|
|
||||
{{
|
||||
formatTime(
|
||||
file.mx_updatedatetime || file.mx_inputdatetime,
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -812,26 +848,33 @@ function handleTreeNodeClick(data) {
|
||||
<el-button
|
||||
v-if="!props.readonly"
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop="handleDeleteOne(file)"
|
||||
/>
|
||||
>
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop="handleDownloadFile(file)"
|
||||
/>
|
||||
<el-dropdown v-if="!props.readonly" placement="top" trigger="click">
|
||||
>
|
||||
<G3Icon icon="lucide:download" />
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="!props.readonly"
|
||||
placement="top"
|
||||
trigger="click"
|
||||
>
|
||||
<el-button
|
||||
type="info"
|
||||
:icon="More"
|
||||
size="small"
|
||||
circle
|
||||
style="margin-left: 12px"
|
||||
/>
|
||||
>
|
||||
<G3Icon icon="lucide:ellipsis" />
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleShowUpdateDialog(file)">
|
||||
@@ -855,9 +898,6 @@ function handleTreeNodeClick(data) {
|
||||
height="100%"
|
||||
show-overflow
|
||||
show-header-overflow
|
||||
:cell-config="{
|
||||
height: 26,
|
||||
}"
|
||||
:sort-config="{
|
||||
trigger: 'cell',
|
||||
}"
|
||||
@@ -872,14 +912,28 @@ function handleTreeNodeClick(data) {
|
||||
<el-checkbox v-model="row._checked" size="large" />
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="mx_filename" title="文件名" sortable align="center">
|
||||
<vxe-column
|
||||
field="mx_filename"
|
||||
title="文件名"
|
||||
sortable
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click.stop="handleShowPreview(row)">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click.stop="handleShowPreview(row)"
|
||||
>
|
||||
{{ row.mx_filename }}
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="mx_inputdatetime" title="上传日期" sortable align="center">
|
||||
<vxe-column
|
||||
field="mx_inputdatetime"
|
||||
title="上传日期"
|
||||
sortable
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatTime(row.mx_inputdatetime) }}
|
||||
</template>
|
||||
@@ -904,7 +958,14 @@ function handleTreeNodeClick(data) {
|
||||
</vxe-column>
|
||||
<vxe-column width="180" title="操作">
|
||||
<template #default="{ row }">
|
||||
<div style="display: flex; align-items: center; justify-content: center">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 28px;
|
||||
"
|
||||
>
|
||||
<el-button
|
||||
v-if="!props.readonly"
|
||||
type="danger"
|
||||
@@ -913,14 +974,26 @@ function handleTreeNodeClick(data) {
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<el-button type="primary" link @click.stop="handleDownloadFile(row)">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
@click.stop="handleDownloadFile(row)"
|
||||
>
|
||||
下载
|
||||
</el-button>
|
||||
<el-dropdown v-if="!props.readonly" placement="top" trigger="click">
|
||||
<el-button type="info" link style="margin-left: 12px"> 更多 </el-button>
|
||||
<el-dropdown
|
||||
v-if="!props.readonly"
|
||||
placement="top"
|
||||
trigger="click"
|
||||
>
|
||||
<el-button type="info" link style="margin-left: 12px">
|
||||
更多
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleShowUpdateDialog(row)">
|
||||
<el-dropdown-item
|
||||
@click="handleShowUpdateDialog(row)"
|
||||
>
|
||||
修改文件信息
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
@@ -937,10 +1010,16 @@ function handleTreeNodeClick(data) {
|
||||
</div>
|
||||
|
||||
<template v-if="!props.readonly" #footer>
|
||||
<el-button type="primary" :icon="HelpFilled" :disabled="loading" @click="handleClickUpload">
|
||||
<el-button type="primary" :disabled="loading" @click="handleClickUpload">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:mouse-pointer" />
|
||||
</el-icon>
|
||||
选择
|
||||
</el-button>
|
||||
<el-button type="primary" :icon="UploadFilled" :disabled="loading" @click="handleSave">
|
||||
<el-button type="primary" :disabled="loading" @click="handleSave">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:upload" />
|
||||
</el-icon>
|
||||
上传
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -953,7 +1032,9 @@ function handleTreeNodeClick(data) {
|
||||
preview-teleported
|
||||
@close="showPreview = false"
|
||||
>
|
||||
<template #toolbar="{ actions, prev, next, reset, activeIndex, setActiveItem }">
|
||||
<template
|
||||
#toolbar="{ actions, prev, next, reset, activeIndex, setActiveItem }"
|
||||
>
|
||||
<ElIcon @click="prev">
|
||||
<Back />
|
||||
</ElIcon>
|
||||
@@ -966,10 +1047,16 @@ function handleTreeNodeClick(data) {
|
||||
<ElIcon @click="actions('zoomOut')">
|
||||
<ZoomOut />
|
||||
</ElIcon>
|
||||
<ElIcon @click="actions('zoomIn', { enableTransition: false, zoomRate: 2 })">
|
||||
<ElIcon
|
||||
@click="actions('zoomIn', { enableTransition: false, zoomRate: 2 })"
|
||||
>
|
||||
<ZoomIn />
|
||||
</ElIcon>
|
||||
<ElIcon @click="actions('clockwise', { rotateDeg: 180, enableTransition: false })">
|
||||
<ElIcon
|
||||
@click="
|
||||
actions('clockwise', { rotateDeg: 180, enableTransition: false })
|
||||
"
|
||||
>
|
||||
<RefreshRight />
|
||||
</ElIcon>
|
||||
<ElIcon @click="actions('anticlockwise')">
|
||||
@@ -999,7 +1086,11 @@ function handleTreeNodeClick(data) {
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="showUpdateDialog = false"> 取消 </el-button>
|
||||
<el-button type="primary" :loading="updateLoading" @click="handleConfirmUpdate">
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="updateLoading"
|
||||
@click="handleConfirmUpdate"
|
||||
>
|
||||
确认
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
@@ -83,58 +83,82 @@ function switchTab(tab, index) {
|
||||
moveScroll(index);
|
||||
}
|
||||
|
||||
const HOME_PATH = "/";
|
||||
|
||||
// 关闭标签
|
||||
async function closeTab(tab) {
|
||||
if (tab.fullPath === HOME_PATH) return; // ❗首页不能关
|
||||
|
||||
const activePath = await tabStore.closeTab(tab.fullPath);
|
||||
|
||||
if (activePath && route.fullPath !== activePath) {
|
||||
router.push(activePath);
|
||||
} else if (!activePath) {
|
||||
router.push("/");
|
||||
router.push(HOME_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭左侧
|
||||
function closeLeft(data) {
|
||||
const currentIndex = tabStore.tabs.findIndex(
|
||||
(item) => item.fullPath === data.fullPath,
|
||||
);
|
||||
if (currentIndex === -1) return;
|
||||
|
||||
// 关闭左侧所有标签
|
||||
tabStore.tabs.slice(0, currentIndex).forEach((item) => {
|
||||
const index = tabStore.tabs.findIndex((t) => t.fullPath === item.fullPath);
|
||||
if (index !== -1) tabStore.tabs.splice(index, 1);
|
||||
if (item.fullPath === route.fullPath) {
|
||||
router.push(data.fullPath);
|
||||
}
|
||||
});
|
||||
tabStore.tabs
|
||||
.slice(0, currentIndex)
|
||||
.filter((item) => item.fullPath !== HOME_PATH) // ❗过滤首页
|
||||
.forEach((item) => {
|
||||
const index = tabStore.tabs.findIndex(
|
||||
(t) => t.fullPath === item.fullPath,
|
||||
);
|
||||
if (index !== -1) tabStore.tabs.splice(index, 1);
|
||||
|
||||
if (item.fullPath === route.fullPath) {
|
||||
router.push(data.fullPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭右侧
|
||||
function closeRight(data) {
|
||||
const currentIndex = tabStore.tabs.findIndex(
|
||||
(item) => item.fullPath === data.fullPath,
|
||||
);
|
||||
if (currentIndex === -1) return;
|
||||
|
||||
tabStore.tabs.slice(currentIndex + 1).forEach((item) => {
|
||||
const index = tabStore.tabs.findIndex((t) => t.fullPath === item.fullPath);
|
||||
if (index !== -1) tabStore.tabs.splice(index, 1);
|
||||
if (item.fullPath === route.fullPath) {
|
||||
router.push(data.fullPath);
|
||||
}
|
||||
});
|
||||
tabStore.tabs
|
||||
.slice(currentIndex + 1)
|
||||
.filter((item) => item.fullPath !== HOME_PATH) // ❗过滤首页
|
||||
.forEach((item) => {
|
||||
const index = tabStore.tabs.findIndex(
|
||||
(t) => t.fullPath === item.fullPath,
|
||||
);
|
||||
if (index !== -1) tabStore.tabs.splice(index, 1);
|
||||
|
||||
if (item.fullPath === route.fullPath) {
|
||||
router.push(data.fullPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭其他
|
||||
function closeOther(tab) {
|
||||
tabStore.tabs = tabStore.tabs.filter((t) => t.fullPath === tab.fullPath);
|
||||
tabStore.tabs = tabStore.tabs.filter(
|
||||
(t) => t.fullPath === tab.fullPath || t.fullPath === HOME_PATH, // ❗保留首页
|
||||
);
|
||||
|
||||
router.push(tab.fullPath);
|
||||
}
|
||||
|
||||
// 关闭全部
|
||||
function closeAll() {
|
||||
tabStore.tabs = [];
|
||||
router.push("/");
|
||||
}
|
||||
tabStore.tabs = tabStore.tabs.filter(
|
||||
(t) => t.fullPath === HOME_PATH, // ❗只保留首页
|
||||
);
|
||||
|
||||
router.push(HOME_PATH);
|
||||
}
|
||||
function toHome() {
|
||||
router.push("/");
|
||||
}
|
||||
|
||||
@@ -63,13 +63,22 @@ function logout() {
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="router.push('/user-center')"
|
||||
>个人中心</el-dropdown-item
|
||||
>
|
||||
<el-dropdown-item @click="router.push('/user-center')">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:user-round-pen" />
|
||||
</el-icon>
|
||||
个人中心
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="showUpdatePassword = !showUpdatePassword">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:lock-keyhole-open" />
|
||||
</el-icon>
|
||||
修改密码
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided @click="logout">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:arrow-right-from-line" />
|
||||
</el-icon>
|
||||
退出登录
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
|
||||
@@ -154,10 +154,10 @@ export function insertFileApi(params) {
|
||||
return httpPost("/file/insert", params);
|
||||
}
|
||||
|
||||
export function deleteFileApi({ id, tableName }) {
|
||||
export function deleteFileApi(subid) {
|
||||
return httpPost("/file/delete", {
|
||||
id,
|
||||
tableName,
|
||||
subid,
|
||||
tableName: "bf_file",
|
||||
bucketName: import.meta.env.PUBLIC_ALIYUN_BUCKET,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
import { getAliyunKeyApi } from "@/request/api";
|
||||
import { getAliyunKeyApi, insertFileApi } from "@/request/api";
|
||||
|
||||
/**
|
||||
* 选择并压缩图片
|
||||
*/
|
||||
export function uploadImage(options = {}) {
|
||||
const { quality = 0.9, maxSize = 512000 } = options
|
||||
const { quality = 0.9, maxSize = 512000 } = options;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof document === 'undefined') {
|
||||
reject(new Error('Require browser environment'))
|
||||
return
|
||||
if (typeof document === "undefined") {
|
||||
reject(new Error("Require browser environment"));
|
||||
return;
|
||||
}
|
||||
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = 'image/*'
|
||||
input.style.display = 'none'
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "image/*";
|
||||
input.style.display = "none";
|
||||
|
||||
input.onchange = async (e) => {
|
||||
const file = e.target.files?.[0]
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) {
|
||||
reject(new Error('No file selected'))
|
||||
return
|
||||
reject(new Error("No file selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!file.type.startsWith('image/')) {
|
||||
throw new Error('Invalid image file')
|
||||
if (!file.type.startsWith("image/")) {
|
||||
throw new Error("Invalid image file");
|
||||
}
|
||||
|
||||
// 创建一个临时URL来加载图片
|
||||
const url = URL.createObjectURL(file)
|
||||
const url = URL.createObjectURL(file);
|
||||
|
||||
// 调用 compressImage 进行压缩
|
||||
const compressResult = await compressImage(url, quality, maxSize)
|
||||
const compressResult = await compressImage(url, quality, maxSize);
|
||||
|
||||
// 释放临时URL
|
||||
URL.revokeObjectURL(url)
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
resolve({
|
||||
blob: compressResult.blob,
|
||||
@@ -44,19 +44,17 @@ export function uploadImage(options = {}) {
|
||||
fileName: file.name,
|
||||
fileExt: getFileExtension(file.name),
|
||||
fileSize: file.size,
|
||||
})
|
||||
});
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
} finally {
|
||||
document.body.removeChild(input);
|
||||
}
|
||||
catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
finally {
|
||||
document.body.removeChild(input)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.body.appendChild(input)
|
||||
input.click()
|
||||
})
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,26 +62,26 @@ export function uploadImage(options = {}) {
|
||||
*/
|
||||
export function uploadVideo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof document === 'undefined') {
|
||||
reject(new Error('Require browser environment'))
|
||||
return
|
||||
if (typeof document === "undefined") {
|
||||
reject(new Error("Require browser environment"));
|
||||
return;
|
||||
}
|
||||
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = 'video/*'
|
||||
input.style.display = 'none'
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "video/*";
|
||||
input.style.display = "none";
|
||||
|
||||
input.onchange = (e) => {
|
||||
const file = e.target.files?.[0]
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) {
|
||||
reject(new Error('No file selected'))
|
||||
return
|
||||
reject(new Error("No file selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.type.startsWith('video/')) {
|
||||
reject(new Error('Invalid video file'))
|
||||
return
|
||||
if (!file.type.startsWith("video/")) {
|
||||
reject(new Error("Invalid video file"));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
@@ -92,121 +90,114 @@ export function uploadVideo() {
|
||||
fileName: file.name,
|
||||
fileExt: getFileExtension(file.name),
|
||||
fileSize: file.size,
|
||||
})
|
||||
});
|
||||
|
||||
document.body.removeChild(input)
|
||||
}
|
||||
document.body.removeChild(input);
|
||||
};
|
||||
|
||||
document.body.appendChild(input)
|
||||
input.click()
|
||||
})
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
// 压缩图片
|
||||
export async function compressImage(url, quality = 0.9, maxSize = 512000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.src = url
|
||||
const img = new Image();
|
||||
img.src = url;
|
||||
|
||||
img.onload = async () => {
|
||||
try {
|
||||
// 获取原图大小
|
||||
const imgSize = await fetch(url)
|
||||
.then(res => res.blob())
|
||||
.then(blob => blob.size)
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => blob.size);
|
||||
|
||||
if (imgSize <= maxSize) {
|
||||
return resolve({ url, size: imgSize, blob: await fetch(url).then(res => res.blob()) })
|
||||
return resolve({ url, size: imgSize, blob: await fetch(url).then((res) => res.blob()) });
|
||||
}
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (!ctx)
|
||||
return reject(new Error('无法获取canvas上下文'))
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return reject(new Error("无法获取canvas上下文"));
|
||||
|
||||
let targetWidth = img.width
|
||||
let targetHeight = img.height
|
||||
let targetWidth = img.width;
|
||||
let targetHeight = img.height;
|
||||
|
||||
// 最大边长限制
|
||||
const maxEdge = 2000
|
||||
const maxEdge = 2000;
|
||||
if (targetWidth > maxEdge || targetHeight > maxEdge) {
|
||||
if (targetWidth > targetHeight) {
|
||||
targetHeight = (maxEdge * targetHeight) / targetWidth
|
||||
targetWidth = maxEdge
|
||||
}
|
||||
else {
|
||||
targetWidth = (maxEdge * targetWidth) / targetHeight
|
||||
targetHeight = maxEdge
|
||||
targetHeight = (maxEdge * targetHeight) / targetWidth;
|
||||
targetWidth = maxEdge;
|
||||
} else {
|
||||
targetWidth = (maxEdge * targetWidth) / targetHeight;
|
||||
targetHeight = maxEdge;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = targetWidth
|
||||
canvas.height = targetHeight
|
||||
canvas.width = targetWidth;
|
||||
canvas.height = targetHeight;
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.drawImage(img, 0, 0, targetWidth, targetHeight)
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
|
||||
|
||||
const getBlob = q =>
|
||||
const getBlob = (q) =>
|
||||
new Promise((resolve, reject) => {
|
||||
canvas.toBlob(
|
||||
blob => (blob ? resolve(blob) : reject(new Error('Blob转换失败'))),
|
||||
'image/jpeg',
|
||||
(blob) => (blob ? resolve(blob) : reject(new Error("Blob转换失败"))),
|
||||
"image/jpeg",
|
||||
q,
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
let blob = await getBlob(quality)
|
||||
let blob = await getBlob(quality);
|
||||
|
||||
// 调整质量直到接近最大文件大小
|
||||
let minQ = 0.5
|
||||
let maxQ = quality
|
||||
let attempts = 0
|
||||
let minQ = 0.5;
|
||||
let maxQ = quality;
|
||||
let attempts = 0;
|
||||
|
||||
while (blob.size > maxSize && maxQ - minQ > 0.01 && attempts < 5) {
|
||||
const midQ = (minQ + maxQ) / 2
|
||||
blob = await getBlob(midQ)
|
||||
const midQ = (minQ + maxQ) / 2;
|
||||
blob = await getBlob(midQ);
|
||||
if (blob.size > maxSize) {
|
||||
maxQ = midQ
|
||||
maxQ = midQ;
|
||||
} else {
|
||||
minQ = midQ;
|
||||
}
|
||||
else {
|
||||
minQ = midQ
|
||||
}
|
||||
attempts++
|
||||
attempts++;
|
||||
}
|
||||
resolve({ blob, size: blob.size, url: URL.createObjectURL(blob) })
|
||||
resolve({ blob, size: blob.size, url: URL.createObjectURL(blob) });
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
img.onerror = () => reject(new Error('图片加载失败'))
|
||||
})
|
||||
img.onerror = () => reject(new Error("图片加载失败"));
|
||||
});
|
||||
}
|
||||
|
||||
export function formatFileSize(size) {
|
||||
if (size < 1024)
|
||||
return `${size} B`
|
||||
else if (size < 1024 * 1024)
|
||||
return `${(size / 1024).toFixed(2)} KB`
|
||||
else if (size < 1024 * 1024 * 1024)
|
||||
return `${(size / (1024 * 1024)).toFixed(2)} MB`
|
||||
else return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`
|
||||
if (size < 1024) return `${size} B`;
|
||||
else if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`;
|
||||
else if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`;
|
||||
else return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
||||
}
|
||||
|
||||
// 获取文件扩展名并进行分类
|
||||
export function getFileExtension(fileName) {
|
||||
// 获取文件扩展名
|
||||
const fileExt = fileName.includes('.')
|
||||
? fileName.slice(fileName.lastIndexOf('.') + 1).toLowerCase() // 获取扩展名并转为小写
|
||||
: ''
|
||||
const fileExt = fileName.includes(".")
|
||||
? fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase() // 获取扩展名并转为小写
|
||||
: "";
|
||||
|
||||
// 如果是office类文件,将其归类到 "office"
|
||||
if (['docx', 'docm', 'xls', 'xlsx'].includes(fileExt)) {
|
||||
return 'office'
|
||||
if (["docx", "docm", "xls", "xlsx"].includes(fileExt)) {
|
||||
return "office";
|
||||
}
|
||||
|
||||
// 返回扩展名
|
||||
return fileExt
|
||||
return fileExt;
|
||||
}
|
||||
|
||||
// 上传到阿里云
|
||||
@@ -216,29 +207,27 @@ export function uploadFile(blob, fileName, fileExt, fileSize, xh, moduleid, fath
|
||||
getAliyunKeyApi()
|
||||
.then(async (res) => {
|
||||
try {
|
||||
const aliyunKey = res.data
|
||||
const formData = new FormData()
|
||||
const aliyunKey = res.data;
|
||||
const formData = new FormData();
|
||||
|
||||
let uniqueName = `${Date.now()}_${Math.random()
|
||||
.toString(36)
|
||||
.slice(2)}`
|
||||
let uniqueName = `${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
||||
|
||||
if (fileExt) {
|
||||
uniqueName += `.${fileExt}`
|
||||
uniqueName += `.${fileExt}`;
|
||||
}
|
||||
|
||||
formData.append('key', `${aliyunKey.dir}${uniqueName}`)
|
||||
formData.append('OSSAccessKeyId', aliyunKey.accessid)
|
||||
formData.append('policy', aliyunKey.policy)
|
||||
formData.append('Signature', aliyunKey.signature)
|
||||
formData.append('file', blob, uniqueName)
|
||||
formData.append("key", `${aliyunKey.dir}${uniqueName}`);
|
||||
formData.append("OSSAccessKeyId", aliyunKey.accessid);
|
||||
formData.append("policy", aliyunKey.policy);
|
||||
formData.append("Signature", aliyunKey.signature);
|
||||
formData.append("file", blob, uniqueName);
|
||||
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.open('POST', aliyunKey.host, true)
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", aliyunKey.host, true);
|
||||
|
||||
xhr.onload = async () => {
|
||||
if (xhr.status === 200 || xhr.status === 204) {
|
||||
const allFilePath = `${aliyunKey.host}/${aliyunKey.dir}${uniqueName}`
|
||||
const allFilePath = `${aliyunKey.host}/${aliyunKey.dir}${uniqueName}`;
|
||||
|
||||
const insertRes = await insertFileApi({
|
||||
father,
|
||||
@@ -248,8 +237,8 @@ export function uploadFile(blob, fileName, fileExt, fileSize, xh, moduleid, fath
|
||||
mx_mapfilename: allFilePath,
|
||||
mx_filesize: fileSize,
|
||||
mx_fileext: fileExt,
|
||||
mx_cate_id: cateid || '',
|
||||
})
|
||||
mx_cate_id: cateid || "",
|
||||
});
|
||||
|
||||
if (insertRes.success) {
|
||||
resolve({
|
||||
@@ -260,33 +249,30 @@ export function uploadFile(blob, fileName, fileExt, fileSize, xh, moduleid, fath
|
||||
mx_mapfilename: allFilePath,
|
||||
mx_filesize: fileSize,
|
||||
mx_fileext: fileExt,
|
||||
mx_cate_id: cateid || '',
|
||||
})
|
||||
}
|
||||
else {
|
||||
reject(new Error(insertRes.data.message))
|
||||
mx_cate_id: cateid || "",
|
||||
});
|
||||
} else {
|
||||
reject(new Error(insertRes.data.message));
|
||||
}
|
||||
} else {
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(new Error(`OSS 上传失败: ${xhr.responseText}`));
|
||||
}
|
||||
else {
|
||||
ElMessage.error('上传失败,请稍后再试')
|
||||
reject(new Error(`OSS 上传失败: ${xhr.responseText}`))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => {
|
||||
ElMessage.error('上传失败,请稍后再试')
|
||||
reject(new Error('OSS 上传异常'))
|
||||
}
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(new Error("OSS 上传异常"));
|
||||
};
|
||||
|
||||
xhr.send(formData)
|
||||
}
|
||||
catch (err) {
|
||||
ElMessage.error('上传失败,请稍后再试')
|
||||
reject(err)
|
||||
xhr.send(formData);
|
||||
} catch (err) {
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(err);
|
||||
}
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
export function getAliyunFileBlob(url) {
|
||||
@@ -294,73 +280,70 @@ export function getAliyunFileBlob(url) {
|
||||
// 创建一个独立的异步函数来处理 fetch 请求
|
||||
async function fetchFile() {
|
||||
try {
|
||||
const response = await fetch(url, { mode: 'cors' })
|
||||
const response = await fetch(url, { mode: "cors" });
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
ElMessage.error(`下载失败:${response.status}`)
|
||||
reject(new Error(`下载失败:${response.status}`))
|
||||
return
|
||||
ElMessage.error(`下载失败:${response.status}`);
|
||||
reject(new Error(`下载失败:${response.status}`));
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件内容
|
||||
const blob = await response.blob()
|
||||
const blob = await response.blob();
|
||||
|
||||
// 返回blob
|
||||
resolve(blob)
|
||||
}
|
||||
catch (error) {
|
||||
resolve(blob);
|
||||
} catch (error) {
|
||||
// 捕获网络请求失败或其他错误
|
||||
ElMessage.error('下载文件时发生错误')
|
||||
reject(error)
|
||||
ElMessage.error("下载文件时发生错误");
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 调用异步函数
|
||||
fetchFile()
|
||||
})
|
||||
fetchFile();
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadZip(
|
||||
files,
|
||||
fileName = '文件合集',
|
||||
callback,
|
||||
) {
|
||||
const zip = new JSZip()
|
||||
const addedFiles = new Set() // 用来存储已添加的文件名
|
||||
export function downloadZip(files, fileName = "文件合集", callback) {
|
||||
const zip = new JSZip();
|
||||
const addedFiles = new Set(); // 用来存储已添加的文件名
|
||||
|
||||
let result = files.map((item) => {
|
||||
let promise = getAliyunFileBlob(item.mx_mapfilename).then((res) => {
|
||||
// 处理文件名重复的情况
|
||||
let uniqueFileName = getUniqueFileName(item.mx_filename, addedFiles)
|
||||
zip.file(uniqueFileName, res, { binary: true })
|
||||
addedFiles.add(uniqueFileName) // 添加文件名到已添加的集合中
|
||||
})
|
||||
return promise
|
||||
})
|
||||
let uniqueFileName = getUniqueFileName(item.mx_filename, addedFiles);
|
||||
zip.file(uniqueFileName, res, { binary: true });
|
||||
addedFiles.add(uniqueFileName); // 添加文件名到已添加的集合中
|
||||
});
|
||||
return promise;
|
||||
});
|
||||
|
||||
Promise.all(result).then(() => {
|
||||
zip.generateAsync({ type: 'blob' }).then((res) => {
|
||||
callback && callback()
|
||||
saveAs(res, `${fileName}.zip`)
|
||||
Promise.all(result)
|
||||
.then(() => {
|
||||
zip.generateAsync({ type: "blob" }).then((res) => {
|
||||
callback && callback();
|
||||
saveAs(res, `${fileName}.zip`);
|
||||
});
|
||||
})
|
||||
}).catch(() => {
|
||||
callback && callback()
|
||||
})
|
||||
.catch(() => {
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
|
||||
// 处理文件名重复的函数
|
||||
function getUniqueFileName(fileName, addedFiles) {
|
||||
let uniqueFileName = fileName
|
||||
let counter = 1
|
||||
let uniqueFileName = fileName;
|
||||
let counter = 1;
|
||||
|
||||
// 如果文件名已经存在,则在文件名后加上 (1), (2), ...
|
||||
while (addedFiles.has(uniqueFileName)) {
|
||||
const fileNameWithoutExtension = uniqueFileName.replace(/\.[^/.]+$/, '')
|
||||
const extension = uniqueFileName.slice(uniqueFileName.lastIndexOf('.'))
|
||||
uniqueFileName = `${fileNameWithoutExtension} (${counter})${extension}`
|
||||
counter++
|
||||
const fileNameWithoutExtension = uniqueFileName.replace(/\.[^/.]+$/, "");
|
||||
const extension = uniqueFileName.slice(uniqueFileName.lastIndexOf("."));
|
||||
uniqueFileName = `${fileNameWithoutExtension} (${counter})${extension}`;
|
||||
counter++;
|
||||
}
|
||||
|
||||
return uniqueFileName
|
||||
return uniqueFileName;
|
||||
}
|
||||
@@ -344,6 +344,8 @@ async function handleTreeLoad(node, resolve) {
|
||||
}
|
||||
|
||||
async function handleTreeNodeClick(nodeData) {
|
||||
console.log("===node===")
|
||||
console.log(nodeData)
|
||||
if (!nodeData || nodeData.b_id === "root" || !nodeData.b_moduleid) return;
|
||||
|
||||
currentNode.value = nodeData;
|
||||
|
||||
@@ -17,6 +17,8 @@ const loading = reactive({
|
||||
|
||||
const emits = defineEmits(["change", "closed"]);
|
||||
|
||||
const showFile = ref(false);
|
||||
|
||||
const showVisible = defineModel(false);
|
||||
|
||||
const form = ref({
|
||||
@@ -136,18 +138,41 @@ function onClosed() {
|
||||
|
||||
<div class="form-item">
|
||||
<div class="label">发布</div>
|
||||
<el-switch v-model="form.b_visible" active-value="1" inactive-value="0" />
|
||||
<el-switch
|
||||
v-model="form.b_visible"
|
||||
active-value="1"
|
||||
inactive-value="0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-item">
|
||||
<div class="label">公告内容</div>
|
||||
<WangEditor v-model="form.b_info" :father="form.b_id" module-id="oa_notices" />
|
||||
<WangEditor
|
||||
v-model="form.b_info"
|
||||
:father="form.b_id"
|
||||
module-id="oa_notices"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="showVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="loading.save" @click="handleSave">确认</el-button>
|
||||
<div class="g3-footer">
|
||||
<el-button type="primary" @click="showFile = true">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:paperclip" />
|
||||
</el-icon>
|
||||
上传附件
|
||||
</el-button>
|
||||
|
||||
<div>
|
||||
<el-button @click="showVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="loading.save" @click="handleSave"
|
||||
>确认</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<G3File v-model="showFile" :father="form.b_id" module-id="oa_notices" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -171,4 +196,10 @@ function onClosed() {
|
||||
min-width: 70px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.g3-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
@@ -191,7 +191,12 @@ async function deleteRows(rows = []) {
|
||||
<template>
|
||||
<div class="g3-flex-container">
|
||||
<div class="g3-header">
|
||||
<el-button type="primary" @click="showCategory = true"> 分类 </el-button>
|
||||
<el-button type="primary" @click="showCategory = true">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:settings" />
|
||||
</el-icon>
|
||||
分类设置
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="g3-container">
|
||||
<el-splitter>
|
||||
@@ -218,8 +223,18 @@ async function deleteRows(rows = []) {
|
||||
<div class="g3-container-right">
|
||||
<div style="width: 100%">
|
||||
<div style="display: flex; height: 32px; margin-bottom: 8px">
|
||||
<el-button type="primary" @click="handleAdd"> 新增 </el-button>
|
||||
<el-button type="danger" @click="handleDeleteRows"> 批量删除 </el-button>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:plus" />
|
||||
</el-icon>
|
||||
新增
|
||||
</el-button>
|
||||
<el-button type="danger" @click="handleDeleteRows">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="g3-table">
|
||||
@@ -279,11 +294,20 @@ async function deleteRows(rows = []) {
|
||||
</template>
|
||||
</vxe-column>
|
||||
|
||||
<vxe-column width="200" align="center" fixed="right" title="操作">
|
||||
<vxe-column
|
||||
width="200"
|
||||
align="center"
|
||||
fixed="right"
|
||||
title="操作"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleEditRow(row)"> 编辑 </el-button>
|
||||
<el-button type="primary" link @click="handleEditRow(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
|
||||
<el-button type="danger" link @click="handleDeleteRow(row)"> 删除 </el-button>
|
||||
<el-button type="danger" link @click="handleDeleteRow(row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
|
||||
@@ -18,7 +18,14 @@ const loading = reactive({
|
||||
|
||||
let oldRowData = {};
|
||||
|
||||
const textareaFields = ["b_sql", "b_resultsql", "b_polyline", "b_polyline2", "b_graph_x", "b_img"];
|
||||
const textareaFields = [
|
||||
"b_sql",
|
||||
"b_resultsql",
|
||||
"b_polyline",
|
||||
"b_polyline2",
|
||||
"b_graph_x",
|
||||
"b_img",
|
||||
];
|
||||
|
||||
const validRules = ref({
|
||||
b_id: [
|
||||
@@ -149,7 +156,9 @@ async function deleteRows(rows = []) {
|
||||
return;
|
||||
}
|
||||
|
||||
const delectedIds = rows.filter((row) => !$table.isInsertByRow(row)).map((row) => row.b_id);
|
||||
const delectedIds = rows
|
||||
.filter((row) => !$table.isInsertByRow(row))
|
||||
.map((row) => row.b_id);
|
||||
|
||||
const tipMessage = `确定要删除选中的用户提醒吗?`;
|
||||
|
||||
@@ -248,7 +257,12 @@ async function saveRow(row) {
|
||||
];
|
||||
} else {
|
||||
// 更新
|
||||
const { isChanged, result } = diffObject(row, oldRowData, ["b_id"], ["_X_ROW_KEY"]);
|
||||
const { isChanged, result } = diffObject(
|
||||
row,
|
||||
oldRowData,
|
||||
["b_id"],
|
||||
["_X_ROW_KEY"],
|
||||
);
|
||||
|
||||
if (!isChanged) {
|
||||
ElMessage.info("没有数据变更");
|
||||
@@ -297,7 +311,7 @@ onMounted(async () => {
|
||||
await getsubtable(tableData, tableDataoriginal, ``);
|
||||
});
|
||||
|
||||
async function handleRefresh(){
|
||||
async function handleRefresh() {
|
||||
await getsubtable(tableData, tableDataoriginal, ``);
|
||||
}
|
||||
</script>
|
||||
@@ -306,11 +320,25 @@ async function handleRefresh(){
|
||||
<div class="g3-flex-container">
|
||||
<div class="g3-header">
|
||||
<div class="g3-header-left">
|
||||
<el-button type="primary" @click="handleAdd"> 新建 </el-button>
|
||||
<el-button type="danger" @click="handleDeleteRows"> 删除 </el-button>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:plus" />
|
||||
</el-icon>
|
||||
新建
|
||||
</el-button>
|
||||
<el-button type="danger" @click="handleDeleteRows">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="g3-header-right">
|
||||
<div class="g3-svg-query" style="margin-right: 10px" @click="handleRefresh">
|
||||
<div
|
||||
class="g3-svg-query"
|
||||
style="margin-right: 10px"
|
||||
@click="handleRefresh"
|
||||
>
|
||||
<G3Icon icon="lucide:refresh-ccw" />
|
||||
</div>
|
||||
<el-dropdown>
|
||||
@@ -398,7 +426,9 @@ async function handleRefresh(){
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
<el-button link @click="cancelEditRow(row)" @click.stop> 取消 </el-button>
|
||||
<el-button link @click="cancelEditRow(row)" @click.stop>
|
||||
取消
|
||||
</el-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button
|
||||
@@ -411,7 +441,12 @@ async function handleRefresh(){
|
||||
编辑
|
||||
</el-button>
|
||||
|
||||
<el-button :disabled="loading.save" type="danger" link @click="handleDeleteRow(row)">
|
||||
<el-button
|
||||
:disabled="loading.save"
|
||||
type="danger"
|
||||
link
|
||||
@click="handleDeleteRow(row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
@@ -425,17 +425,26 @@ function handleShowBatchCopyDialog() {
|
||||
</el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
<el-button type="primary" @click="showPasswordRow = !showPasswordRow"
|
||||
>查看密码</el-button
|
||||
>
|
||||
<el-button type="primary" @click="handleShowBatchCopyDialog"
|
||||
>批量复制权限</el-button
|
||||
>
|
||||
<el-button type="primary" @click="showPasswordRow = !showPasswordRow">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:eye" />
|
||||
</el-icon>
|
||||
查看密码
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleShowBatchCopyDialog">
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:copy" />
|
||||
</el-icon>
|
||||
批量复制权限
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleShowCopyDialog"
|
||||
:disabled="!isSelectedRow"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:copy" />
|
||||
</el-icon>
|
||||
复制权限
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -443,6 +452,9 @@ function handleShowBatchCopyDialog() {
|
||||
:disabled="!isSelectedRow"
|
||||
@click="showEmployee = true"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:book-user" />
|
||||
</el-icon>
|
||||
员工资料
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user