Compare commits

...

7 Commits

43 changed files with 1653 additions and 1292 deletions

View File

@ -6892,7 +6892,7 @@
t && (this.myChart = window.echarts.init(t), setTimeout((function() {
e.updateChart(e.option)
}), 100))
} else console.error("learun[力软信息]提醒你:缺少 echarts 引入")
} else console.error("警告:缺少 echarts 引入")
},
updateChart: function(e) {
console.log(e), this.myChart.resize(), e && this.myChart.setOption(e, !0)
@ -7825,7 +7825,7 @@
e.exports = n("35e8")
},
9224: function(e) {
e.exports = JSON.parse('{"name":"learun-ui-vue","version":"3.3.2","private":true,"description":"vue ui compontents.","author":"tobin","main":"dist2/lui.common.js","company":"力软信息技术(苏州)有限公司","keywords":["vue","learun","learun-ui","learun-ui-vue"],"scripts":{"dev":"vue-cli-service serve","build":"vue-cli-service build","lint":"vue-cli-service lint","test:unit":"vue-cli-service test:unit","prepublishOnly":"npm run lib","lib":"vue-cli-service build --target lib --name learunui --dest dist2 lib/index.js"},"dependencies":{"countup.js":"^2.0.7","element-resize-detector":"^1.2.2","element-ui":"^2.11.0","vue":"^2.6.14","vue-async-computed":"^3.9.0","vue-router":"^3.0.6","vuedraggable":"^2.24.3"},"devDependencies":{"@vue/cli-plugin-babel":"^3.7.0","@vue/cli-plugin-eslint":"^3.7.0","@vue/cli-service":"^3.7.0","@vue/eslint-config-standard":"^4.0.0","@vue/test-utils":"^1.0.0-beta.29","babel-eslint":"^10.0.1","chai":"^4.2.0","core-js":"^2.6.9","css-loader":"^3.1.0","eslint":"^5.16.0","eslint-plugin-vue":"^5.0.0","highlight.js":"^9.15.8","less":"^3.9.0","less-loader":"^5.0.0","markdown-it-chain":"^1.3.0","markdown-it-container":"^2.0.0","shelljs":"^0.8.3","style-loader":"^0.23.1","transliteration":"^2.1.4","vue-markdown-loader":"^2.4.1","vue-template-compiler":"^2.6.10"},"eslintConfig":{"root":true,"env":{"node":true,"browser":true},"extends":["plugin:vue/essential","eslint:recommended"],"rules":{"vue/no-reserved-keys":0,"no-empty":0,"no-useless-escape":0,"no-console":0},"parserOptions":{"parser":"babel-eslint"}},"eslintIgnore":["/src/docs","dist2"],"postcss":{"plugins":{"autoprefixer":{}}},"babel":{"presets":["@vue/app"]}}')
e.exports = JSON.parse('{"name":"learun-ui-vue","version":"3.3.2","private":true,"description":"vue ui compontents.","author":"tobin","main":"dist2/lui.common.js","company":"山东慧创信息科技有限公司","keywords":["vue","learun","learun-ui","learun-ui-vue"],"scripts":{"dev":"vue-cli-service serve","build":"vue-cli-service build","lint":"vue-cli-service lint","test:unit":"vue-cli-service test:unit","prepublishOnly":"npm run lib","lib":"vue-cli-service build --target lib --name learunui --dest dist2 lib/index.js"},"dependencies":{"countup.js":"^2.0.7","element-resize-detector":"^1.2.2","element-ui":"^2.11.0","vue":"^2.6.14","vue-async-computed":"^3.9.0","vue-router":"^3.0.6","vuedraggable":"^2.24.3"},"devDependencies":{"@vue/cli-plugin-babel":"^3.7.0","@vue/cli-plugin-eslint":"^3.7.0","@vue/cli-service":"^3.7.0","@vue/eslint-config-standard":"^4.0.0","@vue/test-utils":"^1.0.0-beta.29","babel-eslint":"^10.0.1","chai":"^4.2.0","core-js":"^2.6.9","css-loader":"^3.1.0","eslint":"^5.16.0","eslint-plugin-vue":"^5.0.0","highlight.js":"^9.15.8","less":"^3.9.0","less-loader":"^5.0.0","markdown-it-chain":"^1.3.0","markdown-it-container":"^2.0.0","shelljs":"^0.8.3","style-loader":"^0.23.1","transliteration":"^2.1.4","vue-markdown-loader":"^2.4.1","vue-template-compiler":"^2.6.10"},"eslintConfig":{"root":true,"env":{"node":true,"browser":true},"extends":["plugin:vue/essential","eslint:recommended"],"rules":{"vue/no-reserved-keys":0,"no-empty":0,"no-useless-escape":0,"no-console":0},"parserOptions":{"parser":"babel-eslint"}},"eslintIgnore":["/src/docs","dist2"],"postcss":{"plugins":{"autoprefixer":{}}},"babel":{"presets":["@vue/app"]}}')
},
9292: function(e, t, n) {
"use strict";

View File

@ -5,6 +5,7 @@ import {
getPageListModel,
stateModel,
GetFormModel,
formModuleModel,
} from './model/formModuleModel';
import { defHttp } from '@/utils/http/axios';
@ -17,6 +18,10 @@ enum Api {
Post_DeleteForm = '/api/FormModule/DeleteForm',
// 根据主键获取实体数据(编辑时使用)
Get_GetForm = '/api/FormModule/GetForm',
// 新增实体数据
Post_AddForm = '/api/FormModule/AddForm',
// 编辑实体数据
Post_UpdateForm = '/api/FormModule/UpdateForm',
}
// 获取分页列表
@ -48,3 +53,18 @@ export function fun_GetForm(params) {
params,
});
}
// 新增实体数据
export function Post_AddForm(params: formModuleModel) {
return defHttp.post<responsesmodel>({
url: Api.Post_AddForm,
params,
});
}
// 编辑实体数据
export function Post_UpdateForm(params: formModuleModel) {
return defHttp.post<responsesmodel>({
url: Api.Post_UpdateForm,
params,
});
}

View File

@ -87,3 +87,106 @@ export interface form {
isMain: number;
}
export type GetFormModel = BasicFetchResult<form>;
// 表单发布实体数据
// 表单发布实体
export interface formModuleEntity {
id: string;
code: string;
formCode: string;
formVerison: string;
icon: string;
name: string;
type: number;
pmoduleId: string;
moduleId: string;
sortCode: number;
enabledMark: number;
description: string;
createDate: string;
createUserId: string;
createUserName: string;
modifyDate: string;
modifyUserId: string;
modifyUserName: string;
scheme: string;
keyWord: string;
tenantId: string;
isMain: number;
}
export type formModuleEntityModel = BasicFetchResult<formModuleEntity>;
// 表单发布实体
export interface elements {
id: string;
domId: string;
name: string;
attr: string;
script: string;
icon: string;
class: string;
remark: string;
sort: number;
moduleId: string;
}
export interface sysModule {
id: string;
cascadeId: string;
name: string;
parentId: string;
parentName: string;
url: string;
iconName: string;
status: number;
sortNo: number;
code: string;
encode: string;
isSys: true;
elements: elements;
}
export type sysModuleModel = BasicFetchResult<sysModule>;
// 表单发布实体
export interface sysModuleElement {
id: string;
domId: string;
name: string;
attr: string;
script: string;
icon: string;
class: string;
remark: string;
sort: number;
moduleId: string;
}
export type sysModuleElementModel = BasicFetchResult<sysModuleElement>;
// 表单发布实体-Column
export interface sysModuleColumn {
moduleColumnId: string;
moduleId: string;
parentId: string;
encode: string;
fullName: string;
sortCode: number;
tenantId: string;
isMain: number;
}
export type sysModuleColumnModel = BasicFetchResult<sysModuleColumn>;
// 表单发布实体
export interface sysModuleForm {
moduleFormId: string;
moduleId: string;
parentId: string;
encode: string;
fullName: string;
sortCode: number;
tenantId: string;
isMain: number;
}
export type sysModuleFormModel = BasicFetchResult<sysModuleForm>;
//
export interface formModuleModel {
formModuleEntity: formModuleEntityModel;
sysModule: sysModuleModel;
sysModuleElement: sysModuleElementModel;
sysModuleColumn: sysModuleColumnModel;
sysModuleForm: sysModuleFormModel;
}

View File

@ -1,7 +1,7 @@
// WFTask
import { defHttp } from '@/utils/http/axios';
import {MyUncompletedParams} from './model/WFTaskModel'
import {MyUncompletedParams,TaskDetailParam} from './model/WFTaskModel'
enum Api {
// 我的待办
@ -12,6 +12,7 @@ import {MyUncompletedParams} from './model/WFTaskModel'
LoadMyReadPage='/api/WFTask/LoadMyReadPage',
// 我的委托
LoadMyDelegatePage='/api/WFTask/LoadMyDelegatePage',
GetTaskDetail='/api/WFTask/Get',
}
/**
@ -37,4 +38,10 @@ import {MyUncompletedParams} from './model/WFTaskModel'
*/
export function getLoadMyDelegatePage(params?: MyUncompletedParams) {
return defHttp.get({ url: Api.LoadMyDelegatePage, params });
}
}
/**
* @description: GetTaskDetail
*/
export function getTaskDetail(params?: TaskDetailParam) {
return defHttp.get({ url: Api.GetTaskDetail, params });
}

View File

@ -7,4 +7,7 @@
limit: number;
startDate: string;
endDate: string;
}
export interface TaskDetailParam {
id: string;
}

View File

@ -21,7 +21,7 @@
<a-tab-pane key="1" tab="自定义表单">
<a-space direction="vertical" size="middle" class="site-space-compact-wrapper">
<a-space-compact block>
<a-input v-model:value="formData.formCode" placeholder="请选择表单" readonly />
<a-input v-model:value="node.formCode" placeholder="请选择表单" readonly />
<a-button >选择</a-button>
</a-space-compact>
<a-space-compact block>

View File

