8/1 限制前端输入字数
This commit is contained in:
@@ -73,17 +73,21 @@
|
||||
ref="uploadRef"
|
||||
:show-file-list="true"
|
||||
name="files"
|
||||
:on-exceed="handleExceed"
|
||||
:headers="headerToken()"
|
||||
:on-remove="handleAvatarRemove"
|
||||
:on-change="handleProgress"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
accept=".doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png,.gif,.bmp,.webp"
|
||||
accept=".doc,.docx,.xls,.xlsx,.jpg,.jpeg,.png,.gif,.bmp,.webp,.zip"
|
||||
>
|
||||
<div class="uploadBtn flex flex-items-center">
|
||||
<el-icon><Upload /></el-icon>
|
||||
<span>上传文件</span>
|
||||
</div>
|
||||
<template #tip>仅支持doc/docx/xls/xlsx/jpg/png/gif等</template>
|
||||
<template #tip>
|
||||
<div>仅支持doc/docx/xls/xlsx/jpg/png/gif/bmp/webp/zip等格式</div>
|
||||
<span style="font-size: smaller">最多上传 {{ MAX_FILE_COUNT }} 个文件</span>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -108,7 +112,7 @@ import { addHandleLog, getHandleLog, updateHandleLog, uploadAttachments } from '
|
||||
import { UploadFiles, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { Upload } from '@element-plus/icons-vue'; // 确保引入图标
|
||||
import { Upload } from '@element-plus/icons-vue'; // 确保引入图标组件╬╬╬
|
||||
|
||||
const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/handleLog/uploadAttachments';
|
||||
const route = useRoute();
|
||||
@@ -152,33 +156,29 @@ const handleAvatarRemove: UploadProps['onRemove'] = (uploadFile: UploadUserFile,
|
||||
};
|
||||
|
||||
// 定义大小限制常量 (单位: MB)
|
||||
const MAX_SINGLE_FILE_SIZE = 10 * 1024 * 1024; // 10MB in bytes
|
||||
const MAX_TOTAL_FILE_SIZE = 20 * 1024 * 1024; // 20MB in bytes
|
||||
const MAX_SINGLE_FILE_SIZE = 10 * 1024 * 1024; // 10MB
|
||||
const MAX_TOTAL_FILE_SIZE = 20 * 1024 * 1024; // 20MB
|
||||
const MAX_FILE_COUNT = 9; // 最大上传文件数量
|
||||
const uploadRef = ref();
|
||||
// 添加一个锁,防止 on-change 递归调用导致重复提示
|
||||
const isChecking = ref(false);
|
||||
const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
|
||||
ElMessage.warning(`最多只能上传 ${MAX_FILE_COUNT} 个文件,当前已上传 ${uploadFiles.length} 个文件`);
|
||||
};
|
||||
const handleProgress: UploadProps['onChange'] = (uploadFile: UploadUserFile, uploadFiles: UploadFiles) => {
|
||||
// 如果正在校验中,直接返回,避免重复执行
|
||||
// 先校验当前触发的文件类型
|
||||
if (!beforeAvatarUpload(uploadFile)) {
|
||||
uploadRef.value.handleRemove(uploadFile);
|
||||
uploadRef.value?.handleRemove(uploadFile);
|
||||
return;
|
||||
}
|
||||
if (isChecking.value) return;
|
||||
// 加锁
|
||||
isChecking.value = true;
|
||||
// 创建一个新数组来存储校验通过的文件
|
||||
|
||||
const validFiles: CustomUploadFile[] = [];
|
||||
let newFilesTotalSize = 0;
|
||||
let hasError = false;
|
||||
let errorMsg = '';
|
||||
|
||||
// 1. 遍历所有文件,筛选出符合单文件大小要求的文件,并计算新文件总大小
|
||||
// 遍历所有文件,校验新文件
|
||||
for (const file of uploadFiles) {
|
||||
// 只校验新上传的文件 (有 raw 属性)
|
||||
if (file.raw) {
|
||||
// 检查单个文件大小
|
||||
if (file.raw.size > MAX_SINGLE_FILE_SIZE) {
|
||||
// 如果发现单个文件超标,标记错误,并不将该文件加入 validFiles
|
||||
if (!hasError) {
|
||||
errorMsg = `文件 ${file.name} 大小超过 10MB,已自动移除`;
|
||||
hasError = true;
|
||||
@@ -187,57 +187,37 @@ const handleProgress: UploadProps['onChange'] = (uploadFile: UploadUserFile, upl
|
||||
}
|
||||
newFilesTotalSize += file.raw.size;
|
||||
}
|
||||
// 将非超标文件(包括旧文件和未超标的新文件)暂时加入
|
||||
console.log(file);
|
||||
validFiles.push({
|
||||
...file,
|
||||
ossId: (file as CustomUploadFile).ossId ?? null
|
||||
});
|
||||
}
|
||||
|
||||
// 2. 如果存在单文件超标的情况,先处理这部分逻辑
|
||||
if (hasError) {
|
||||
ElMessage.error(errorMsg);
|
||||
// 更新 fileList 为移除了超标文件的列表
|
||||
fileList.value = validFiles;
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 检查新文件总大小是否超过 20MB
|
||||
if (newFilesTotalSize > MAX_TOTAL_FILE_SIZE) {
|
||||
ElMessage.error(`所有新上传文件的总大小不能超过 20MB,当前已选新文件总大小约为 ${(newFilesTotalSize / 1024 / 1024).toFixed(2)}MB`);
|
||||
|
||||
// 策略:移除最后添加的那个导致超标的文件
|
||||
// 注意:这里需要找到最后添加的那个文件。uploadFile 参数就是当前触发的文件
|
||||
// 但如果是一次性选择多个文件,uploadFile 可能是其中一个。
|
||||
// 更稳妥的方式是:如果总和超标,则移除所有新文件中最后加入的那个,或者提示用户手动减少。
|
||||
// 这里我们尝试移除最后加入的一个新文件
|
||||
|
||||
// 找出所有新文件
|
||||
const newFiles = validFiles.filter((f) => f.raw);
|
||||
if (newFiles.length > 0) {
|
||||
// 移除最后一个新文件
|
||||
const lastNewFile = newFiles[newFiles.length - 1];
|
||||
const filteredFiles = validFiles.filter((f) => f.uid !== lastNewFile.uid);
|
||||
fileList.value = filteredFiles;
|
||||
} else {
|
||||
// 理论上不会走到这里,因为如果没有新文件,总大小不会增加
|
||||
fileList.value = validFiles;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 校验全部通过,更新 fileList
|
||||
// 只有当 validFiles 与当前 fileList 不同时才赋值,避免不必要的触发
|
||||
if (validFiles.length !== fileList.value.length || validFiles.some((f, i) => f.uid !== fileList.value[i]?.uid)) {
|
||||
// 只有文件列表真正变化时才更新,避免不必要的响应式触发
|
||||
const currentList = fileList.value;
|
||||
if (validFiles.length !== currentList.length || validFiles.some((f, i) => f.uid !== currentList[i]?.uid)) {
|
||||
fileList.value = validFiles;
|
||||
}
|
||||
|
||||
// 解锁,允许下一次变更触发校验
|
||||
// 使用 nextTick 或 setTimeout 确保 DOM 更新后再解锁,防止极快连续操作的问题
|
||||
setTimeout(() => {
|
||||
isChecking.value = false;
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const blockedExts = ['.exe', '.bat', '.cmd', '.msi'];
|
||||
@@ -259,6 +239,8 @@ const allowExts = [
|
||||
'.gif',
|
||||
'.bmp',
|
||||
'.webp',
|
||||
// archive
|
||||
'.zip',
|
||||
// 专业/矢量图
|
||||
'.psd',
|
||||
'.ai',
|
||||
@@ -389,7 +371,7 @@ function handleBack() {
|
||||
width: 100%;
|
||||
}
|
||||
&:deep(.el-upload-list) {
|
||||
max-height: 200px;
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="flex flex-col h-full p-2">
|
||||
<pageheader title="办事记录"></pageheader>
|
||||
<pageheader></pageheader>
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
@@ -37,7 +37,7 @@
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="办事内容" align="center" prop="content">
|
||||
<template #default="scope">
|
||||
<div class="color-blue" v-html="scope.row.content"></div>
|
||||
<div class="color-blue moreRowEllipsis" v-html="scope.row.content"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="求助人" align="center" prop="seekName" width="120" />
|
||||
@@ -50,7 +50,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="附属材料" width="100" align="center" prop="handlePosition">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" @click="openDiage(scope.row)" link>点击查看</el-button>
|
||||
<el-button type="primary" v-if="scope.row.handleLogFileList?.length > 0" @click="openDialog(scope.row)" link>点击查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
@@ -64,15 +64,15 @@
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
<!-- 添加或修改办事记录对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<ul class="ulbox" v-if="dialog.files.length > 0">
|
||||
<ul class="ulBox" v-if="dialog.files.length > 0">
|
||||
<li @click="handleDown(item)" class="files_item" v-for="(item, index) in dialog.files" :key="index">
|
||||
<div>
|
||||
{{ item.fileName }}
|
||||
</div>
|
||||
<span class="clickdown">点击下载</span>
|
||||
<span class="clickDown">点击下载</span>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="ulbox" v-else>
|
||||
<ul class="ulBox" v-else>
|
||||
<li class="files_item_no">
|
||||
<div>暂无数据</div>
|
||||
</li>
|
||||
@@ -83,14 +83,13 @@
|
||||
</template>
|
||||
|
||||
<script setup name="HandleLog" lang="ts">
|
||||
import { listHandleLog, delHandleLog } from '@/api/system/HandleLog/index';
|
||||
import { HandleLogVO, HandleLogQuery, HandleLogForm } from '@/api/system/HandleLog/type';
|
||||
import { listHandleLog, delHandleLog } from '@/api/system/HandleLog';
|
||||
import { HandleLogVO, HandleLogQuery, HandleLogForm, FileVO } from '@/api/system/HandleLog/type';
|
||||
import { checkPermi } from '@/utils/permission';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const handleLogList = ref<HandleLogVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
@@ -99,7 +98,6 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const handleLogFormRef = ref<ElFormInstance>();
|
||||
|
||||
const initFormData: HandleLogForm = {
|
||||
id: undefined,
|
||||
@@ -126,7 +124,7 @@ const data = reactive<PageData<HandleLogForm, HandleLogQuery>>({
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
const { queryParams } = toRefs(data);
|
||||
|
||||
/** 查询办事记录列表 */
|
||||
const getList = async () => {
|
||||
@@ -169,7 +167,7 @@ const handleAdd = () => {
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: HandleLogVO) => {
|
||||
const handleUpdate = (row?: HandleLogVO) => {
|
||||
const _id = row ? row.id : ids.value[0];
|
||||
router.push({
|
||||
path: '/repair/editHandleLog',
|
||||
@@ -192,14 +190,14 @@ const dialog = reactive({
|
||||
title: '',
|
||||
files: []
|
||||
});
|
||||
|
||||
const openDiage = (row) => {
|
||||
// 查看附属材料
|
||||
const openDialog = (row: HandleLogVO) => {
|
||||
dialog.visible = true;
|
||||
dialog.title = '查看附属材料';
|
||||
console.log(row);
|
||||
dialog.files = row.handleLogFileList ?? [];
|
||||
};
|
||||
const handleDown = (item) => {
|
||||
// 下载文件
|
||||
const handleDown = (item: FileVO) => {
|
||||
proxy?.$download.oss(item.ossId);
|
||||
};
|
||||
onMounted(() => {
|
||||
@@ -210,8 +208,16 @@ onMounted(() => {
|
||||
<style lang="scss" scoped>
|
||||
.el-table {
|
||||
height: calc(100% - 80px);
|
||||
// 超出部分省略号 3 行
|
||||
.moreRowEllipsis {
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
.ulbox {
|
||||
.ulBox {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
@@ -233,12 +239,12 @@ onMounted(() => {
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
color: #409eff;
|
||||
.clickdown {
|
||||
.clickDown {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.clickdown {
|
||||
.clickDown {
|
||||
color: #cccc;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user