Compare commits

...

3 Commits

Author SHA1 Message Date
靈ヾ魂
6156ad08fe update README.md.
Signed-off-by: 靈ヾ魂 <283591387@qq.com>
2025-12-05 11:13:17 +00:00
jxx
5e5b921a84 增加文件上传重命名及自动过滤特殊符号功能 2025-12-05 18:52:25 +08:00
jxx
8cb8bbe4f3 增加文件上传压缩方法base.compressImg() 2025-12-05 18:51:51 +08:00
5 changed files with 737 additions and 384 deletions

View File

@@ -1,5 +1,6 @@
## Vue + .Net8前后端分离不一样的快速开发框架(支持信创)
## 框架核心
@@ -41,32 +42,32 @@ App、H5、微信小程序: [http://app.volcore.xyz/](http://app.volcore.xyz/) <
sqlsugar: [https://www.donet5.com/](https://www.donet5.com/)
## 框架移动端uniapp已发布,同样全自动生成代码,扫描小程序二维码即可查看
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/home.png)
![Home](/imgs/home.png)
## 1、标准页面
整个页面所有前后端代码,全部由代码生成器界面上配置生成,并支持并后端业务代码扩展
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/page1.png)
![Home](/imgs/page1.png)
## 2、主子表页面
同样由代码生成器自动生成,零代码实现整个页面主子表的新建、编辑、删除、查询、导入、导出功能
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/main-01.png)
![Home](/imgs/main-01.png)
主子表编辑页面
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/main-02.png)
![Home](/imgs/main-02.png)
## 3、审批流程配置
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/flow.png)
![Home](/imgs/flow.png)
## 4、数据审批
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/flow02.png)
![Home](/imgs/flow02.png)
## 5、树形结构
只需少量配置即可完成树形结构配置编辑,按层级加载数据等功能
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/tree.png)
![Home](/imgs/tree.png)
## 6、图表统计
框架提供了丰富的图表统计,能复制就能开发
![Home](https://github.com/cq-panda/Vue.NetCore/blob/master/imgs/state.png)
![Home](/imgs/state.png)
其他功能。。。。。

View File

@@ -0,0 +1,180 @@
/**
* 创建图片对象
* @param {File} file - 图片文件
* @returns {Promise<HTMLImageElement>} - 图片对象
*/
function createImage(file) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.src = URL.createObjectURL(file);
});
}
/**
* 检查图片是否包含透明度
* @param {HTMLImageElement} img - 图片对象
* @returns {Promise<boolean>} - 是否包含透明度
*/
function checkImageHasAlpha(img) {
return new Promise((resolve) => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// 获取图像数据
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 检查是否有像素的alpha通道值小于255即透明
for (let i = 3; i < data.length; i += 4) {
if (data[i] < 255) {
resolve(true);
return;
}
}
resolve(false);
});
}
/**
* @param {string} mimeType - 目标MIME类型
* @param {number} originalSize - 原始文件大小(字节)
* @param {number} maxSize - 最大允许大小(字节)
* @param {Function} onProgress - 进度回调函数
* @returns {Promise<Blob>} - 压缩后的Blob对象
*/
function compressWithBinarySearch(canvas, mimeType, originalSize, maxSize, onProgress) {
return new Promise((resolve) => {
let minQuality = 0.1;
let maxQuality = 1.0;
let bestBlob = null;
let bestSize = originalSize;
// 最多尝试10次平衡效率和精度
const maxIterations = 10;
let iterations = 0;
function updateProgress(currentIteration) {
if (onProgress) {
const progress = Math.round((currentIteration / maxIterations) * 100);
onProgress(progress);
}
}
function compress(quality) {
canvas.toBlob(
(blob) => {
iterations++;
updateProgress(iterations);
if (!blob) {
// 如果转换失败,使用默认质量
canvas.toBlob(resolve, mimeType, 0.5);
return;
}
const blobSize = blob.size;
// 更新最佳结果
if (blobSize < bestSize) {
bestBlob = blob;
bestSize = blobSize;
}
// 检查是否符合条件或达到最大迭代次数
if (blobSize <= maxSize || iterations >= maxIterations || maxQuality - minQuality < 0.01) {
resolve(bestBlob);
return;
}
// 二分调整质量
if (blobSize > maxSize) {
// 压缩后仍太大,降低质量
maxQuality = quality;
} else {
// 压缩后符合要求,尝试提高质量以获得更好效果
minQuality = quality;
}
// 下一次尝试的质量
const nextQuality = (minQuality + maxQuality) / 2;
compress(nextQuality);
},
mimeType,
quality
);
}
// 开始压缩
compress(0.8);
});
}
/**
* @param {File} file - 上传的图片文件
* @param {Object} options - 压缩选项
* @param {number} options.maxSize - 最大允许大小字节默认400KB
* @param {number} options.initialQuality - 初始压缩质量0-1默认0.7
* @param {Function} options.onProgress - 进度回调函数
* @returns {Promise<File>} - 压缩后的图片文件
*/
export async function compressImage(file, options = {}) {
const {
maxSize = 300 * 1024,
initialQuality = 0.7,
onProgress
} = options;
// 如果文件已经小于等于最大尺寸,直接返回
if (file.size <= maxSize) {
return file;
}
// 创建图片对象
const img = await createImage(file);
// 创建canvas并绘制图片
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸保持原始宽高比
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 根据文件类型选择压缩策略
const fileType = file.type;
let compressedBlob;
if (fileType === 'image/png') {
// PNG处理检查是否有透明度决定压缩策略
const hasAlpha = await checkImageHasAlpha(img);
if (hasAlpha) {
// 有透明度的PNG使用PNG压缩但可能效果有限
compressedBlob = await compressWithBinarySearch(canvas, 'image/png', file.size, maxSize, onProgress);
} else {
// 无透明度的PNG转换为JPEG压缩效果更好
compressedBlob = await compressWithBinarySearch(canvas, 'image/jpeg', file.size, maxSize, onProgress);
}
} else {
// 其他格式如JPEG、WebP等直接压缩
compressedBlob = await compressWithBinarySearch(canvas, fileType, file.size, maxSize, onProgress);
}
// 将Blob转换为File对象
return new File([compressedBlob], file.name, {
type: compressedBlob.type,
lastModified: file.lastModified
});
}
// 默认导出
export default compressImage;