@ -14,6 +14,10 @@
<a-button :disabled="data.defaultZoom >= 3.9" :icon="h(ZoomInOutlined)" @click="processZoomIn()">
</a-button>
</a-tooltip>
<div class="ml-2 tag-box">
<a-tag color="processing">正在审核</a-tag>
<a-tag color="success">已审核</a-tag>
</div>
</a-space>
</div>
@ -22,6 +26,7 @@
</div>
</div>
<div class="my-process-designer__container">
<div class="my-process-designer__canvas" ref="bpmn-canvas" id="view"></div>
</div>
</div>
@ -33,6 +38,8 @@
import { SaveOutlined, ZoomOutOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
import BpmnViewer from 'bpmn-js/lib/Viewer'
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
const emit = defineEmits(['event', 'element-click']);
const data = reactive({
bpmnModeler: null,
defaultZoom: 1,
@ -40,7 +47,7 @@
const props = defineProps({
xml: String,
flowViewer:{
flowViewer: {
type: Object,
default: () => ({
finishedTaskSet: [],
@ -48,7 +55,11 @@
unfinishedTaskSet: [],
rejectedTaskSet: [],
})
}
},
events: {
type: Array,
default: () => ["element.click"]
},
})
watch(
() => props.xml,
@ -71,6 +82,19 @@
MoveCanvasModule
],
})
initModelListeners()
}
function initModelListeners() {
const EventBus = data.bpmnModerler.get("eventBus");
// , . - ,
props.events.forEach(event => {
EventBus.on(event, function (eventObj) {
let eventName = event.replace('.', "-");
let element = eventObj ? eventObj.element : null;
emit(eventName, element, eventObj);
emit('event', eventName, element, eventObj);
});
});
}
async function createDiagram(xml) {
const viewer = data.bpmnModerler
@ -103,6 +127,7 @@
//
function setNodeColor() {
const elementRegistry = data.bpmnModerler.get('elementRegistry')
console.log(elementRegistry)
let { finishedTaskSet, rejectedTaskSet, unfinishedTaskSet, finishedSequenceFlowSet } = props.flowViewer
if (Array.isArray(finishedSequenceFlowSet)) {
finishedSequenceFlowSet.forEach(item => {
@ -120,6 +145,7 @@
}
})
}
console.log(unfinishedTaskSet)
if (Array.isArray(unfinishedTaskSet)) {
unfinishedTaskSet.forEach(item => {
if (elementRegistry._elements[item]) {
@ -161,13 +187,22 @@
function getOperationTagType(type) {
return 'success';
}
</script>
<style lang="less" scoped>
.my-process-designer {
width: 100%;
}
.tag-box{
float: right;
}
::v-deep .ant-tag-success{
padding: 5px 11px;
}
::v-deep .ant-tag-processing{
padding: 5px 11px;
}
::v-deep .bjs-container a {
visibility: hidden;
}

View File

@ -180,6 +180,7 @@
"workflow":{
"scheme_preview":"流程模板设计",
"create_preview":"流程发起",
"task_preview":"流程详情"
"task_audit_preview":"审核节点",
"task_look_preview":"查看流程"
}
}

View File

@ -39,10 +39,21 @@ export const LoginRoute: AppRouteRecordRaw = {
title: t('routes.basic.login'),
},
};
export const H5HtmlRoute: AppRouteRecordRaw = {
path: '/h5html',
name: 'h5html',
component: () => import('@/views/demo/h5html/index.vue'),
meta: {
title: t('routes.basic.h5html'),
},
};
// Basic routing without permission
// 未经许可的基本路由
export const basicRoutes = [
H5HtmlRoute,
LoginRoute,
RootRoute,
...mainOutRoutes,

View File

@ -48,17 +48,29 @@ const dashboard: AppRouteModule = {
component: () => import('@/views/demo/workflow/create/preview.vue'),
},
{
path: 'task_preview/:id',
name: 'TaskPreview',
path: 'task_audit_preview/:id',
name: 'TaskAuditPreview',
meta: {
hideMenu: true,
title: t('routes.demo.workflow.task_preview'),
title: t('routes.demo.workflow.task_audit_preview'),
ignoreKeepAlive: true,
showMenu: false,
currentActiveMenu: '/workflow/create',
currentActiveMenu: '/workflow/task',
},
component: () => import('@/views/demo/workflow/task/detail.vue'),
}
component: () => import('@/views/demo/workflow/task/process/audit.vue'),
},
{
path: 'task_look_preview/:id',
name: 'TaskLookPreview',
meta: {
hideMenu: true,
title: t('routes.demo.workflow.task_look_preview'),
ignoreKeepAlive: true,
showMenu: false,
currentActiveMenu: '/workflow/task',
},
component: () => import('@/views/demo/workflow/task/process/look.vue'),
},
],
};

38
src/utils/base.ts Normal file
View File

@ -0,0 +1,38 @@
/**
*
*/
export function formatDate(v, format) {
if (!v) return "";
var d = v;
if (typeof v === 'string') {
if (v.indexOf("/Date(") > -1)
d = new Date(parseInt(v.replace("/Date(", "").replace(")/", ""), 10));
else
d = new Date(Date.parse(v.replace(/-/g, "/").replace("T", " ").split(".")[0]));//.split(".")[0] 用来处理出现毫秒的情况,截取掉.xxx否则会出错
}
var o = {
"M+": d.getMonth() + 1, //month
"d+": d.getDate(), //day
"h+": d.getHours(), //hour
"H+": d.getHours(), //hour
"m+": d.getMinutes(), //minute
"s+": d.getSeconds(), //second
"q+": Math.floor((d.getMonth() + 3) / 3), //quarter
"S": d.getMilliseconds() //millisecond
};
if (/(y+)/.test(format)) {
format = format.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(format)) {
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
}
}
return format;
}
export function dateFormat(date,format = 'yyyy-MM-dd hh:mm:ss'){
return formatDate(date,format);
}

View File

@ -89,7 +89,7 @@ const transform: AxiosTransform = {
if (options.errorMessageMode === 'modal') {
createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg });
} else if (options.errorMessageMode === 'message') {
createMessage.error(timeoutMsg);
// createMessage.error(timeoutMsg);
}
throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'));

View File

