feat: 【BPM 工作流】完善操作按钮、流程签名组件
parent
66ac3de5c1
commit
01f929e10f
|
@ -53,7 +53,8 @@
|
||||||
"pinia": "catalog:",
|
"pinia": "catalog:",
|
||||||
"vue": "catalog:",
|
"vue": "catalog:",
|
||||||
"vue-dompurify-html": "catalog:",
|
"vue-dompurify-html": "catalog:",
|
||||||
"vue-router": "catalog:"
|
"vue-router": "catalog:",
|
||||||
|
"vue3-signature": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/crypto-js": "catalog:"
|
"@types/crypto-js": "catalog:"
|
||||||
|
|
|
@ -37,11 +37,12 @@ export async function getProcessDefinitionPage(params: PageParam) {
|
||||||
|
|
||||||
/** 查询流程定义列表 */
|
/** 查询流程定义列表 */
|
||||||
export async function getProcessDefinitionList(params: any) {
|
export async function getProcessDefinitionList(params: any) {
|
||||||
return requestClient.get<
|
return requestClient.get<BpmProcessDefinitionApi.ProcessDefinitionVO[]>(
|
||||||
PageResult<BpmProcessDefinitionApi.ProcessDefinitionVO>
|
'/bpm/process-definition/list',
|
||||||
>('/bpm/process-definition/list', {
|
{
|
||||||
params,
|
params,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 查询流程定义列表(简单列表) */
|
/** 查询流程定义列表(简单列表) */
|
||||||
|
|
|
@ -14,6 +14,7 @@ export namespace BpmModelApi {
|
||||||
/** 流程定义 VO */
|
/** 流程定义 VO */
|
||||||
export interface ProcessDefinitionVO {
|
export interface ProcessDefinitionVO {
|
||||||
id: string;
|
id: string;
|
||||||
|
key?: string;
|
||||||
version: number;
|
version: number;
|
||||||
deploymentTime: number;
|
deploymentTime: number;
|
||||||
suspensionState: number;
|
suspensionState: number;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import type { PageParam, PageResult } from '@vben/request';
|
import type { PageParam, PageResult } from '@vben/request';
|
||||||
|
|
||||||
|
import type { BpmTaskApi } from '../task';
|
||||||
|
|
||||||
import type { BpmModelApi } from '#/api/bpm/model';
|
import type { BpmModelApi } from '#/api/bpm/model';
|
||||||
import type { BpmCandidateStrategyEnum, BpmNodeTypeEnum } from '#/utils';
|
import type { BpmCandidateStrategyEnum, BpmNodeTypeEnum } from '#/utils';
|
||||||
|
|
||||||
|
@ -67,25 +69,26 @@ export namespace BpmProcessInstanceApi {
|
||||||
processDefinition: BpmModelApi.ProcessDefinitionVO;
|
processDefinition: BpmModelApi.ProcessDefinitionVO;
|
||||||
processInstance: BpmProcessInstanceApi.ProcessInstanceVO;
|
processInstance: BpmProcessInstanceApi.ProcessInstanceVO;
|
||||||
status: number;
|
status: number;
|
||||||
|
todoTask: BpmTaskApi.TaskVO;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 抄送流程实例 VO
|
// 抄送流程实例 VO
|
||||||
export type CopyVO = {
|
export type CopyVO = {
|
||||||
|
activityId: string;
|
||||||
|
activityName: string;
|
||||||
|
createTime: number;
|
||||||
|
createUser: User;
|
||||||
id: number;
|
id: number;
|
||||||
startUser: User;
|
|
||||||
processInstanceId: string;
|
processInstanceId: string;
|
||||||
processInstanceName: string;
|
processInstanceName: string;
|
||||||
processInstanceStartTime: number;
|
processInstanceStartTime: number;
|
||||||
activityId: string;
|
|
||||||
activityName: string;
|
|
||||||
taskId: string;
|
|
||||||
reason: string;
|
reason: string;
|
||||||
createUser: User;
|
startUser: User;
|
||||||
createTime: number;
|
|
||||||
summary: {
|
summary: {
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
}[];
|
}[];
|
||||||
|
taskId: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +176,7 @@ export async function getApprovalDetail(params: any) {
|
||||||
|
|
||||||
/** 获取下一个执行的流程节点 */
|
/** 获取下一个执行的流程节点 */
|
||||||
export async function getNextApprovalNodes(params: any) {
|
export async function getNextApprovalNodes(params: any) {
|
||||||
return requestClient.get<BpmProcessInstanceApi.ProcessInstanceVO>(
|
return requestClient.get<BpmProcessInstanceApi.ApprovalNodeInfo[]>(
|
||||||
`/bpm/process-instance/get-next-approval-nodes`,
|
`/bpm/process-instance/get-next-approval-nodes`,
|
||||||
{ params },
|
{ params },
|
||||||
);
|
);
|
||||||
|
|
|
@ -89,8 +89,8 @@ export const getTaskListByProcessInstanceId = async (id: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 获取所有可退回的节点 */
|
/** 获取所有可退回的节点 */
|
||||||
export const getTaskListByReturn = async (data: any) => {
|
export const getTaskListByReturn = async (id: string) => {
|
||||||
return await requestClient.get('/bpm/task/list-by-return', data);
|
return await requestClient.get(`/bpm/task/list-by-return?id=${id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 退回 */
|
/** 退回 */
|
||||||
|
|
|
@ -441,30 +441,6 @@ export const ErpBizType = {
|
||||||
|
|
||||||
// ========== BPM 模块 ==========
|
// ========== BPM 模块 ==========
|
||||||
|
|
||||||
export const BpmModelType = {
|
|
||||||
BPMN: 10, // BPMN 设计器
|
|
||||||
SIMPLE: 20, // 简易设计器
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BpmModelFormType = {
|
|
||||||
NORMAL: 10, // 流程表单
|
|
||||||
CUSTOM: 20, // 业务表单
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BpmProcessInstanceStatus = {
|
|
||||||
NOT_START: -1, // 未开始
|
|
||||||
RUNNING: 1, // 审批中
|
|
||||||
APPROVE: 2, // 审批通过
|
|
||||||
REJECT: 3, // 审批不通过
|
|
||||||
CANCEL: 4, // 已取消
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BpmAutoApproveType = {
|
|
||||||
NONE: 0, // 不自动通过
|
|
||||||
APPROVE_ALL: 1, // 仅审批一次,后续重复的审批节点均自动通过
|
|
||||||
APPROVE_SEQUENT: 2, // 仅针对连续审批的节点自动通过
|
|
||||||
};
|
|
||||||
|
|
||||||
// 候选人策略枚举 ( 用于审批节点。抄送节点 )
|
// 候选人策略枚举 ( 用于审批节点。抄送节点 )
|
||||||
export enum BpmCandidateStrategyEnum {
|
export enum BpmCandidateStrategyEnum {
|
||||||
/**
|
/**
|
||||||
|
@ -594,6 +570,40 @@ export enum BpmNodeTypeEnum {
|
||||||
USER_TASK_NODE = 11,
|
USER_TASK_NODE = 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程任务操作按钮
|
||||||
|
*/
|
||||||
|
export enum BpmTaskOperationButtonTypeEnum {
|
||||||
|
/**
|
||||||
|
* 加签
|
||||||
|
*/
|
||||||
|
ADD_SIGN = 5,
|
||||||
|
/**
|
||||||
|
* 通过
|
||||||
|
*/
|
||||||
|
APPROVE = 1,
|
||||||
|
/**
|
||||||
|
* 抄送
|
||||||
|
*/
|
||||||
|
COPY = 7,
|
||||||
|
/**
|
||||||
|
* 委派
|
||||||
|
*/
|
||||||
|
DELEGATE = 4,
|
||||||
|
/**
|
||||||
|
* 拒绝
|
||||||
|
*/
|
||||||
|
REJECT = 2,
|
||||||
|
/**
|
||||||
|
* 退回
|
||||||
|
*/
|
||||||
|
RETURN = 6,
|
||||||
|
/**
|
||||||
|
* 转办
|
||||||
|
*/
|
||||||
|
TRANSFER = 3,
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务状态枚举
|
* 任务状态枚举
|
||||||
*/
|
*/
|
||||||
|
@ -667,3 +677,51 @@ export enum BpmFieldPermissionType {
|
||||||
*/
|
*/
|
||||||
WRITE = '2',
|
WRITE = '2',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程模型类型
|
||||||
|
*/
|
||||||
|
export const BpmModelType = {
|
||||||
|
BPMN: 10, // BPMN 设计器
|
||||||
|
SIMPLE: 20, // 简易设计器
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程模型表单类型
|
||||||
|
*/
|
||||||
|
export const BpmModelFormType = {
|
||||||
|
NORMAL: 10, // 流程表单
|
||||||
|
CUSTOM: 20, // 业务表单
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例状态
|
||||||
|
*/
|
||||||
|
export const BpmProcessInstanceStatus = {
|
||||||
|
NOT_START: -1, // 未开始
|
||||||
|
RUNNING: 1, // 审批中
|
||||||
|
APPROVE: 2, // 审批通过
|
||||||
|
REJECT: 3, // 审批不通过
|
||||||
|
CANCEL: 4, // 已取消
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动审批类型
|
||||||
|
*/
|
||||||
|
export const BpmAutoApproveType = {
|
||||||
|
NONE: 0, // 不自动通过
|
||||||
|
APPROVE_ALL: 1, // 仅审批一次,后续重复的审批节点均自动通过
|
||||||
|
APPROVE_SEQUENT: 2, // 仅针对连续审批的节点自动通过
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批操作按钮名称
|
||||||
|
*/
|
||||||
|
export const OPERATION_BUTTON_NAME = new Map<number, string>();
|
||||||
|
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.APPROVE, '通过');
|
||||||
|
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.REJECT, '拒绝');
|
||||||
|
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.TRANSFER, '转办');
|
||||||
|
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.DELEGATE, '委派');
|
||||||
|
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.ADD_SIGN, '加签');
|
||||||
|
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.RETURN, '退回');
|
||||||
|
OPERATION_BUTTON_NAME.set(BpmTaskOperationButtonTypeEnum.COPY, '抄送');
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
/**
|
||||||
|
* 下载工具模块
|
||||||
|
* 提供多种文件格式的下载功能
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片下载配置接口
|
||||||
|
*/
|
||||||
|
interface ImageDownloadOptions {
|
||||||
|
/** 图片 URL */
|
||||||
|
url: string;
|
||||||
|
/** 指定画布宽度 */
|
||||||
|
canvasWidth?: number;
|
||||||
|
/** 指定画布高度 */
|
||||||
|
canvasHeight?: number;
|
||||||
|
/** 将图片绘制在画布上时带上图片的宽高值,默认为 true */
|
||||||
|
drawWithImageSize?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础文件下载函数
|
||||||
|
* @param data - 文件数据 Blob
|
||||||
|
* @param fileName - 文件名
|
||||||
|
* @param mimeType - MIME 类型
|
||||||
|
*/
|
||||||
|
export const download0 = (data: Blob, fileName: string, mimeType: string) => {
|
||||||
|
try {
|
||||||
|
// 创建 blob
|
||||||
|
const blob = new Blob([data], { type: mimeType });
|
||||||
|
// 创建 href 超链接,点击进行下载
|
||||||
|
window.URL = window.URL || window.webkitURL;
|
||||||
|
const href = URL.createObjectURL(blob);
|
||||||
|
const downA = document.createElement('a');
|
||||||
|
downA.href = href;
|
||||||
|
downA.download = fileName;
|
||||||
|
downA.click();
|
||||||
|
// 销毁超链接
|
||||||
|
window.URL.revokeObjectURL(href);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('文件下载失败:', error);
|
||||||
|
throw new Error(
|
||||||
|
`文件下载失败: ${error instanceof Error ? error.message : '未知错误'}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发文件下载的通用方法
|
||||||
|
* @param url - 下载链接
|
||||||
|
* @param fileName - 文件名
|
||||||
|
*/
|
||||||
|
const triggerDownload = (url: string, fileName: string) => {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = fileName;
|
||||||
|
a.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const download = {
|
||||||
|
/**
|
||||||
|
* 下载 Excel 文件
|
||||||
|
* @param data - 文件数据 Blob
|
||||||
|
* @param fileName - 文件名
|
||||||
|
*/
|
||||||
|
excel: (data: Blob, fileName: string) => {
|
||||||
|
download0(data, fileName, 'application/vnd.ms-excel');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载 Word 文件
|
||||||
|
* @param data - 文件数据 Blob
|
||||||
|
* @param fileName - 文件名
|
||||||
|
*/
|
||||||
|
word: (data: Blob, fileName: string) => {
|
||||||
|
download0(data, fileName, 'application/msword');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载 Zip 文件
|
||||||
|
* @param data - 文件数据 Blob
|
||||||
|
* @param fileName - 文件名
|
||||||
|
*/
|
||||||
|
zip: (data: Blob, fileName: string) => {
|
||||||
|
download0(data, fileName, 'application/zip');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载 HTML 文件
|
||||||
|
* @param data - 文件数据 Blob
|
||||||
|
* @param fileName - 文件名
|
||||||
|
*/
|
||||||
|
html: (data: Blob, fileName: string) => {
|
||||||
|
download0(data, fileName, 'text/html');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载 Markdown 文件
|
||||||
|
* @param data - 文件数据 Blob
|
||||||
|
* @param fileName - 文件名
|
||||||
|
*/
|
||||||
|
markdown: (data: Blob, fileName: string) => {
|
||||||
|
download0(data, fileName, 'text/markdown');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载 JSON 文件
|
||||||
|
* @param data - 文件数据 Blob
|
||||||
|
* @param fileName - 文件名
|
||||||
|
*/
|
||||||
|
json: (data: Blob, fileName: string) => {
|
||||||
|
download0(data, fileName, 'application/json');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载图片(允许跨域)
|
||||||
|
* @param options - 图片下载配置
|
||||||
|
*/
|
||||||
|
image: (options: ImageDownloadOptions) => {
|
||||||
|
const {
|
||||||
|
url,
|
||||||
|
canvasWidth,
|
||||||
|
canvasHeight,
|
||||||
|
drawWithImageSize = true,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const image = new Image();
|
||||||
|
// image.setAttribute('crossOrigin', 'anonymous')
|
||||||
|
image.src = url;
|
||||||
|
image.addEventListener('load', () => {
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = canvasWidth || image.width;
|
||||||
|
canvas.height = canvasHeight || image.height;
|
||||||
|
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||||
|
ctx?.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
if (drawWithImageSize) {
|
||||||
|
ctx.drawImage(image, 0, 0, image.width, image.height);
|
||||||
|
} else {
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataUrl = canvas.toDataURL('image/png');
|
||||||
|
triggerDownload(dataUrl, 'image.png');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('图片下载失败:', error);
|
||||||
|
throw new Error(
|
||||||
|
`图片下载失败: ${error instanceof Error ? error.message : '未知错误'}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
image.addEventListener('error', () => {
|
||||||
|
throw new Error('图片加载失败');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Base64 字符串转换为文件对象
|
||||||
|
* @param base64 - Base64 字符串
|
||||||
|
* @param fileName - 文件名
|
||||||
|
* @returns File 对象
|
||||||
|
*/
|
||||||
|
base64ToFile: (base64: string, fileName: string): File => {
|
||||||
|
// 输入验证
|
||||||
|
if (!base64 || typeof base64 !== 'string') {
|
||||||
|
throw new Error('base64 参数必须是非空字符串');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 base64 按照逗号进行分割,将前缀与后续内容分隔开
|
||||||
|
const data = base64.split(',');
|
||||||
|
if (data.length !== 2 || !data[0] || !data[1]) {
|
||||||
|
throw new Error('无效的 base64 格式');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 利用正则表达式从前缀中获取类型信息(image/png、image/jpeg、image/webp等)
|
||||||
|
const typeMatch = data[0].match(/:(.*?);/);
|
||||||
|
if (!typeMatch || !typeMatch[1]) {
|
||||||
|
throw new Error('无法解析 base64 类型信息');
|
||||||
|
}
|
||||||
|
const type = typeMatch[1];
|
||||||
|
|
||||||
|
// 从类型信息中获取具体的文件格式后缀(png、jpeg、webp)
|
||||||
|
const typeParts = type.split('/');
|
||||||
|
if (typeParts.length !== 2 || !typeParts[1]) {
|
||||||
|
throw new Error('无效的 MIME 类型格式');
|
||||||
|
}
|
||||||
|
const suffix = typeParts[1];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 使用 atob() 对 base64 数据进行解码,结果是一个文件数据流以字符串的格式输出
|
||||||
|
const bstr = window.atob(data[1]);
|
||||||
|
|
||||||
|
// 获取解码结果字符串的长度
|
||||||
|
const n = bstr.length;
|
||||||
|
// 根据解码结果字符串的长度创建一个等长的整型数字数组
|
||||||
|
const u8arr = new Uint8Array(n);
|
||||||
|
|
||||||
|
// 优化的 Uint8Array 填充逻辑
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
// 使用 charCodeAt() 获取字符对应的字节值(Base64 解码后的字符串是字节级别的)
|
||||||
|
// eslint-disable-next-line unicorn/prefer-code-point
|
||||||
|
u8arr[i] = bstr.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回 File 文件对象
|
||||||
|
return new File([u8arr], `${fileName}.${suffix}`, { type });
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Base64 解码失败: ${error instanceof Error ? error.message : '未知错误'}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,5 +1,6 @@
|
||||||
export * from './constants';
|
export * from './constants';
|
||||||
export * from './dict';
|
export * from './dict';
|
||||||
|
export * from './download';
|
||||||
export * from './formatTime';
|
export * from './formatTime';
|
||||||
export * from './formCreate';
|
export * from './formCreate';
|
||||||
export * from './rangePickerProps';
|
export * from './rangePickerProps';
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { BpmCategoryApi } from '#/api/bpm/category';
|
||||||
import type { BpmProcessDefinitionApi } from '#/api/bpm/definition';
|
import type { BpmProcessDefinitionApi } from '#/api/bpm/definition';
|
||||||
|
|
||||||
import { computed, nextTick, onMounted, ref } from 'vue';
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||||
|
@ -33,7 +34,9 @@ const processInstanceId: any = route.query.processInstanceId; // 流程实例编
|
||||||
const loading = ref(true); // 加载中
|
const loading = ref(true); // 加载中
|
||||||
const categoryList: any = ref([]); // 分类的列表
|
const categoryList: any = ref([]); // 分类的列表
|
||||||
const activeCategory = ref(''); // 当前选中的分类
|
const activeCategory = ref(''); // 当前选中的分类
|
||||||
const processDefinitionList = ref([]); // 流程定义的列表
|
const processDefinitionList = ref<
|
||||||
|
BpmProcessDefinitionApi.ProcessDefinitionVO[]
|
||||||
|
>([]); // 流程定义的列表
|
||||||
|
|
||||||
// 实现 groupBy 功能
|
// 实现 groupBy 功能
|
||||||
const groupBy = (array: any[], key: string) => {
|
const groupBy = (array: any[], key: string) => {
|
||||||
|
@ -107,8 +110,12 @@ const handleGetProcessDefinitionList = async () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 用于存储搜索过滤后的流程定义 */
|
||||||
|
const filteredProcessDefinitionList = ref<
|
||||||
|
BpmProcessDefinitionApi.ProcessDefinitionVO[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
/** 搜索流程 */
|
/** 搜索流程 */
|
||||||
const filteredProcessDefinitionList = ref([]); // 用于存储搜索过滤后的流程定义
|
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
if (searchName.value.trim()) {
|
if (searchName.value.trim()) {
|
||||||
// 如果有搜索关键字,进行过滤
|
// 如果有搜索关键字,进行过滤
|
||||||
|
@ -150,10 +157,15 @@ const processDefinitionGroup: any = computed(() => {
|
||||||
|
|
||||||
const grouped = groupBy(filteredProcessDefinitionList.value, 'category');
|
const grouped = groupBy(filteredProcessDefinitionList.value, 'category');
|
||||||
// 按照 categoryList 的顺序重新组织数据
|
// 按照 categoryList 的顺序重新组织数据
|
||||||
const orderedGroup = {};
|
const orderedGroup: Record<
|
||||||
categoryList.value.forEach((category: any) => {
|
string,
|
||||||
|
BpmProcessDefinitionApi.ProcessDefinitionVO[]
|
||||||
|
> = {};
|
||||||
|
categoryList.value.forEach((category: BpmCategoryApi.CategoryVO) => {
|
||||||
if (grouped[category.code]) {
|
if (grouped[category.code]) {
|
||||||
orderedGroup[category.code] = grouped[category.code];
|
orderedGroup[category.code] = grouped[
|
||||||
|
category.code
|
||||||
|
] as BpmProcessDefinitionApi.ProcessDefinitionVO[];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return orderedGroup;
|
return orderedGroup;
|
||||||
|
@ -191,7 +203,7 @@ const availableCategories = computed(() => {
|
||||||
const availableCategoryCodes = Object.keys(processDefinitionGroup.value);
|
const availableCategoryCodes = Object.keys(processDefinitionGroup.value);
|
||||||
|
|
||||||
// 过滤出有流程的分类
|
// 过滤出有流程的分类
|
||||||
return categoryList.value.filter((category: CategoryVO) =>
|
return categoryList.value.filter((category: BpmCategoryApi.CategoryVO) =>
|
||||||
availableCategoryCodes.includes(category.code),
|
availableCategoryCodes.includes(category.code),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -229,11 +241,7 @@ onMounted(() => {
|
||||||
allow-clear
|
allow-clear
|
||||||
@input="handleQuery"
|
@input="handleQuery"
|
||||||
@clear="handleQuery"
|
@clear="handleQuery"
|
||||||
>
|
/>
|
||||||
<template #prefix>
|
|
||||||
<IconifyIcon icon="mdi:search-web" />
|
|
||||||
</template>
|
|
||||||
</InputSearch>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -289,15 +297,6 @@ onMounted(() => {
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TODO: 发起流程按钮 -->
|
|
||||||
<!-- <template #actions>
|
|
||||||
<div class="flex justify-end px-4">
|
|
||||||
<Button type="link" @click="handleSelect(definition)">
|
|
||||||
发起流程
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</template> -->
|
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
@ -7,16 +7,7 @@ import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
|
||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
import { formatDateTime } from '@vben/utils';
|
import { formatDateTime } from '@vben/utils';
|
||||||
|
|
||||||
import {
|
import { Avatar, Card, Col, message, Row, TabPane, Tabs } from 'ant-design-vue';
|
||||||
Avatar,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Col,
|
|
||||||
message,
|
|
||||||
Row,
|
|
||||||
TabPane,
|
|
||||||
Tabs,
|
|
||||||
} from 'ant-design-vue';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getApprovalDetail as getApprovalDetailApi,
|
getApprovalDetail as getApprovalDetailApi,
|
||||||
|
@ -39,6 +30,9 @@ import {
|
||||||
SvgBpmRunningIcon,
|
SvgBpmRunningIcon,
|
||||||
} from '#/views/bpm/processInstance/detail/modules/icons';
|
} from '#/views/bpm/processInstance/detail/modules/icons';
|
||||||
|
|
||||||
|
import ProcessInstanceBpmnViewer from './modules/bpm-viewer.vue';
|
||||||
|
import ProcessInstanceOperationButton from './modules/operation-button.vue';
|
||||||
|
import ProcessInstanceSimpleViewer from './modules/simple-bpm-viewer.vue';
|
||||||
import BpmProcessInstanceTaskList from './modules/task-list.vue';
|
import BpmProcessInstanceTaskList from './modules/task-list.vue';
|
||||||
import ProcessInstanceTimeline from './modules/time-line.vue';
|
import ProcessInstanceTimeline from './modules/time-line.vue';
|
||||||
|
|
||||||
|
@ -72,7 +66,7 @@ const processInstanceLoading = ref(false); // 流程实例的加载中
|
||||||
const processInstance = ref<BpmProcessInstanceApi.ProcessInstanceVO>(); // 流程实例
|
const processInstance = ref<BpmProcessInstanceApi.ProcessInstanceVO>(); // 流程实例
|
||||||
const processDefinition = ref<any>({}); // 流程定义
|
const processDefinition = ref<any>({}); // 流程定义
|
||||||
const processModelView = ref<any>({}); // 流程模型视图
|
const processModelView = ref<any>({}); // 流程模型视图
|
||||||
// const operationButtonRef = ref(); // 操作按钮组件 ref
|
const operationButtonRef = ref(); // 操作按钮组件 ref
|
||||||
const auditIconsMap: {
|
const auditIconsMap: {
|
||||||
[key: string]:
|
[key: string]:
|
||||||
| typeof SvgBpmApproveIcon
|
| typeof SvgBpmApproveIcon
|
||||||
|
@ -162,6 +156,7 @@ async function getApprovalDetail() {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 注意:data.processDefinition.formCustomViewPath 是组件的全路径,例如说:/crm/contract/detail/index.vue
|
// 注意:data.processDefinition.formCustomViewPath 是组件的全路径,例如说:/crm/contract/detail/index.vue
|
||||||
|
|
||||||
BusinessFormComponent.value = registerComponent(
|
BusinessFormComponent.value = registerComponent(
|
||||||
data?.processDefinition?.formCustomViewPath || '',
|
data?.processDefinition?.formCustomViewPath || '',
|
||||||
);
|
);
|
||||||
|
@ -169,6 +164,9 @@ async function getApprovalDetail() {
|
||||||
|
|
||||||
// 获取审批节点,显示 Timeline 的数据
|
// 获取审批节点,显示 Timeline 的数据
|
||||||
activityNodes.value = data.activityNodes;
|
activityNodes.value = data.activityNodes;
|
||||||
|
|
||||||
|
// 获取待办任务显示操作按钮
|
||||||
|
operationButtonRef.value?.loadTodoTask(data.todoTask);
|
||||||
} catch {
|
} catch {
|
||||||
message.error('获取审批详情失败!');
|
message.error('获取审批详情失败!');
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -249,9 +247,7 @@ onMounted(async () => {
|
||||||
<template>
|
<template>
|
||||||
<Page auto-content-height>
|
<Page auto-content-height>
|
||||||
<Card
|
<Card
|
||||||
class="h-full"
|
|
||||||
:body-style="{
|
:body-style="{
|
||||||
height: 'calc(100% - 140px)',
|
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
paddingTop: '12px',
|
paddingTop: '12px',
|
||||||
}"
|
}"
|
||||||
|
@ -306,18 +302,25 @@ onMounted(async () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 流程操作 -->
|
<!-- 流程操作 -->
|
||||||
<div class="flex-1">
|
<div class="process-tabs-container flex flex-1 flex-col">
|
||||||
<Tabs v-model:active-key="activeTab" class="mt-0">
|
<Tabs v-model:active-key="activeTab" class="mt-0 h-full">
|
||||||
<TabPane tab="审批详情" key="form">
|
<TabPane tab="审批详情" key="form" class="tab-pane-content">
|
||||||
<Row :gutter="[48, 24]">
|
<Row :gutter="[48, 24]" class="h-full">
|
||||||
<Col :xs="24" :sm="24" :md="18" :lg="18" :xl="16">
|
<Col
|
||||||
|
:xs="24"
|
||||||
|
:sm="24"
|
||||||
|
:md="18"
|
||||||
|
:lg="18"
|
||||||
|
:xl="16"
|
||||||
|
class="h-full"
|
||||||
|
>
|
||||||
<!-- 流程表单 -->
|
<!-- 流程表单 -->
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
processDefinition?.formType === BpmModelFormType.NORMAL
|
processDefinition?.formType === BpmModelFormType.NORMAL
|
||||||
"
|
"
|
||||||
|
class="h-full"
|
||||||
>
|
>
|
||||||
<!-- v-model="detailForm.value" -->
|
|
||||||
<form-create
|
<form-create
|
||||||
v-model="detailForm.value"
|
v-model="detailForm.value"
|
||||||
v-model:api="fApi"
|
v-model:api="fApi"
|
||||||
|
@ -330,23 +333,41 @@ onMounted(async () => {
|
||||||
v-if="
|
v-if="
|
||||||
processDefinition?.formType === BpmModelFormType.CUSTOM
|
processDefinition?.formType === BpmModelFormType.CUSTOM
|
||||||
"
|
"
|
||||||
|
class="h-full"
|
||||||
>
|
>
|
||||||
<BusinessFormComponent :id="processInstance?.businessKey" />
|
<BusinessFormComponent :id="processInstance?.businessKey" />
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col :xs="24" :sm="24" :md="6" :lg="6" :xl="8">
|
<Col :xs="24" :sm="24" :md="6" :lg="6" :xl="8" class="h-full">
|
||||||
<div class="mt-2">
|
<div class="mt-4 h-full">
|
||||||
<ProcessInstanceTimeline :activity-nodes="activityNodes" />
|
<ProcessInstanceTimeline :activity-nodes="activityNodes" />
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
|
|
||||||
<TabPane tab="流程图" key="diagram">
|
<TabPane tab="流程图" key="diagram" class="tab-pane-content">
|
||||||
<div>待开发</div>
|
<div class="h-full">
|
||||||
|
<ProcessInstanceSimpleViewer
|
||||||
|
v-show="
|
||||||
|
processDefinition.modelType &&
|
||||||
|
processDefinition.modelType === BpmModelType.SIMPLE
|
||||||
|
"
|
||||||
|
:loading="processInstanceLoading"
|
||||||
|
:model-view="processModelView"
|
||||||
|
/>
|
||||||
|
<ProcessInstanceBpmnViewer
|
||||||
|
v-show="
|
||||||
|
processDefinition.modelType &&
|
||||||
|
processDefinition.modelType === BpmModelType.BPMN
|
||||||
|
"
|
||||||
|
:loading="processInstanceLoading"
|
||||||
|
:model-view="processModelView"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
|
|
||||||
<TabPane tab="流转记录" key="record">
|
<TabPane tab="流转记录" key="record" class="tab-pane-content">
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<BpmProcessInstanceTaskList
|
<BpmProcessInstanceTaskList
|
||||||
ref="taskListRef"
|
ref="taskListRef"
|
||||||
|
@ -357,19 +378,65 @@ onMounted(async () => {
|
||||||
</TabPane>
|
</TabPane>
|
||||||
|
|
||||||
<!-- TODO 待开发 -->
|
<!-- TODO 待开发 -->
|
||||||
<TabPane tab="流转评论" key="comment" v-if="false">
|
<TabPane
|
||||||
<div>待开发</div>
|
tab="流转评论"
|
||||||
|
key="comment"
|
||||||
|
v-if="false"
|
||||||
|
class="tab-pane-content"
|
||||||
|
>
|
||||||
|
<div class="h-full">待开发</div>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<div class="flex justify-start gap-x-2 p-4">
|
<div class="px-4">
|
||||||
<Button type="primary">驳回</Button>
|
<ProcessInstanceOperationButton
|
||||||
<Button type="primary">同意</Button>
|
ref="operationButtonRef"
|
||||||
|
:process-instance="processInstance"
|
||||||
|
:process-definition="processDefinition"
|
||||||
|
:user-options="userOptions"
|
||||||
|
:normal-form="detailForm"
|
||||||
|
:normal-form-api="fApi"
|
||||||
|
:writable-fields="writableFields"
|
||||||
|
@success="getDetail"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Card>
|
</Card>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.ant-tabs-content {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-tabs-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-content) {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-tabs-tabpane) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-pane-content {
|
||||||
|
height: calc(100vh - 420px);
|
||||||
|
padding-right: 12px;
|
||||||
|
overflow: hidden auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineOptions({ name: 'ProcessInstanceBpmnViewer' });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1>BPMN Viewer</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,88 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
|
import { Button, message, Space, Tooltip } from 'ant-design-vue';
|
||||||
|
import Vue3Signature from 'vue3-signature';
|
||||||
|
|
||||||
|
import { uploadFile } from '#/api/infra/file';
|
||||||
|
import { download } from '#/utils';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'BpmProcessInstanceSignature',
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(['success']);
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
title: '流程签名',
|
||||||
|
onOpenChange(visible) {
|
||||||
|
if (!visible) {
|
||||||
|
modalApi.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onConfirm: () => {
|
||||||
|
submit();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const signature = ref<InstanceType<typeof Vue3Signature>>();
|
||||||
|
|
||||||
|
const open = async () => {
|
||||||
|
modalApi.open();
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ open });
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
message.success({
|
||||||
|
content: '签名上传中请稍等。。。',
|
||||||
|
});
|
||||||
|
const signFileUrl = await uploadFile({
|
||||||
|
file: download.base64ToFile(
|
||||||
|
signature?.value?.save('image/jpeg') || '',
|
||||||
|
'签名',
|
||||||
|
),
|
||||||
|
});
|
||||||
|
emits('success', signFileUrl);
|
||||||
|
modalApi.close();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal class="h-[500px] w-[900px]">
|
||||||
|
<div class="mb-2 flex justify-end">
|
||||||
|
<Space>
|
||||||
|
<Tooltip title="撤销上一步操作">
|
||||||
|
<Button @click="signature?.undo()">
|
||||||
|
<template #icon>
|
||||||
|
<IconifyIcon icon="mi:undo" class="mb-[4px] size-[16px]" />
|
||||||
|
</template>
|
||||||
|
撤销
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title="清空画布">
|
||||||
|
<Button @click="signature?.clear()">
|
||||||
|
<template #icon>
|
||||||
|
<IconifyIcon
|
||||||
|
icon="mdi:delete-outline"
|
||||||
|
class="mb-[4px] size-[16px]"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<span>清除</span>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Vue3Signature
|
||||||
|
class="mx-auto border-[1px] border-solid border-gray-300"
|
||||||
|
ref="signature"
|
||||||
|
w="874px"
|
||||||
|
h="324px"
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineOptions({ name: 'ProcessInstanceSimpleViewer' });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h1>Simple BPM Viewer</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -43,7 +43,7 @@ const statusIconMap: Record<
|
||||||
// 审批未开始
|
// 审批未开始
|
||||||
'-1': { color: '#909398', icon: 'mdi:clock-outline' },
|
'-1': { color: '#909398', icon: 'mdi:clock-outline' },
|
||||||
// 待审批
|
// 待审批
|
||||||
'0': { color: '#00b32a', icon: 'mdi:loading' },
|
'0': { color: '#ff943e', icon: 'mdi:loading', animation: 'animate-spin' },
|
||||||
// 审批中
|
// 审批中
|
||||||
'1': { color: '#448ef7', icon: 'mdi:loading', animation: 'animate-spin' },
|
'1': { color: '#448ef7', icon: 'mdi:loading', animation: 'animate-spin' },
|
||||||
// 审批通过
|
// 审批通过
|
||||||
|
|
|
@ -45,14 +45,14 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
cellConfig: {
|
cellConfig: {
|
||||||
height: 64,
|
height: 64,
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions<BpmProcessInstanceApi.ProcessInstanceVO>,
|
} as VxeTableGridOptions<BpmProcessInstanceApi.CopyVO>,
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 表格操作按钮的回调函数 */
|
/** 表格操作按钮的回调函数 */
|
||||||
function onActionClick({
|
function onActionClick({
|
||||||
code,
|
code,
|
||||||
row,
|
row,
|
||||||
}: OnActionClickParams<BpmProcessInstanceApi.ProcessInstanceVO>) {
|
}: OnActionClickParams<BpmProcessInstanceApi.CopyVO>) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 'detail': {
|
case 'detail': {
|
||||||
onDetail(row);
|
onDetail(row);
|
||||||
|
|
|
@ -528,6 +528,9 @@ catalogs:
|
||||||
vue-tsc:
|
vue-tsc:
|
||||||
specifier: 2.2.10
|
specifier: 2.2.10
|
||||||
version: 2.2.10
|
version: 2.2.10
|
||||||
|
vue3-signature:
|
||||||
|
specifier: ^0.2.4
|
||||||
|
version: 0.2.4
|
||||||
vxe-pc-ui:
|
vxe-pc-ui:
|
||||||
specifier: ^4.5.35
|
specifier: ^4.5.35
|
||||||
version: 4.6.8
|
version: 4.6.8
|
||||||
|
@ -758,6 +761,9 @@ importers:
|
||||||
vue-router:
|
vue-router:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.5.1(vue@3.5.13(typescript@5.8.3))
|
version: 4.5.1(vue@3.5.13(typescript@5.8.3))
|
||||||
|
vue3-signature:
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 0.2.4(vue@3.5.13(typescript@5.8.3))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/crypto-js':
|
'@types/crypto-js':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
|
@ -6220,6 +6226,9 @@ packages:
|
||||||
resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
|
resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
default-passive-events@2.0.0:
|
||||||
|
resolution: {integrity: sha512-eMtt76GpDVngZQ3ocgvRcNCklUMwID1PaNbCNxfpDXuiOXttSh0HzBbda1HU9SIUsDc02vb7g9+3I5tlqe/qMQ==}
|
||||||
|
|
||||||
define-data-property@1.1.4:
|
define-data-property@1.1.4:
|
||||||
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -10018,6 +10027,9 @@ packages:
|
||||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
signature_pad@3.0.0-beta.4:
|
||||||
|
resolution: {integrity: sha512-cOf2NhVuTiuNqe2X/ycEmizvCDXk0DoemhsEpnkcGnA4kS5iJYTCqZ9As7tFBbsch45Q1EdX61833+6sjJ8rrw==}
|
||||||
|
|
||||||
simple-swizzle@0.2.2:
|
simple-swizzle@0.2.2:
|
||||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||||
|
|
||||||
|
@ -11163,6 +11175,11 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.5.13
|
vue: ^3.5.13
|
||||||
|
|
||||||
|
vue3-signature@0.2.4:
|
||||||
|
resolution: {integrity: sha512-XFwwFVK9OG3F085pKIq2SlNVqx32WdFH+TXbGEWc5FfEKpx8oMmZuAwZZ50K/pH2FgmJSE8IRwU9DDhrLpd6iA==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.13
|
||||||
|
|
||||||
vue@3.5.13:
|
vue@3.5.13:
|
||||||
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
|
resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -16351,6 +16368,8 @@ snapshots:
|
||||||
bundle-name: 4.1.0
|
bundle-name: 4.1.0
|
||||||
default-browser-id: 5.0.0
|
default-browser-id: 5.0.0
|
||||||
|
|
||||||
|
default-passive-events@2.0.0: {}
|
||||||
|
|
||||||
define-data-property@1.1.4:
|
define-data-property@1.1.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-define-property: 1.0.1
|
es-define-property: 1.0.1
|
||||||
|
@ -20470,6 +20489,8 @@ snapshots:
|
||||||
|
|
||||||
signal-exit@4.1.0: {}
|
signal-exit@4.1.0: {}
|
||||||
|
|
||||||
|
signature_pad@3.0.0-beta.4: {}
|
||||||
|
|
||||||
simple-swizzle@0.2.2:
|
simple-swizzle@0.2.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-arrayish: 0.3.2
|
is-arrayish: 0.3.2
|
||||||
|
@ -21801,6 +21822,12 @@ snapshots:
|
||||||
is-plain-object: 3.0.1
|
is-plain-object: 3.0.1
|
||||||
vue: 3.5.13(typescript@5.8.3)
|
vue: 3.5.13(typescript@5.8.3)
|
||||||
|
|
||||||
|
vue3-signature@0.2.4(vue@3.5.13(typescript@5.8.3)):
|
||||||
|
dependencies:
|
||||||
|
default-passive-events: 2.0.0
|
||||||
|
signature_pad: 3.0.0-beta.4
|
||||||
|
vue: 3.5.13(typescript@5.8.3)
|
||||||
|
|
||||||
vue@3.5.13(typescript@5.8.3):
|
vue@3.5.13(typescript@5.8.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-dom': 3.5.13
|
'@vue/compiler-dom': 3.5.13
|
||||||
|
|
|
@ -198,3 +198,4 @@ catalog:
|
||||||
zod: ^3.24.3
|
zod: ^3.24.3
|
||||||
zod-defaults: ^0.1.3
|
zod-defaults: ^0.1.3
|
||||||
highlight.js: ^11.11.1
|
highlight.js: ^11.11.1
|
||||||
|
vue3-signature: ^0.2.4
|
||||||
|
|
Loading…
Reference in New Issue