View File

@@ -1,4 +1,5 @@
import common from '@/uitils/common.js'
import {compressImage } from './VolImgCompress.js'
import store from '@/store/index'
const getImgUrls = (imgs) => {
return imgs
@@ -27,6 +28,8 @@ const getFormValues = (formFields, formOptions) => {
if (typeof val == 'function') {
formValues[key] = formFields[key]()
continue
} else if (typeof val == 'string' && val) {
val = val.trim();
}
//解决下拉框清除后不能保存数据的问题
if (val === undefined) {
@@ -282,9 +285,13 @@ const getSearchParameters = (proxy, formFields, formRules) => {
//查询下面所有的子节点,如:选中的是父节点,应该查询下面所有的节点数据--待完
if (value && value.length) {
let nodes = proxy.base.getTreeAllChildren(value[value.length - 1], option.orginData)
if (!(nodes?.length)) {
value = [value[value.length - 1]]
} else {
value = nodes.map((x) => {
return x.id
})
}
displayType = 'selectList'
}
} else if (displayType == 'treeSelect' && Array.isArray(value)) {
@@ -335,11 +342,22 @@ const resetFileName = async (files, callbck) => {
if (!files?.length) return
for (let index = 0; index < files.length; index++) {
let originalFile = files[index]
if (!originalFile.size) {
continue;
}
const uniqueFileName = await callbck?.(originalFile) || generateUniqueFileName(originalFile.name);
const newFile = new File([originalFile], uniqueFileName, {
if (uniqueFileName===false) {
continue;
}
let extension='';
if (!uniqueFileName.includes('.')) {
extension='.'+originalFile.name.split('.').pop();
}
const newFile = new File([originalFile], uniqueFileName+extension, {
type: originalFile.type,
lastModified: originalFile.lastModified
});
newFile.input=originalFile.input
files.splice(index, 1, newFile);
}
}
@@ -360,5 +378,6 @@ export default {
getAccessToken,
isEmptyValue,
getSearchParameters,
resetFileName
resetFileName,
compressImage
}

View File

@@ -3,21 +3,11 @@
<div>
<!-- style="margin-bottom: 10px" -->
<div class="input-btns" style="display: flex">
<input
ref="input"
type="file"
style="display: none"
@change="handleChange"
:multiple="multiple"
/>
<input ref="input" type="file" style="display: none" @change="handleChange" :multiple="multiple" />
<div v-if="img" class="upload-img">
<!-- v-for="(file,index) in fileInfo.length>0?fileInfo: files" -->
<div
v-for="(file, index) in files"
:key="index"
:style="{ height: imgInfo.height + 'px', width: imgInfo.width + 'px' }"
class="img-item"
>
<div v-for="(file, index) in files" :key="index"
:style="{ height: imgInfo.height + 'px', width: imgInfo.width + 'px' }" class="img-item">
<div class="operation">
<div class="action">
<i class="el-icon-view view" @click="previewImg(index)"></i>
@@ -28,48 +18,26 @@
<img :src="getImgSrc(file, index) + access_token" @error="handleImageError" />
</div>
<div
:style="{ height: imgInfo.height + 'px', width: imgInfo.width + 'px' }"
v-show="!autoUpload || (autoUpload && files.length < maxFile)"
class="img-selector"
:class="getSelector()"
>
<div :style="{ height: imgInfo.height + 'px', width: imgInfo.width + 'px' }"
v-show="!autoUpload || (autoUpload && files.length < maxFile)" class="img-selector" :class="getSelector()">
<div class="selector" @click="handleClick">
<i
:style="{ 'font-size': imgInfo.iconSize + 'px' }"
:class="imgInfo.icon"
></i>
<i :style="{ 'font-size': imgInfo.iconSize + 'px' }" :class="imgInfo.icon"></i>
</div>
<div
v-if="!autoUpload"
class="s-btn"
:class="{ readonly: changed }"
@click="upload"
>
<div v-if="!autoUpload" class="s-btn" :class="{ readonly: changed }" @click="upload">
<div>{{ loadText }}</div>
</div>
</div>
</div>
<el-button v-else @click="handleClick">{{
$ts("选择" + (img ? "图片" : "文件"))
$ts('选择' + (img ? '图片' : '文件'))
}}</el-button>
<el-button
v-if="!autoUpload && !img"
type="info"
:disabled="changed"
@click="upload(true)"
:loading="loadingStatus"
>{{ $ts("上传文件") }}</el-button
>
<el-button v-if="!autoUpload && !img" type="info" :disabled="changed" @click="upload(true)"
:loading="loadingStatus">{{ $ts('上传文件') }}</el-button>
</div>
<slot></slot>
<div v-if="desc">
<el-alert
:title="getText() + '文件大小不超过' + (maxSize || 50) + 'M'"
type="info"
show-icon
>
<el-alert :title="getText() + '文件大小不超过' + (maxSize || 50) + 'M'" type="info" show-icon>
</el-alert>
</div>
<slot name="content"></slot>
@@ -95,96 +63,97 @@
</template>
<script>
//import OSS from 'ali-oss'
const OSS = {};
import VolImageViewer from "./VolImageViewer.vue";
const OSS = {}
//import VolImageViewer from './VolImageViewer.vue'
import { defineAsyncComponent } from 'vue'
export default {
components: {
"vol-image-viewer": VolImageViewer,
'vol-image-viewer': defineAsyncComponent(() => import('@/components/basic/VolImageViewer.vue')),
},
props: {
desc: {
//是否显示默认介绍
//是否多选
type: Boolean,
default: false,
default: false
},
fileInfo: {
//用于接收上传的文件,也可以加以默认值,显示已上传的文件,用户上传后会覆盖默认值
type: Array,
default: () => {
return [];
}, //格式[{name:'1.jpg',path:'127.0.01/1.jpg'}]
return []
} //格式[{name:'1.jpg',path:'127.0.01/1.jpg'}]
},
downLoad: {
//是否可以点击文件下载
type: Boolean,
default: true,
default: true
},
multiple: {
//是否多选
type: Boolean,
default: false,
default: false
},
maxFile: {
//最多可选文件数量必须multiple=true才会生效
type: Number,
default: 5,
default: 5
},
maxSize: {
//文件限制大小3M
type: Number,
default: 50,
default: 50
},
autoUpload: {
//选择文件后是否自动上传
type: Boolean,
default: true,
default: true
},
img: {
//图片类型 img>excel>fileTypes三种文件类型优先级
type: Boolean,
default: false,
default: false
},
excel: {
//excel文件
type: Boolean,
default: false,
default: false
},
fileTypes: {
//指定上传文件的类型
type: Array,
default: () => {
return [];
},
return []
}
},
url: {
//上传的url
type: String,
default: "",
default: ''
},
uploadBefore: {
//返回false会中止执行
//上传前
type: Function,
default: (files) => {
return true;
},
return true
}
},
uploadAfter: {
//返回false会中止执行
//上传后
type: Function,
default: (result, files) => {
return true;
},
return true
}
},
onChange: {
//选择文件时 //返回false会中止执行
type: Function,
default: (files) => {
return true;
},
return true
}
},
// clear: {
// //上传完成后是否清空文件列表
@@ -194,36 +163,36 @@ export default {
fileList: {
//是否显示选择的文件列表
type: Boolean,
default: true,
default: true
},
fileClick: {
//点击文件事件
type: Function,
default: (index, file, files) => {
return true;
},
return true
}
},
removeBefore: {
//移除文件事件
type: Function,
default: (index, file, files) => {
return true;
},
return true
}
},
append: {
//此属性已废弃,多文件上传,默认追加文件
type: Boolean,
default: false,
default: false
},
compress: {
//开启图片压缩,后面根据需要再完善
//开启图片压缩
type: Boolean,
default: false,
default: true
},
compressMinSize: {
//压缩的最小比例
type: Number,
default: 0.1,
default: 0.7
},
imgOption: {
//图片上传信息
@@ -234,327 +203,250 @@ export default {
//iconSize:40,//上传图标大小
// height: 65, //图片高度
// width: 65,//图片宽度
};
},
},
}
}
}
},
data() {
return {
defaultImg: new URL("@/assets/imgs/error-img.png", import.meta.url).href,
defaultImg: new URL('@/assets/imgs/error-img.png', import.meta.url).href,
// errorImg: 'this.src="' + require('@/assets/imgs/error-img.png') + '"',
changed: false, //手动上传成功后禁止重复上传,必须重新选择
model: true,
files: [],
bigImg: "",
imgTypes: ["gif", "jpg", "jpeg", "png", "bmp", "webp", "jfif"],
bigImg: '',
imgTypes: ['gif', 'jpg', 'jpeg', 'png', 'bmp', 'webp', 'jfif'],
loadingStatus: false,
loadText: "上传文件",
access_token: "",
loadText: '上传文件',
access_token: '',
imgInfo: {
icon: "el-icon-camera-solid",
icon: 'el-icon-camera-solid',
iconSize: 35,
height: 65, //图片高度
width: 65, //图片宽度
},
};
width: 65 //图片宽度
}
}
},
created() {
Object.assign(this.imgInfo, this.imgOption);
const tk = (this.$store.getters.getUserInfo() || { accessToken: "" }).accessToken;
Object.assign(this.imgInfo, this.imgOption)
const tk = (this.$store.getters.getUserInfo() || { accessToken: '' }).accessToken
if (tk) {
this.access_token = "?access_token=" + tk;
this.access_token = '?access_token=' + tk
}
//默认有图片的禁止上传操作
if (this.fileInfo) {
this.changed = true;
this.changed = true
}
this.cloneFile(this.fileInfo);
this.cloneFile(this.fileInfo)
},
watch: {
fileInfo: {
handler(files) {
this.cloneFile(files);
},
deep: true,
this.cloneFile(files)
},
deep: true
}
},
methods: {
cloneFile(files) {
this.files = files.map((x) => {
return {
name: x.name || this.getFileName(x.path),
path: x.path,
};
});
path: x.path
}
})
},
getFileName(path) {
if (!path) {
return "未定义文件名";
return '未定义文件名'
}
let _index = path.lastIndexOf("/");
return path.substring(_index + 1);
let _index = path.lastIndexOf('/')
return path.substring(_index + 1)
},
previewImg(index) {
const imgs = this.files.map((x) => {
return this.getImgSrc(x) + this.access_token;
});
this.$refs.viewer.show(imgs, index);
return this.getImgSrc(x) + this.access_token
})
this.$refs.viewer.show(imgs, index)
// this.base.previewImg(this.getImgSrc(this.files[index]));
// window.open(this.getImgSrc((this.files.length>0?this.files:this.fileInfo)[index]));
},
getSelector() {
if (this.autoUpload) {
return "auto-selector";
return 'auto-selector'
}
return "submit-selector";
return 'submit-selector'
},
getImgSrc(file, index) {
if (file.hasOwnProperty("path")) {
if (file.hasOwnProperty('path')) {
if (this.base.isUrl(file.path)) {
return file.path;
return file.path
}
//2020.12.27增加base64图片操作
if (file.path.indexOf("/9j/") != -1) {
return "data:image/jpeg;base64," + file.path;
if (file.path.indexOf('/9j/') != -1) {
return 'data:image/jpeg;base64,' + file.path
}
if (file.path.substr(0, 1) == "/") {
file.path = file.path.substr(1);
if (file.path.substr(0, 1) == '/') {
file.path = file.path.substr(1)
}
return this.http.ipAddress + file.path;
return (this.$global.oss?.url || this.http.ipAddress) + file.path
}
return window.URL.createObjectURL(file);
return window.URL.createObjectURL(file)
},
fileOnClick(index, file) {
if (!this.fileClick(index, file, this.files)) {
return;
return
}
//点击不下载
if (!this.downLoad) {
return;
return
}
if (!file.path) {
this.$message.error("请先上传文件");
return;
this.$message.error('请先上传文件')
return
}
this.base.dowloadFile(
file.path + this.access_token,
file.name,
{
Authorization: this.$store.getters.getToken(),
Authorization: this.$store.getters.getToken()
},
this.http.ipAddress
);
)
},
getText() {
if (this.img) {
return "只能上传图片,";
return '只能上传图片,'
} else if (this.excel) {
return "只能上传excel文件,";
return '只能上传excel文件,'
}
},
handleClick() {
this.$refs.input.click();
this.$refs.input.click()
},
handleChange(e) {
//this.compress开启图片压缩,后面根据需要再完善
// this.clearFiles();
var result = this.checkFile(e.target.files);
var result = this.checkFile(e.target.files)
if (!result) {
return;
return
}
this.changed = false;
this.changed = false
//如果传入了FileInfo需要自行处理移除FileInfo
if (!this.onChange(e.target.files)) {
return;
return
}
for (let index = 0; index < e.target.files.length; index++) {
const element = e.target.files[index];
element.input = true;
const element = e.target.files[index]
element.input = true
}
if (!this.multiple) {
this.files.splice(0);
this.files.splice(0)
}
this.files.push(...e.target.files);
this.files.push(...e.target.files)
this.$refs.input.value = null;
this.$refs.input.value = null
if (this.autoUpload && result) {
this.upload(false);
this.upload(false)
}
},
removeFile(index) {
//如果传入了FileInfo需要自行处理移除FileInfo
//t移除文件
let removeFile = this.files[index];
let removeFile = this.files[index]
if (!this.removeBefore(index, removeFile, this.fileInfo)) {
return
}
//删除的还没上传的文件
if (removeFile.input) {
this.files.splice(index, 1);
this.files.splice(index, 1)
} else {
this.fileInfo.splice(index, 1);
}
if (!this.removeBefore(index, removeFile, this.fileInfo)) {
return;
this.fileInfo.splice(index, 1)
}
},
clearFiles() {
this.files.splice(0);
this.files.splice(0)
},
getFiles() {
return this.files;
return this.files
},
convertToFile(dataurl, filename) {
let arr = dataurl.split(",");
let mime = arr[0].match(/:(.*?);/)[1];
let suffix = mime.split("/")[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
async compressImg() {
if (!this.compress||!this.img) return;
for (let index = 0; index < this.files.length; index++) {
let originalFile = this.files[index]
if (originalFile.size > 300 * 1024) {
try {
const newFile = await this.base.compressImage(originalFile, { initialQuality: this.compressMinSize });
newFile.input = originalFile.input
this.files.splice(index, 1, newFile);
// console.log(newFile.size)
} catch (error) {
console.log('图片压缩异常', error)
}
// new File返回File对象 第一个参数是 ArraryBuffer 或 Bolb 或Arrary 第二个参数是文件名
// 第三个参数是 要放到文件中的内容的 MIME 类型
return new File([u8arr], `${filename}.${suffix}`, {
type: mime,
input: true,
});
},
async compressImg(file) {
let fileSize = file.size / 1024 / 1024;
let read = new FileReader();
read.readAsDataURL(file);
return new Promise((resolve, reject) => {
read.onload = (e) => {
let img = new Image();
img.src = e.target.result;
let _this = this;
img.onload = function () {
//默认按比例压缩
let w = this.width;
let h = this.height;
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.setAttribute("width", w);
canvas.setAttribute("height", h);
ctx.drawImage(this, 0, 0, w, h);
let rate = 0.3;
if (fileSize > 2) {
rate = 0.1;
} else if (fileSize > 1) {
rate = 0.1;
}
if (_this.compressMinSize > rate) {
rate = _this.compressMinSize;
}
// rate=1;
let base64 = canvas.toDataURL("image/jpeg", rate);
resolve(_this.convertToFile(base64, file.name));
};
};
});
},
async uploadOSS() {
this.http.get("api/alioss/getAccessToken", {}, false).then(async (x) => {
if (!x.status) return this.$Message.error(x.message);
let client = new OSS({
// yourRegion填写Bucket所在地域。以华东1杭州为例Region填写为oss-cn-hangzhou。
region: x.data.region,
// 从STS服务获取的临时访问密钥AccessKey ID和AccessKey Secret
accessKeyId: x.data.accessKeyId,
accessKeySecret: x.data.accessKeySecret,
// 从STS服务获取的安全令牌SecurityToken
stsToken: x.data.securityToken,
// 填写Bucket名称。
bucket: x.data.bucket,
});
console.log(this.files);
for (let index = 0; index < this.files.length; index++) {
const file = this.files[index];
if (file.input) {
let result = await client.put(
x.data.bucketFolder + "/" + x.data.unique + file.name,
file
);
file.path = result.url;
file.newName = x.data.unique + file.name;
}
}
this.fileInfo.splice(0);
// }
let _files = this.files.map((file) => {
return {
name: file.newName || file.name,
path: file.path,
};
});
this.fileInfo.push(..._files);
//2021.09.25修复文件上传后不能同时下载的问题
this.files = _files;
});
return;
},
async upload(vail) {
if (vail && !this.checkFile()) return false;
if (vail && !this.checkFile()) return false
if (!this.url) {
return this.$message.error("没有配置好Url");
return this.$message.error('没有配置好Url')
}
if (!this.files || this.files.length == 0) {
return this.$message.error("请选择文件");
return this.$message.error('请选择文件')
}
//开启压缩
await this.compressImg();
//过滤文件符号
await this.base.resetFileName(this.files, (file) => {
if (file.name?.includes(' ') || file.name?.includes(',') || file.name?.includes('+')) {
return file.name.replaceAll(' ', '').replaceAll('+', '').replaceAll(',', '')
}
return false;
})
//增加上传时自定义参数后台使用获取Utilities.HttpContext.Current.Request.Query["字段"]
let params = {};
if (!this.uploadBefore(this.files, params)) {
return;
let params = {}
if (! await this.uploadBefore(this.files, params)) {
return
}
let paramText = "";
let paramText = ''
if (Object.keys(params).length) {
paramText = "?1=1";
paramText = '?1=1'
for (const key in params) {
let value = params[key];
if (typeof value == "object") {
value = JSON.stringify(value);
let value = params[key]
if (typeof value == 'object') {
value = JSON.stringify(value)
}
paramText += `&${key}=${value}`;
paramText += `&${key}=${value}`
}
}
this.loadingStatus = true;
this.loadText = "上传中..";
this.loadingStatus = true
this.loadText = '上传中..'
if (window.oss && window.oss.ali.use) {
await this.uploadOSS();
this.loadingStatus = false;
this.loadText = "上传文件";
await this.uploadOSS()
this.loadingStatus = false
this.loadText = '上传文件'
if (!this.uploadAfter({ status: true }, this.files)) {
this.changed = false;
return;
this.changed = false
return
} else {
this.changed = true;
this.changed = true
}
this.$message.success("上传成功");
return;
this.$message.success('上传成功')
return
}
var forms = new FormData();
var forms = new FormData()
for (let index = 0; index < this.files.length; index++) {
let file = this.files[index];
let file = this.files[index]
if (file.input) {
//2023.07.10暂时屏蔽图片压缩
//let name = file.name.split('.');
//name = name[name.length - 1].toLocaleLowerCase();
//let isImg = this.imgTypes.indexOf(name) != -1;
// if (isImg && (name == 'jpg' || name == 'jpeg')) {
// //>200KB的开启压缩
// if (isImg && file.size / 1024 / 1024 > 0.2) {
// console.log('压缩前' + file.size);
// file = await this.compressImg(file);
// file.compress = true;
// this.files[index] = file;
// this.files[index].input = true;
// console.log('压缩后' + file.size);
// }
// }
forms.append("fileInput", file, file.name);
forms.append('fileInput', file, file.name)
}
}
// forms.append("fileInput", this.files);
@@ -563,174 +455,143 @@ export default {
.post(
this.url + paramText,
forms,
this.autoUpload ? "正在上传文件" : "",
this.autoUpload ? '正在上传文件' : '',
//高版本axios这里必须要指定header
{
headers: { "Content-Type": "multipart/form-data" },
headers: { 'Content-Type': 'multipart/form-data' }
}
)
.then(
(x) => {
// this.$refs.uploadFile.clearFiles();
this.loadingStatus = false;
this.loadText = "上传文件";
this.loadingStatus = false
this.loadText = '上传文件'
if (!this.uploadAfter(x, this.files)) {
this.changed = false;
return;
this.changed = false
return
} else {
this.changed = true;
this.changed = true
}
this.changed = x.status;
this.changed = x.status
if (!x.status) {
this.$message.error(x.message);
this.$message.error(x.message)
// this.files = null;
return;
return
}
this.$message.success(x.message);
this.$message.success(x.message)
//单选清除以前的数据
// if (!this.multiple) {
this.fileInfo.splice(0);
this.fileInfo.splice(0)
// }
let _files = this.files.map((file) => {
return {
name: file.name,
path: file.path || x.data + file.name,
};
});
this.fileInfo.push(..._files);
path: file.path || x.data + file.name
}
})
this.fileInfo.push(..._files)
//2021.09.25修复文件上传后不能同时下载的问题
this.files = _files;
this.files = _files
},
(error) => {
this.loadText = "上传文件";
this.loadingStatus = false;
this.loadText = '上传文件'
this.loadingStatus = false
}
);
)
},
format(file, checkFileType) {
const format = file.name.split(".").pop().toLocaleLowerCase() || "";
let fileIcon = "el-icon-document";
const format = file.name.split('.').pop().toLocaleLowerCase() || ''
let fileIcon = 'el-icon-document'
if (this.fileTypes.length > 0 && checkFileType != undefined) {
if (this.fileTypes.indexOf(format) != -1) {
return true;
return true
}
return false;
return false
}
if (
checkFileType &&
!(checkFileType instanceof Array) &&
checkFileType != "img" &&
checkFileType != "excel"
checkFileType != 'img' &&
checkFileType != 'excel'
) {
if (checkFileType.indexOf(format) > -1) {
return true;
return true
} else {
return false;
return false
}
}
if (checkFileType == "img" || this.imgTypes.indexOf(format) > -1) {
if (checkFileType == "img") {
if (checkFileType == 'img' || this.imgTypes.indexOf(format) > -1) {
if (checkFileType == 'img') {
if (this.imgTypes.indexOf(format) > -1) {
return true;
return true
} else {
return false;
return false
}
}
fileIcon = "el-icon-picture-outline";
fileIcon = 'el-icon-picture-outline'
}
if (
["mp4", "m3u8", "rmvb", "avi", "swf", "3gp", "mkv", "flv"].indexOf(format) > -1
) {
fileIcon = "el-icon-document";
}
if (["mp3", "wav", "wma", "ogg", "aac", "flac"].indexOf(format) > -1) {
fileIcon = "el-icon-document";
}
if (["doc", "txt", "docx", "pages", "epub", "pdf"].indexOf(format) > -1) {
fileIcon = "el-icon-document";
}
if (
checkFileType == "excel" ||
["numbers", "csv", "xls", "xlsx"].indexOf(format) > -1
) {
if (checkFileType == "excel") {
if (["numbers", "csv", "xls", "xlsx"].indexOf(format) > -1) {
return true;
if (checkFileType == 'excel' || ['numbers', 'csv', 'xls', 'xlsx'].indexOf(format) > -1) {
if (checkFileType == 'excel') {
if (['numbers', 'csv', 'xls', 'xlsx'].indexOf(format) > -1) {
return true
} else {
return false;
return false
}
}
fileIcon = "el-icon-document";
}
return fileIcon;
return fileIcon
},
beforeUpload() { },
checkFile(inputFiles) {
const files = this.files;
const files = this.files
if (
this.multiple &&
files.length + (inputFiles || []).length > (this.maxFile || 5)
) {
if (this.multiple && files.length + (inputFiles || []).length > (this.maxFile || 5)) {
this.$message.error(
"最多只能选【" +
(this.maxFile || 5) +
"】" +
(this.img ? "张图片" : "个文件") +
""
);
return false;
'最多只能选【' + (this.maxFile || 5) + '】' + (this.img ? '张图片' : '个文件') + ''
)
return false
}
if (!inputFiles) {
inputFiles = this.files.filter((x) => {
return x.input;
});
return x.input
})
}
let names = [];
let names = []
for (let index = 0; index < inputFiles.length; index++) {
const file = inputFiles[index];
const file = inputFiles[index]
if (names.indexOf(file.name) != -1) {
file.name = "(" + index + ")" + file.name;
file.name = '(' + index + ')' + file.name
}
names.push(file.name);
if (this.img && !this.format(file, "img")) {
this.$message.error("选择的文件【" + file.name + "】只能是图片格式");
return false;
names.push(file.name)
if (this.img && !this.format(file, 'img')) {
this.$message.error('选择的文件【' + file.name + '】只能是图片格式')
return false
}
if (this.excel && !this.format(file, "excel")) {
this.$message.error("选择的文件【" + file.name + "】只能是excel文件");
return false;
if (this.excel && !this.format(file, 'excel')) {
this.$message.error('选择的文件【' + file.name + '】只能是excel文件')
return false
}
if (
this.fileTypes &&
this.fileTypes.length > 0 &&
!this.format(file, this.fileTypes)
) {
if (this.fileTypes && this.fileTypes.length > 0 && !this.format(file, this.fileTypes)) {
this.$message.error(
"选择的文件【" +
file.name +
"】只能是【" +
this.fileTypes.join(",") +
"】格式"
);
return false;
'选择的文件【' + file.name + '】只能是【' + this.fileTypes.join(',') + '】格式'
)
return false
}
if (file.size > (this.maxSize || 50) * 1024 * 1024) {
this.$message.error(
"选择的文件【" + file.name + "】不能超过:" + (this.maxSize || 50) + "M"
);
return false;
'选择的文件【' + file.name + '】不能超过:' + (this.maxSize || 50) + 'M'
)
return false
}
}
return true;
return true
},
handleImageError($e) {
$e.target.src = this.defaultImg;
},
},
};
$e.target.src = this.defaultImg
}
}
}
</script>
<style lang="less" scoped>
.upload-list {
@@ -910,8 +771,7 @@ export default {
height: 100%;
position: relative;
.m-img {
}
.m-img {}
.mask {
position: absolute;

View File

@@ -0,0 +1,293 @@
export default {
"审批流程":"workflow",
"基础设置":"settings",
"基础组件":"components",
"框架文档":"doc",
"仓库管理":"Warehouse",
"设备管理":"Equipment",
"最多只能选[5]张图片": "You can only select [5] pictures at most",
"最多只能选[5]个文件": "Only [5] files can be selected at most",
"只能选择excel文件": "Only Excel files can be selected",
"文件大小不能超过": "The file size cannot exceed",
"最多可输入[{$ts}]个字符": "a maximum of [{$ts}] characters can be entered",
"第[{$ts}]行,[{$ts}]验证未通过": "Line [{$ts},{$ts}] failed verificatio",
"删除成功,共[{$ts}]条数据": "Deletion succeeded, with a total of [{$ts}] data",
"[{$ts}]不能为空": "[{$ts}] is required",
"[{$ts},{$ts}]不能为空": "[{$ts},{$ts}] is required",
"无数据": "No data",
"[{$ts}]重复": "[{$ts}] repeated",
"搜索": "Search",
"详情": "Details",
"重复": "repeated",
"重复记录": "Repeated recording",
"重置": "Reset",
"重置筛选条件": "Reset filter",
"角色管理": "Role info",
"角色名称": "Role",
"角色": "Role",
"设置": "Setting",
"保存筛选条件": "Save filter",
"保存成功,共{$ts}条数据": "Saved successfully, {$ts} item in total",
"选择": "Select",
"选择文件": "Select file",
"请选择行": "Please select rows",
"修改人": "Modifier",
"修改密码": "Password",
"修改时间": "Modify time",
"模块": "Module",
"月": "Months",
"更多": "More",
"名字": "Name",
"邮箱": "Mail",
"女": "Male",
"男": "Ma",
"菜单": "Menu",
"菜单名称": "Menu name",
"菜单设置": "Menu",
"提示": "Message",
"否": "No",
"父级ID": "Parent ID",
"上级角色": "Parent role",
"密码": "Password",
"权限": "Permissio",
"个人中心": "Personal Center",
"请输入": "Please input",
"请选择": "Please select",
"请选择文件": "Please select file",
"其他": "Other",
"必须是数字": "not a number",
"备注": "Notes",
"确认": "OK",
"是": "Yes",
"不存在": "does not exist",
"系统": "System",
"表名": "Table Name",
"电话": "Tel",
"时间": "Time",
"排序号": "Sort NO",
"状态": "Status",
"操作成功": "Success",
"删除成功": "Successfully Delete",
"保存成功": "Successfully save",
"摘要": "Summary",
"超级管理员": "Super Admi",
"确定": "Confirm",
"用户管理": "User info",
"用户名": "Account",
"用户权限": "User permission",
"用户基础信息": "User info",
"用户名或密码错误": "Account or password incorrect",
"值": "Value",
"查看": "View",
"警告": "Warning",
"最多{$ts}个字符": "Up to {$ts} characters",
"上传文件": "Upload",
"上传": "Upload",
"文件上传成功": "Upload succeeded",
"代码生成": "Coder",
"公司名称": "Company",
"公司地址": "Company address",
"公司管理": "Company info",
"所属公司": "Company name",
"公司类别": "Company type",
"保存后继续添加": "Continue adding after saving",
"成本": "Cost",
"国家": "Country",
"国家代码": "CountryCode",
"创建时间": "Create time",
"创建人": "Creator",
"验证码": "code",
"关闭": "Close",
"只能是日期格式": "Can only be in date format",
"取消": "Cancel",
"不能大于": "cannot be greater tha",
"不能小于": "cannot be less tha",
"选中checkbox隐藏/显示列数据": "Select check box to hide / show column data",
"中国": "China",
"中文": "Chinese",
"描述": "Descriptio",
"数据字典": "Dictionary",
"字典名称": "Dictionary Name",
"字典编号": "Dictionary Number",
"完成": "Done",
"字典数据": "Data Source",
"数据源": "Data Source",
"下拉框绑定设置": "Data source",
"日期": "Date",
"删除": "Delete",
"天": "Days",
"帐号": "Account",
"操作类型": "Action type",
"新建": "Add",
"添加子级": "Add a subset",
"添加备注": "Add note",
"添加行": "Add Row",
"添加同级": "Add Siblings",
"地址": "Address",
"全选": "All",
"不能为空": "is required",
"参数设置": "Parameters",
"真实姓名": "Real Name",
"【{$ts}】不是模板中的列": "【{$ts}】 is not a column in the template",
"第[{$ts}]行,[{$ts}]验证未通过,必须是日期格式": "Line [{$ts},{$ts}] validation failed, must be in date format",
"第[{$ts}]行,[{$ts}]验证未通过,不能为空": "Line [{$ts},{$ts}] failed verification, cannot be empty",
"[{$ts}]数据字典缺失": "[{$ts}] no data source is configured",
"第[{$ts}]行,[{$ts}]验证未通过,只能输入": "Line [{$ts},{$ts}] failed verification, only input",
"账号登录": "Login account",
"正在登陆": "Logging",
"登录": "Login",
"登陆成功": "Login Succeeded",
"语言设置": "Language",
"系统设置": "System",
"日志管理": "Logger",
"英文": "English",
"德语": "Deutsch",
"印尼语": "Indonesia",
"语言包": "Package",
"权限管理": "Permission",
"其他权限": "Other",
"菜单列表": "Menu list",
"确认要删除选择的数据吗?": "Are you sure you want to delete the selected data?",
"正在处理": "Processing",
"查询": "Search",
"编辑": "Edit",
"生成语言包": "Create package",
"导入": "Import",
"导出": "Export",
"新增": "Add",
"请输入正确的手机号": "Please input the correct mobile phone number",
"密码长度不能小于6位": "The password length cannot be less than 6 digits",
"只能是整数": "required is an integer",
"只能是数字": "required are numbers",
"必须是一个邮箱地址": "It must be an email address",
"是否启用": "Enable",
"sql语句": "Sql",
"旧密码不能为空": "Old password cannot be empty\\r\\n",
"新密码不能为空": "New password cannot be empty",
"旧密码不正确": "The old password is incorrect",
"新密码不能与旧密码相同": "The new password cannot be the same as the old password",
"密码修改成功\\r\\n": "Password modified successfully",
"不能选择此角色": "This role cannot be selected",
"用户名已经被注册\\r\\n": "The user name has been registered",
"用户新建成功.帐号[{$ts}],密码[{$ts}]": "User created successfully. Account number [{$ts}], password [{$ts}]",
"没有权限": "No permission",
"不能修改自己的角色": "You cannot modify your own role",
"角色名【{$ts}】已存在": "Role name [{$ts}] already exists\\r\\n",
"上级角色不能选择自己": "Superior roles cannot choose themselves",
"不能选择此上级角色,选择的上级角色与当前角色形成依赖关系": "This superior role cannot be selected. The selected superior role is dependent on the current role",
"服务器处理出现异常": "Server processing exceptio",
"未找到上传的文件": "Upload file not found",
"[{$ts}]不是模板中的列": "[{$ts}] is not a column in the template",
"[{$ts}]列名重复": "Duplicate column name [{$ts}]",
"导入文件列必须与导入模板相同": "The import file columns must be the same as the import template",
"下载模板": "Download template",
"上传结果": "Import result",
"保存": "Save",
"请上传文件": "Please upload the file",
"上传失败": "Upload failed",
"皮肤": "Theme",
"框架文档": "Document",
"安全退出": "Log out",
"首页": "Home",
"角色ID": "Role ID",
"部门名称": "Department",
"删除行": "Delete row",
"刷新": "Refresh",
"字典明细": "Dictionary details",
"是否可用": "Enable",
"数据源Text": "Text",
"数据源Value": "Value",
"数据源ID": "ID",
"系统日志": "Logger",
"开始时间": "Start time",
"用户名称": "Name",
"请求地址": "Url",
"日志类型": "Log type",
"响应状态": "Status",
"时长": "Duratio",
"请求参数": "Request",
"响应参数": "Response",
"异常信息": "Exception",
"用户IP": "User IP",
"浏览器类型": "Browser",
"性别": "Gender",
"操作": "Actio",
"头像": "Header",
"注册时间": "Reg time",
"审核": "Audit",
"视图/表名": "Table/View",
"菜单ID": "Menu ID",
"用户信息": "User info",
"验证码不正确": "Incorrect verification code",
"手机用户": "Mobile users",
"语言管理": "Language",
"简体中文": "zh-cn",
"繁体中文": "zh-tw",
"英语": "English",
"法语": "French",
"西班牙语": "Spanish",
"俄语": "Russian",
"高级查询": "Query",
"角色列表": "Role list",
"姓名": "Name",
"阿拉伯语": "Arabic",
"只能上传excel文件,文件大小不超过5M": "Only Excel files can be uploaded, and the file size shall not exceed 5m",
"选择的文件【{$ts}】只能是excel文件": "The selected file [{$ts}] can only be an excel file",
"选择的文件【{$ts}】只能是图片格式": "The selected file [{$ts}] can only be in picture format",
"最多只能选【{$ts}】张图片": "You can only select [{$ts}] pictures at most",
"最多只能选【{$ts}】个文件": "You can only select [{$ts}] files at most",
"不支持此文件格式": "This file format is not supported",
"文件不能超过[{$ts}]m": "File cannot exceed [{$ts}] m",
"上传中": "Uploading",
"文件列表": "File list",
"文件名": "Filen name",
"大小": "Size",
"未能处理导入的文件,请检查导入的文件是否正确": "Failed to process the imported file. Please check whether the imported file is correct",
"Token已过期": "The token has expired",
"密码长度不能少于6位": "Password length cannot be less than 6",
"密码修改成功": "Password modified successfully",
"用户不存在": "user does not exist",
"当前菜单存在子菜单,请先删除子菜单": "There are sub menus in the current menu. Please delete the sub menu first",
"【字典项名称】不能有重复的值": "[dictionary item name] cannot have duplicate values",
"【字典项Key】不能有重复的值": "[dictionary key] cannot have duplicate values",
"字典编号[{$ts}]已存在": "Dictionary number [{$ts}] already exists\\n\\n",
"账号": "account",
"越南语": "Vietnamese",
"泰语": "Thai",
"结束时间": "End time",
"是否显示": "Show or not",
"列名": "Field",
"拖动列名可调整表格列显示顺序": "Drag column names to adjust the display order of table columns",
"集团租户": "Group",
"组织构架": "Organizational",
"集团管理": "Group",
"数据分库": "Database",
"演示菜单": "Example",
"表单设计": "Form Design",
"流程管理": "Workflow",
"一对多生成": "Multiple Tables",
"新窗口编辑": "New Tab",
"打印设计": "Print",
"消息推送": "Message",
"定时任务": "Tasks",
"名称": "Name",
"编号": "Code",
"类型": "Type",
"集团名称": "Group name",
"大屏数据": "Data",
"MES业务": "MES",
"工作台设计器": "Workbench Designer",
"数据验证未通过!": "Data validation failed!",
"开发文档": "Document",
"外部链接": "Link",
"窗口编辑": "Window Edit",
"报表管理": "Report",
"单据编码": "Document code",
"工作台": "Workstation",
"租户分库": "Tenant Management",
"组件示例": "Component Example",
"组件扩展": "Component extension",
"已签收": "已签收-01",
"业务系统": "Business system",
"系统管理": "System management"
}