Files
klp-oa/klp-ui/src/utils/klp.js
jhd 89cbe18c72 feat(file): 完善文件管理功能,增加图片管理和权限控制
- 添加管理员权限验证,删除按钮仅对管理员显示
- 实现文件编辑权限控制,仅创建者或管理员可编辑
- 新增多图上传功能,支持文件和图片两种上传模式
- 实现图片预览轮播功能,支持缩略图导航和计数显示
- 添加文件替换功能,支持编辑模式下替换主文件
- 优化图片管理界面,支持添加、删除和替换操作
- 重构上传组件,使用OSS直传替代原有拖拽上传
- 新增图片关联API接口,支持文件与多张图片关联
- 实现批量图片上传处理,按顺序串行上传避免冲突
- 优化表单重置逻辑,清空临时文件和图片数据
- 添加文件类型自动识别和分类展示功能
- 修复可见用户加载异常导致的重复ID问题
- 优化错误处理机制,提升用户体验和系统稳定性
2026-07-13 13:06:58 +08:00

352 lines
9.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import QRCode from 'qrcode';
/**
* 通用js方法封装处理
* Copyright (c) 2019 klp
*/
// 日期格式化
export function parseTime(time, pattern) {
if (arguments.length === 0 || !time) {
return null
}
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
// 表单重置
export function resetForm(refName) {
if (this.$refs[refName]) {
try {
this.$refs[refName].resetFields();
} catch (e) {
console.warn('resetFields error:', e);
}
}
}
// 添加日期范围
export function addDateRange(params, dateRange, propName) {
let search = params;
search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
dateRange = Array.isArray(dateRange) ? dateRange : [];
if (typeof (propName) === 'undefined') {
search.params['beginTime'] = dateRange[0];
search.params['endTime'] = dateRange[1];
} else {
search.params['begin' + propName] = dateRange[0];
search.params['end' + propName] = dateRange[1];
}
return search;
}
// 回显数据字典
export function selectDictLabel(datas, value) {
if (value === undefined) {
return "";
}
var actions = [];
Object.keys(datas).some((key) => {
if (datas[key].value == ('' + value)) {
actions.push(datas[key].label);
return true;
}
})
if (actions.length === 0) {
actions.push(value);
}
return actions.join('');
}
// 回显数据字典(字符串、数组)
export function selectDictLabels(datas, value, separator) {
if (value === undefined || value.length ===0) {
return "";
}
if (Array.isArray(value)) {
value = value.join(",");
}
var actions = [];
var currentSeparator = undefined === separator ? "," : separator;
var temp = value.split(currentSeparator);
Object.keys(value.split(currentSeparator)).some((val) => {
var match = false;
Object.keys(datas).some((key) => {
if (datas[key].value == ('' + temp[val])) {
actions.push(datas[key].label + currentSeparator);
match = true;
}
})
if (!match) {
actions.push(temp[val] + currentSeparator);
}
})
return actions.join('').substring(0, actions.join('').length - 1);
}
// 字符串格式化(%s )
export function sprintf(str) {
var args = arguments, flag = true, i = 1;
str = str.replace(/%s/g, function () {
var arg = args[i++];
if (typeof arg === 'undefined') {
flag = false;
return '';
}
return arg;
});
return flag ? str : '';
}
// 转换字符串undefined,null等转化为""
export function parseStrEmpty(str) {
if (!str || str == "undefined" || str == "null") {
return "";
}
return str;
}
// 数据合并
export function mergeRecursive(source, target) {
for (var p in target) {
try {
if (target[p].constructor == Object) {
source[p] = mergeRecursive(source[p], target[p]);
} else {
source[p] = target[p];
}
} catch (e) {
source[p] = target[p];
}
}
return source;
};
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export function handleTree(data, id, parentId, children) {
let config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children'
};
var childrenListMap = {};
var nodeIds = {};
var tree = [];
for (let d of data) {
let parentId = d[config.parentId];
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = [];
}
nodeIds[d[config.id]] = d;
childrenListMap[parentId].push(d);
}
for (let d of data) {
let parentId = d[config.parentId];
if (nodeIds[parentId] == null) {
tree.push(d);
}
}
for (let t of tree) {
adaptToChildrenList(t);
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (let c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
}
return tree;
}
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName];
var part = encodeURIComponent(propName) + "=";
if (value !== null && value !== "" && typeof (value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
let params = propName + '[' + key + ']';
var subPart = encodeURIComponent(params) + "=";
result += subPart + encodeURIComponent(value[key]) + "&";
}
}
} else {
result += part + encodeURIComponent(value) + "&";
}
}
}
return result
}
// 验证是否为blob格式
export function blobValidate(data) {
return data.type !== 'application/json'
}
/**
* 保存二维码为图片
* @param {string} code 二维码内容
* @param {string} text 下方文字
* @param {number} index 索引,用于生成文件名
* @param {Object} context Vue组件实例上下文需要包含$message、barcodeWidth、barcodeHeight
*/
export async function saveAsImage(code, text, index, context) {
// 确保上下文存在
if (!context) {
console.error('缺少组件上下文请传入Vue实例');
return;
}
try {
// 检查QRCode库是否加载
if (typeof QRCode === 'undefined') {
throw new Error('QRCode库未加载请确保已引入');
}
// 创建临时canvas用于绘制二维码和文字
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
throw new Error('无法获取canvas上下文');
}
// 从上下文获取尺寸参数,提供默认值
const barcodeWidth = context.barcodeWidth || 200;
const barcodeHeight = context.barcodeHeight || 200;
const textHeight = 30; // 文字区域高度
canvas.width = barcodeWidth;
canvas.height = barcodeHeight + textHeight;
// 绘制二维码
const qrCanvas = document.createElement('canvas');
qrCanvas.width = barcodeWidth;
qrCanvas.height = barcodeHeight;
// 等待二维码绘制完成
await new Promise((resolve, reject) => {
QRCode.toCanvas(qrCanvas, code, {
width: barcodeWidth,
height: barcodeHeight,
margin: 0,
errorCorrectionLevel: 'M'
}, (error) => {
if (error) reject(error);
else resolve();
});
});
// 将二维码绘制到主canvas
ctx.drawImage(qrCanvas, 0, 0);
// 绘制文字(处理文字过长情况)
ctx.fillStyle = '#000';
ctx.font = '14px Arial, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
// 处理过长文字最多显示2行
const maxTextWidth = barcodeWidth - 20; // 预留边距
let displayText = text;
if (ctx.measureText(text).width > maxTextWidth) {
// 尝试截断并添加省略号
let i = text.length;
while (ctx.measureText(text.substring(0, i)).width > maxTextWidth && i > 0) {
i--;
}
displayText = text.substring(0, i) + '...';
}
ctx.fillText(displayText, barcodeWidth / 2, barcodeHeight + 5);
// 创建图片链接并下载
canvas.toBlob(blob => {
if (!blob) {
throw new Error('无法生成图片blob对象');
}
try {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
// 处理文件名特殊字符
a.download = `二维码_${index + 1}.png`;
a.href = url;
// 模拟点击下载
document.body.appendChild(a);
const event = new MouseEvent('click');
a.dispatchEvent(event);
// 清理资源
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 100);
context.$message.success('图片保存成功');
} catch (urlError) {
console.error('创建下载链接失败:', urlError);
context.$message.error('创建下载链接失败');
}
}, 'image/png'); // 明确指定MIME类型
} catch (error) {
console.error('保存图片失败:', error);
context.$message.error(`保存图片失败: ${error.message || '未知错误'}`);
}
}