@ -158,7 +158,7 @@
}
getOutKeyList({tableNames: fieldTableValue.value, dbCode: receivedData.dbCode}).then((data: AreaRespVO[]) => {
let arr: any[] = []
if(data[0]){
if(data && data[0]){
data[0].db_codecolumnsList.forEach(item =>{
arr.push({
label: item.dbColumnName,

View File

@ -8,7 +8,43 @@ import { ComponentType } from '@/components/Form/src/types';
import { componentMap as Cmp } from '../components';
import { Component } from 'vue';
import { getDeptList,getAccountList,getPosGroupList } from '@/api/demo/system';
//获取部门列表数据
const deptTreeData = await Promise.all([getDeptListData()])
function getDeptListData(){
let param = {
page: 1,
limit: 9999
};
return getDeptList( param ).then( data => {
return data
})
}
//获取职级列表数据
const positionTreeData = await Promise.all([getPositionListData()])
function getPositionListData(){
let param = {
page: 1,
limit: 9999
};
return getPosGroupList( param ).then( data => {
return data
})
}
//获取人员选择列表数据
const userTreeData = await Promise.all([getUserListData()])
function getUserListData(){
let param = {
page: 1,
limit: 9999
};
return getAccountList( param ).then( data => {
return data.items
})
}
const componentMap = new Map<string, Component>();
//如果有其它控件,可以在这里初始化
@ -56,41 +92,33 @@ export const customComponents: IVFormComponent[] = [
componentProps: {},
},
{
component: 'Select',
label: '公司选择',
component: 'TreeSelect',
label: '职级选择',
icon: 'gg:select',
field: '',
colProps: { span: 24 },
componentProps: {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
fieldNames:{
children: 'children',
label: 'name',
value: 'id',
},
treeData: positionTreeData[0],
},
},
{
component: 'Select',
component: 'TreeSelect',
label: '部门选择',
icon: 'gg:select',
icon: 'clarity:tree-view-line',
field: '',
colProps: { span: 24 },
componentProps: {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
fieldNames:{
children: 'children',
label: 'name',
value: 'id',
},
treeData: deptTreeData[0],
},
},
{
@ -100,16 +128,11 @@ export const customComponents: IVFormComponent[] = [
field: '',
colProps: { span: 24 },
componentProps: {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
fieldNames:{
label: 'name',
value: 'account',
},
options: userTreeData[0],
},
},
];

View File

@ -0,0 +1,49 @@
import { BasicColumn, FormSchema } from '@/components/Table';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns: BasicColumn[] = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '分类',
dataIndex: 'category',
},
{
title: '类型',
dataIndex: 'formType',
width: 80,
customRender: ({ record }) => {
const status = record.formType;
const enable = ~~status === 0;
const color = enable ? '#67c23a' : '#e6a23c';
const text = enable ? '常规表单' : '视图表单';
return h(Tag, { color: color }, () => text);
},
},
{
title: '创建人',
dataIndex: 'createUserName'
},
{
title: '创建时间',
dataIndex: 'createDate'
},
// {
// title: '备注',
// dataIndex: 'remark',
// },
];
export const searchFormSchema: FormSchema[] = [
{
field: 'key',
label: '关键字',
component: 'Input',
colProps: { span: 8 },
},
];

View File

@ -0,0 +1,121 @@
<template>
<BasicTable @register="registerTable">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction :actions="[
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
color: 'error',
popConfirm: {
title: '是否删除该数据',
confirm: handleDelete.bind(null, record),
},
}
]" />
</template>
</template>
<template #toolbar>
<a-button type="primary" @click="handleAddForm(eFormPreview!)"> </a-button>
</template>
</BasicTable>
<VformRender ref="eFormPreview" :formConfig="formConfig" @renderdata="renderdata" />
</template>
<script lang="ts" setup>
import { onMounted, ref, nextTick, unref,reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getFormGroupList,getBaseConfigList } from '@/api/formdesign/index';
import { columns, searchFormSchema } from './index.data';
import { cloneDeep } from 'lodash-es';
import VformRender from '../form-design/components/VformRender/index.vue';
import { IFormConfig,IToolbarMethods } from '../form-design/typings/v-form-component';
const eFormPreview = ref<null | IToolbarMethods>(null);
const [registerTable, { reload, getSelectRows }] = useTable({
title: '表单列表',
api: getFormGroupList,
rowKey: 'f_Id',
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
useSearchForm: true,
showTableSetting: true,
bordered: true,
beforeFetch: (data) => {
//
var temp = {
page: data.page,
limit: data.limit,
keyWord: data.key,
category: data.f_Category
};
return temp;
},
afterFetch: (data) => {
},
handleSearchInfoFn(info) {
return info;
},
actionColumn: {
width: 180,
title: '操作',
dataIndex: 'action',
// slots: { customRender: 'action' },
fixed: undefined,
},
});
const formConfig = ref<IFormConfig>({
//
schemas: [],
layout: 'horizontal',
labelLayout: 'flex',
labelWidth: 100,
labelCol: {},
wrapperCol: {},
currentItem: {
component: '',
componentProps: {},
},
activeKey: 1,
});
const handleAddForm = (Modal: IToolbarMethods) => {
console.log('formConfig',formConfig)
const config = cloneDeep(formConfig.value);
Modal?.showModal(config);
}
function handleEdit(record: Recordable) {
}
function handleDelete(record: Recordable) {
// openAccountModal(true, {
// record,
// });
}
function getPublicForm(){
getBaseConfigList({ id: "ed985a1e-b007-43d1-af14-be4e44018c8b" }).then((res: AreaRespVO[]) =>{
let obj = JSON.parse(res.scheme.scheme)
console.log('res',obj.formInfo)
formConfig.value.schemas = obj.formInfo.schemas
})
}
//
function renderdata(e){
console.log('renderdata',e)
}
onMounted(() => {
getPublicForm()
})
</script>

View File

@ -104,9 +104,14 @@
// });
}
function getPublicForm(){
getBaseConfigList({ id: "ed985a1e-b007-43d1-af14-be4e44018c8b" }).then((res: AreaRespVO[]) =>{
getBaseConfigList({ id: "e03bd1db-7a4f-43b2-9e8a-f6cd8c2126be" }).then((res: AreaRespVO[]) =>{
let obj = JSON.parse(res.scheme.scheme)
console.log('res',obj.formInfo)
if(obj.formInfo.schemas){
obj.formInfo.schemas.forEach(item =>{
})
}
formConfig.value.schemas = obj.formInfo.schemas
})
}

View File

@ -35,28 +35,48 @@
</div>
</div>
<div class="design-content">
<ModalForm v-show="stepsCurrent === 0" :isNextSteps="isNextSteps" />
<ModalDesign v-show="stepsCurrent === 1" :isSubmitClick="isSubmitClick" />
<ModalForm
v-show="stepsCurrent == 0"
@change-form-verisons="changeFormVerisons"
ref="modalFrom_formData"
/>
<ModalDesign
v-show="stepsCurrent == 1"
:modalFormVerison="modalFormVerison"
ref="modalDesign_config"
/>
</div>
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import { ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import ModalForm from './modalForm.vue';
import ModalDesign from './modalDesign.vue';
import { Post_AddForm, Post_UpdateForm } from '@/api/demo/formModule';
//
let stepsCurrent = ref();
let stepsCurrent = ref(0);
//
let isNextSteps = ref(false);
//
let isSubmitClick = ref(false);
//
let formEdit = ref(false);
//
const modalFrom_formData = ref();
const modalDesign_config = ref();
const modalFormVerison = ref('');
const [registerModal, { closeModal }] = useModalInner((data: any) => {
console.log(75, data);
formEdit.value = data.formEdit;
// if(){
// }
stepsCurrent.value = 0;
isSubmitClick.value = false;
});
@ -78,10 +98,120 @@
isNextSteps.value = false;
closeModal();
}
//
function submitClick() {
async function submitClick() {
const postData = getForm();
if (formEdit.value) {
await Post_UpdateForm(postData);
} else {
await Post_AddForm(postData);
}
closeModal();
isSubmitClick.value = true;
}
function getForm() {
const formData = modalFrom_formData.value.formData;
const config = modalDesign_config.value.config;
//
let formModuleEntity = {};
formModuleEntity.id = formData.id;
formModuleEntity.code = formData.code;
formModuleEntity.formCode = formData.formCode.id;
formModuleEntity.formVerison = formData.formVerison.value;
formModuleEntity.icon = formData.icon;
formModuleEntity.name = formData.name;
formModuleEntity.type = formData.type;
formModuleEntity.pmoduleId = formData.pmoduleId;
formModuleEntity.moduleId = '';
formModuleEntity.sortCode = formData.sortCode;
formModuleEntity.enabledMark = formData.enabledMark;
formModuleEntity.description = formData.description;
// formModuleEntity.createDate= ;
// formModuleEntity.createUserId= ;
// formModuleEntity.createUserName= ;
formModuleEntity.modifyDate = new Date();
// formModuleEntity.modifyUserId= ;
// formModuleEntity.modifyUserName= ;
formModuleEntity.scheme = JSON.stringify(config);
formModuleEntity.keyWord = '';
formModuleEntity.tenantId = '';
formModuleEntity.isMain = '';
// sysModule
let sysModule = {};
sysModule.id = '';
sysModule.cascadeId = '';
sysModule.name = formData.name;
sysModule.parentId = formData.pmoduleId;
sysModule.parentName = '';
sysModule.url = '';
sysModule.iconName = formData.icon;
sysModule.status = 1;
sysModule.sortNo = formData.sortCode;
sysModule.code = formData.code;
sysModule.encode = '';
sysModule.isSys = formData.isSys;
sysModule.elements = [];
// sysModuleElement
let sysModuleElement = [];
if (config.table.btns) {
config.table.btns.forEach((t) => {
let temp = {};
temp.id = '';
temp.domId = t.prop;
temp.name = t.label;
temp.attr = '';
temp.script = '';
temp.icon = t.icon;
temp.class = t.class;
temp.remark = '';
temp.sort = t.sort;
temp.moduleId = '';
sysModuleElement.push(temp);
});
}
// sysModuleColumn
let sysModuleColumn = [];
if (config.table.columns) {
config.table.columns.forEach((t) => {
let temp = {};
temp.encode = t.prop;
temp.fullName = t.label;
sysModuleColumn.push(temp);
});
}
// sysModuleForm
let sysModuleForm = [];
if (config.table.querys) {
config.table.querys.forEach((t) => {
let temp = {};
temp.encode = t.key;
temp.fullName = t.label;
sysModuleForm.push(temp);
});
}
// postData
let postData = {};
postData.formModuleEntity = formModuleEntity;
postData.sysModule = sysModule;
postData.sysModuleElement = sysModuleElement;
postData.sysModuleColumn = sysModuleColumn;
postData.sysModuleForm = sysModuleForm;
console.log('postData', postData);
return postData;
}
// modalFormmodalDesign
function changeFormVerisons(formVerison) {
modalFormVerison.value = formVerison;
}
</script>
<style scoped>
.form-box {

View File

@ -11,7 +11,50 @@
@check="handleCheck"
/>
</template>
<BasicTable @register="registerTable" />
<BasicTable @register="btnsTable">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'isRowBtn'">
<a-switch
v-model:checked="record.isRowBtn"
:disabled="['Add', 'Import', 'Export'].includes(record.prop)"
/>
</template>
<template v-if="column.key === 'isWFlow'">
<div v-if="record.prop == 'Add'">
<a-switch v-model:checked="record.isWFlow" />
</div>
</template>
<template v-if="column.key === 'wFlowCode'">
<div v-if="record.prop == 'Add'">
<a-select
ref="select"
placeholder="请选择"
size="small"
v-model:value="record.wFlowCode"
:options="wflist"
:field-names="{ label: 'dbColumnName', value: 'dbColumnName' }"
/>
</div>
</template>
<template v-if="column.key === 'class'">
<a-select
ref="select"
placeholder="请选择"
size="small"
v-model:value="record.class"
:options="classList"
/>
</template>
<template v-if="column.key === 'sort'">
<a-input-number v-model:value="record.sort" :min="0" />
</template>
<template v-if="column.key === 'icon'">
<div v-if="record.prop in ['Add', 'Import', 'Export']">
<IconPicker v-model:value="record.icon" />
</div>
</template>
</template>
</BasicTable>
</lrlayout>
</template>
<script lang="ts" setup>
@ -19,6 +62,7 @@
import { BasicTable, useTable } from '@/components/Table';
import lrlayout from '@/components/lrLayout';
import { BasicTree } from '@/components/Tree';
import { IconPicker } from '/@/components/Icon';
import { btns } from './config.data';
@ -33,11 +77,16 @@
// config
const config = inject('formConfig');
const btnsData = ref(config.btns);
const btnsData = ref(config.table.btns);
console.log(38, btnsTree);
const classList = [
{ label: 'primary', value: 'primary' },
{ label: 'success', value: 'success' },
{ label: 'error', value: 'error' },
{ label: 'warning', value: 'warning' },
];
const [registerTable, { reload }] = useTable({
const [btnsTable, { reload }] = useTable({
rowKey: 'id',
dataSource: btnsData,
columns: btns(),

View File

@ -11,7 +11,7 @@
@check="handleCheck"
/>
</template>
<BasicTable @register="registerTable">
<BasicTable @register="columnsTable">
<template #toolbar>
<span style="margin-right: 8px">是否分页</span>
<a-switch class="mars-switch" v-model:checked="config.table.isPage" />
@ -78,7 +78,7 @@
{ value: 'right', label: '右' },
];
const [registerTable, { reload }] = useTable({
const [columnsTable, { reload }] = useTable({
rowKey: 'key',
dataSource: columnsData,
columns: columns(),

View File

@ -21,6 +21,8 @@ export function btns(): BasicColumn[] {
{ title: '行按钮', dataIndex: 'isRowBtn', width: '80', align: 'center' },
{ title: '创建流程', dataIndex: 'isWFlow', width: '80', align: 'center' },
{ title: '流程模版', dataIndex: 'wFlowCode', width: '240' },
{ title: '权限标识', dataIndex: 'class', width: '120' },
{ title: '排序', dataIndex: 'sort', width: '80' },
{ title: '图标', dataIndex: 'icon', width: '240' },
];
}

View File

@ -1,280 +0,0 @@
<template>
<lrlayout style="background: #f1f2f5" :left="240">
<template #left>
<lrPanel title="列表关联字段" style="padding: 8px 0 0 0">
<a-radio class="block-radio" :options="colslist" v-model="config.left.colField" />
</lrPanel>
</template>
<lrPanel title="设置" style="padding: 8px 0 0 4px">
<el-form style="padding: 16px; maxwidth: 400px" size="mini" ref="form" label-width="80px">
<el-form-item label="树形标题">
<el-input v-model="config.left.title" />
</el-form-item>
<div style="text-align: center; margin-bottom: 16px">
<a-radio-group v-model="config.left.dataType" size="mini" @change="handleDataTypeChange">
<a-radio-button label="1">静态数据</a-radio-button>
<a-radio-button label="2">数据字典</a-radio-button>
<a-radio-button label="3">数据源</a-radio-button>
</a-radio-group>
</div>
<!--静态数据-->
<div v-if="config.left.dataType == 1">
<a-tree
ref="tree"
:data="config.left.options"
default-expand-all
draggable
node-key="value"
:expand-on-click-node="false"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
<span>
<a-button
type="text"
size="mini"
icon="el-icon-plus"
@click="handleNodeAdd(data)"
/>
<a-button
class="danger"
type="text"
size="mini"
icon="el-icon-delete"
@click="handleNodeRemove(node, data)"
/>
</span>
</span>
</template>
</a-tree>
<div style="margin-left: 22px">
<a-button
size="mini"
type="text"
icon="el-icon-circle-plus-outline"
@click="handleParentNodeAdd"
>添加父级</a-button
>
</div>
</div>
<!--数据字典-->
<div v-else-if="config.left.dataType == 2">
<l-tree-select
v-model="config.left.dataCode"
:options="lr_dataItemClassifysTree"
placeholder="请选择数据字典"
size="mini"
/>
</div>
<!--远端数据-->
<div v-else>
<el-form-item label="数据源">
<l-select
v-model="config.left.dataCode"
placeholder="请选择数据源"
size="mini"
:options="lr_dataSource"
labelKey="f_Name"
valueKey="f_Code"
@change="handleDataSourceChange"
/>
</el-form-item>
<el-form-item label="关联字段">
<l-select
v-model="config.left.dataValueKey"
placeholder="请选择选项关联字段"
size="mini"
:options="myColNameList"
/>
</el-form-item>
<el-form-item label="显示字段">
<l-select
v-model="config.left.dataLabelKey"
placeholder="请选择选项显示字段"
size="mini"
:options="myColNameList"
/>
</el-form-item>
<el-form-item label="id字段">
<l-select
v-model="config.left.dataIdKey"
placeholder="请选择选项id字段"
size="mini"
:options="myColNameList"
/>
</el-form-item>
<el-form-item label="pid字段">
<l-select
v-model="config.left.dataPIdKey"
placeholder="请选择选项父级id字段"
size="mini"
:options="myColNameList"
/>
</el-form-item>
</div>
</el-form>
</lrPanel>
<l-dialog
:title="dialogTitle"
v-model:visible="dialogVisible"
:height="200"
@close="closeDialog"
@ok="handleDialogAdd"
>
<div class="l-from-body">
<el-form
:model="dialogForm"
size="mini"
:rules="dialogRules"
ref="dialogForm"
label-width="80px"
>
<el-form-item label="选项名" prop="label">
<el-input v-model="dialogForm.label" />
</el-form-item>
<el-form-item label="选项值" prop="value">
<el-input v-model="dialogForm.value" />
</el-form-item>
</el-form>
</div>
</l-dialog>
</lrlayout>
</template>
<script lang="ts" setup>
import { inject, defineProps } from 'vue';
import { BasicTable, useTable } from '@/components/Table';
import lrlayout from '@/components/lrLayout';
import { BasicTree } from '@/components/Tree';
import lrPanel from '@/components/lrPanel';
import { columns } from './config.data';
// props,
const props = defineProps({
colslist: {
type: Object,
default: () => ({}), //
},
});
// config
const config = inject('formConfig');
let dialogTitle = '添加选项';
let dialogVisible = false;
const dialogForm = ref({
label: '',
value: '',
});
let dialogRules = {
label: { required: true, message: '请输入选项名', trigger: 'null' },
value: { required: true, message: '请输入选项值', trigger: 'null' },
};
let pData = undefined;
function myColNameList() {
if (config.left.dataCode) {
const colNameList = config.left.dataCode;
return colNameList.map((t) => {
return { value: t, label: t };
});
} else {
return [];
}
}
// created() {
// lr_loadDataItemClassifys();
// lr_loadDataSourceList();
// if (config.left.dataType == 3) {
// lr_loadDataSourceColNames(config.left.dataCode);
// }
// },
// methods: {
function handleDataTypeChange() {
config.left.dataIdKey = '';
config.left.dataPIdKey = '';
config.left.dataCode = '';
config.left.dataValueKey = '';
config.left.dataLabelKey = '';
}
function handleParentNodeAdd() {
pData = undefined;
dialogTitle = '添加父级选项';
dialogVisible = true;
}
function handleNodeAdd(data) {
pData = data;
dialogTitle = `添加【${data.label}】的子选项`;
dialogVisible = true;
}
function handleNodeRemove(node, data) {
const parent = node.parent;
const children = parent.data.children || parent.data;
const index = children.findIndex((d) => d.id === data.id);
children.splice(index, 1);
}
// function handleDialogAdd() {
// dialogForm.validate((valid) => {
// if (valid) {
// const { label, value } = dialogForm;
// const node = $refs.tree.getNode(value);
// if (node) $message.error('');
// else {
// const pData = pData;
// const newNode = {
// label,
// value: dialogInputType == 'number' ? Number(value) : value,
// };
// if (pData) {
// if (!pData.children) $set(pData, 'children', []);
// pData.children.push(newNode);
// } else {
// $set(config.left.options, config.left.options.length, newNode);
// }
// dialogVisible = false;
// }
// }
// });
// }
function closeDialog() {
dialogForm.clearValidate();
dialogForm.value = {};
}
function handleDataSourceChange(val) {
config.left.dataValueKey = '';
config.left.dataLabelKey = '';
config.left.dataIdKey = '';
config.left.dataPIdKey = '';
if (!$validatenull(val)) {
// lr_loadDataSourceColNames(val);
}
}
</script>
<style lang="scss">
.block-radio {
padding: 8px;
box-sizing: border-box;
.el-radio {
display: block;
margin-bottom: 8px;
}
}
</style>
<style lang="scss" scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
</style>

View File

@ -2,7 +2,7 @@
<lrlayout style="background: #f1f2f5" :left="240">
<template #left>
<lrPanel title="列表关联字段" style="padding: 8px 0 0 0">
<a-radio-group :options="colslist" v-model="config.left.colField" />
<a-radio-group :options="colslist" v-model:value="config.left.colField" />
</lrPanel>
</template>
<lrPanel title="设置" style="padding: 8px 0 0 4px">
@ -11,10 +11,15 @@
<a-input v-model="config.left.title" />
</a-form-item>
<div style="text-align: center; margin-bottom: 16px">
<a-radio-group v-model="config.left.dataType" size="mini" @change="handleDataTypeChange">
<a-radio-button label="1">静态数据</a-radio-button>
<a-radio-button label="2">数据字典</a-radio-button>
<a-radio-button label="3">数据源</a-radio-button>
<a-radio-group
v-model:value="config.left.dataType"
size="mini"
button-style="solid"
@change="handleDataTypeChange"
>
<a-radio-button value="1">静态数据</a-radio-button>
<a-radio-button value="2">数据字典</a-radio-button>
<a-radio-button value="3">数据源</a-radio-button>
</a-radio-group>
</div>
<!--静态数据-->

View File

@ -13,7 +13,7 @@
</template>
<a-layout style="background: #f1f2f5">
<a-layout-sider :style="{ width: '1000px' }">
<BasicTable @register="registerTable">
<BasicTable @register="queryTable">
<template #toolbar>
<div class="l-panel--item" size="mini">
<a-radio-group
@ -63,7 +63,7 @@
const querysData = ref(config.table.querys);
const radioData = ref(config.queryType);
const [registerTable, { reload }] = useTable({
const [queryTable, { reload }] = useTable({
canResize: 'true',
showIndexColumn: 'false',
rowKey: 'key',

View File

@ -261,3 +261,25 @@ export const formSchema: FormSchema[] = [
},
},
];
export const modalColumns: BasicColumn[] = [
{
title: '名称',
dataIndex: 'name',
width: 200,
},
{
dataIndex: 'scheme',
ifShow: false,
},
{
title: '分类',
dataIndex: 'category',
width: 80,
},
{
title: '操作',
dataIndex: 'action',
width: 80,
},
];

View File

@ -10,12 +10,17 @@
<template #toolbar>
<PermissionBtn @btn-event="onBtnClicked" />
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'pmoduleId'">
{{ findModuleName(pmoduleIds, record.pmoduleId) }}
</template>
</template>
</BasicTable>
<FormModal @submitsuccess="submitsuccess" @register="registerModal" v-if="formModalVisible" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, nextTick, ref } from 'vue';
import { reactive, nextTick, ref, onMounted } from 'vue';
import { BasicTable, useTable } from '@/components/Table';
@ -23,10 +28,12 @@
import PermissionBtn from '@/components/PermissionBtn/index.vue';
import { useMessage } from '@/hooks/web/useMessage';
import { useModal } from '@/components/Modal';
import { TreeItem } from '@/components/Tree';
import MenuTree from './FormTree.vue';
import FormModal from './FormModal.vue';
import { getMenuList } from '@/api/demo/system';
import { fun_GetPageList, fun_DeleteForm } from '@/api/demo/formModule';
import { formModuleColumns, searchFormSchema } from './formModule.data';
@ -61,6 +68,8 @@
const childRef = ref<any>();
//
const formModalVisible = ref(true);
//
const pmoduleIds = ref<TreeItem[]>([]);
// searchInfo
function handleSelect(ModuleId = '') {
@ -72,7 +81,9 @@
//
function handleAddForm() {
formModalVisible.value = true;
openModal(true, {});
openModal(true, {
formEdit: false,
});
}
//
function handleEdit() {
@ -81,9 +92,12 @@
return createMessage.warn('请选择一个按钮进行编辑');
}
const record = rows[0];
record.type = '2';
// record.type = '2';
formModalVisible.value = true;
openModal(true, record);
openModal(true, {
formEdit: true,
record: record,
});
}
//
async function handleDelete() {
@ -137,4 +151,29 @@
break;
}
}
//
function findModuleName(modules, pmoduleId) {
for (const module of modules) {
if (module.id === pmoduleId) {
return module.name;
}
if (Array.isArray(module.children) && module.children.length > 0) {
const foundName = findModuleName(module.children, pmoduleId);
if (foundName) {
return foundName;
}
}
}
return '';
}
//
async function fetch() {
pmoduleIds.value = await getMenuList();
}
onMounted(() => {
fetch();
});
</script>

View File

@ -22,7 +22,7 @@
</template>
<script lang="ts" setup>
import { ref, provide, onMounted } from 'vue';
import { ref, provide, defineExpose, watch, defineProps } from 'vue';
import WebcodeLayout from './config/layout.vue';
import webcodeLefttree from './config/leftTree.vue';
import webcodeColumns from './config/columns.vue';
@ -30,6 +30,24 @@
import webcodeBtns from './config/btns.vue';
import { functionGetPreviewForm, functionGetSchemeInfoEntity } from '@/api/demo/formScheme';
// props
const props = defineProps({
modalFormVerison: {
type: Object,
default: () => ({}), //
},
});
watch(
() => props.modalFormVerison,
(newVal) => {
validateSteps(newVal.value);
},
{
immediate: true,
},
);
//
const pageActiveName = 'tab01';
//
@ -69,25 +87,53 @@
isPage: true,
columns: [],
querys: [],
btns: [],
sidx: '',
isDESC: false,
},
btns: [
{ label: '新增', id: 'Add', prop: 'Add', icon: 'el-icon-plus', isRowBtn: false },
{ label: '导入', id: 'Import', prop: 'Import', icon: 'el-icon-upload2', isRowBtn: false },
{ label: '导出', id: 'Export', prop: 'Export', icon: 'el-icon-download', isRowBtn: false },
{ label: '编辑', id: 'Edit', prop: 'Edit', isRowBtn: true },
{ label: '删除', id: 'Delete', prop: 'Delete', isRowBtn: true },
{ label: '详情', id: 'Details', prop: 'Details', isRowBtn: true },
{
label: '新增',
id: 'Add',
prop: 'Add',
icon: 'el-icon-plus',
isRowBtn: false,
class: 'primary',
sort: 0,
},
{
label: '导入',
id: 'Import',
prop: 'Import',
icon: 'el-icon-upload2',
isRowBtn: false,
class: 'primary',
sort: 1,
},
{
label: '导出',
id: 'Export',
prop: 'Export',
icon: 'el-icon-download',
isRowBtn: false,
class: 'primary',
sort: 2,
},
{ label: '编辑', id: 'Edit', prop: 'Edit', isRowBtn: true, class: 'success', sort: 3 },
{ label: '删除', id: 'Delete', prop: 'Delete', isRowBtn: true, class: 'error', sort: 4 },
{ label: '详情', id: 'Details', prop: 'Details', isRowBtn: true, class: 'primary', sort: 5 },
],
});
const formScheme = ref('');
//
async function validateSteps() {
async function validateSteps(keyValue: string) {
if (!keyValue) {
return;
}
//
let keyValue: string = '4afddef9-e234-458c-a4a8-f67a9728a634';
// let keyValue: string = '4afddef9-e234-458c-a4a8-f67a9728a634';
const scheme = await functionGetPreviewForm({ keyValue: keyValue });
formScheme.value = JSON.parse(scheme.scheme);
console.log(scheme);
@ -146,9 +192,6 @@
config.value.table.querys.push({
key: t.label + t.field,
label: t.label,
// width: 120,
// align: 'left',
// isMinWidth: false,
});
});
@ -156,16 +199,21 @@
const schemeInfo = await functionGetSchemeInfoEntity({ id: scheme.schemeInfoId });
if (schemeInfo.formType === 1) {
//
config.value.btns = config.value.btns.filter((t) =>
config.value.table.btns = config.value.btns.filter((t) =>
['Import', 'Export', 'Details'].includes(t.id),
);
} else {
config.value.table.btns = config.value.btns;
}
config.value.btns.forEach((t) => {
console.log(187, config.value.table.btns);
config.value.table.btns.forEach((t) => {
btnsTree.value.push(t);
});
}
validateSteps();
provide('formConfig', config.value);
defineExpose({
config,
});
</script>

View File

@ -0,0 +1,143 @@
<template>
<BasicModal
@register="registerModal"
@ok="modalSubmit"
title="选择表单"
width="60%"
height="800"
useWrapper="false"
>
<template #left>
<BasicTree
ref="asyncExpandTreeRef"
title="表单分类"
:treeData="treeData"
:defaultExpandAll="true"
:fieldNames="{ key: 'itemValue', title: 'label' }"
@select="handleSelect"
/>
</template>
<BasicTable @register="registerTable" :searchInfo="searchInfo" style="height: 100%">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
label: '预览',
onClick: () => {
previewModal(record);
},
},
]"
/>
</template>
</template>
</BasicTable>
</BasicModal>
<!-- <VFormPreview ref="eFormPreview" :formConfig="formConfig" /> -->
</template>
<script lang="ts" setup>
import { onMounted, ref, defineEmits, reactive } from 'vue';
import { BasicModal, useModal } from '@/components/Modal';
import { BasicTree, TreeItem } from '@/components/Tree';
import { BasicTable, useTable, TableAction } from '@/components/Table';
// import { IFormConfig } from '@/views/demo/form-design/typings/v-form-component';
// import VFormPreview from '@/views/demo/form-design/components/VFormPreview/index.vue';
import { functionLoadFormSort, functionLoadFormPage } from '@/api/demo/formScheme';
import { modalColumns, searchFormSchema } from './formModule.data';
const emit = defineEmits(['get-scheme-row']);
const searchInfo = reactive<Recordable>({});
//
const treeData = ref<TreeItem[]>([]);
async function fetch() {
treeData.value = await functionLoadFormSort();
}
function handleSelect(category = '') {
searchInfo.category = category;
clearSelectedRowKeys();
reload();
}
//
const [registerTable, { getSelectRows, reload, clearSelectedRowKeys }] = useTable({
api: functionLoadFormPage,
columns: modalColumns,
rowKey: 'id',
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
searchInfo: {},
canResize: true,
striped: false,
// 使
useSearchForm: false,
//
showTableSetting: false,
//
bordered: true,
//
showIndexColumn: true,
tableSetting: { fullScreen: true },
isCanResizeParent: true,
beforeFetch: (data) => {
//
var temp = {
page: data.page,
limit: data.limit,
isEnabled: '1',
type: '1',
};
return temp;
},
rowSelection: {
//
type: 'radio',
},
handleSearchInfoFn(info) {
return info;
},
});
//
const [registerModal, { closeModal }] = useModal();
//
function modalSubmit() {
let row = getSelectRows();
emit('get-scheme-row', row);
closeModal();
clearSelectedRowKeys();
reload();
}
// // endregion
// const formConfig = ref<IFormConfig>({
// //
// schemas: [],
// layout: 'horizontal',
// labelLayout: 'flex',
// labelWidth: 100,
// labelCol: {},
// wrapperCol: {},
// currentItem: {
// component: '',
// componentProps: {},
// },
// activeKey: 1,
// });
function previewModal(record) {
console.log(record);
formConfig.value.schemas = record.scheme;
}
onMounted(() => {
fetch();
});
</script>

View File

@ -1,83 +1,170 @@
<template>
<div class="l-rblock">
<div class="l-page-pane">
<BasicForm ref="formModuleRef" @register="registerForm" :model="formData">
<template #bodycell="{ model, field }">
{{ model }}
{{ field }}
<template v-if="field === 'formCode'">
<a-input
v-model:value="formData.formCode"
@change="custmerformChange(model)"
@click="modelShow"
:span="24"
:placeholder="请选择"
<lrlayout class="l-tab-page">
<div class="l-rblock">
<div class="l-page-pane">
<a-form
ref="formModuleRef"
:rules="rules"
:model="formData"
labelAlign="right"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="编号" name="code">
<a-input v-model:value="formData.code" />
</a-form-item>
<a-form-item label="名称" name="code">
<a-input v-model:value="formData.name" />
</a-form-item>
<a-form-item label="图标" name="icon">
<IconPicker v-model:value="formData.icon" />
</a-form-item>
<a-form-item label="表单选择" name="formCode" @click="handleShow">
<a-input v-model:value="formData.formCode.name">
<template #addonAfter>
<FileTextOutlined />
</template>
</a-input>
</a-form-item>
<a-form-item label="表单版本" name="formVerison">
<a-select v-model:value="formData.formVerison" :options="formVerisons" />
</a-form-item>
<a-form-item label="上级" name="pmoduleId">
<a-tree-select
v-model:value="formData.pmoduleId"
:tree-data="pmoduleIds"
:field-names="{ label: 'name', value: 'id' }"
/>
</template>
<template v-if="field === 'formVerison'">
<a-select
v-model:value="formData.formVerison"
:options="formVerisons"
:span="24"
:placeholder="请选择"
/>
</template>
</template>
</BasicForm>
<div class="formLine"></div>
</a-form-item>
<a-form-item label="状态" name="enabledMark">
<a-radio-group
v-model:value="formData.enabledMark"
size="mini"
@change="radioChange"
button-style="solid"
>
<a-radio-button value="1"></a-radio-button>
<a-radio-button value="0"></a-radio-button>
</a-radio-group>
</a-form-item>
<a-form-item label="是否系统" name="isSys">
<a-radio-group
v-model:value="formData.isSys"
size="mini"
@change="radioChange"
button-style="solid"
>
<a-radio-button value="true"></a-radio-button>
<a-radio-button value="false"></a-radio-button>
</a-radio-group>
</a-form-item>
<a-form-item label="排序" name="sortCode">
<a-input-number v-model:value="formData.sortCode" :min="0" />
</a-form-item>
<a-form-item label="描述" name="description">
<a-textarea v-model:value="formData.description" />
</a-form-item>
</a-form>
<div class="formLine"></div>
</div>
</div>
</div>
<ModuleModal @register="registerModal" @get-scheme-row="getSchemeRow" />
</lrlayout>
</template>
<script lang="ts" setup>
import { ref, provide, computed } from 'vue';
import { BasicForm, useForm } from '/@/components/Form';
import { FileTextOutlined } from '@ant-design/icons-vue';
import { defineEmits, ref, onMounted, watch, defineExpose } from 'vue';
import { IconPicker } from '@/components/Icon';
import { TreeItem } from '@/components/Tree';
import { useModal } from '@/components/Modal';
import { getMenuList } from '@/api/demo/system';
import ModuleModal from './modalForm-Modal.vue';
import { functionGetSchemePageList } from '@/api/demo/formScheme';
import { formSchema } from './formModule.data';
// emit
const emit = defineEmits(['change-form-verisons']);
//
const labelCol = { span: 4 };
const wrapperCol = { span: 20 };
const [registerForm, { getFieldsValue, setFieldsValue, resetFields, validate }] = useForm({
labelWidth: 100,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: { lg: 24, md: 24 },
});
//
const [registerModal, { openModal }] = useModal();
const formModuleRef = ref<any>();
// options
const formVerisons = ref([]);
// options
const pmoduleIds = ref<TreeItem[]>([]);
//
let formData = {
const formData = ref({
type: 1,
code: '',
name: '',
icon: 'el-icon-star-off',
icon: 'ant-design:star-outlined',
formCode: '',
formVerison: '',
pmoduleId: '',
moduleId: '',
sortCode: '',
enabledMark: 1,
isSys: false,
sortCode: '0',
description: '',
});
//
let rules = {
code: [{ required: true, message: '请输入' }],
name: [{ required: true, message: '请输入' }],
icon: [{ component: 'IconPicker', required: true, message: '请输入' }],
formCode: [{ required: true, message: '请输入' }],
formVerison: [{ required: true, message: '请选择版本' }],
pmoduleId: [{ required: true, message: '请输入' }],
enabledMark: [{ required: true }],
};
const formVerisons = ref([]);
// formVerison
watch(
() => formData.value.formVerison,
() => {
changevalidateSteps();
},
);
async function custmerformChange(model) {
console.log(model);
let versioins = [];
let query = {
schemeInfoId: model.formCode,
};
const data = await functionGetSchemePageList(query);
data.array.forEach((element) => {
versioins.push({
label: element.createDate,
value: element.id,
});
});
formVerisons.value = versioins;
//
function handleShow() {
openModal();
}
//
async function getSchemeRow(row) {
let formVerisons_temp = [];
formData.value.formCode = row[0];
//
const historyData = await functionGetSchemePageList({ schemeInfoId: row[0].id });
historyData.items.forEach((t) => {
formVerisons_temp.push({ label: t.createDate, value: t.id });
});
formVerisons.value = formVerisons_temp;
formData.value.formVerison = formVerisons_temp[0];
}
//
function changevalidateSteps() {
emit('change-form-verisons', formData.value.formVerison);
}
//
async function fetch() {
pmoduleIds.value = await getMenuList();
}
defineExpose({
formData,
});
onMounted(() => {
fetch();
});
</script>
<style lang="less">

View File

@ -27,14 +27,11 @@
</Upload> -->
<a-button type="primary" @click="handleDownByData"></a-button>
</template>
<!-- <template #bodyCell="{ column, record }">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'category'">
<Select
v-model:value="record.category"
:options="categoryOptioins"
/>
{{ findModuleName(treeData, record.category) }}
</template>
</template> -->
</template>
</BasicTable>
<!-- 树的橱窗 -->
<FormSchemeDrawer @register="registerDrawer" @success="handleSuccess" />
@ -48,9 +45,10 @@
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, nextTick, ref } from 'vue';
import { reactive, nextTick, ref, onMounted } from 'vue';
import { BasicTable, useTable } from '@/components/Table';
import { TreeItem } from '@/components/Tree';
import { PageWrapper } from '@/components/Page';
import { useMessage } from '@/hooks/web/useMessage';
import { useDrawer } from '@/components/Drawer';
@ -67,7 +65,12 @@
// import { uploadApi } from '/@/api/sys/upload';
import { columns, searchFormSchema } from './formScheme.data';
import { functionLoadFormPage, functionGetForm, functionDeleteForm } from '@/api/demo/formScheme';
import {
functionLoadFormSort,
functionLoadFormPage,
functionGetForm,
functionDeleteForm,
} from '@/api/demo/formScheme';
const { createConfirm, createMessage } = useMessage();
@ -277,4 +280,33 @@
break;
}
}
const treeData = ref<TreeItem[]>([]);
//
function findModuleName(modules, pmoduleId) {
for (const module of modules) {
if (module.itemValue === pmoduleId) {
return module.itemName;
}
if (Array.isArray(module.children) && module.children.length > 0) {
const foundName = findModuleName(module.children, pmoduleId);
if (foundName) {
return foundName;
}
}
}
return '';
}
//
async function fetch() {
treeData.value = await functionLoadFormSort();
}
onMounted(() => {
fetch();
});
</script>

View File

@ -76,8 +76,8 @@
beforeFetch: (data) => {
//
var temp = {
pageIndex: data.page,
pageSize: data.limit,
page: data.page,
limit: data.limit,
keyWord: data.key,
dbCode: receiceDbCode.value
};

View File

@ -230,29 +230,8 @@ export const formSchema: FormSchema[] = [
colProps: {
span: 24,
},
// componentProps: () => {
// return {
// api: getDataBaseCodeList,
// // 接口返回数据
// resultField: 'result',
// labelField: 'text',
// valueField: 'value',
// };
// }
componentProps: {
// api: () => {
// return new Promise((resolve) => {
// resolve([
// {
// title: 'Parent Node',
// value: '0-0',
// },
// ]);
// });
// },
api: () => getDataBaseCodeList().then((data: AreaRespVO[]) => {
console.log('aaaaadata',data)
return new Promise((resolve) => {
resolve(data);
});
@ -264,15 +243,8 @@ export const formSchema: FormSchema[] = [
console.log('ApiTreeSelect====>:', e, v);
},
onLoadData: ({ treeData, resolve, treeNode }) => {
console.log('treeNode====>:', treeNode);
console.log('treeData====>:', treeData);
setTimeout(() => {
// const children: Recordable[] = [
// { title: `Child Node ${treeNode.eventKey}-0`, value: `${treeNode.eventKey}-0` },
// { title: `Child Node ${treeNode.eventKey}-1`, value: `${treeNode.eventKey}-1` },
// ];
const children: Recordable[] = []
console.log('children',children)
treeData.value.forEach(item =>{
if(item.id == treeNode.id){
if(item.childNodes){
@ -285,7 +257,6 @@ export const formSchema: FormSchema[] = [
}
}
})
console.log('children22',children)
children.forEach((item) => {
item.isLeaf = false;
item.children = [];

View File

@ -15,7 +15,7 @@
</BasicTable>
</BasicDrawer>
<a-modal width="90%" height="80%" v-model:open="postOpen" title="流程模板预览" @ok="postHandleOk">
<a-modal width="70%" height="80%" v-model:open="postOpen" title="流程模板预览" @ok="postHandleOk">
<process-designer :key="designerOpen" style="border:1px solid rgba(0, 0, 0, 0.1);" ref="modelDesigner"
v-loading="designerData.loading" :pageFlow="flowContent" :pageView="content" :pageType="'detail'"
@save="onSaveDesigner" />

View File

@ -111,7 +111,7 @@
},
});
function handleDetail(record){
go('/dashboard/task_preview/detail?id=' + record.id);
go('/dashboard/task_look_preview/detail?processId=' + record.id);
}
function handleRevocation(record){
console.log(record)

View File

@ -107,7 +107,7 @@
},
});
function handleDetail(record){
go('/dashboard/task_preview/detail?id=' + record.id);
go('/dashboard/task_look_preview/detail?processId=' + record.id);
}
function handleRevocation(record){
console.log(record)

View File

@ -1,109 +0,0 @@
<template>
<PageWrapper :class="prefixCls">
<a-tabs v-model:activeKey="activeName">
<a-tab-pane key="form" tab="表单信息">
</a-tab-pane>
<a-tab-pane key="flow" tab="流程信息" force-render>
<div class="process-design" :style="'display: flex; height:' + designerData.height">
<process-viewer :key="`designer-${id}`" :xml="flowContent" :flowViewer="flowViewer"/>
</div>
</a-tab-pane>
</a-tabs>
</PageWrapper>
</template>
<script lang="ts" setup>
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount } from 'vue';
import ProcessViewer from '@/components/ProcessViewer/index.vue';
import { PageWrapper } from '@/components/Page';
import { SendOutlined, SaveOutlined, CloseCircleOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
import { getBPMN } from '@/api/sys/WFProcess'
import { getLoadMyUserList } from '@/api/sys/WFDelegate'
import { useRoute } from 'vue-router'
import { useMultipleTabStore } from '@/store/modules/multipleTab';
import { useRouter } from 'vue-router';
import { buildGUID } from '@/utils/uuid';
import { useMessage } from '/@/hooks/web/useMessage';
const { createConfirm, createMessage } = useMessage();
const prefixCls = 'preview-box'
const tabStore = useMultipleTabStore();
const router = useRouter();
const content = ref('')
const flowContent = ref('')
const flowViewer = ref({})
const route = useRoute()
const id = route.query.id
const designerOpen = ref(false)
const formRef = ref();
const labelCol = { span: 7 };
const wrapperCol = { span: 13 };
const designerData = reactive({
loading: false,
xmlString: '',
controlForm: {
prefix: 'flowable',
},
height: document.documentElement.clientHeight - 230.5 + "px;",
midVisible: false,
isCustmerTitle: false,
nodeUsers: [],
selectUsersVisible: false,
isDraft: false,
delegateUsers: []
})
const activeName = ref('flow')
async function getDetailInfo() {
let data = await getBPMN({ id: id })
flowContent.value = data.flowContent
flowViewer.value = data.flowViewer
// var result = {
// // xml
// flowContent: "",
// // id
// flowViewer: {
// // id
// finishedTaskSet: [],
// // 线id
// finishedSequenceFlowSet: [],
// // id
// unfinishedTaskSet: [],
// // id
// rejectedTaskSet: [],
// }
// //
// }
}
function closePreview() {
if (!id) {
tabStore.closeTabByKey('/dashboard/task_preview/detail', router);
} else {
// /dashboard/create_preview/add?id=1
tabStore.closeTabByKey('/dashboard/task_preview/detail?id=' + id, router);
}
}
onBeforeMount(() => {
getDetailInfo()
})
</script>
<style lang="less" scoped>
.preview-box {
background-color: @component-background;
.btn-box {
padding: 10px;
justify-content: flex-end;
display: flex;
}
}
.form-box {
width: 480px;
}
</style>

View File

@ -110,7 +110,7 @@
}
}
function handleDetail(record) {
go('/dashboard/task_preview/detail?id=' + record.id);
go('/dashboard/task_look_preview/detail?processId=' + record.id);
}
</script>

View File

@ -122,7 +122,7 @@
},
});
function handleDetail(record) {
go('/dashboard/task_preview/detail?id=' + record.id);
go('/dashboard/task_look_preview/detail?processId=' + record.id);
}
async function handleUrge(record) {
var query = {

View File

@ -1,575 +1,293 @@
<template>
<l-fullscreen-dialog
:title="`${title}`"
:visible.sync="midVisible"
:showOk="false"
<PageWrapper :class="prefixCls">
<a-tabs v-model:activeKey="activeName">
<a-tab-pane key="form" tab="表单信息">
@closed="handleClosed"
@opened="handleOpened"
</a-tab-pane>
<a-tab-pane key="flow" tab="流程信息(审核)" force-render>
<div class="process-design" :style="'display: flex; height:' + designerData.height">
<process-viewer :key="`designer-${id}`" :events="[
'element.click',
]" @element-click="elementClick" :xml="flowContent" :flowViewer="flowViewer" />
<div class="info-box" v-if="designerData.nodeLogs.length>0" >
<a-drawer v-model:open="infoOpen" class="custom-class" title="记录信息" placement="right">
<a-timeline>
<a-timeline-item v-for="(item,index) in designerData.nodeLogs" :key="index">
<div class="title">{{item.time}}</div>
<a-card hoverable size="small">
<div class="type-title">{{item.name}}</div>
<div class="content">
<span class="link" v-for="(userName,index2) in item.userNames">{{userName}}</span>
<!-- <l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user> -->
{{item.des}}
</div>
</a-card>
</a-timeline-item>
</a-timeline>
</a-drawer>
ref="formDialog"
>
</div>
</div>
</a-tab-pane>
</a-tabs>
<template #headerRight v-if="isRead && task && task.f_State == 1" >
<el-button size="mini" type="primary" @click="handleRead" >{{$t('确认阅读')}}</el-button>
</template>
</PageWrapper>
<l-layout class="l-tab-page" :right="400">
<l-panel :style="{'padding-right':isRead?'':0 }" >
<div class="l-auto-window" style="padding: 0 8px;" >
<el-tabs v-model="activeName" @tab-click="handleTabClick" >
<el-tab-pane v-if="hasWfForm" :label="$t('表单信息')" name="form">
<div class="l-rblock" v-loading="formSchemeLoding">
<template v-if="showForm" >
<l-form-viewer
v-if="formType == '1'"
:formInfo="formInfo"
:isWfForm="true"
:authFieldsMap="formAuthFieldsMap"
ref="wfForm"
></l-form-viewer>
<component ref="wfForm" v-else :requiredMap="formRequiredMap" :authFieldsMap="formAuthFieldsMap" :isWfForm="true" :is="sysFormComponent"></component>
</template>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('流程信息')" name="wfinfo">
<l-layout style="background: #f1f2f5;" :right="320">
<l-panel class="flow-panel" style="padding:0;padding-top:0;" >
<template #title>
<el-button-group>
<el-tooltip effect="dark" :content="$t('复原')" placement="bottom">
<el-button size="mini" icon="el-icon-aim" @click="resetZoom"></el-button>
</el-tooltip>
<el-tooltip effect="dark" :content="$t('放大')" placement="bottom">
<el-button size="mini" icon="el-icon-zoom-in" @click="handlerZoom(0.1)"></el-button>
</el-tooltip>
<el-tooltip effect="dark" :content="$t('缩小')" placement="bottom">
<el-button size="mini" icon="el-icon-zoom-out" @click="handlerZoom(-0.1)"></el-button>
</el-tooltip>
</el-button-group>
<div style="float:right;" >
<el-tag size="small" effect="plain" style="margin-right: 8px;">正在审核</el-tag>
<el-tag size="small" effect="plain" style="margin-right: 8px;" type="success">已审核</el-tag>
</div>
</template>
<b-wflow-viewer
ref="bflow"
@elementClick="elementClick"
>
</b-wflow-viewer>
</l-panel>
<template #right >
<l-panel v-if="nodeLogs.length>0" class="flow-panel" style="padding:0;padding-top:0;" >
<template #title >
记录信息
</template>
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
<el-timeline>
<el-timeline-item :type="item.type" v-for="(item,index) in nodeLogs" :key="index" :timestamp="item.time" placement="top">
<el-card shadow="hover">
<div class="title" >{{item.name}}</div>
<div class="content">
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
{{item.des}}
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</l-panel>
</template>
</l-layout>
</el-tab-pane>
<el-tab-pane :label="$t('流转记录')" name="wflogs">
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
<el-timeline>
<el-timeline-item :type="item.type" v-for="(item,index) in logs" :key="index" :timestamp="item.time" placement="top">
<el-card shadow="hover">
<div class="title" >{{item.name}}</div>
<div class="content">
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
{{item.des}}
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</el-tab-pane>
</el-tabs>
</div>
</l-panel>
<template #right v-if="!isRead">
<l-panel style="padding-left:0;" title="审批栏" >
<div class="l-rblock" style="padding:8px;" >
<el-form :model="formData" :rules="myRules" size="mini" ref="form" >
<el-form-item :label="isCreateAgain?'备注':'审批意见'" prop="des">
<el-input
type="textarea"
v-model="formData.des"
placeholder="请输入"
rows="3"
>
</el-input >
</el-form-item>
<el-form-item class="l-task-btns" >
<el-button v-for="(btn,index) in taskBtns" :key="index" :type="btn.type" @click="handleBtnClick(btn)" >{{btn.name}}</el-button>
</el-form-item>
</el-form>
<l-wf-audit-info :data="userLogs" ></l-wf-audit-info>
</div>
</l-panel>
</template>
</l-layout>
<l-dialog
:width="500"
:height="nodeUsers.length * 48 + 88"
title="选择下一审核节点人员"
:visible.sync="selectUsersVisible"
@ok="handleSelectUsersSave"
@close="handleSelectUsersCloseForm"
:showClose="false"
>
<select-users ref="selectUsers" :nodeList="nodeUsers"></select-users>
</l-dialog>
<l-dialog
:title="$t(tUserType == 1?`选择转移人员`:`选择加签人员`)"
:visible.sync="selectTUserVisible"
:height="480"
width="1024px"
:hasBtns="false"
>
<l-user-select-panel @change="handleChange" :multiple="false" ref="userSelectPanel" ></l-user-select-panel>
</l-dialog>
<l-dialog
:title="$t('驳回节点选择')"
:visible.sync="selectRejectNodeVisible"
:height="136"
:width="500"
@ok="handleSelectRejectNodeSave"
@close="handleRejectNodeCloseForm"
:showClose="false"
>
<select-reject-node ref="selectRejectNode" :nodeList="completedNodes"></select-reject-node>
</l-dialog>
<!--选择签章-->
<l-dialog
:title="$t('选择签章')"
:visible.sync="selectSignVisible"
:height="480"
:width="508"
@ok="handleSelectSignSave"
@closed="handleSelectSignCloseForm"
@opened="handleSelectSignOpenForm"
>
<select-sign ref="SelectSign" ></select-sign>
</l-dialog>
</l-fullscreen-dialog>
</template>
<script>
import mixin from '../../../mixins/wf'
import SelectUsers from './selectAuditUsers.vue'
import SelectRejectNode from './selectRejectNode.vue'
import SelectSign from './selectSign.vue'
<script lang="ts" setup>
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount } from 'vue';
import ProcessViewer from '@/components/ProcessViewer/index.vue';
import { PageWrapper } from '@/components/Page';
import { SendOutlined, SaveOutlined, CloseCircleOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
import { getBPMN } from '@/api/sys/WFProcess'
import { getLoadMyUserList } from '@/api/sys/WFDelegate'
import { getTaskDetail } from '@/api/sys/WFTask'
import { useRoute } from 'vue-router'
import { useMultipleTabStore } from '@/store/modules/multipleTab';
import { useRouter } from 'vue-router';
import { buildGUID } from '@/utils/uuid';
import { useMessage } from '/@/hooks/web/useMessage';
import { dateFormat } from '@/utils/base'
const { createConfirm, createMessage } = useMessage();
const api = window.$api.workflow.process
const apiStamp = window.$api.workflow.stamp
export default {
mixins:[mixin()],
components:{
SelectUsers,
SelectRejectNode,
SelectSign
const prefixCls = 'preview-box'
const tabStore = useMultipleTabStore();
const router = useRouter();
const content = ref('')
const flowContent = ref('')
const flowViewer = ref({})
const route = useRoute()
const processId = route.query.processId
const taskId = route.query.taskId
const designerOpen = ref(false)
const formRef = ref();
const labelCol = { span: 7 };
const wrapperCol = { span: 13 };
const infoOpen = ref(true)
const designerData = reactive({
loading: false,
xmlString: '',
controlForm: {
prefix: 'flowable',
},
props:{
isCreateAgain:Boolean,
isRead:Boolean
},
data () {
return {
midVisible:false,
formData:{
des:''
},
rules:{
des:[
{ required: true, message: '请填写审批意见',trigger: 'blur' }
],
},
height: document.documentElement.clientHeight - 200.5 + "px;",
midVisible: false,
isCustmerTitle: false,
nodeUsers: [],
selectUsersVisible: false,
currentBtn:null,
nodeUsers:[],
selectUsersVisible:false,
selectTUserVisible:false,
tUserType:1, // 1 2 ,
selectRejectNodeVisible:false, //
selectSignVisible:false, //
stampList:[]
}
},
computed:{
myRules(){
if(this.isCreateAgain || this.isRead){
return {}
}
else{
return this.rules
}
},
completedNodes(){
const nodes = this.$deepClone(this.wfData)
return nodes.filter(t=>t.hasFinish && t.id != this.currentNode.id)
},
},
watch:{
visible: {
handler (n) {
this.midVisible = n
}
},
},
methods:{
resetZoom(){
this.$refs.bflow.reset()
},
handlerZoom(r){
this.$refs.bflow.handlerZoom(r)
},
elementClick(node){
if(node){
this.nodeLogs = this.nodeMap[node.id] || []
}
else{
this.nodeLogs = []
}
},
resetFormToMe(){
this.$refs.form && this.$refs.form.resetFields()
this.taskBtns = []
},
setForm(){
this.$refs.form && this.$refs.form.clearValidate()
this.currentNode = this.wfData.find(t=>t.id == this.task.f_UnitId)
//
const btns = []
if(this.currentNode.type =='startEvent'){
btns.push({
code:'learun_create',
name:'提交',
type:'primary'
})
}
else{
this.currentNode.btnlist.forEach(btn => {
if(btn.code == 'agree'){
btn.type = 'primary'
}
else if(btn.code == 'disagree'){
btn.type = 'danger'
}
btns.push(btn)
})
if(this.currentNode.isAddSign){
btns.push({
code:'learun_sign',
name:'加签',
type:'success'
})
}
if(this.currentNode.isTransfer){
btns.push({
code:'learun_transfer',
name:'转移',
type:'success'
})
}
}
this.taskBtns = btns
},
validateForm(){
return this.$formValidateWraper(this.$refs.form)
},
handleBtnClick(btn){
this.$refs.formDialog.showLoading('流程处理中...')
this.$nextTick(async ()=>{
this.currentBtn = btn
if(!(await this.validateForm())){
this.$refs.formDialog.hideLoading()
return
}
if(!(await this.validateWfForm())){
this.$refs.formDialog.hideLoading()
return
}
if(!(await this.saveWfForm(btn.code))){
this.$refs.formDialog.hideLoading()
return
}
let res
switch(btn.code){
case 'learun_create':
res = await this.$awaitWraper(api.createAgain({
processId:this.processId,
des:`重新提交${this.formData.des?'-':''}${this.formData.des}`
}))
break
case 'learun_sign':
this.tUserType = 2
this.selectTUserVisible = true
break
case 'learun_transfer':
this.tUserType = 1
this.selectTUserVisible = true
break
default:
if(this.task.f_Type == 6){//
res = await this.$awaitWraper(api.signAudit(this.taskId,{
code:btn.code,
name:btn.name,
des:this.formData.des
}))
}
else {
if(this.currentNode.rejectType == '2' && btn.code == 'disagree'){
this.selectRejectNodeVisible = true
this.$refs.formDialog.hideLoading()
return
}
if(btn.isSign){
//
const stampList = await this.$awaitWraper(apiStamp.getList(this.loginInfo.f_UserId))
if(stampList && stampList.length >0){
this.stampList = stampList
this.selectSignVisible = true
this.$refs.formDialog.hideLoading()
return
}
}
res = await this.audit()
}
break
}
this.$refs.formDialog.hideLoading()
if(res){
this.midVisible = false
this.$emit('refresh')
}
})
},
async audit(){
//
if(this.currentBtn.isNextAuditor){
const res = await api.getNextUsers({processId:this.processId,nodeId:this.currentNode.id})
const nodeUserMap = res.data.data
const nodeUsers = []
for(let key in nodeUserMap){
const nodeUserItem = nodeUserMap[key]
if(nodeUserItem.length > 1){
nodeUsers.push({
name:this.wfData.find(t=>t.id == key).name,
id:key,
options:nodeUserItem.map(t=>{return{value:t.id,label:t.name} })
})
}
}
this.nodeUsers = nodeUsers
if(this.nodeUsers.length > 0){
this.selectUsersVisible = true
return
}
}
return await this.$awaitWraper(api.audit(this.taskId,{
code:this.currentBtn.code,
name:this.currentBtn.name,
des:this.formData.des
}))
},
handleSelectUsersSave(){
this.selectUsersVisible = false
this.$refs.formDialog.showLoading('流程处理中...')
const nextUsers = this.$refs.selectUsers.getForm()
this.$nextTick(async ()=>{
const res = await this.$awaitWraper(api.audit(this.taskId,{
code:this.currentBtn.code,
name:this.currentBtn.name,
nextUsers: nextUsers,
des:this.formData.des
}))
if(res){
this.midVisible = false
}
this.$refs.formDialog.hideLoading()
this.$emit('refresh')
})
},
handleSelectUsersCloseForm(){
this.$refs.selectUsers.resetForm()
},
handleChange(userInfo){
if(userInfo){
const title = this.tUserType == 1?'转移':'加签'
if(this.loginInfo.f_UserId == userInfo.f_UserId){
this.$message({
type: 'warning',
message: `${title}不能给自己本人`
})
return
}
this.$confirm(`是否确定${title}${userInfo.f_RealName}?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.selectTUserVisible = false
this.$refs.formDialog.showLoading('流程处理中...')
this.$nextTick(async ()=>{
let res
if(this.tUserType == 1){
res = await this.$awaitWraper(api.transferUser(this.taskId,{
toUserId:userInfo.f_UserId,
des:`转移给${userInfo.f_RealName}${this.formData.des?'-':''}${this.formData.des}`
}))
}
else{
res = await this.$awaitWraper(api.sign(this.taskId,{
toUserId:userInfo.f_UserId,
des:`加签给${userInfo.f_RealName}${this.formData.des?'-':''}${this.formData.des}`
}))
}
this.$refs.formDialog.hideLoading()
if(res){
this.midVisible = false
this.$emit('refresh')
}
})
}).catch(() => {
this.$message({
type: 'info',
message: `已取消${title}`
})
})
}
},
async handleSelectRejectNodeSave(){
if(await this.$refs.selectRejectNode.validateForm()){
this.$refs.formDialog.showLoading('流程处理中...')
const nextId = this.$refs.selectRejectNode.getForm()
this.selectRejectNodeVisible = false
this.$nextTick(async ()=>{
const res = await this.$awaitWraper(api.audit(this.taskId,{
code:this.currentBtn.code,
name:this.currentBtn.name,
nextId: nextId,
des:this.formData.des
}))
if(res){
this.midVisible = false
}
this.$refs.formDialog.hideLoading()
this.$emit('refresh')
})
}
},
handleRejectNodeCloseForm(){
this.$refs.selectRejectNode.resetForm()
},
async handleRead(){
this.$refs.formDialog.showLoading('流程处理中...')
const res = await this.$awaitWraper(api.readAudit(this.taskId))
if(res){
this.midVisible = false
}
this.$refs.formDialog.hideLoading()
this.$emit('refresh')
},
//
async handleSelectSignSave(){
if(await this.$refs.SelectSign.validateForm()){
this.$refs.formDialog.showLoading('流程处理中...')
const {f_StampId,f_Password} = this.$refs.SelectSign.getForm()
this.selectSignVisible = false
this.$nextTick(async ()=>{
const res = await this.$awaitWraper(api.audit(this.taskId,{
code:this.currentBtn.code,
name:this.currentBtn.name,
stampImg:f_StampId,
stampPassWord:f_Password,
des:this.formData.des
}))
if(res){
this.midVisible = false
}
this.$refs.formDialog.hideLoading()
this.$emit('refresh')
})
}
},
handleSelectSignCloseForm(){
this.$refs.SelectSign.resetForm()
},
handleSelectSignOpenForm(){
this.$refs.SelectSign.setForm(this.stampList)
}
isDraft: false,
delegateUsers: [],
task: null,
process: null,
logs: [],//
nodeMap: {},//
userLogs: [],//
nodeLogs: [],
taskBtns: [],
})
const activeName = ref('flow')
function elementClick(element) {
console.log('elementClick')
console.log(element)
if (element) {
designerData.nodeLogs = designerData.nodeMap[element.id] || []
infoOpen.value = true
}
}
else {
designerData.nodeLogs = []
}
}
async function getDetailInfo() {
let data = await getBPMN({ id: processId })
flowContent.value = data.flowContent
flowViewer.value = data.flowViewer
}
async function getTaskInfo() {
let data = await getTaskDetail({ id: taskId })
designerData.process = data.process
designerData.task = data.task
setLogsAndTasks(data.logs, data.tasks)
}
function setLogsAndTasks(logs, tasks) {
const res = []
const taskMap = {}
const nodeMap = {}
const userLogs = []
tasks.forEach(task => {
nodeMap[task.unitId] = nodeMap[task.unitId] || [{
unitId: task.unitId,
name: task.unitName,
userIds: [],
userNames: [],
des: '正在审核',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary',
isFinish: false
}]
if (task.type == 2) {
taskMap[task.unitId + task.type] = taskMap[task.unitId + task.type] || {
unitId: task.unitId,
name: task.unitName,
userIds: [],
userNames: [],
des: '正在查阅',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary'
}
taskMap[task.unitId + task.type].userIds.push(task.userId)
taskMap[task.unitId + task.type].userNames.push(task.userName)
if (nodeMap[task.unitId].length == 1) {
nodeMap[task.unitId].push({
unitId: task.unitId,
name: task.unitName,
userIds: [],
userNames: [],
des: '正在查阅',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary',
isFinish: true
})
}
nodeMap[task.unitId][1].userIds.push(task.userId)
nodeMap[task.unitId][1].userNames.push(task.userName)
}
else {
taskMap[task.unitId] = taskMap[task.unitId] || {
unitId: task.unitId,
name: task.unitName,
userIds: [],
userNames: [],
des: '正在审核',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary'
}
taskMap[task.unitId].userIds.push(task.userId)
nodeMap[task.unitId][0].userIds.push(task.userId)
taskMap[task.unitId].userNames.push(task.userName)
nodeMap[task.unitId][0].userNames.push(task.userName)
}
})
for (let key in taskMap) {
res.push(taskMap[key])
}
for (let key in nodeMap) {
nodeMap[key] = nodeMap[key].filter(t => t.userIds.length > 0)
}
logs.forEach(log => {
res.push({
unitId: log.unitId,
name: log.unitName,
userIds: [log.userId],
userNames: [log.userName],
des: log.des ? log.des : log.f_OperationName,
time: dateFormat(log.createDate),
type: 'info'
})
nodeMap[log.unitId] = nodeMap[log.unitId] || []
nodeMap[log.unitId].push({
unitId: log.unitId,
name: log.unitName,
userIds: [log.userId],
userNames: [log.userName],
time: dateFormat(log.createDate),
des: log.des ? log.des : log.f_OperationName,
type: 'info',
isFinish: true
})
if (log.f_TaskType == 1 && !['sign'].includes(log.f_OperationCode)) { //
const userLogIndex = userLogs.findIndex(t => t.id == log.unitId)
if (userLogIndex == -1) {
userLogs.push({
id: log.unitId,
name: log.unitName,
user: log.f_UserName,
time: dateFormat(log.createDate),
des: log.des,
img: log.f_StampImg
})
}
}
})
designerData.logs = res
designerData.nodeMap = nodeMap
designerData.userLogs = userLogs.sort(function (a, b) {
return b.time < a.time ? -1 : 1
})
//console.log(logs,'logs')
}
function closePreview() {
if (!id) {
tabStore.closeTabByKey('/dashboard/task_preview/detail', router);
} else {
// /dashboard/create_preview/add?id=1
tabStore.closeTabByKey('/dashboard/task_preview/detail?id=' + id, router);
}
}
onBeforeMount(() => {
getDetailInfo()
getTaskInfo()
})
</script>
<style lang="less" scoped>
.info-box {
display: inline-block;
width: 300px;
position: absolute;
right: 0;
margin-top: 40px;
<style lang="scss">
.l-task-btns{
.el-button{
margin: 0;
margin-top: 8px;
margin-right: 8px;
}
}
.ant-timeline-item-content {
.title {
color: #909399;
line-height: 1;
margin-bottom: 8px;
font-size: 13px;
}
.type-title {
font-size: 12px;
font-weight: bold;
margin-bottom: 8px;
}
.link{
color:#409EFF;
}
}
.preview-box {
background-color: @component-background;
height: 100%;
.btn-box {
padding: 10px;
justify-content: flex-end;
display: flex;
}
}
.form-box {
width: 480px;
}
</style>

View File

@ -1,153 +1,229 @@
<template>
<l-fullscreen-dialog
:title="`${$t('查看流程')}【${title}】`"
:visible.sync="midVisible"
:showOk="false"
@closed="handleClosed"
@opened="handleOpened"
ref="formDialog"
>
<l-layout class="l-tab-page" :right="400">
<l-panel :style="{ 'padding-right':userLogs.length >0?0:''}" >
<div class="l-auto-window" style="padding: 0 8px;" >
<el-tabs v-model="activeName" @tab-click="handleTabClick" >
<el-tab-pane v-if="hasWfForm" :label="$t('表单信息')" name="form">
<div class="l-rblock" v-loading="formSchemeLoding">
<template v-if="showForm" >
<l-form-viewer
v-if="formType == '1'"
:formInfo="formInfo"
:isWfForm="true"
:authFieldsMap="formAuthFieldsMap"
ref="wfForm"
></l-form-viewer>
<component ref="wfForm" v-else :requiredMap="formRequiredMap" :authFieldsMap="formAuthFieldsMap" :isWfForm="true" :is="sysFormComponent"></component>
</template>
</div>
</el-tab-pane>
<el-tab-pane :label="$t('流程信息')" name="wfinfo">
<l-layout style="background: #f1f2f5;" :right="320">
<l-panel class="flow-panel" style="padding:0;padding-top:0;" >
<template #title>
<el-button-group>
<el-tooltip effect="dark" :content="$t('复原')" placement="bottom">
<el-button size="mini" icon="el-icon-aim" @click="resetZoom"></el-button>
</el-tooltip>
<el-tooltip effect="dark" :content="$t('放大')" placement="bottom">
<el-button size="mini" icon="el-icon-zoom-in" @click="handlerZoom(0.1)"></el-button>
</el-tooltip>
<el-tooltip effect="dark" :content="$t('缩小')" placement="bottom">
<el-button size="mini" icon="el-icon-zoom-out" @click="handlerZoom(-0.1)"></el-button>
</el-tooltip>
</el-button-group>
<div style="float:right;" >
<el-tag size="small" effect="plain" style="margin-right: 8px;">正在审核</el-tag>
<el-tag size="small" effect="plain" style="margin-right: 8px;" type="success">已审核</el-tag>
</div>
</template>
<b-wflow-viewer
ref="bflow"
@elementClick="elementClick"
>
</b-wflow-viewer>
</l-panel>
<template #right >
<l-panel v-if="nodeLogs.length>0" class="flow-panel" style="padding:0;padding-top:0;" >
<template #title >
记录信息
</template>
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
<el-timeline>
<el-timeline-item :type="item.type" v-for="(item,index) in nodeLogs" :key="index" :timestamp="item.time" placement="top">
<el-card shadow="hover">
<div class="title" >{{item.name}}</div>
<div class="content">
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
{{item.des}}
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</l-panel>
</template>
</l-layout>
</el-tab-pane>
<el-tab-pane :label="$t('流转记录')" name="wflogs">
<div class="l-rblock l-time-line-wraper" style="padding:8px;overflow:hidden auto;" >
<el-timeline>
<el-timeline-item :type="item.type" v-for="(item,index) in logs" :key="index" :timestamp="item.time" placement="top">
<el-card shadow="hover">
<div class="title" >{{item.name}}</div>
<div class="content">
<l-user v-for="(userId,index2) in item.userIds" :key="index2" :value="userId" ></l-user>
{{item.des}}
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
</el-tab-pane>
</el-tabs>
</div>
</l-panel>
<template #right >
<l-panel v-if="userLogs.length >0" style="padding-left:0;" title="审批信息" >
<div class="l-rblock" style="padding:8px;" >
<l-wf-audit-info :data="userLogs" ></l-wf-audit-info>
</div>
</l-panel>
</template>
</l-layout>
</l-fullscreen-dialog>
</template>
<script>
import mixin from '../../../mixins/wf'
export default {
mixins:[mixin()],
data () {
return {
midVisible:false,
}
},
watch:{
visible: {
handler (n) {
this.midVisible = n
}
},
},
methods:{
resetZoom(){
this.$refs.bflow.reset()
},
handlerZoom(r){
this.$refs.bflow.handlerZoom(r)
},
elementClick(node){
if(node){
this.nodeLogs = this.nodeMap[node.id] || []
}
else{
this.nodeLogs = []
}
},
setForm(){
if(this.type == 'look' && this.task)
{
this.currentNode = this.wfData.find(t=>t.id == this.task.f_UnitId)
}
else{
this.currentNode = this.wfData.find(t=>t.type == 'startEvent')
}
}
<PageWrapper :class="prefixCls">
<a-tabs v-model:activeKey="activeName">
<a-tab-pane key="form" tab="表单信息">
</a-tab-pane>
<a-tab-pane key="flow" tab="流程信息" force-render>
<div class="process-design" :style="'display: flex; height:' + designerData.height">
<process-viewer :key="`designer-${id}`" :events="[
'element.click',
]" @element-click="elementClick" :xml="flowContent" :flowViewer="flowViewer" />
</div>
</a-tab-pane>
</a-tabs>
</PageWrapper>
</template>
<script lang="ts" setup>
import { h, ref, provide, reactive, onMounted, defineProps, computed, defineEmits, onBeforeMount } from 'vue';
import ProcessViewer from '@/components/ProcessViewer/index.vue';
import { PageWrapper } from '@/components/Page';
import { SendOutlined, SaveOutlined, CloseCircleOutlined, ZoomInOutlined, RotateLeftOutlined, RotateRightOutlined, ClearOutlined } from '@ant-design/icons-vue';
import { getBPMN } from '@/api/sys/WFProcess'
import { getLoadMyUserList } from '@/api/sys/WFDelegate'
import { getTaskDetail } from '@/api/sys/WFTask'
import { useRoute } from 'vue-router'
import { useMultipleTabStore } from '@/store/modules/multipleTab';
import { useRouter } from 'vue-router';
import { buildGUID } from '@/utils/uuid';
import { useMessage } from '/@/hooks/web/useMessage';
import {dateFormat} from '@/utils/base'
const { createConfirm, createMessage } = useMessage();
const prefixCls = 'preview-box'
const tabStore = useMultipleTabStore();
const router = useRouter();
const content = ref('')
const flowContent = ref('')
const flowViewer = ref({})
const route = useRoute()
const processId = route.query.processId
const taskId = route.query.taskId
const designerOpen = ref(false)
const formRef = ref();
const labelCol = { span: 7 };
const wrapperCol = { span: 13 };
const designerData = reactive({
loading: false,
xmlString: '',
controlForm: {
prefix: 'flowable',
},
height: document.documentElement.clientHeight - 230.5 + "px;",
midVisible: false,
isCustmerTitle: false,
nodeUsers: [],
selectUsersVisible: false,
isDraft: false,
delegateUsers: [],
task: null,
process: null,
logs: [],//
nodeMap: {},//
userLogs: [],//
nodeLogs: [],
taskBtns: [],
})
const activeName = ref('flow')
function elementClick(element) {
console.log('elementClick')
console.log(element)
}
}
</script>
async function getDetailInfo() {
let data = await getBPMN({ id: processId })
flowContent.value = data.flowContent
flowViewer.value = data.flowViewer
}
async function getTaskInfo() {
let data = await getTaskDetail({ id: taskId })
designerData.process = data.process
designerData.task = data.task
setLogsAndTasks(data.logs, data.tasks)
}
function setLogsAndTasks(logs, tasks) {
const res = []
const taskMap = {}
const nodeMap = {}
const userLogs = []
tasks.forEach(task => {
nodeMap[task.unitId] = nodeMap[task.unitId] || [{
unitId: task.unitId,
name: task.unitName,
userIds: [],
des: '正在审核',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary',
isFinish: false
}]
if (task.type == 2) {
taskMap[task.unitId + task.type] = taskMap[task.unitId + task.type] || {
unitId: task.unitId,
name: task.unitName,
userIds: [],
des: '正在查阅',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary'
}
taskMap[task.unitId + task.type].userIds.push(task.userId)
if (nodeMap[task.unitId].length == 1) {
nodeMap[task.unitId].push({
unitId: task.unitId,
name: task.unitName,
userIds: [],
des: '正在查阅',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary',
isFinish: true
})
}
nodeMap[task.unitId][1].userIds.push(task.userId)
}
else {
taskMap[task.unitId] = taskMap[task.unitId] || {
unitId: task.unitId,
name: task.unitName,
userIds: [],
des: '正在审核',
time: `当前-创建时间:${dateFormat(task.createDate)}`,
type: 'primary'
}
taskMap[task.unitId].userIds.push(task.userId)
nodeMap[task.unitId][0].userIds.push(task.userId)
}
})
for (let key in taskMap) {
res.push(taskMap[key])
}
for (let key in nodeMap) {
nodeMap[key] = nodeMap[key].filter(t => t.userIds.length > 0)
}
logs.forEach(log => {
res.push({
unitId: log.unitId,
name: log.unitName,
userIds: [log.userId],
des: log.des ? log.des : log.f_OperationName,
time: dateFormat(log.createDate),
type: 'info'
})
nodeMap[log.unitId] = nodeMap[log.unitId] || []
nodeMap[log.unitId].push({
unitId: log.unitId,
name: log.unitName,
userIds: [log.userId],
time: dateFormat(log.createDate),
des: log.des ? log.des : log.f_OperationName,
type: 'info',
isFinish: true
})
if (log.f_TaskType == 1 && !['sign'].includes(log.f_OperationCode)) { //
const userLogIndex = userLogs.findIndex(t => t.id == log.unitId)
if (userLogIndex == -1) {
userLogs.push({
id: log.unitId,
name: log.unitName,
user: log.f_UserName,
time: dateFormat(log.createDate),
des: log.des,
img: log.f_StampImg
})
}
}
})
designerData.logs = res
designerData.nodeMap = nodeMap
designerData.userLogs = userLogs.sort(function (a, b) {
return b.time < a.time ? -1 : 1
})
//console.log(logs,'logs')
}
function closePreview() {
if (!id) {
tabStore.closeTabByKey('/dashboard/task_preview/detail', router);
} else {
// /dashboard/create_preview/add?id=1
tabStore.closeTabByKey('/dashboard/task_preview/detail?id=' + id, router);
}
}
onBeforeMount(() => {
getDetailInfo()
getTaskInfo()
})
</script>
<style lang="less" scoped>
.preview-box {
background-color: @component-background;
.btn-box {
padding: 10px;
justify-content: flex-end;
display: flex;
}
}
.form-box {
width: 480px;
}
</style>

View File

@ -107,7 +107,7 @@
},
});
function handleDetail(record){
go('/dashboard/task_preview/detail?id=' + record.id);
go('/dashboard/task_look_preview/detail?processId=' + record.id);
}
function handleRevocation(record){
console.log(record)

View File

@ -20,7 +20,7 @@
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { reactive ,h} from 'vue'
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { PageWrapper } from '@/components/Page';
import { getLoadMyUncompletedPage } from '@/api/sys/WFTask'
@ -103,7 +103,7 @@
},
});
function handleDetail(record){
go('/dashboard/task_preview/detail?id=' + record.id);
go('/dashboard/task_audit_preview/detail?processId=' + record.processId+"&taskId="+record.id);
}

View File

@ -129,7 +129,7 @@
const userInfo = await userStore.login({
password: data.password,
account: data.account,
mode: 'modal', //
mode: 'none', //
});
console.log(userInfo)
localStorage.setItem('fireUserLoginName',userInfo.name)